Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions laptop Allocation/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python-envs.pythonProjects": []
}
87 changes: 87 additions & 0 deletions laptop Allocation/laptop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from dataclasses import dataclass
from enum import Enum
from typing import Dict, List
import sys
import numpy as np #to build and mnaiplate our sadness grid
from scipy.optimize import linear_sum_assignment #to find optimal laptop allocaation to minimize sadness across all users

class OperatingSystem(Enum):
MACOS = "macOS"
ARCH = "Arch Linux"
UBUNTU = "Ubuntu"

@dataclass(frozen=True)
class Person:
name: str
age: int
# Sorted in order of preference, most preferred is first.
preferred_operating_systems: List[OperatingSystem]


@dataclass(frozen=True)
class Laptop:
id: int
manufacturer: str
model: str
screen_size_in_inches: float
operating_system: OperatingSystem

#library of laptops
laptop = [
Laptop(id=1, manufacturer="Dell", model="XPS", screen_size_in_inches=13, operating_system=OperatingSystem.ARCH),
Laptop(id=2, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system=OperatingSystem.UBUNTU),
Laptop(id=3, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system=OperatingSystem.UBUNTU),
Laptop(id=4, manufacturer="Apple", model="macBook", screen_size_in_inches=13, operating_system=OperatingSystem.MACOS),
Laptop(id=5, manufacturer="Apple", model="macBook", screen_size_in_inches=13, operating_system=OperatingSystem.MACOS),
Laptop(id=6, manufacturer="Dell", model="macBook", screen_size_in_inches=13, operating_system=OperatingSystem.ARCH),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dell have started making macBooks? who knew? 😄

Laptop(id=7, manufacturer="Apple", model="macBook", screen_size_in_inches=13, operating_system=OperatingSystem.MACOS),
Laptop(id=8, manufacturer="Apple", model="macBook", screen_size_in_inches=13, operating_system=OperatingSystem.MACOS),
]
# Preset dataset of people
people = [
Person(name="Sara", age=31, preferred_operating_systems=[OperatingSystem.ARCH,OperatingSystem.UBUNTU]),
Person(name="Shabs", age=40, preferred_operating_systems=[OperatingSystem.ARCH,OperatingSystem.MACOS,OperatingSystem.UBUNTU]),
Person(name="Jawad", age= 36, preferred_operating_systems=[OperatingSystem.MACOS,OperatingSystem.UBUNTU,OperatingSystem.ARCH]),
Person(name="Mike", age=35, preferred_operating_systems=[OperatingSystem.MACOS,OperatingSystem.ARCH]),
Person(name="Mawra", age=28, preferred_operating_systems=[OperatingSystem.MACOS]),
Person(name="Fatma", age= 22, preferred_operating_systems=[OperatingSystem.UBUNTU,OperatingSystem.ARCH]),
Person(name="Muhib", age= 19, preferred_operating_systems=[OperatingSystem.MACOS,OperatingSystem.UBUNTU]),

]

def sadness(person: Person, laptop: Laptop) -> int:
if laptop.operating_system == person.preferred_operating_systems[0]:
return 0
elif len(person.preferred_operating_systems) > 1 and laptop.operating_system == person.preferred_operating_systems[1]:
return 1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard-coding the 0,1,2 feels clunky here. If you're explicitly saying that if it's not in the top 3 it's terrible, then that's one thing. But this code looks like a failure to use index to get the ranking of the laptop. Either explicitly have a "maximum rank for any happiness" (as you appear to have here, but don't say) or use and index (making sure it copes with not found correctly)

elif len(person.preferred_operating_systems) > 2 and laptop.operating_system == person.preferred_operating_systems[2]:
return 2
else:
return 100

#I have chose to use Hungarian Algorithm Approach to solve the problem.

def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Person, Laptop]:
n_people = len(people) #length of people []
n_laptops = len(laptops) #length of laptops []
if n_laptops < n_people:
raise ValueError("Not enough laptops to allocate one to each person.")
sadness_matrix = np.zeros((n_people, n_laptops), dtype= int) #npzero mean each cell in 2d grid is a zero and dtype is datatype int so it int 0
for i, person in enumerate(people): #enumerate gives us both index position and the item itself from the list
for j, laptop in enumerate(laptops):
sadness_matrix[i,j] = sadness(person, laptop) #this matrix represents complete laptop allocation
# Hungarian algorithm to run on our sadness matrix
row_indices, col_indices = linear_sum_assignment(sadness_matrix) #which person which laptop

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're using a "black box" algorithm here. It is entirely opaque what it is doing or how it is working. For me, this would trigger adding some test files to check that it is working how I expect it to.

# Map people to laptops
allocation = {}
for i, j in zip(row_indices, col_indices):#it pairs up results (person indices and laptop indices). The loop then uses those pairs to build the final allocation dictionary
allocation[people[i].name] = laptops[j]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've declared the function as Dict[Person,Laptop] but are return Dict[str,Laptop]. I'm guessing you actually want the former?

return allocation


def print_allocation(allocation: Dict[Person, Laptop]):
for name, lap in allocation.items():
print(f"{name} gets Laptop {lap.id} ({lap.operating_system.value})")

allocation = allocate_laptops(people, laptop)
print_allocation(allocation)
Loading