diff --git a/LISEZMOI.md b/LISEZMOI.md index a580829..3f76666 100644 --- a/LISEZMOI.md +++ b/LISEZMOI.md @@ -1,5 +1,14 @@ # Libraire de calcul Jugement majoritaire +## Etude + +Une étude de l'existant est dans le répertoire étude. + +Ce projet est plutot un jouet comparé à l'existant. +L'idée ici serait d'avoir une API commune ou à minima des formats d'échanges communs. + +## Cette Librairie + Le fonctionnement actuel est de fournir un fichier json contenant la votation. Ce fichier n'a pas de connaissance des votants, juste de leur vote. diff --git a/code/jugement_majoritaire/__init__.py b/code/jugement_majoritaire/__init__.py new file mode 100644 index 0000000..d3e5a6f --- /dev/null +++ b/code/jugement_majoritaire/__init__.py @@ -0,0 +1,104 @@ +import json +import sys + +verbose=False + +def collect_votes(votes,candidats,mentions,warnings): + collect={} + default_mention=mentions-1 + for vote in votes: + # missing candidat in vote picks the worse one + for candidat in candidats: + if not candidat in vote: + vote[candidat]=default_mention + + for candidat,mention in vote.items(): + if mention > default_mention or mention < 0: + mention = default_mention + warnings.append("index de mention invalide, soit la liste des mentions est erronnée soit la mention dans le vote est erronée") + if candidat in collect: + if mention in collect[candidat]: + collect[candidat][mention]=collect[candidat][mention]+1 + else: + collect[candidat][mention]=1 + else: + collect[candidat]={mention:1} + return collect + +def jugement_majoritaire(poll): + + votants=poll['votants']['decompte'] + candidats=poll['candidats'] + nombre_candidats=len(candidats) + + # l'ordre des mentions est de la meilleure à la pire (reject) + nom_mentions=poll['mentions'] + mentions=len(nom_mentions) + + votes=poll["votation"]["votes"] + if verbose: + print('candidats:' + str(candidats)) + print(votes) + + warnings=[] + + collect=collect_votes(votes,list(candidats),mentions,warnings) + if verbose: + print(collect) + + votant_median_check= votants / 2 if votants % 2 == 0 else ((votants-1) / 2) +1 + + votant_median=votants // 2 + votants % 2 + + if votant_median_check != votant_median: + print('[ERROR] le nombre median de votants semble erroné. contactez le developpeur de ce code.' + str(votant_median_check)) + + merite={} + mention_mediane={} + merite_pourcent={} + + # cumul : du meilleur au pire + # range_mentions = range(len(mentions)) + # cumul du pire au meilleur + range_mentions = range(mentions-1,-1,-1) + + for candidat in list(candidats): + vote=collect[candidat] + cumul=0 + m=[0 for i in range(mentions)] + mention_m=None + pourcent=[0 for i in range(mentions)] + for mention in range_mentions: + if mention in vote: + cumul=cumul+vote[mention] + pourcent[mention]= ( 100 * vote[mention] ) / votants + if cumul >= votant_median and mention_m is None: + mention_m=mention + m[mention]=cumul + if cumul < votants: + print('[ERROR] le cumul des votes doit correspondre au nombre de votants. contactez le developpeur de ce code.') + mention_mediane[candidat]=mention_m + merite[candidat]=m + merite_pourcent[candidat]=pourcent + + if verbose: + print(merite) + print(mention_mediane) + + # les gagnants sont ceux qui ont la mention mediane minimale ( la meilleure ) + found=[] + for mention in range(0,mentions): + for candidat,merite_median in mention_mediane.items(): + if merite_median == mention: + found.append({candidat:candidats[candidat]}) + if len(found) > 0: + break + + if verbose: + print(found) + print(nom_mentions[mention]) + + result = {'resultat':{'mention':nom_mentions[mention],'candidats':found},'merite':merite,'profil':merite_pourcent,"warnings":warnings} + + return result + diff --git a/code/parse_sample.py b/code/parse_sample.py index 6a57d0f..8fb5bd2 100644 --- a/code/parse_sample.py +++ b/code/parse_sample.py @@ -1,5 +1,6 @@ import json import sys +from jugement_majoritaire import jugement_majoritaire if len(sys.argv) > 1: poll_file=sys.argv[1] @@ -15,101 +16,6 @@ with open(poll_file,'r') as poll_fd: if verbose: print(poll) -votants=poll['votants']['decompte'] -candidats=poll['candidats'] -nombre_candidats=len(candidats) - -# l'ordre des mentions est de la meilleure à la pire (reject) -nom_mentions=poll['mentions'] -mentions=len(nom_mentions) - -default_mention=mentions-1 - -votes=poll["votation"]["votes"] -if verbose: - print('candidats:' + str(candidats)) - print(votes) - -warnings=[] -default_vote={} -for candidat in candidats: - default_vote[candidat]=default_mention - -collect={} -for vote in votes: - - # missing candidat in vote picks the worse one - for candidat in candidats: - if not candidat in vote: - vote[candidat]=default_mention - - for candidat,mention in vote.items(): - if mention > default_mention or mention < 0: - mention = default_mention - warnings.append("index de mention invalide, soit la liste des mentions est erronnée soit la mention dans le vote est erronée") - if candidat in collect: - if mention in collect[candidat]: - collect[candidat][mention]=collect[candidat][mention]+1 - else: - collect[candidat][mention]=1 - else: - collect[candidat]={mention:1} - -if verbose: - print(collect) - -votant_median_check= votants / 2 if votants % 2 == 0 else ((votants-1) / 2) +1 - -votant_median=votants // 2 + votants % 2 - -if votant_median_check != votant_median: - print('[ERROR] le nombre median de votants semble erroné. contactez le developpeur de ce code.' + str(votant_median_check)) - -merite={} -mention_mediane={} -merite_pourcent={} - -# cumul : du meilleur au pire -# range_mentions = range(len(mentions)) -# cumul du pire au meilleur -range_mentions = range(mentions-1,-1,-1) - -for candidat in candidats: - vote=collect[candidat] - cumul=0 - m=[0 for i in range(mentions)] - mention_m=None - pourcent=[0 for i in range(mentions)] - for mention in range_mentions: - if mention in vote: - cumul=cumul+vote[mention] - pourcent[mention]= ( 100 * vote[mention] ) / votants - if cumul >= votant_median and mention_m is None: - mention_m=mention - m[mention]=cumul - if cumul < votants: - print('[ERROR] le cumul des votes doit correspondre au nombre de votants. contactez le developpeur de ce code.') - mention_mediane[candidat]=mention_m - merite[candidat]=m - merite_pourcent[candidat]=pourcent - -if verbose: - print(merite) - print(mention_mediane) - -# les gagnants sont ceux qui ont la mention mediane minimale ( la meilleure ) -found=[] -for mention in range(0,mentions): - for candidat,merite_median in mention_mediane.items(): - if merite_median == mention: - found.append({candidat:candidats[candidat]}) - if len(found) > 0: - break - -if verbose: - print(found) - print(nom_mentions[mention]) - -result = {'resultat':{'mention':nom_mentions[mention],'candidats':found},'merite':merite,'profil':merite_pourcent,"warnings":warnings} +result = jugement_majoritaire(poll) print(json.dumps(result)) diff --git a/etude/existant.md b/etude/existant.md index 2d51911..ffa4361 100644 --- a/etude/existant.md +++ b/etude/existant.md @@ -22,15 +22,85 @@ https://en.wikipedia.org/wiki/Jugement_majoritaire |source|info|interet| |------------------|-----------------------------|-------------| -|https://github.com/AlexJade23/JugementMajoritaire|RAS VIDE|1/20| -|https://github.com/ostix360/JugementMajoritaire|Où est l'algo ?|2/20| +|https://github.com/MieuxVoter/mieuxvoter.fr||18/20| |https://github.com/CitoyensDeDemain/JugementMajoritaire|Il y a un algo, mais pas de format de donnée, données hardcodées / API et pas de procédure d'install|11/20| +|https://github.com/ostix360/JugementMajoritaire|Où est l'algo ?|2/20| +|https://github.com/AlexJade23/JugementMajoritaire|RAS VIDE|1/20| | + + +# https://mieuxvoter.fr/en + +C'est la référence, les théoriciens du vote majoritaire ont été invités à participer à l'élaboration de ce site. + +Par contre pour trouver la librairie de base... + +https://github.com/MieuxVoter/mieuxvoter.fr + +image docker + + +https://app.mieuxvoter.fr/en/votes/ult-kxm-vzcr + +https://app.mieuxvoter.fr/en/results/ult-kxm-vzcr + +https://app.mieuxvoter.fr/en/admin/ult-kxm-vzcr/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6dHJ1ZSwiZWxlY3Rpb24iOiJ1bHRreG12emNyIn0.TzkM380pk0eVo8_iHJGYANxlapVbp5Z3jxLQSzqLpRM + + +https://app.mieuxvoter.fr/fr/votes/ult-kxm-vzcr : même en français 'Very good' ... + +Obligation de noter tous les participants. + +## Librairie python + +https://github.com/MieuxVoter/majority-judgment-library-python + +Très courte ( ./majority_judgment/__init__.py 145 lignes ) + +``` +>>> from majority_judgment import majority_judgment +>>> data = { +... 'Pizza': [!, 0, 3, 0, 2, 0, 3, 1, 2, 3], +... 'Chips': [0, 1, 0, 2, 1, 2, 2, 3, 2, 3], +... 'Pasta': [0, 1, 0, 1, 2, 1, 3, 2, 3, 3], +... 'Bread': [0, 1, 2, 1, 1, 2, 1, 2, 2, 3], +... } +>>> majority_judgment(data, reverse=False) +{'Chips': 0, 'Pasta': 1, 'Pizza': 2, 'Bread': 3} + +``` + +(!) ? + +## API REST python + +https://github.com/MieuxVoter/majority-judgment-api-python + +License: GNU aGPLV3 / CECILL variant affero compliant + +|postgres|| +|python| >= 3.11 | + +serveur uvicorn + +``` +uvicorn app.main:app --reload --env-file .env.local +``` + +profiles : + +|core| if you only need the backend and database| +|dashboard| if you only need Metabase| +|image| if you only need to store images| +|backup| for restic| + +Election Candidat Grade Vote + # david chavalarias https://github.com/davidchavalarias/jugement-majoritaire -Dans le cadre d'une soutenance en 2014 le porjet n'a pas été maintenu ni forké. +Dans le cadre d'une soutenance en 2014 le projet n'a pas été maintenu ni forké. Une application sous symfony2 ( php Doctrine ) @@ -443,22 +513,3 @@ langage for smart contracts : blockchain donc. # https://github.com/jeromeschwaederle/Vote_Jugement_Majoritaire python simple - -# https://mieuxvoter.fr/en - - -https://github.com/MieuxVoter/mieuxvoter.fr - -image docker - - -https://app.mieuxvoter.fr/en/votes/ult-kxm-vzcr - -https://app.mieuxvoter.fr/en/results/ult-kxm-vzcr - -https://app.mieuxvoter.fr/en/admin/ult-kxm-vzcr/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6dHJ1ZSwiZWxlY3Rpb24iOiJ1bHRreG12emNyIn0.TzkM380pk0eVo8_iHJGYANxlapVbp5Z3jxLQSzqLpRM - - -https://app.mieuxvoter.fr/fr/votes/ult-kxm-vzcr : même en français 'Very good' ... - -Obligation de noter tous les participants. \ No newline at end of file