def dumbledore(): l_groups = [] l_students = [] for group in Groups.objects: Groups.objects( group_name=group.group_name ).update( members=[], preferences=[] ) group.reload() for student in Students.objects: Students.objects( identikey=student.identikey ).update( group_assigned=None ) student.reload() removeExtraGroups() registerStudents() ret_val = unpopular() if ret_val != 0: return ret_val for group in Groups.objects: l_groups.append(group) for student in Students.objects: l_students.append(student) matched = sortThemStudents(l_students, l_groups) writeToDatabase(matched) success_list = [] for group in matched: s_list = [] print(group.group_name + ":") for student in matched[group]: s_list.append(student) for student in matched[group]: success = 0 if len(student.work_with) > 0: for s in student.work_with: if s in s_list: success += 1 success_list.append(success) # out_string += (student.student_name + "," # + group.group_name + "," # + str(success) + "\n") print("\t" + student.student_name) print(averagePreference()) print(avgFriendsPlaced(success_list)) prefDistribution() count(matched) writeResults() # with open("results.csv", 'w') as fp: # fp.write(out_string) return matched
def registerStudents(): storeIdentikeyListJson() updateCountJson() known_score = 0 learn_score = 0 ip_score = 0 ec = 0 for student in Students.objects: addWorkWith(student) for group in student.preferences: for attr in group.skills: if attr in student.known_skills and known_score < MAX_SKILL_LEN: known_score += KNOWN_WEIGHT if attr in student.learn_skills and learn_score < MAX_SKILL_LEN: learn_score += LEARN_WEIGHT if student.ip_pref == 'NO_PREF': ip_score = 0 elif student.ip_pref == 'RETAIN' and group.ip == 'OPEN': ip_score = IP_WEIGHT else: ip_score = -IP_WEIGHT if student.extra_credit: ec = EXTRA_CREDIT pref = calcGroupPreference(known_score, learn_score, ip_score, ec) pref_doc = Preference(student=student, pref_score=pref) Groups.objects(group_name=group.group_name).update( add_to_set__preferences=pref_doc)
def loadProjects(group_data): print("In Load projects") if len(Groups.objects.all()) > 0: Groups.drop_collection() print("Dropping collections") # group_data = dataSet(group_path) for line in group_data: print("parsing: " + line) parseGroups(line)
def nopeStudents(student, group, matched): if len(student.dont_work_with) > 0: for s in student.dont_work_with: if s in matched[group]: matched[group].remove(s) print("Removing " + s.student_name + " from group " + group.group_name) Groups.objects( group_name=group.group_name, preferences__student=s).update( dec__preferences__S__pref_score=GROUP_WEIGHT * 10) group.reload() return group.preferences, matched
def buildDB(student_path, group_path): #assert(len(student_path) > 0) if len(Groups.objects.all()) > 0: Groups.drop_collection() if len(Students.objects.all()) > 0: Students.drop_collection() student_data = dataSet(student_path) group_data = dataSet(group_path) for line in group_data.readData: g = parseGroups(line) # TODO add proper mongoengine command here if this doesn't work for line in student_data.readData: s = parseStudent(line)
def writeToDatabase(matched): for group in matched: for student in matched[group]: Groups.objects( group_name=group.group_name ).update( add_to_set__members=student ) Students.objects( identikey=student.identikey ).update( group_assigned=group ) group.reload() student.reload()
def partnerUpStudents(student, group): if len(student.work_with) > 0: # group.update(inc__preferences__S__pref_score=GROUP_WEIGHT) Groups.objects(group_name=group.group_name, preferences__student=student).update( inc__preferences__S__pref_score=GROUP_WEIGHT) group.reload() # s_to_update = group(preferences__student=student) # new_score = s_to_update.pref_score + GROUP_WEIGHT # s_to_update.update(pref_score=new_score) for s in student.work_with: Groups.objects(group_name=group.group_name, preferences__student=s).update( inc__preferences__S__pref_score=GROUP_WEIGHT) group.reload() return group.preferences
def removeExtraGroups(): print("REMOVING EXTRA GROUPS") opt_groups = [] opt_dict = {} for group in Groups.objects: if group.option: opt_groups.append(group) for group in opt_groups: if group.opt_category in opt_dict: opt_dict[group.opt_category].append(group) else: opt_dict[group.opt_category] = [group] for cat in opt_dict: del_list = [] max_pref = 100 # Just needs to be greater than 5 chosen_group = None for group in opt_dict[cat]: avg = avgPref(group) if avg < max_pref: max_pref = avg if chosen_group: del_list.append(chosen_group) chosen_group = None chosen_group = group else: del_list.append(group) for group in del_list: print("WARNING: Removing group" + group.group_name) Groups.objects(group_name=group.group_name).delete() for student in Students.objects: if group in student.preferences: ##! We have a couple options here, we can replace removed ##! groups with the chosen group, or just delete the groups ##! TODO Add variable flag to select either replacing or deleting ##! TODO add logic to replace Students.objects( identikey=student.identikey ).update(pull__preferences=group) student.reload()
def addGroup(data): name = data["name"] print("Adding " + name + " to database") paid = data["paid"] ip = data["ipPref"] ##! Have to update the projectInformation.js option = data["option"] if option: opt_category = data["optionCategory"] skills = data["skills"] group_to_add = Groups(group_name=name, paid=paid, ip=ip, option=option, skills=skills) group_to_add.save() if option: group_to_add.update(opt_category=opt_category) group_to_add.reload()
def swapThemStudents(shortGroup, firstPass): print("Fixing " + shortGroup.group_name) for group in Groups.objects: if group == shortGroup: continue if len(group.members) > OPT_SIZE: for student in group.members: if len(shortGroup.members) >= MIN_SIZE: return if (shortGroup in student.preferences and not checkLeader(student, shortGroup) and not finalNopeStudents(student, shortGroup)): Groups.objects(group_name=group.group_name).update( pull__members=student) group.reload() # group.members.remove(student) Groups.objects(group_name=shortGroup.group_name).update( add_to_set__members=student) shortGroup.reload() # shortGroup.members.append(student) if len(group.members) == OPT_SIZE: break if len(group.members) == 0: break elif not firstPass and len(group.members) > MIN_SIZE: #TODO add guard against overdrawing from group to below min_size for student in group.members: if len(group.members) == MIN_SIZE: break if len(shortGroup.members) >= MIN_SIZE: return if (shortGroup in student.preferences and not checkLeader(student, shortGroup) and not finalNopeStudents(student, shortGroup)): Groups.objects(group_name=group.group_name).update( pull__members=student) group.reload() # group.members.remove(student) Groups.objects(group_name=shortGroup.group_name).update( add_to_set__members=student) shortGroup.reload()
def sortThemStudents(): fall_through = False students_free = [] for student in Students.objects: students_free.append(student) matched = {} student_prefers = {} group_prefers = {} modPrefsForStudents() for student in Students.objects: student_prefers[student] = student.preferences for group in Groups.objects: # pref_list = [] # for pref in group.preferences: # pref_list.append(pref) group_prefers[group] = group.preferences ##! First step is to ensure lightly chosen paid groups are filled ret, paid_dict = payForStudents() if ret != 0: return ret if paid_dict: for g in paid_dict: for s in paid_dict[g]: matched[g].append(s) students_free.remove(s) while students_free: s = students_free.pop(0) s_list = student_prefers[s] if len(s_list) < 1: print(s.student_name + " is out of options") return 1, matched g = s_list.pop(0) # g_name = g_ref.group_name # index = 0 # g = None # for group in groups: # if group.group_name == g_name: # g = group match = matched.get(g) if not match: # group has no matches yet # print(g.group_name + " has no matches yet.") ##! TODO So much code repetition, fix this noise matched[g] = [s] if (s.leadership != "STRONG_FOLLOW" and s.leadership != "STRONG_LEAD"): Groups.objects(group_name=g.group_name).update(has_leader=True) g.reload() s.reload() elif s.leadership == "STRONG_LEAD": Groups.objects(group_name=g.group_name).update( has_strong_leader=True, has_leader=True) g.reload() s.reload() group_prefers[g] = partnerUpStudents(s, g) group_prefers[g], matched = nopeStudents(s, g, matched) elif len(match) < OPT_SIZE and not fall_through: #Open space in group # print(g.group_name + " is being filled") if checkLeader(s, g): students_free.append(s) else: matched[g].append(s) if (s.leadership != "STRONG_FOLLOW" and s.leadership != "STRONG_LEAD"): Groups.objects(group_name=g.group_name).update( has_leader=True) g.reload() s.reload() if s.leadership == "STRONG_LEAD": Groups.objects(group_name=g.group_name).update( has_strong_leader=True, has_leader=True) g.reload() s.reload() group_prefers[g] = partnerUpStudents(s, g) group_prefers[g], matched = nopeStudents(s, g, matched) ##! Be more lenient on group size for second pass students elif len(match) < MAX_SIZE and fall_through: #Open space in group # print(g.group_name + " is being filled even more") if checkLeader(s, g): students_free.append(s) else: matched[g].append(s) if (s.leadership != "STRONG_FOLLOW" and s.leadership != "STRONG_LEAD"): Groups.objects(group_name=g.group_name).update( has_leader=True) g.reload() s.reload() if s.leadership == "STRONG_LEAD": Groups.objects(group_name=g.group_name).update( has_strong_leader=True, has_leader=True) g.reload() s.reload() group_prefers[g] = partnerUpStudents(s, g) group_prefers[g], matched = nopeStudents(s, g, matched) else: # print(g.group_name + " is competitive.") g_list = group_prefers[g] replaced = False for m in match: for pref in g_list: if pref.student == m: cur_pref = pref.pref_score elif pref.student == s: new_pref = pref.pref_score if cur_pref < new_pref: #replace less preferred student with current student # print("Replacing " + m.student_name + " with " + s.student_name) if (checkLeader(s, g) and not (m.leadership == "STRONG_LEAD")): continue else: matched[g].remove(m) matched[g].append(s) if (s.leadership != "STRONG_FOLLOW" and s.leadership != "STRONG_LEAD"): Groups.objects(group_name=g.group_name).update( has_leader=True) g.reload() s.reload() if s.leadership == "STRONG_LEAD": Groups.objects(group_name=g.group_name).update( has_strong_leader=True, has_leader=True) g.reload() s.reload() if len(student_prefers[m]) > 0: students_free.append(m) else: #No op, but this will break things, so here's one #solution, but: #TODO: make this work better if len(match) < MAX_SIZE: matched[g].append(m) replaced = True group_prefers[g] = partnerUpStudents(s, g) group_prefers[g], matched = nopeStudents(s, g, matched) break if not replaced: if len(s_list) > 0: students_free.append(s) else: if len(match) < MAX_SIZE: matched[g].append(s) if len(students_free) < 1: unsorted = checkComplete(matched) if len(unsorted) > 0: for identikey in unsorted: ##! This process takes an obscenely long time. ##! I don't know how to streamline these updates, ##! but this operation is one of the slowest in the ##! entire algorithm ##! TODO OPTIMIZE PRIME student = Students.objects.get(identikey=identikey) for group in student.preferences: for pref in group.preferences: Groups.objects(group_name=group.group_name).update( pull__preferences__student=student) score = pref.pref_score + GROUP_WEIGHT np = Preference(student=student, pref_score=score) Groups.objects(group_name=group.group_name).update( add_to_set__preferences=np) group.reload() group_prefers[group] = group.preferences students_free.append(student) student_prefers[student] = student.preferences print(student.student_name + " is being re-sorted.") fall_through = True ##! TODO this should be separate, single responsibility principle and all for group in matched: for student in matched[group]: Groups.objects(group_name=group.group_name).update( add_to_set__members=student) group.reload() # group.members.append(student) swapController() warnLeaders() ##! TODO same here for group in Groups.objects: if group.paid and len(group.members) < MIN_SIZE: print("MATCHING FAILED: paid group was unfilled: " + group.group_name) return 1, matched ##! TODO this is a weird way to update the local object for group in Groups.objects: matched[group] = [] matched[group] = group.members for student in group.members: Students.objects.get(identikey=student.identikey).update( group_assigned=group) student.reload() return 0, matched
def removeGroup(group): print("WARNING: Removing group: " + group.group_name) Groups.objects(group_name=group.group_name).delete() for student in Students.objects: if group in student.preferences: student.update(pull__preferences=group)