44 # I tried to write explicit code that does not require any |
44 # I tried to write explicit code that does not require any |
45 # additional comments (with the exception of the set notation for |
45 # additional comments (with the exception of the set notation for |
46 # the convenience of any mathematicians that happen to read this |
46 # the convenience of any mathematicians that happen to read this |
47 # piece of code ;). |
47 # piece of code ;). |
48 |
48 |
49 def __init__(self, orgs, popularity, mentors, slots, |
49 def __init__(self, orgs, popularity, max, slots, |
50 max_slots_per_org, min_slots_per_org, iterative): |
50 max_slots_per_org, min_slots_per_org, iterative): |
51 """Initializes the allocator. |
51 """Initializes the allocator. |
52 |
52 |
53 Args: |
53 Args: |
54 orgs: a list of all the orgs that need to be allocated |
54 orgs: a list of all the orgs that need to be allocated |
70 self.min_slots_per_org = min_slots_per_org |
70 self.min_slots_per_org = min_slots_per_org |
71 self.orgs = set(orgs) |
71 self.orgs = set(orgs) |
72 self.popularity = None |
72 self.popularity = None |
73 self.total_popularity = None |
73 self.total_popularity = None |
74 self.initial_popularity = popularity |
74 self.initial_popularity = popularity |
75 self.mentors = mentors |
75 self.max = max |
76 self.iterative = iterative |
76 self.iterative = iterative |
77 |
77 |
78 def allocate(self, locked_slots, adjusted_slots): |
78 def allocate(self, locked_slots): |
79 """Allocates the slots and returns the result. |
79 """Allocates the slots and returns the result. |
80 |
80 |
81 Args: |
81 Args: |
82 locked_slots: a dict with orgs and the number of slots they get |
82 locked_slots: a dict with orgs and the number of slots they get |
83 adjusted_slots: a dict with orgs and the number of extra slots they get |
83 adjusted_slots: a dict with orgs and the number of extra slots they get |
84 """ |
84 """ |
85 |
85 |
86 self.locked_slots = locked_slots |
86 self.locked_slots = locked_slots |
87 self.adjusted_slots = adjusted_slots |
|
88 |
87 |
89 self.buildSets() |
88 self.buildSets() |
90 |
89 |
91 if not sum(self.popularity.values()) or not sum(self.mentors.values()): |
90 if not sum(self.popularity.values()) or not sum(self.max.values()): |
92 return self.popularity |
91 return self.popularity |
93 |
92 |
94 if self.iterative: |
93 if self.iterative: |
95 return self.iterativeAllocation() |
94 return self.iterativeAllocation() |
96 else: |
95 else: |
102 |
101 |
103 popularity = self.initial_popularity.copy() |
102 popularity = self.initial_popularity.copy() |
104 |
103 |
105 # set s |
104 # set s |
106 locked_slots = self.locked_slots |
105 locked_slots = self.locked_slots |
107 adjusted_slots = self.adjusted_slots |
|
108 |
106 |
109 # set a and b |
107 # set a and b |
110 locked_orgs = set(locked_slots.keys()) |
108 locked_orgs = set(locked_slots.keys()) |
111 adjusted_orgs = set(adjusted_slots.keys()) |
|
112 |
109 |
113 # set a' and b' |
110 # set a' and b' |
114 unlocked_orgs = self.orgs.difference(locked_orgs) |
111 unlocked_orgs = self.orgs.difference(locked_orgs) |
115 |
112 |
116 # set a*b and a'*b' |
|
117 locked_and_adjusted_orgs = locked_orgs.intersection(adjusted_orgs) |
|
118 |
|
119 # a+o and b+o should be o |
113 # a+o and b+o should be o |
120 locked_orgs_or_orgs = self.orgs.union(locked_orgs) |
114 locked_orgs_or_orgs = self.orgs.union(locked_orgs) |
121 adjusted_orgs_or_orgs = self.orgs.union(adjusted_orgs) |
|
122 |
115 |
123 total_popularity = sum(popularity.values()) |
116 total_popularity = sum(popularity.values()) |
124 |
|
125 # an item can be only a or b, so a*b should be empty |
|
126 if locked_and_adjusted_orgs: |
|
127 raise Error("Cannot have an org locked and adjusted") |
|
128 |
117 |
129 # a+o should be o, testing length is enough though |
118 # a+o should be o, testing length is enough though |
130 if len(locked_orgs_or_orgs) != len(self.orgs): |
119 if len(locked_orgs_or_orgs) != len(self.orgs): |
131 raise Error("Unknown org as locked slot") |
120 raise Error("Unknown org as locked slot") |
132 |
121 |
133 # same for b+o |
|
134 if len(adjusted_orgs_or_orgs) != len(self.orgs): |
|
135 raise Error("Unknown org as adjusted slot") |
|
136 |
|
137 self.adjusted_orgs = adjusted_orgs |
|
138 self.unlocked_orgs = unlocked_orgs |
122 self.unlocked_orgs = unlocked_orgs |
139 self.locked_orgs = locked_orgs |
123 self.locked_orgs = locked_orgs |
140 self.popularity = popularity |
124 self.popularity = popularity |
141 self.total_popularity = total_popularity |
125 self.total_popularity = total_popularity |
142 |
126 |
145 """ |
129 """ |
146 |
130 |
147 slots = int(math.floor(float(slots))) |
131 slots = int(math.floor(float(slots))) |
148 slots = min(slots, self.max_slots_per_org) |
132 slots = min(slots, self.max_slots_per_org) |
149 slots = max(slots, self.min_slots_per_org) |
133 slots = max(slots, self.min_slots_per_org) |
150 slots = min(slots, self.mentors[org]) |
134 slots = min(slots, self.max[org]) |
151 |
135 |
152 return slots |
136 return slots |
153 |
137 |
154 def iterativeAllocation(self): |
138 def iterativeAllocation(self): |
155 """A simple iterative algorithm. |
139 """A simple iterative algorithm. |