From 4afdc9f14725c3d780bb909236ac31231bc6eec4 Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Mon, 20 Apr 2026 18:14:16 +0100 Subject: [PATCH 1/4] feat: implement laptop allocation using permutation and sadness matrix --- Sprint5-exercise/laptop-allocation.py | 95 +++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 Sprint5-exercise/laptop-allocation.py diff --git a/Sprint5-exercise/laptop-allocation.py b/Sprint5-exercise/laptop-allocation.py new file mode 100644 index 000000000..365644587 --- /dev/null +++ b/Sprint5-exercise/laptop-allocation.py @@ -0,0 +1,95 @@ +from enum import Enum +from typing import List,Dict +from dataclasses import dataclass + +from itertools import permutations +import sys + +class OperatingSystem(Enum): + UBUNTU = "ubuntu" + MACOS="makos" + ARCH = "arch linux" + +@dataclass (frozen=True) +class Person: + name:str + age:int + preferred_operating_system:List[OperatingSystem] + + +@dataclass(frozen=True) +class Laptop: + id: int + manufacturer: str + model: str + screen_size_in_inches: float + operating_system: OperatingSystem + +def sadness(person:Person,operating_system:OperatingSystem)->int: + sad:int =100 + for index, os in enumerate(person.preferred_operating_system): + if(os==operating_system): + sad=index + return sad + + return sad + +def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Person, Laptop]: + how_many_people= len(people) + how_many_laptops = len(laptops) + if how_many_laptops < how_many_people: + raise ValueError("Not enough laptops for all people") + matrix = [[0 for i in range(how_many_laptops)] for _ in range(how_many_people)] + for i, person in enumerate(people): + for j,laptop in enumerate(laptops): + matrix[i][j] = sadness(person,laptop.operating_system) + + best_perm = None + min_sadness=100000000000 + for perm in permutations(range(how_many_laptops)): + + total =0 + for i in range(how_many_people): + + total+= matrix[i][perm[i]] + + + if total< min_sadness : + min_sadness = total + best_perm = perm + results = {} + for index, person in enumerate(people): + results[person.name]= laptops[best_perm[index]] + + + return results + +def main()->None: + people = [ + Person( + name="Imran", + age=22, + preferred_operating_system=[OperatingSystem.UBUNTU, OperatingSystem.ARCH,OperatingSystem.MACOS], + ), + Person( + name="Eliza", + age=34, + preferred_operating_system=[OperatingSystem.UBUNTU, OperatingSystem.ARCH], + ), + Person( + name="Ahmad", + age=34, + preferred_operating_system=[OperatingSystem.MACOS], + ), + + ] + laptops = [ + Laptop(id=1, manufacturer="Dell", model="XPS", screen_size_in_inches=13, operating_system=OperatingSystem.MACOS), + Laptop(id=2, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system=OperatingSystem.MACOS), + Laptop(id=3, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system=OperatingSystem.UBUNTU), + + ] + + print(allocate_laptops(people,laptops)) + +main() \ No newline at end of file From 532fc1bf14b64ef6b338c0ca32c3205bdfcdbef4 Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Tue, 21 Apr 2026 16:11:54 +0100 Subject: [PATCH 2/4] reformat --- Sprint5-exercise/laptop-allocation.py | 148 +++++++++++++++----------- 1 file changed, 87 insertions(+), 61 deletions(-) diff --git a/Sprint5-exercise/laptop-allocation.py b/Sprint5-exercise/laptop-allocation.py index 365644587..075b0ff1c 100644 --- a/Sprint5-exercise/laptop-allocation.py +++ b/Sprint5-exercise/laptop-allocation.py @@ -1,20 +1,22 @@ from enum import Enum -from typing import List,Dict +from typing import List, Dict from dataclasses import dataclass from itertools import permutations -import sys + + class OperatingSystem(Enum): UBUNTU = "ubuntu" - MACOS="makos" + MACOS = "macos" ARCH = "arch linux" -@dataclass (frozen=True) + +@dataclass class Person: - name:str - age:int - preferred_operating_system:List[OperatingSystem] + name: str + age: int + preferred_operating_system: List[OperatingSystem] @dataclass(frozen=True) @@ -25,71 +27,95 @@ class Laptop: screen_size_in_inches: float operating_system: OperatingSystem -def sadness(person:Person,operating_system:OperatingSystem)->int: - sad:int =100 + +def sadness(person: Person, operating_system: OperatingSystem) -> int: + sad: int = 100 for index, os in enumerate(person.preferred_operating_system): - if(os==operating_system): - sad=index + if os == operating_system: + sad = index return sad return sad -def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Person, Laptop]: - how_many_people= len(people) + +def allocate_laptops( + people: List[Person], laptops: List[Laptop] +) -> Dict[Person, Laptop]: + how_many_people = len(people) how_many_laptops = len(laptops) if how_many_laptops < how_many_people: - raise ValueError("Not enough laptops for all people") + raise ValueError("Not enough laptops for all people") matrix = [[0 for i in range(how_many_laptops)] for _ in range(how_many_people)] for i, person in enumerate(people): - for j,laptop in enumerate(laptops): - matrix[i][j] = sadness(person,laptop.operating_system) - + for j, laptop in enumerate(laptops): + matrix[i][j] = sadness(person, laptop.operating_system) + best_perm = None - min_sadness=100000000000 + min_sadness = 100000000000 for perm in permutations(range(how_many_laptops)): - - total =0 - for i in range(how_many_people): - - total+= matrix[i][perm[i]] - - - if total< min_sadness : + + total = 0 + for i in range(how_many_people): + + total += matrix[i][perm[i]] + + if total < min_sadness: min_sadness = total best_perm = perm - results = {} + results = {} for index, person in enumerate(people): - results[person.name]= laptops[best_perm[index]] - - - return results - -def main()->None: - people = [ - Person( - name="Imran", - age=22, - preferred_operating_system=[OperatingSystem.UBUNTU, OperatingSystem.ARCH,OperatingSystem.MACOS], - ), - Person( - name="Eliza", - age=34, - preferred_operating_system=[OperatingSystem.UBUNTU, OperatingSystem.ARCH], - ), - Person( - name="Ahmad", - age=34, - preferred_operating_system=[OperatingSystem.MACOS], - ), - - ] - laptops = [ - Laptop(id=1, manufacturer="Dell", model="XPS", screen_size_in_inches=13, operating_system=OperatingSystem.MACOS), - Laptop(id=2, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system=OperatingSystem.MACOS), - Laptop(id=3, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system=OperatingSystem.UBUNTU), - - ] - - print(allocate_laptops(people,laptops)) - -main() \ No newline at end of file + results[person.name] = laptops[best_perm[index]] + + return results + + +def main() -> None: + people = [ + Person( + name="Imran", + age=22, + preferred_operating_system=[ + OperatingSystem.UBUNTU, + OperatingSystem.ARCH, + OperatingSystem.MACOS, + ], + ), + Person( + name="Eliza", + age=34, + preferred_operating_system=[OperatingSystem.UBUNTU, OperatingSystem.ARCH], + ), + Person( + name="Ahmad", + age=34, + preferred_operating_system=[OperatingSystem.MACOS], + ), + ] + laptops = [ + Laptop( + id=1, + manufacturer="Dell", + model="XPS", + screen_size_in_inches=13, + operating_system=OperatingSystem.MACOS, + ), + Laptop( + id=2, + manufacturer="Dell", + model="XPS", + screen_size_in_inches=15, + operating_system=OperatingSystem.MACOS, + ), + Laptop( + id=3, + manufacturer="Dell", + model="XPS", + screen_size_in_inches=15, + operating_system=OperatingSystem.UBUNTU, + ), + ] + + print(allocate_laptops(people, laptops)) + + +main() From 99908444cf3a98223a9963c55806b9f006017cc2 Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Tue, 5 May 2026 19:57:55 +0100 Subject: [PATCH 3/4] Use Hungarian algorthms and avoids the unhashable List problem --- Sprint5-exercise/laptop-allocation.py | 54 +++++++++++---------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/Sprint5-exercise/laptop-allocation.py b/Sprint5-exercise/laptop-allocation.py index 075b0ff1c..e74d3ecd4 100644 --- a/Sprint5-exercise/laptop-allocation.py +++ b/Sprint5-exercise/laptop-allocation.py @@ -1,9 +1,7 @@ from enum import Enum -from typing import List, Dict +from typing import Dict from dataclasses import dataclass - -from itertools import permutations - +from scipy.optimize import linear_sum_assignment class OperatingSystem(Enum): @@ -12,11 +10,11 @@ class OperatingSystem(Enum): ARCH = "arch linux" -@dataclass +@dataclass (frozen=True) class Person: name: str age: int - preferred_operating_system: List[OperatingSystem] + preferred_operating_system: tuple[OperatingSystem,...] @dataclass(frozen=True) @@ -39,56 +37,48 @@ def sadness(person: Person, operating_system: OperatingSystem) -> int: def allocate_laptops( - people: List[Person], laptops: List[Laptop] + people: list[Person], laptops: list[Laptop] ) -> Dict[Person, Laptop]: how_many_people = len(people) how_many_laptops = len(laptops) if how_many_laptops < how_many_people: raise ValueError("Not enough laptops for all people") - matrix = [[0 for i in range(how_many_laptops)] for _ in range(how_many_people)] + sadness_matrix = [[0 for i in range(how_many_laptops)] for _ in range(how_many_people)] + for i, person in enumerate(people): for j, laptop in enumerate(laptops): - matrix[i][j] = sadness(person, laptop.operating_system) - - best_perm = None - min_sadness = 100000000000 - for perm in permutations(range(how_many_laptops)): - - total = 0 - for i in range(how_many_people): + sadness_matrix[i][j] = sadness(person, laptop.operating_system) + # print(sadness_matrix); + row_indexes, column_indexes = linear_sum_assignment(sadness_matrix) + result = {} - total += matrix[i][perm[i]] - - if total < min_sadness: - min_sadness = total - best_perm = perm - results = {} - for index, person in enumerate(people): - results[person.name] = laptops[best_perm[index]] - - return results + for row, column in zip(row_indexes, column_indexes): + person = people[row] + laptop = laptops[column] + result[person] = laptop + return result def main() -> None: people = [ Person( name="Imran", age=22, - preferred_operating_system=[ + preferred_operating_system=( OperatingSystem.UBUNTU, OperatingSystem.ARCH, OperatingSystem.MACOS, - ], + ), ), Person( name="Eliza", age=34, - preferred_operating_system=[OperatingSystem.UBUNTU, OperatingSystem.ARCH], + preferred_operating_system=(OperatingSystem.UBUNTU,), ), Person( name="Ahmad", age=34, - preferred_operating_system=[OperatingSystem.MACOS], + preferred_operating_system=(OperatingSystem.UBUNTU, OperatingSystem.MACOS,), ), ] laptops = [ @@ -97,11 +87,11 @@ def main() -> None: manufacturer="Dell", model="XPS", screen_size_in_inches=13, - operating_system=OperatingSystem.MACOS, + operating_system=OperatingSystem.ARCH ), Laptop( id=2, - manufacturer="Dell", + manufacturer="HM", model="XPS", screen_size_in_inches=15, operating_system=OperatingSystem.MACOS, From 981f35c29dcdfe4f69e632e8b426a3eed9b553f7 Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Tue, 5 May 2026 20:02:39 +0100 Subject: [PATCH 4/4] use preferred_operating_system.index() --- Sprint5-exercise/laptop-allocation.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Sprint5-exercise/laptop-allocation.py b/Sprint5-exercise/laptop-allocation.py index e74d3ecd4..8d8a474a0 100644 --- a/Sprint5-exercise/laptop-allocation.py +++ b/Sprint5-exercise/laptop-allocation.py @@ -27,14 +27,10 @@ class Laptop: def sadness(person: Person, operating_system: OperatingSystem) -> int: - sad: int = 100 - for index, os in enumerate(person.preferred_operating_system): - if os == operating_system: - sad = index - return sad - - return sad - + try: + return person.preferred_operating_system.index(operating_system) + except ValueError: + return 100 def allocate_laptops( people: list[Person], laptops: list[Laptop]