app/soc/logic/allocations.py
changeset 1751 17c7a7a48dc7
parent 1748 f789ffe213a3
child 1854 79c9f683f23b
--- a/app/soc/logic/allocations.py	Sun Mar 08 15:00:59 2009 +0000
+++ b/app/soc/logic/allocations.py	Sun Mar 08 16:26:17 2009 +0000
@@ -47,24 +47,19 @@
   # the convenience of any mathematicians that happen to read this
   # piece of code ;).
 
-  def __init__(self, orgs, applications, mentors, slots,
+  def __init__(self, orgs, popularity, mentors, slots,
                max_slots_per_org, min_slots_per_org, iterative):
     """Initializes the allocator.
 
     Args:
       orgs: a list of all the orgs that need to be allocated
-      applications: a dictionary with for each org a list of applicants
+      popularity: the amount of applications per org
       mentors: the amount of assigned mentors per org
       slots: the total amount of available slots
       max_slots_per_org: how many slots an org should get at most
       min_slots_per_org: how many slots an org should at least get
     """
 
-    all_applications = []
-
-    for _, value in applications.iteritems():
-      all_applications += value
-    
     self.locked_slots = {}
     self.adjusted_slots = {}
     self.adjusted_orgs = []
@@ -74,9 +69,8 @@
     self.max_slots_per_org = max_slots_per_org
     self.min_slots_per_org = min_slots_per_org
     self.orgs = set(orgs)
-    self.applications = applications
+    self.initial_popularity = popularity
     self.mentors = mentors
-    self.all_applications = set(all_applications)
     self.iterative = iterative
 
   def allocate(self, locked_slots, adjusted_slots):
@@ -92,6 +86,9 @@
 
     self.buildSets()
 
+    if not sum(self.popularity.values()) or not sum(self.mentors.values()):
+      return {}
+
     if self.iterative:
       return self.iterativeAllocation()
     else:
@@ -101,8 +98,9 @@
     """Allocates slots with the specified constraints
     """
 
+    popularity = self.initial_popularity.copy()
+
     # set s
-    all_applications = self.all_applications
     locked_slots = self.locked_slots
     adjusted_slots = self.adjusted_slots
 
@@ -112,17 +110,16 @@
 
     # set a' and b'
     unlocked_orgs = self.orgs.difference(locked_orgs)
-    # unadjusted_orgs = self.orgs.difference(adjusted_orgs)
 
     # set a*b and a'*b'
     locked_and_adjusted_orgs = locked_orgs.intersection(adjusted_orgs)
-    
-    # unlocked_and_unadjusted_orgs = unlocked_orgs.intersection(unadjusted_orgs)
 
     # a+o and b+o should be o
     locked_orgs_or_orgs = self.orgs.union(locked_orgs)
     adjusted_orgs_or_orgs = self.orgs.union(adjusted_orgs)
 
+    total_popularity = sum(popularity.values())
+
     # an item can be only a or b, so a*b should be empty
     if locked_and_adjusted_orgs:
       raise Error("Cannot have an org locked and adjusted")
@@ -135,17 +132,11 @@
     if len(adjusted_orgs_or_orgs) != len(self.orgs):
       raise Error("Unknown org as adjusted slot")
 
-    # set l and l'
-    locked_applications = set(itertools.chain(*locked_slots.keys()))
-    unlocked_applications = all_applications.difference(locked_applications)
-
     self.adjusted_orgs = adjusted_orgs
     self.unlocked_orgs = unlocked_orgs
     self.locked_orgs = locked_orgs
-    self.unlocked_applications = unlocked_applications
-
-    popularity = ((k, len(v)) for k, v in self.applications.iteritems())
-    self.popularity = dict(popularity)
+    self.popularity = popularity
+    self.total_popularity = total_popularity
 
   def rangeSlots(self, slots, org):
     """Returns the amount of slots for the org within the required bounds.
@@ -166,23 +157,20 @@
     adjusted_slots = self.adjusted_slots
     locked_orgs = self.locked_orgs
     locked_slots = self.locked_slots
-    unlocked_applications = self.unlocked_applications
 
-    unlocked_applications_count = len(unlocked_applications)
-    unallocated_applications_count = unlocked_applications_count
+    unallocated_popularity = self.total_popularity - len(locked_slots)
 
     available_slots = self.slots
     allocations = {}
 
     for org in self.orgs:
-      org_applications = self.applications[org]
-      org_applications_count = len(org_applications)
+      popularity = self.popularity[org]
       mentors = self.mentors[org]
 
       if org in locked_orgs:
         slots = locked_slots[org]
-      elif unallocated_applications_count:
-        weight = float(org_applications_count) / float(unallocated_applications_count)
+      elif unallocated_popularity:
+        weight = float(popularity) / float(unallocated_popularity)
         slots = int(math.floor(weight*available_slots))
 
       if org in adjusted_orgs:
@@ -194,7 +182,7 @@
 
       allocations[org] = slots
       available_slots -= slots
-      unallocated_applications_count -= org_applications_count
+      unallocated_popularity -= popularity
 
     return allocations
 
@@ -207,9 +195,7 @@
     locked_orgs = self.locked_orgs
     locked_slots = self.locked_slots
     unlocked_orgs = self.unlocked_orgs
-    unlocked_applications = self.unlocked_applications
-
-    total_popularity = sum(self.popularity.values())
+    total_popularity = self.total_popularity
 
     available_slots = self.slots
     allocations = {}
@@ -223,6 +209,7 @@
       total_popularity -= popularity
       available_slots -= slots
       allocations[org] = slots
+      del self.popularity[org]
 
     # adjust the orgs in need of adjusting
     for org in adjusted_orgs:
@@ -231,6 +218,7 @@
       adjustment = (float(total_popularity)/float(available_slots))*slots
       adjustment = int(math.ceil(adjustment))
       self.popularity[org] += adjustment
+      total_popularity += adjustment
 
     # adjust the popularity so that the invariants are always met
     for org in unlocked_orgs:
@@ -248,9 +236,6 @@
 
     # do the actual calculation
     for org in unlocked_orgs:
-      org_applications = self.applications[org]
-      org_applications_count = len(org_applications)
-
       popularity = self.popularity[org]
       raw_slots = (float(popularity)/float(total_popularity))*available_slots
       slots = int(math.floor(raw_slots))