45 # I tried to write explicit code that does not require any |
45 # I tried to write explicit code that does not require any |
46 # additional comments (with the exception of the set notation for |
46 # additional comments (with the exception of the set notation for |
47 # the convenience of any mathematicians that happen to read this |
47 # the convenience of any mathematicians that happen to read this |
48 # piece of code ;). |
48 # piece of code ;). |
49 |
49 |
50 def __init__(self, orgs, applications, slots, max_slots_per_org): |
50 def __init__(self, orgs, applications, mentors, slots, |
|
51 max_slots_per_org, min_slots_per_org, iterative): |
51 """Initializes the allocator. |
52 """Initializes the allocator. |
52 |
53 |
53 Args: |
54 Args: |
54 orgs: a list of all the orgs that need to be allocated |
55 orgs: a list of all the orgs that need to be allocated |
55 applications: a dictionary with for each org a list of applicants |
56 applications: a dictionary with for each org a list of applicants |
|
57 mentors: the amount of assigned mentors per org |
56 slots: the total amount of available slots |
58 slots: the total amount of available slots |
|
59 max_slots_per_org: how many slots an org should get at most |
|
60 min_slots_per_org: how many slots an org should at least get |
57 """ |
61 """ |
58 |
62 |
59 all_applications = [] |
63 all_applications = [] |
60 |
64 |
61 for _, value in applications.iteritems(): |
65 for _, value in applications.iteritems(): |
62 all_applications += value |
66 all_applications += value |
63 |
67 |
64 self.locked_slots = {} |
68 self.locked_slots = {} |
65 self.adjusted_slots = {} |
69 self.adjusted_slots = {} |
66 self.adjusted_orgss = [] |
70 self.adjusted_orgs = [] |
67 self.locked_orgs = [] |
71 self.locked_orgs = [] |
68 self.unlocked_applications = [] |
72 self.unlocked_applications = [] |
69 self.slots = slots |
73 self.slots = slots |
70 self.max_slots_per_org = max_slots_per_org |
74 self.max_slots_per_org = max_slots_per_org |
|
75 self.min_slots_per_org = min_slots_per_org |
71 self.orgs = set(orgs) |
76 self.orgs = set(orgs) |
72 self.applications = applications |
77 self.applications = applications |
|
78 self.mentors = mentors |
73 self.all_applications = set(all_applications) |
79 self.all_applications = set(all_applications) |
|
80 self.iterative = iterative |
74 |
81 |
75 def allocate(self, locked_slots, adjusted_slots): |
82 def allocate(self, locked_slots, adjusted_slots): |
76 """Allocates the slots and returns the result. |
83 """Allocates the slots and returns the result. |
77 |
84 |
78 Args: |
85 Args: |
127 |
134 |
128 # set l and l' |
135 # set l and l' |
129 locked_applications = set(itertools.chain(*locked_slots.keys())) |
136 locked_applications = set(itertools.chain(*locked_slots.keys())) |
130 unlocked_applications = all_applications.difference(locked_applications) |
137 unlocked_applications = all_applications.difference(locked_applications) |
131 |
138 |
132 self.adjusted_orgss = adjusted_orgs |
139 self.adjusted_orgs = adjusted_orgs |
|
140 self.unlocked_orgs = unlocked_orgs |
133 self.locked_orgs = locked_orgs |
141 self.locked_orgs = locked_orgs |
134 self.unlocked_applications = unlocked_applications |
142 self.unlocked_applications = unlocked_applications |
|
143 |
|
144 popularity = ((k, len(v)) for k, v in self.applications.iteritems()) |
|
145 self.popularity = dict(popularity) |
135 |
146 |
136 def iterativeAllocation(self): |
147 def iterativeAllocation(self): |
137 """A simple iterative algorithm. |
148 """A simple iterative algorithm. |
138 """ |
149 """ |
139 |
150 |
140 adjusted_orgs = self.adjusted_orgss |
151 adjusted_orgs = self.adjusted_orgs |
141 adjusted_slots = self.adjusted_slots |
152 adjusted_slots = self.adjusted_slots |
142 locked_orgs = self.locked_orgs |
153 locked_orgs = self.locked_orgs |
143 locked_slots = self.locked_slots |
154 locked_slots = self.locked_slots |
144 unlocked_applications = self.unlocked_applications |
155 unlocked_applications = self.unlocked_applications |
145 |
156 |
150 allocations = {} |
161 allocations = {} |
151 |
162 |
152 for org in self.orgs: |
163 for org in self.orgs: |
153 org_applications = self.applications[org] |
164 org_applications = self.applications[org] |
154 org_applications_count = len(org_applications) |
165 org_applications_count = len(org_applications) |
|
166 mentors = self.mentors[org] |
155 |
167 |
156 if org in locked_orgs: |
168 if org in locked_orgs: |
157 slots = locked_slots[org] |
169 slots = locked_slots[org] |
158 else: |
170 else: |
159 weight = float(org_applications_count) / unallocated_applications_count |
171 weight = float(org_applications_count) / unallocated_applications_count |
161 |
173 |
162 if org in adjusted_orgs: |
174 if org in adjusted_orgs: |
163 slots += adjusted_slots[org] |
175 slots += adjusted_slots[org] |
164 |
176 |
165 slots = min(slots, self.max_slots_per_org) |
177 slots = min(slots, self.max_slots_per_org) |
166 slots = min(slots, org_applications_count) |
178 slots = min(slots, mentors) |
167 slots = min(slots, available_slots) |
179 slots = min(slots, available_slots) |
168 |
180 |
169 allocations[org] = slots |
181 allocations[org] = slots |
170 available_slots -= slots |
182 available_slots -= slots |
171 unallocated_applications_count -= org_applications_count |
183 unallocated_applications_count -= org_applications_count |