Le code est en deux parties. Un premier fichier qui me génère une liste d'élèves. Pour vous ça permettra de voir le format des données à produire pour faire tourner le code.
#!/usr/bin/env python3"""Ce programme créé une liste (aléatoire) d'élèves qui sera lue par le programme suivant qui optimisera la répartitiondes étudiants en classes.INTERET : permet de comprendre comment les données sontstructurées dans le programme suivant.USAGE : Lancer le code suivi du nom du fichier dans lequel lesdonnées seront écrites. Exemple : python3 createList.py eleves.dat"""importsysimportnumpyasnpnbEleve=170nbLV2Esp=40nbFoot=15defwriteEleve(fout,n,sexe,espagnol,foot):"""Ecrit la liste des élèves dans le descripteur de fichier "fout". C'est là qu'il faut faire d'éventuelles modifications pour rajouter des options, etc."""fout.write("%7d%4d%7d%5d\n"%(n,sexe,espagnol,foot))returnn+1if__name__=="__main__":try:fout=open(sys.argv[1],"w")except:print("Run this code followed by the name of the file where you intend to write")exit()fout.write("#Numéro sexe espagnol foot\n")#Commentaire en tête de fichiern=0nF=0nE=0""" le fichier est structuré ainsi : D'abord les footbaleurs, puis les hispanisant, suivi des autres."""whilenF<nbFoot:foot=1espagnol=0sexe=int(np.random.rand()*2)# donne 0, ou 1 !n=writeEleve(fout,n,sexe,espagnol,foot)nF+=1whilenE<nbLV2Esp:foot=0espagnol=1sexe=int(np.random.rand()*2)n=writeEleve(fout,n,sexe,espagnol,foot)nE+=1whilen<nbEleve:foot=0espagnol=0sexe=int(np.random.rand()*2)n=writeEleve(fout,n,sexe,espagnol,foot)fout.close()
Voici le code qui applique l'algorithme.
#!/usr/bin/env python3importsysimportnumpyasnp""" Ce programme consomme une liste d'élèves (en argument) avec leurs options.Il les répartis ensuite entre classe en utilisant l'algorithme de Monte-Carlo Metropolis.Exemple : python3 metropolis.py eleves.dat"""defreadList(fname):""" Lis le fichier dont le nom est fname (formaté en colonnes de chiffres) et retourne une matrice (de type np.array) dont chaque ligne correspont à un élève et à ses options (0 ou 1 selon que l'option est choisie)."""data=np.loadtxt(fname,dtype=int)returndataclassclasse:"""Une structure permettant de gérer les classes."""def__init__(self,ldata):""" création d'une classe vide, ldata est la liste complète des élèves du niveau de cette classe."""self.nbMembres=0self.nbFemelles=0self.nbMales=0self.nbEspagnoles=0self.nbFoot=0self.listMembres=[]# Liste des identifiants des élèves de la classeself.ldata=ldata# Liste de l'ensemble des données sur TOUS les élèvesdef__iadd__(self,ide):""" Ajoute l'élève identifié par son numéro ide à la classe """self.listMembres.append(self.ldata[ide][0])self.nbMembres+=1ifself.ldata[ide][1]==0:self.nbFemelles+=1else:self.nbMales+=1self.nbEspagnoles+=self.ldata[ide][2]self.nbFoot+=self.ldata[ide][3]returnselfdef__isub__(self,ide):""" Retire l'élève identifier par son numéro à la classe """self.listMembres.remove(self.ldata[ide][0])self.nbMembres-=1ifself.ldata[ide][1]==0:self.nbFemelles-=1else:self.nbMales-=1self.nbEspagnoles-=self.ldata[ide][2]self.nbFoot-=self.ldata[ide][3]returnself""" Deux méthode permettant de décrire la classe """def__str__(self):s="class nbEleves %d nbFemelles %d nbEspagnoles %d nbFoots %d"%(self.nbMembres,self.nbFemelles,self.nbEspagnoles,self.nbFoot)returnsdef__repr(self):returnself.__str__()defdeplaceEleve(nouvelleClasse,ide,listeClasse,ldata):""" Fonction qui déplace un élève d'une classe à une autre : nouvelleClasse et le numéro de la nouvelle classe dans listeClasse ide est le numéro de l'élève dans ldata """ifldata[ide][4]!=None:# Vérifie que l'élève avait déjà été affecté à une classe auparavantlisteClasse[ldata[ide][4]]-=ideifnouvelleClasse!=None:# Vérifie que l'affectation se fait bien vers une nouvelle classelisteClasse[nouvelleClasse]+=ideldata[ide][4]=nouvelleClassedefcout(listeClasse,ldata,nbEsp):""" Fonction de cout C'est la fonction essentielle du processus. C'est elle qui conditionne la réussite du processus d'affectation. Elle doit augmenter quand un élève n'est pas affecté conformément aux critère choisis. Elle doit décroître quand les critères sont vérifiés. Actuellement 5 critères : a : les classes doivent toutes avoir le même nombre d'élèves. b : autant d'hispanisant dans chacune des classes qui en ont c : ceux qui font du foot doivent impérativement être dans la classe 3 d : les hispanisants sont dans les classes 5 et 6 e : tous les élèves doivent se voir affecter une classe """nbE=len(ldata)# nombre d'élèvesnbC=len(listeClasse)# nombre de classesC=0a=1b=0.5c=10d=4e=50fori,classeinenumerate(listeClasse):### équilibre des classesC+=a*(classe.nbMembres-nbE/nbC)**2### foot en classe 3 (#2)ifi==2:C-=c*classe.nbFoot#print(i,C)else:C+=c*classe.nbFoot#print(i,C)ifi>3:C-=d*classe.nbEspagnoleselse:C+=d*classe.nbEspagnoles### équilibre espagnolesC+=b*(listeClasse[4].nbEspagnoles-listeClasse[5].nbEspagnoles)**2### élève non affectéforiinrange(nbE):if(ldata[i][4]==None):C+=ereturnCdefmetropolis(lClasses,ldata,nbEsp,oldC,beta):# Choisie un élève au hasard, et une classe au hasard,# affecte l'élève dans la classe,# calcul la fonction de coût,# compare à l'ancienne valeure,# choisi de valider l'affectation ou de revenir à l'état précédentide=int(np.random.rand()*len(ldata))cl=int(np.random.rand()*len(lClasses))#oldCl = len(lClasses)+1#if (ldata[ide][4] != None):oldCl=ldata[ide][4]deplaceEleve(cl,ide,lclasses,ldata)nC=cout(lClasses,ldata,nbEsp)p=np.random.rand()ifnp.exp(beta*(nC-oldC))<p:return1,lClasses,ldata,nCelse:#print("ancien - nouveau",oldC,nC)deplaceEleve(oldCl,ide,lclasses,ldata)return0,lClasses,ldata,oldCdefmainMetropolis(lClasses,ldata,nbEsp,oldC):""" Applique l'algorithme de MC Metropolis Nloop fois. Plus l'affection est complexe, plus Nloop doit être grand. Si tout va bien, à la fin, les élèves sont affectés dans les classes conformément aux critères."""C=cout(lClasses,ldata,nbEsp)# Paramètres de l'algorithmebeta=1# conditionne la distribution de BoltzmannNloop=10000# Nombre d'itérations à réaliser# Le taux d'acceptation des modifications des classes# doit avoisinner les 50 %. En fonction de ce taux (moyenné)# le paramètre Beta va être modifié pour faire tendre# le taux vers 50%accept_min=0.4incr=1.25accept_max=0.6decr=0.8accept=0.5mix=0.95# Paramètre pour calculer la moyenne glissante exponentielle :-)# Plus c'est grand, plus la moyenne est calculée sur un grand nombre#de configurations précédentes.foriinrange(Nloop):acc,lClasses,ldata,C=metropolis(lClasses,ldata,nbEsp,C,beta)accept=(1-mix)*acc+mix*acceptifaccept<accept_min:beta*=incrifaccept>accept_max:beta*=decrprint(i,accept,C)returnlClasses,ldataif__name__=="__main__":""" Lecture du fichier des élèves """try:data=readList(sys.argv[1])except:print("Run this code followed by the name of the file where you intend to read students data")exit()#print("OK\n ",data)ldata=[]nbEsp=0foreindata:le=list(e)le.append(None)ldata.append(le)nbEsp+=e[2]#print(ldata)################# create classes C0=classe(ldata)C1=classe(ldata)C2=classe(ldata)C3=classe(ldata)C4=classe(ldata)C5=classe(ldata)print(C0)lclasses=[C0,C1,C2,C3,C4,C5]################## Affectation manuelle d'élèves dans des classes### Ici j'ai fait n'importe quoi, meilleur est### l'état initial, plus rapide sera le succès final.print(lclasses[1])deplaceEleve(2,0,lclasses,ldata)deplaceEleve(2,1,lclasses,ldata)deplaceEleve(2,1,lclasses,ldata)deplaceEleve(2,3,lclasses,ldata)print(ldata[:5])C=cout(lclasses,ldata,nbEsp)print(C)deplaceEleve(2,2,lclasses,ldata)deplaceEleve(2,4,lclasses,ldata)deplaceEleve(2,5,lclasses,ldata)deplaceEleve(2,6,lclasses,ldata)C=cout(lclasses,ldata,nbEsp)print(C)deplaceEleve(2,7,lclasses,ldata)deplaceEleve(2,8,lclasses,ldata)deplaceEleve(2,9,lclasses,ldata)deplaceEleve(2,10,lclasses,ldata)deplaceEleve(1,16,lclasses,ldata)deplaceEleve(1,17,lclasses,ldata)deplaceEleve(1,18,lclasses,ldata)deplaceEleve(1,19,lclasses,ldata)C=cout(lclasses,ldata,nbEsp)print(C)################ OPtimisationmainMetropolis(lclasses,ldata,nbEsp,C)### C'est finiforclasseinlclasses:print(classe)# On peut rajouter une méthode dans "classe"# pour imprimer plus de détails. Par exemple la liste# des élèves de la classe.
J'ai essayé d'ajouter beaucoup de commentaires pour aider... J'espère que ça sera suffisant car mon code est assez brouillon.
[^] # Re: Formulation formelle
Posté par ǝpɐןƃu∀ nǝıɥʇʇɐW-ǝɹɹǝıԀ (site web personnel) . En réponse au message programme et algo de tri. Évalué à 9.
Le code est en deux parties. Un premier fichier qui me génère une liste d'élèves. Pour vous ça permettra de voir le format des données à produire pour faire tourner le code.
Voici le code qui applique l'algorithme.
J'ai essayé d'ajouter beaucoup de commentaires pour aider... J'espère que ça sera suffisant car mon code est assez brouillon.
« IRAFURORBREVISESTANIMUMREGEQUINISIPARETIMPERAT » — Odes — Horace