Commit aa5295a3 by Pierre-antoine Comby

le dépot est propre

parents
.gitignore 0 → 100644
 __pycache__/ *.csv
algorithms.py 0 → 100644
 """ This script contains both the standard and extended Gale-Shapley algorithms for solving matching games. A matching game is defined by two sets called suitors and reviewers. Each suitor (and reviewer) has associated with it an ordered preference of the elements of the corresponding set. A solution to a matching game is any mapping between the set of suitors and reviewers. """ from collections import Counter from copy import deepcopy import numpy as np def galeshapley(suitor_pref_dict, reviewer_pref_dict): """ The Gale-Shapley algorithm. This is known to provide a unique, stable suitor-optimal matching. The algorithm is as follows: (1) Assign all suitors and reviewers to be unmatched. (2) Take any unmatched suitor, s, and their most preferred reviewer, r. - If r is unmatched, match s to r. - Else, if r is matched, consider their current partner, r_partner. - If r prefers s to r_partner, unmatch r_partner from r and match s to r. - Else, leave s unmatched and remove r from their preference list. (3) Go to (2) until all suitors are matched, then end. Parameters ---------- suitor_pref_dict : dict A dictionary with suitors as keys and their respective preference lists as values review_pref_dict : dict A dictionary with reviewers as keys and their respective preference lists as values Returns ------- matching : dict The suitor-optimal (stable) matching with suitors as keys and the reviewer they are matched with as values """ suitors = [s for s in suitor_pref_dict] matching = {s: None for s in suitors} while suitors != []: s = suitors.pop(0) r = suitor_pref_dict[s][0] if r not in matching.values(): matching[s] = r else: for suitr, revwr in matching.items(): if revwr == r: r_partner = suitr if reviewer_pref_dict[r].index(s) < reviewer_pref_dict[r].index( r_partner ): matching[r_partner] = None matching[s] = r suitors.append(r_partner) else: suitor_pref_dict[s].remove(r) suitors.append(s) return matching def get_free_residents(resident_prefs, matching): """ Return a list of all residents who are currently unmatched but have a non-empty preference list. """ return [ resident for resident in resident_prefs if resident_prefs[resident] and not any([resident in match for match in matching.values()]) ] def get_worst_idx(hospital, hospital_prefs, matching): """ Find the index of the worst resident currently assigned to `hospital` according to their preferences. """ return max( [ hospital_prefs[hospital].index(resident) for resident in hospital_prefs[hospital] if resident in matching[hospital] ] ) def resident_hospital(resident_prefs, hospital_prefs, capacities): """ Provide a stable, resident-optimal matching for the given instance of HR using the algorithm set out in [Gale, Shapley 1962]. """ matching = {hospital: [] for hospital in hospital_prefs} free_residents = get_free_residents(resident_prefs, matching) while free_residents: resident = free_residents[0] hospital = resident_prefs[resident][0] i = 0 while capacities[hospital] <= 0: i += 1 hospital = resident_prefs[resident][i] <<<<<<< HEAD ======= >>>>>>> 7158617afbb760d3a35b62a2705688d11b9d0b1b matching[hospital].append(resident) if len(matching[hospital]) > capacities[hospital]: worst = get_worst_idx(hospital, hospital_prefs, matching) resident = hospital_prefs[hospital][worst] matching[hospital].remove(resident) if len(matching[hospital]) == capacities[hospital]: worst = get_worst_idx(hospital, hospital_prefs, matching) successors = hospital_prefs[hospital][worst + 1 :] if successors: for resident in successors: hospital_prefs[hospital].remove(resident) if hospital in resident_prefs[resident]: resident_prefs[resident].remove(hospital) free_residents = get_free_residents(resident_prefs, matching) for hospital, matches in matching.items(): sorted_matches = sorted(matches, key=hospital_prefs[hospital].index) matching[hospital] = sorted_matches return matching def hrt_super_res(resident_prefs, hospital_prefs, capacities): """ Determine whether a super-stable, resident-optimal matching exists for the given instance of HR. If so, return the matching. """ # ================================== # Needs adjusting for ties in prefs. # ================================== matching = {h: [] for h in hospital_prefs.keys()} fulls = {h: False for h in hospital_prefs.keys()} free_residents = [r for r in resident_prefs.keys()] while [r for r in free_residents if resident_prefs[r]]: r = free_residents.pop(0) r_prefs = resident_prefs[r] h_best = r_prefs[0] matching[h_best] += [r] if len(matching[h_best]) > capacities[h_best]: r_worst = hospital_prefs[h_best][-1] if r_worst in matching[h_best]: matching[h_best].remove(r_worst) resident_prefs[r_worst].remove(h_best) hospital_prefs[h_best].remove(r_worst) if len(matching[h_best]) == capacities[h_best]: fulls[h_best] = True worst_idx = np.max( [ hospital_prefs[h_best].index(resident) for resident in hospital_prefs[h_best] if resident in matching[h_best] ] ) successors = hospital_prefs[h_best][worst_idx + 1 :] if successors: for resident in successors: hospital_prefs[h_best].remove(resident) resident_prefs[resident].remove(h_best) resident_match_counts = Counter([tuple(res) for res in matching.values()]) if np.any( [count > 1 for count in resident_match_counts.values()] ) or np.any(fulls.values()): raise ValueError("No super-stable matching exists.") return matching
bus.py 0 → 100755
 #! /usr/bin/env python3 BUS = ['Nausi[car] de la vallee du [van]', 'Au [bus]cher', 'La grosse [caisse]', 'Ha[van]a Club', 'l houm[bus]', '[Van]ted', 'Pernod-Ri[Car]d'] NB_BUS=8 class Bus(object): """Un bus contient des équipes , remplis par des 1A en fonction de leur réponse à un questionnaire """ def __init__(self, nom, places, places_2a,reponse_criteres,size_equipe): self.nom = nom # nom du bus self.criteres = reponse_criteres # critère et pondération self.note = dict() # note de tous les 1A par rapport à ce bus. self.rank_unA = [] self.passengers = [] self.old_passengers = [] self.size_team = [int(s) for s in size_equipe] self.teams = [] self.places = places self.places_2a = places_2a self.places_1a = places-places_2a def __repr__(self): ret = self.nom return"Bus_"+ret def __str__(self): return "Bus {}".format(self.nom) def __str__(self): return "Bus {}".format(self.nom) def gen_note(self, list_unA): for unA in list_unA: score_unA = unA.scores_bus[self] rank_unA = unA.rank_bus.index(self) if rank_unA == NB_BUS-1: note_bus = score_unA/rank_unA else: #note_bus = (score_unA-unA.scores_bus[unA.rank_bus[rank_unA+1]] + 2)/(rank_unA+1) p = NB_BUS - rank_unA nextu = unA.scores_bus[unA.rank_bus[rank_unA+1]] tmp = ((NB_BUS - rank_unA) * score_unA - (NB_BUS - rank_unA - 1) * nextu) / (rank_unA + 1) note_bus = tmp #note_bus = (score_unA**p - next**(p - 1)) # note_bus = (score_unA-unA.scores_bus[unA.rank_bus[rank_unA+1]]) self.note[unA] = note_bus def gen_rank(self): self.rank_unA = list(self.note.items()) self.rank_unA = sorted(self.rank_unA,key=lambda x:x[1],reverse = True) self.rank_unA = [r[0] for r in self.rank_unA] def partial_rank(self, students): return [student for student in self.rank_unA if student in students] def make_teams(self): print(self.nom) n_chef_tot = sum(self.size_team) n_equipe = len(self.size_team) N = len(self.passengers) size_goal = [0]*len(self.size_team) for i in range(len(self.size_team)): size_goal[i] = int(self.size_team[i]*N/n_chef_tot)+1 i = 0 places_equipe=sum(size_goal) girls = [p for p in self.passengers if p.infos["genre"] == 'F' or p.infos["genre"] == 'N'] not_girls = [p for p in self.passengers if p.infos["genre"] == 'M'] # # for e in size_goal: # equipe = [] # for k in range(int(len(girls)*e/places_equipe)): # if girls: # equipe.append(girls.pop()) # for k in range(int(len(not_girls)*e/places_equipe)): # if not_girls: # equipe.append(not_girls.pop()) # print(len(equipe)) # self.teams.append(equipe) i=0 self.teams=[[None]*s for s in size_goal] while girls : if None in self.teams[i]: self.teams[i].append(girls.pop()) self.teams[i].remove(None) i +=1; i %= n_equipe; for i in range(len(self.size_team)): if len(self.teams[i])-self.teams[i].count(None) == 1: #Si une fille est seule on l'enlève. g_alone=self.teams[i].pop() self.teams[i].append(None) next_ind = (i+1)%n_equipe self.teams[next_ind].remove(None) self.teams[next_ind].append(g_alone) remain =True while not_girls and remain: if None in self.teams[i]: self.teams[i].append(not_girls.pop()) self.teams[i].remove(None) i +=1; i %= n_equipe; #cleaned unused places for l in self.teams: while None in l: l.remove(None) #affichage for k in range(len(self.size_team)): print(self.size_team[k],size_goal[k],len(self.teams[k]),self.teams[k]) print(len(self.passengers),sum(size_goal)) def partial_rank(self, students): return [student for student in self.rank_unA if student in students]
hardcode.json 0 → 100644
 { "aspique":[978,1004,1112,1042,1092,1083,1145,963,975,1059,934,931,1082,1046,1084,961,1097,1195,944,1106,952,942,1071,1134], "chytem":[1002], "fanfare":[947,997,929,930, 1066], "hooligens":[1050,1006,962,1013], "med":[951,956], "saphire":[1118,1111], "satelist":[1016,1114], "vieux":[974, 1066,943] }
main.py 0 → 100755
 #!/usr/bin/env python3 # -*- coding:utf8 -* """ Script pour le remplissages des 1A dans les bus du WEI TODO : - adapter parse_wiki - géneration structure donnée - implémentation algorithme """ import sys import csv from collections import OrderedDict import copy from unA import * from bus import * import parsewiki import algorithms import random import json def get_1A_from_csv(database): list_unA = [] with open(database, newline='') as csvfile: table = csv.DictReader(csvfile, delimiter=',') for people in table: info = {i: people[i] for i in INFOS} if info["dept"] == 'A"2': # on aime pas les chimiste info["dept"] = "A''2" criteres = {c: int(people[c]) for c in CRITERES} list_unA.append(UnA(info, criteres)) return list_unA def get_bus_from_csv(database): list_bus = [] with open(database, newline='') as csvfile: table = csv.DictReader(csvfile, delimiter=',') for bus in table: nom = bus["bus"] places_2a = int(bus["places_2a"]) places = int(bus["places"]) size_equipe=list(bus["equipes"]) criteres = {c: int(bus[c]) for c in CRITERES} list_bus.append(Bus(nom,places,places_2a, criteres,size_equipe)) return list_bus def rang_moyen(bus, bus_match): s = 0 for eleve in bus_match: s += eleve.rank_bus.index(bus) + 1 if len(bus_match) == 0: return 0 return s / len(bus_match) def note_moyenne(bus, bus_match): s = 0 for eleve in bus_match: s += eleve.scores_bus[bus] if len(bus_match) == 0: return 0 return s / len(bus_match) def rang_moyen(bus, bus_match): s = 0 for eleve in bus_match: s += eleve.rank_bus.index(bus) + 1 if len(bus_match) == 0: return 0 return s / len(bus_match) def note_moyenne(bus, bus_match): s = 0 for eleve in bus_match: s += eleve.scores_bus[bus] if len(bus_match) == 0: return 0 return s / len(bus_match) def main(unA_file, bus_file): list_unA = get_1A_from_csv(unA_file) #list_unA = [] #for x in list_unAB: # if x.infos['genre'] == 'F': # list_unA.append(x) list_bus = get_bus_from_csv(bus_file) for unA in list_unA: unA.gen_score(list_bus) unA.gen_rank() for bus in list_bus: random.shuffle(list_unA) bus.gen_note(list_unA) bus.gen_rank() return list_bus, list_unA def split_students(students, bus_places): <<<<<<< HEAD """On remplis les bus au fur et à mesure """ ======= >>>>>>> 7158617afbb760d3a35b62a2705688d11b9d0b1b bus_ranks = {bus: bus.partial_rank(students) for bus in list_bus} students_ranks = {student: student.rank_bus for student in students} return algorithms.resident_hospital(students_ranks, bus_ranks, bus_places) def merge_bus(bus_matches_by_dpt): final_match = {bus: [] for bus in list_bus} for dpt in bus_matches_by_dpt: for bus in bus_matches_by_dpt[dpt]: match = bus_matches_by_dpt[dpt][bus] final_match[bus].extend(match) return final_match <<<<<<< HEAD def get_unA(idwei, students): for s in students: if int(s.infos["idwei"]) == idwei: return s def hardcode(file, bus_by_name,students): with open(file) as config: assigned =json.load(config) # assignment = {bus_by_name[b]: list(map(lambda x:get_unA(x,students),assigned[b])) for b in assigned} for b in assigned: bus = bus_by_name[b] bus.places_1a -= len(assigned[b]) to_place=[] for idwei in assigned[b]: u = get_unA(idwei,students) if u != None: to_place.append(u) bus.passengers.extend(to_place) for s in to_place: try: students.remove(s) except: print(s) def make_repartition(list_bus,students): list_dpt = set([s.infos["dept"] for s in students]) N = len(students) places_by_bus = {bus:bus.places_1a for bus in list_bus} part_students = [f for f in students if f.infos['genre'] == 'F'] n_filles = len(part_students) # pas de fille dans le bus aspique cette année. bus_places= {bus: int((bus.places_1a*n_filles)/N)+1 for bus in list_bus} bus_matches_by_dpt = dict() # on commence par répartir les filles qui sont considéré comme un département bus_matches_by_dpt["filles"] = split_students(part_students, bus_places) for bus in bus_matches_by_dpt["filles"]: places_by_bus[bus] -= len(bus_matches_by_dpt["filles"][bus]) # pour le reste des départements. for dpt in list_dpt: random.shuffle(list_bus) students = [s for s in students if s not in part_students] part_students = [s for s in students if s.infos['dept'] == dpt] places_need = len(part_students) bus_places = {bus: 0 for bus in list_bus} working_places = {bus: places_by_bus[bus] for bus in list_bus} while places_need > 0: for bus in list_bus: if places_need > 0 and working_places[bus] > 0: bus_places[bus] += 1 working_places[bus] -= 1 places_need -= 1 for bus in list_bus: if bus_places[bus] == 0 and working_places[bus] > 0: bus_places[bus] += 1 bus_matches_by_dpt[dpt] = split_students(part_students, bus_places) for bus in bus_matches_by_dpt[dpt]: places_by_bus[bus] -= len(bus_matches_by_dpt[dpt][bus]) final_match = merge_bus(bus_matches_by_dpt) return final_match def csv_bus_output(list_bus): fieldnames= [ "nom", "prenom", "genre", "dept", "tel", "urgence_nom", "urgence_tel", "mail", "infos" ] for bus in match: with open("bus/"+bus.nom+".csv",'w+',newline='') as csvfile: writer = csv.DictWriter(csvfile, fieldnames=fieldnames,delimiter=',') writer.writeheader() for s in bus.passengers: to_write = {i:s.infos[i] for i in fieldnames} # to_write.update({"rank_bus":s.rank_bus.index(bus),"fav_bus":s.rank_bus[0]}) writer.writerow(to_write) def csv_team_output(list_bus): for bus in list_bus: infos = [ "nom", "prenom", "genre", "dept", "tel", ] fieldnames = infos + ["equipe"] with open("bus_team/"+bus.nom+".csv","w+",newline='') as csvfile: writer = csv.DictWriter(csvfile, fieldnames=fieldnames,delimiter=',') writer.writeheader() for t in bus.teams: for s in t: to_write = {i:s.infos[i] for i in infos} to_write["equipe"] = bus.teams.index(t)+1 writer.writerow(to_write) list_bus, students = main("unA.csv", "bus.csv") bus_by_name={bus.nom:bus for bus in list_bus} # pour harcoder sans se prendre la tete print(len(students), [bus.places_1a for bus in list_bus], sum([bus.places_1a for bus in list_bus])) hardcode("hardcode.json",bus_by_name,students) print([len(bus.passengers) for bus in list_bus]) match = make_repartition(list_bus,students) for bus in match: bus.passengers.extend(match[bus]) bus.make_teams() csv_bus_output(list_bus) csv_team_output(list_bus) n=0 m=0 for bus in list_bus: n += bus.places m += len(bus.passengers)+bus.places_2a print(n,m) ======= def latex_output(final_match): print("\\documentclass[fontsize=12pt,twoside=false,parskip=half, french]{scrartcl}") print("\\usepackage[utf8]{inputenc}") print("\\usepackage[T1]{fontenc}") print("\\usepackage{ltablex}") print("\\usepackage{babel}") print("\\usepackage{palatino}\n") print("\\renewcommand{\\arraystretch}{1.5}\n") print("\\begin{document}") print("\\setlength{\\tabcolsep}{0.2cm}") for bus in final_match: print(" \\section{{{}}}".format(bus)) match = final_match[bus] print(" \\begin{center}") print(" \\begin{tabularx}{\\textwidth}{|l|l|} \\hline") i = 0 for student in match: if i % 2 == 0: print(" {} &".format(student)) else: print(" {} \\\\ \\hline".format(student)) i += 1 if i % 2 == 1: print(" \\\\ \\hline") print(" \\end{tabularx}") print(" \\end{center}\n") print("\\newpage") print("\\end{document}") #for dpt in bus_matches_by_dpt: # print("\n\n\n#{}".format(dpt.upper())) # for bus in bus_matches_by_dpt[dpt]: # match = bus_matches_by_dpt[dpt][bus] # print("\n {} {} {}\n".format(bus, rang_moyen(bus, match), note_moyenne(bus, match))) # for student in match: # print(" {}".format(student)) list_bus, students = main("test.csv", "bus_test.csv") list_dpt = set([s.infos["dept"] for s in students]) places_by_bus = {bus: 43 for bus in list_bus} bus_matches_by_dpt = {} part_students = [f for f in students if f.infos['genre'] == 'F'] bus_places = {bus:int(2 + len(part_students)/7) for bus in list_bus} bus_matches_by_dpt["filles"] = split_students(part_students, bus_places) for bus in bus_matches_by_dpt["filles"]: places_by_bus[bus] -= len(bus_matches_by_dpt["filles"][bus]) for dpt in list_dpt: random.shuffle(list_bus) students = [s for s in students if s not in part_students] part_students = [s for s in students if s.infos['dept'] == dpt] places_need = len(part_students) bus_places = {bus: 0 for bus in list_bus} working_places = {bus: places_by_bus[bus] for bus in list_bus} while places_need > 0: #student_by_bus = int(places_need / 7) #for bus in list_bus: # if places_need == 0: # bus_places[bus] += 0 # if places_by_bus[bus] <= 0: # bus_places[bus] += 0 # else: # bus_places[bus] += min(places_by_bus[bus], student_by_bus) # places_need -= bus_places[bus] for bus in list_bus: if places_need > 0 and working_places[bus] > 0: bus_places[bus] += 1 working_places[bus] -= 1 places_need -= 1 for bus in list_bus: if bus_places[bus] == 0 and working_places[bus] > 0: bus_places[bus] += 1 bus_matches_by_dpt[dpt] = split_students(part_students, bus_places) for bus in bus_matches_by_dpt[dpt]: places_by_bus[bus] -= len(bus_matches_by_dpt[dpt][bus]) final_match = merge_bus(bus_matches_by_dpt) latex_output(final_match) #print("BUS RESULTS") #for dpt in bus_matches_by_dpt: # print("\n\n\n#{}".format(dpt.upper())) # for bus in bus_matches_by_dpt[dpt]: # match = bus_matches_by_dpt[dpt][bus] # print("\n {} {} {}\n".format(bus, rang_moyen(bus, match), note_moyenne(bus, match))) # for student in match: # print(" {}".format(student)) #print("Name, average rank, avarage mark") #for bus in final_match: # match = final_match[bus] # print("{} {} {}".format(bus, rang_moyen(bus, match), note_moyenne(bus, match))) #print("\n\n\nStudent by dpt and bus\n\n") #for dpt in bus_matches_by_dpt: # print("\n\n\n#{}".format(dpt.upper())) # for bus in bus_matches_by_dpt[dpt]: # match = bus_matches_by_dpt[dpt][bus] # print("\n {} {} {}".format(bus, rang_moyen(bus, match), note_moyenne(bus, match))) # for student in match: # print(" {}".format(student)) >>>>>>> 7158617afbb760d3a35b62a2705688d11b9d0b1b
parsewiki.py 0 → 100755
 #!/usr/bin/env python3 # -*- coding:utf-8 -* """Pour récupérer des infos à partir du wiki.""" import time import re #import urllib.request import pprint #: URL de la page wiki des bus URL = "https://wiki.crans.org/OrganisationWei{}/Bus?action=raw".format( time.localtime()[0]) FILE = "rawpage" def get_raw(): """Récupère le contenu de la page.""" return open(FILE).read() # page = urllib.request.urlopen(URL) # text = page.read().decode("utf-8") return text def parse_names(raw): """Récupère les tableaux de Bus (= un tableau après un titre commençant par '== Bus').""" names = [] l = re.findall("== (?:Bi)?Bus.*==[^|]*\n((?:\|\|.*\|\|\n)+)", raw) for table in l: obj = re.search("Nom de l'équipe[^|]*\|\|", table) after = table[obj.end():] end = after.index("\n") after = after[:end] teams = re.findall("([^|]+)\|\|", after) teams = [t.strip() for t in teams] names.append(teams) return names def get_team_names(): raw = get_raw() teams = parse_names(raw) return teams if __name__ == "__main__": for t in get_team_names(): print(t)
rawpage 0 → 100644
 ##acl +GroupeBde:admin #acl +GroupeBde:admin GroupeWei:read,write GroupeAdmin:read,write,revert,delete,admin All: ## Ajouter un # au début de la 1ère ligne et ## Retirer le 1er # de la ligne précédente pour rendre la page inaccessible aux 1As = Les Bus du WEI 2018 = Deadline : 30 juin 2018 * Lol. -- [[Wiki20-100|Un vieux con de GC WEI]] <> * Merci pour ta sagesse, nous sommes jeunes et naïfs -- WikiPagnyx <> {{{#!wiki caution L'accès de cette page est verrouillé pour ne pas spoiler le WEI aux 1As.