def try_paneling(potential_pairings, all_judges, num_to_panel, gap): if len(potential_pairings) == 0 or num_to_panel <= 0: # Base case, failed to panel print("Failed to panel") return {} rounds = sorted(potential_pairings, key=lambda r: (argmin(r.judges.all(), lambda j: j.rank).rank,) + \ tuple([-1 * i for i in tab_logic.team_comp(r, current_round_number)])) base_judge = argmax(rounds[:num_to_panel][-1].judges.all(), lambda j: j.rank) print("Found maximally ranked judge {0}".format(base_judge)) potential_panelists = [j for j in all_judges if j.rank > (float(base_judge.rank) - float(gap))] print("Potential panelists:", potential_panelists) # If we don't have enough potential panelists, try again with fewer panels if len(potential_panelists) < 2 * num_to_panel: print("Not enough judges to panel!: ", len(potential_panelists), num_to_panel) return try_paneling(potential_pairings, all_judges, num_to_panel - 1, gap) panel_assignments = [] rounds_to_panel = rounds[:num_to_panel] num_to_panel = len(rounds_to_panel) for pairing in rounds_to_panel: panel_assignments.append([j for j in pairing.judges.all()]) # Do it twice so we get panels of 3 for i in (0,1): graph_edges = [] for (judge_i, judge) in enumerate(potential_panelists): for (pairing_i, pairing) in enumerate(rounds_to_panel): if not judge_conflict(judge, pairing.gov_team, pairing.opp_team): judges = panel_assignments[pairing_i] + [judge] graph_edges.append((pairing_i, judge_i + num_to_panel, calc_weight_panel(judges))) pprint.pprint(graph_edges) judge_assignments = mwmatching.maxWeightMatching(graph_edges, maxcardinality=True) print(judge_assignments) if ((-1 in judge_assignments[:num_to_panel]) or (num_to_panel > 0 and len(graph_edges) == 0)): print("Scratches are causing a retry") return try_paneling(potential_pairings, all_judges, num_to_panel - 1, gap) # Save the judges to the potential panel assignments judges_used = [] for i in range(num_to_panel): judge = potential_panelists[judge_assignments[i] - num_to_panel] panel_assignments[i].append(judge) judges_used.append(judge) # Remove any used judges from the potential panelist pool for judge in judges_used: print("Removing {0}".format(judge)) potential_panelists.remove(judge) print("panels: ", panel_assignments) result = {} for (panel_i, panel) in enumerate(panel_assignments): result[rounds_to_panel[panel_i]] = panel return result
def try_paneling(potential_pairings, all_judges, num_to_panel, gap): if len(potential_pairings) == 0 or num_to_panel <= 0: # Base case, failed to panel print("Failed to panel") return {} rounds = sorted(potential_pairings, key=lambda r: (argmin(r.judges.all(), lambda j: j.rank).rank,) + \ tuple([-1 * i for i in tab_logic.team_comp(r, current_round_number)])) base_judge = argmax(rounds[:num_to_panel][-1].judges.all(), lambda j: j.rank) print("Found maximally ranked judge {0}".format(base_judge)) potential_panelists = [j for j in all_judges if j.rank > (float(base_judge.rank) - float(gap))] print("Potential panelists:", potential_panelists) # If we don't have enough potential panelists, try again with fewer panels if len(potential_panelists) < 2 * num_to_panel: print("Not enough judges to panel!: ", len(potential_panelists), num_to_panel) return try_paneling(potential_pairings, all_judges, num_to_panel - 1, gap) panel_assignments = [] rounds_to_panel = rounds[:num_to_panel] num_to_panel = len(rounds_to_panel) for pairing in rounds_to_panel: panel_assignments.append([j for j in pairing.judges.all()]) # Do it twice so we get panels of 3 for i in (0,1): graph_edges = [] for (judge_i, judge) in enumerate(potential_panelists): for (pairing_i, pairing) in enumerate(rounds_to_panel): if not judge_conflict(judge, pairing.gov_team, pairing.opp_team): judges = panel_assignments[pairing_i] + [judge] graph_edges.append((pairing_i, judge_i + num_to_panel, calc_weight_panel(judges))) judge_assignments = mwmatching.maxWeightMatching(graph_edges, maxcardinality=True) print(judge_assignments) if ((-1 in judge_assignments[:num_to_panel]) or (num_to_panel > 0 and len(graph_edges) == 0)): print("Scratches are causing a retry") return try_paneling(potential_pairings, all_judges, num_to_panel - 1, gap) # Save the judges to the potential panel assignments judges_used = [] for i in range(num_to_panel): judge = potential_panelists[judge_assignments[i] - num_to_panel] panel_assignments[i].append(judge) judges_used.append(judge) # Remove any used judges from the potential panelist pool for judge in judges_used: print("Removing {0}".format(judge)) potential_panelists.remove(judge) print("panels: ", panel_assignments) result = {} for (panel_i, panel) in enumerate(panel_assignments): result[rounds_to_panel[panel_i]] = panel return result
def view_round(request, round_number, errors=None): if errors is None: errors = [] valid_pairing, byes = True, [] round_pairing = list(Round.objects.filter(round_number=round_number)) random.seed(1337) random.shuffle(round_pairing) round_pairing.sort(key=lambda x: tab_logic.team_comp(x, round_number), reverse=True) #For the template since we can't pass in something nicer like a hash round_info = [pair for pair in round_pairing] paired_teams = [team.gov_team for team in round_pairing ] + [team.opp_team for team in round_pairing] n_over_two = Team.objects.filter(checked_in=True).count() / 2 valid_pairing = len(round_pairing) >= n_over_two or round_number == 0 for present_team in Team.objects.filter(checked_in=True): if not (present_team in paired_teams): errors.append("%s was not in the pairing" % (present_team)) byes.append(present_team) pairing_exists = len(round_pairing) > 0 pairing_released = TabSettings.get("pairing_released", 0) == 1 judges_assigned = all((r.judges.count() > 0 for r in round_info)) excluded_judges = Judge.objects.exclude( judges__round_number=round_number).filter( checkin__round_number=round_number) non_checkins = Judge.objects.exclude( judges__round_number=round_number).exclude( checkin__round_number=round_number) available_rooms = Room.objects.exclude( round__round_number=round_number).exclude(rank=0) size = max(list(map(len, [excluded_judges, non_checkins, byes]))) # The minimum rank you want to warn on warning = 5 judge_slots = [1, 2, 3] # A seemingly complex one liner to do a fairly simple thing # basically this generates the table that the HTML will display such that the output looks like: # [ Byes ][Judges not in round but checked in][Judges not in round but not checked in] # [ Team1][ CJudge1 ][ Judge1 ] # [ Team2][ CJudge2 ][ Judge2 ] # [ ][ CJudge3 ][ Judge3 ] # [ ][ ][ Judge4 ] excluded_people = list( zip(*[ x + [""] * (size - len(x)) for x in [ list(byes), list(excluded_judges), list(non_checkins), list(available_rooms) ] ])) return render(request, 'pairing_control.html', locals())
def view_round(request, round_number, errors = None): if errors is None: errors = [] valid_pairing, byes = True, [] print "1: ",time.time() round_pairing = list(Round.objects.filter(round_number = round_number)) random.seed(1337) random.shuffle(round_pairing) round_pairing.sort(key = lambda x: tab_logic.team_comp(x, round_number), reverse = True) print "2: ",time.time() #For the template since we can't pass in something nicer like a hash round_info = [[pair]+[None]*8 for pair in round_pairing] for pair in round_info: pair[1] = tab_logic.tot_wins(pair[0].gov_team) pair[2] = tab_logic.tot_speaks(pair[0].gov_team) pair[3] = tab_logic.num_govs(pair[0].gov_team) pair[4] = tab_logic.num_opps(pair[0].gov_team) pair[5] = tab_logic.tot_wins(pair[0].opp_team) pair[6] = tab_logic.tot_speaks(pair[0].opp_team) pair[7] = tab_logic.num_govs(pair[0].opp_team) pair[8] = tab_logic.num_opps(pair[0].opp_team) print "3: ",time.time() paired_teams = [team.gov_team for team in round_pairing] + [team.opp_team for team in round_pairing] n_over_two = Team.objects.filter(checked_in=True).count() / 2 valid_pairing = len(round_pairing) >= n_over_two for present_team in Team.objects.filter(checked_in=True): if not (present_team in paired_teams): errors.append("%s was not in the pairing" % (present_team)) byes.append(present_team) pairing_exists = len(round_pairing) > 0 excluded_judges = Judge.objects.exclude(judges__round_number = round_number).filter(checkin__round_number = round_number) non_checkins = Judge.objects.exclude(judges__round_number = round_number).exclude(checkin__round_number = round_number) size = max(map(len, [excluded_judges, non_checkins, byes])) # The minimum rank you want to warn on warning = 5 judge_slots = [1,2,3] print "4: ",time.time() # A seemingly complex one liner to do a fairly simple thing # basically this generates the table that the HTML will display such that the output looks like: # [ Byes ][Judges not in round but checked in][Judges not in round but not checked in] # [ Team1][ CJudge1 ][ Judge1 ] # [ Team2][ CJudge2 ][ Judge2 ] # [ ][ CJudge3 ][ Judge3 ] # [ ][ ][ Judge4 ] excluded_people = zip(*map( lambda x: x+[""]*(size-len(x)), [list(byes), list(excluded_judges), list(non_checkins)])) return render_to_response('display_info.html', locals(), context_instance=RequestContext(request))
def view_round(request, round_number): errors, excluded_teams = [], [] round_pairing = list(Round.objects.filter(round_number=round_number)) random.seed(1337) random.shuffle(round_pairing) round_pairing.sort(key = lambda x: tab_logic.team_comp(x, round_number), reverse = True) #For the template since we can't pass in something nicer like a hash round_info = [pair for pair in round_pairing] paired_teams = [team.gov_team for team in round_pairing] + [team.opp_team for team in round_pairing] n_over_two = Team.objects.filter(checked_in=True).count() / 2 for present_team in Team.objects.filter(checked_in=True): if not (present_team in paired_teams): excluded_teams.append(present_team) for team in excluded_teams: if not Bye.objects.filter(round_number=round_number, bye_team=team).exists(): errors.append("{} is checked-in but has no round or bye".format(team)) pairing_exists = len(round_pairing) > 0 pairing_released = TabSettings.get("pairing_released", 0) == 1 judges_assigned = all((r.judges.count() > 0 for r in round_info)) excluded_judges = Judge.objects.exclude(judges__round_number=round_number).filter(checkin__round_number = round_number) non_checkins = Judge.objects.exclude(judges__round_number=round_number).exclude(checkin__round_number = round_number) available_rooms = Room.objects.exclude(round__round_number=round_number).exclude(rank=0) size = max(list(map(len, [excluded_judges, non_checkins, excluded_teams]))) # The minimum rank you want to warn on warning = 5 judge_slots = [1,2,3] # A seemingly complex one liner to do a fairly simple thing # basically this generates the table that the HTML will display such that the output looks like: # [ Byes ][Judges not in round but checked in][Judges not in round but not checked in] # [ Team1][ CJudge1 ][ Judge1 ] # [ Team2][ CJudge2 ][ Judge2 ] # [ ][ CJudge3 ][ Judge3 ] # [ ][ ][ Judge4 ] excluded_people = list(zip(*[x+[""]*(size-len(x)) for x in [list(excluded_teams), list(excluded_judges), list(non_checkins), list(available_rooms)]])) return render(request, 'pairing/pairing_control.html', locals())
def add_judges(pairings, judges, panel_points): # First clear any existing judge assignments for pairing in pairings: pairing.judges.clear() current_round_number = TabSettings.objects.get(key="cur_round").value - 1 # Try to have consistent ordering with the round display random.seed(1337) random.shuffle(pairings) random.seed(1337) random.shuffle(judges) # Order the judges and pairings by power ranking (high speaking teams get high ranked judges) judges = sorted(judges, key=lambda j: j.rank, reverse = True) pairings.sort(key=lambda x: tab_logic.team_comp(x, current_round_number), reverse = True) pairing_groups = [list() for panel_point in panel_points] + [list()] panel_gaps = {} current_group = 0 for pairing in pairings: pairing_groups[current_group].append(pairing) if current_group < len(panel_points) and pairing == panel_points[current_group][0]: panel_gaps[current_group] = panel_points[current_group][1] current_group += 1 for (group_i, group) in enumerate(pairing_groups): num_rounds = len(group) # Assign chairs (single judges) to each round using perfect pairing graph_edges = [] for (judge_i, judge) in enumerate(judges): for (pairing_i, pairing) in enumerate(group): if not judge_conflict(judge, pairing.gov_team, pairing.opp_team): graph_edges.append((pairing_i, judge_i + len(group), calc_weight(judge_i, pairing_i))) judge_assignments = mwmatching.maxWeightMatching(graph_edges, maxcardinality=True) # If there is no possible assignment of chairs, raise an error if -1 in judge_assignments[:num_rounds] or (num_rounds > 0 and len(graph_edges) == 0): if len(graph_edges) == 0: raise errors.JudgeAssignmentError("Impossible to assign judges, consider reducing your gaps if you are making panels, otherwise find some more judges.") elif -1 in judge_assignments[:num_rounds]: pairing_list = judge_assignments[:len(pairings)] bad_pairing = pairings[pairing_list.index(-1)] raise errors.JudgeAssignmentError("Could not find a judge for: %s" % str(bad_pairing)) else: raise errors.JudgeAssignmentError() # Save the judges to the pairings for i in range(num_rounds): group[i].judges.add(judges[judge_assignments[i] - num_rounds]) group[i].chair = judges[judge_assignments[i] - num_rounds] group[i].save() # Remove any assigned judges from the judging pool for pairing in group: for judge in pairing.judges.all(): judges.remove(judge) # Function that tries to panel num_to_panel rounds of the potential_pairings # Has built in logic to retry with lower number of panels if we fail due # to either scratches or wanting to many rounds def try_paneling(potential_pairings, all_judges, num_to_panel, gap): if len(potential_pairings) == 0 or num_to_panel <= 0: # Base case, failed to panel print("Failed to panel") return {} rounds = sorted(potential_pairings, key=lambda r: (argmin(r.judges.all(), lambda j: j.rank).rank,) + \ tuple([-1 * i for i in tab_logic.team_comp(r, current_round_number)])) base_judge = argmax(rounds[:num_to_panel][-1].judges.all(), lambda j: j.rank) print("Found maximally ranked judge {0}".format(base_judge)) potential_panelists = [j for j in all_judges if j.rank > (float(base_judge.rank) - float(gap))] print("Potential panelists:", potential_panelists) # If we don't have enough potential panelists, try again with fewer panels if len(potential_panelists) < 2 * num_to_panel: print("Not enough judges to panel!: ", len(potential_panelists), num_to_panel) return try_paneling(potential_pairings, all_judges, num_to_panel - 1, gap) panel_assignments = [] rounds_to_panel = rounds[:num_to_panel] num_to_panel = len(rounds_to_panel) for pairing in rounds_to_panel: panel_assignments.append([j for j in pairing.judges.all()]) # Do it twice so we get panels of 3 for i in (0,1): graph_edges = [] for (judge_i, judge) in enumerate(potential_panelists): for (pairing_i, pairing) in enumerate(rounds_to_panel): if not judge_conflict(judge, pairing.gov_team, pairing.opp_team): judges = panel_assignments[pairing_i] + [judge] graph_edges.append((pairing_i, judge_i + num_to_panel, calc_weight_panel(judges))) judge_assignments = mwmatching.maxWeightMatching(graph_edges, maxcardinality=True) print(judge_assignments) if ((-1 in judge_assignments[:num_to_panel]) or (num_to_panel > 0 and len(graph_edges) == 0)): print("Scratches are causing a retry") return try_paneling(potential_pairings, all_judges, num_to_panel - 1, gap) # Save the judges to the potential panel assignments judges_used = [] for i in range(num_to_panel): judge = potential_panelists[judge_assignments[i] - num_to_panel] panel_assignments[i].append(judge) judges_used.append(judge) # Remove any used judges from the potential panelist pool for judge in judges_used: print("Removing {0}".format(judge)) potential_panelists.remove(judge) print("panels: ", panel_assignments) result = {} for (panel_i, panel) in enumerate(panel_assignments): result[rounds_to_panel[panel_i]] = panel return result # Use the try_paneling function for any rounds that have been marked as panel # points, note that we start with trying to panel the entire bracket and # rely on try_paneling's retries to fix it if group_i in panel_gaps and panel_gaps[group_i]: panels = try_paneling(group, judges, len(group), panel_gaps[group_i]) for (pairing, panelists) in panels.items(): for panelist in panelists: if panelist not in pairing.judges.all(): pairing.judges.add(panelist) judges.remove(panelist) pairing.save()
def view_round(request, round_number): errors, excluded_teams = [], [] round_pairing = list(Round.objects.filter(round_number=round_number)) tot_rounds = TabSettings.get("tot_rounds", 5) random.seed(1337) random.shuffle(round_pairing) round_pairing.sort(key=lambda x: tab_logic.team_comp(x, round_number), reverse=True) #For the template since we can't pass in something nicer like a hash round_info = [pair for pair in round_pairing] paired_teams = [team.gov_team for team in round_pairing ] + [team.opp_team for team in round_pairing] n_over_two = Team.objects.filter(checked_in=True).count() / 2 for present_team in Team.objects.filter(checked_in=True): if present_team not in paired_teams: excluded_teams.append(present_team) excluded_teams_no_bye = [ team for team in excluded_teams if not Bye.objects.filter( round_number=round_number, bye_team=team).exists() ] num_excluded = len(excluded_teams_no_bye) pairing_exists = len(round_pairing) > 0 pairing_released = TabSettings.get("pairing_released", 0) == 1 judges_assigned = all((r.judges.count() > 0 for r in round_info)) excluded_judges = Judge.objects.exclude( judges__round_number=round_number).filter( checkin__round_number=round_number) non_checkins = Judge.objects.exclude( judges__round_number=round_number).exclude( checkin__round_number=round_number) available_rooms = Room.objects.exclude( round__round_number=round_number).exclude(rank=0) size = max(list(map(len, [excluded_judges, non_checkins, excluded_teams]))) # The minimum rank you want to warn on warning = 5 judge_slots = [1, 2, 3] # A seemingly complex one liner to do a fairly simple thing # Generates a nested list like: # [ Byes ][Judges not in round][Judges not in round] # [ Team1][ CJudge1 ][ Judge1 ] # [ Team2][ CJudge2 ][ Judge2 ] # [ ][ CJudge3 ][ Judge3 ] # [ ][ ][ Judge4 ] excluded_people = list( zip(*[ x + [""] * (size - len(x)) for x in [ list(excluded_teams), list(excluded_judges), list(non_checkins), list(available_rooms) ] ])) return render(request, "pairing/pairing_control.html", locals())
def add_judges(pairings, judges, panel_points): # First clear any existing judge assignments for pairing in pairings: pairing.judges.clear() current_round_number = TabSettings.objects.get(key="cur_round").value - 1 # Try to have consistent ordering with the round display random.seed(1337) random.shuffle(pairings) random.seed(1337) random.shuffle(judges) # Order the judges and pairings by power ranking (high speaking teams get high ranked judges) judges = sorted(judges, key=lambda j: j.rank, reverse = True) pairings.sort(key=lambda x: tab_logic.team_comp(x, current_round_number), reverse = True) pprint.pprint(pairings) pairing_groups = [list() for panel_point in panel_points] + [list()] panel_gaps = {} current_group = 0 for pairing in pairings: pairing_groups[current_group].append(pairing) if current_group < len(panel_points) and pairing == panel_points[current_group][0]: panel_gaps[current_group] = panel_points[current_group][1] current_group += 1 pprint.pprint(panel_points) for (group_i, group) in enumerate(pairing_groups): num_rounds = len(group) # Assign chairs (single judges) to each round using perfect pairing graph_edges = [] for (judge_i, judge) in enumerate(judges): for (pairing_i, pairing) in enumerate(group): if not judge_conflict(judge, pairing.gov_team, pairing.opp_team): graph_edges.append((pairing_i, judge_i + len(group), calc_weight(judge_i, pairing_i))) judge_assignments = mwmatching.maxWeightMatching(graph_edges, maxcardinality=True) # If there is no possible assignment of chairs, raise an error if -1 in judge_assignments[:num_rounds] or (num_rounds > 0 and len(graph_edges) == 0): if len(graph_edges) == 0: raise errors.JudgeAssignmentError("Impossible to assign judges, consider reducing your gaps if you are making panels, otherwise find some more judges.") elif -1 in judge_assignments[:num_rounds]: pairing_list = judge_assignments[:len(pairings)] bad_pairing = pairings[pairing_list.index(-1)] raise errors.JudgeAssignmentError("Could not find a judge for: %s" % str(bad_pairing)) else: raise errors.JudgeAssignmentError() # Save the judges to the pairings for i in range(num_rounds): group[i].judges.add(judges[judge_assignments[i] - num_rounds]) group[i].chair = judges[judge_assignments[i] - num_rounds] group[i].save() # Remove any assigned judges from the judging pool for pairing in group: for judge in pairing.judges.all(): judges.remove(judge) # Function that tries to panel num_to_panel rounds of the potential_pairings # Has built in logic to retry with lower number of panels if we fail due # to either scratches or wanting to many rounds def try_paneling(potential_pairings, all_judges, num_to_panel, gap): if len(potential_pairings) == 0 or num_to_panel <= 0: # Base case, failed to panel print("Failed to panel") return {} rounds = sorted(potential_pairings, key=lambda r: (argmin(r.judges.all(), lambda j: j.rank).rank,) + \ tuple([-1 * i for i in tab_logic.team_comp(r, current_round_number)])) base_judge = argmax(rounds[:num_to_panel][-1].judges.all(), lambda j: j.rank) print("Found maximally ranked judge {0}".format(base_judge)) potential_panelists = [j for j in all_judges if j.rank > (float(base_judge.rank) - float(gap))] print("Potential panelists:", potential_panelists) # If we don't have enough potential panelists, try again with fewer panels if len(potential_panelists) < 2 * num_to_panel: print("Not enough judges to panel!: ", len(potential_panelists), num_to_panel) return try_paneling(potential_pairings, all_judges, num_to_panel - 1, gap) panel_assignments = [] rounds_to_panel = rounds[:num_to_panel] num_to_panel = len(rounds_to_panel) for pairing in rounds_to_panel: panel_assignments.append([j for j in pairing.judges.all()]) # Do it twice so we get panels of 3 for i in (0,1): graph_edges = [] for (judge_i, judge) in enumerate(potential_panelists): for (pairing_i, pairing) in enumerate(rounds_to_panel): if not judge_conflict(judge, pairing.gov_team, pairing.opp_team): judges = panel_assignments[pairing_i] + [judge] graph_edges.append((pairing_i, judge_i + num_to_panel, calc_weight_panel(judges))) pprint.pprint(graph_edges) judge_assignments = mwmatching.maxWeightMatching(graph_edges, maxcardinality=True) print(judge_assignments) if ((-1 in judge_assignments[:num_to_panel]) or (num_to_panel > 0 and len(graph_edges) == 0)): print("Scratches are causing a retry") return try_paneling(potential_pairings, all_judges, num_to_panel - 1, gap) # Save the judges to the potential panel assignments judges_used = [] for i in range(num_to_panel): judge = potential_panelists[judge_assignments[i] - num_to_panel] panel_assignments[i].append(judge) judges_used.append(judge) # Remove any used judges from the potential panelist pool for judge in judges_used: print("Removing {0}".format(judge)) potential_panelists.remove(judge) print("panels: ", panel_assignments) result = {} for (panel_i, panel) in enumerate(panel_assignments): result[rounds_to_panel[panel_i]] = panel return result # Use the try_paneling function for any rounds that have been marked as panel # points, note that we start with trying to panel the entire bracket and # rely on try_paneling's retries to fix it if group_i in panel_gaps and panel_gaps[group_i]: panels = try_paneling(group, judges, len(group), panel_gaps[group_i]) for (pairing, panelists) in panels.items(): for panelist in panelists: if panelist not in pairing.judges.all(): pairing.judges.add(panelist) judges.remove(panelist) pairing.save()
def sort_key(round_obj): team_comp_result = tab_logic.team_comp(round_obj, current_round_number) get_rank = lambda judge: judge.rank rank_tuple = (argmin(round_obj.judges.all(), get_rank).rank, ) return rank_tuple + tuple([-1 * i for i in team_comp_result])