diff --git a/.DS_Store b/.DS_Store index ce584036d310ff852c50dff6063d64ba8881c0a3..c6bf50dfd786e007f7389525a204a30892ff7c32 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/RotTable.py b/RotTable.py index 9f841efe35b5e7de98443db1b6948ec1a040ef33..57a77141fb2f9b28f02bb74489e76a1e7c09ca85 100644 --- a/RotTable.py +++ b/RotTable.py @@ -5,6 +5,7 @@ import numpy class RotTable: """Represents the rotation table""" + #The standart Rotation table given by the base problem __ORIGINAL_ROT_TABLE = {\ "AA": [35.62, 7.2, -154, 0.06, 0.6, 0],\ "AC": [34.4, 1.1, 143, 1.3, 5, 0],\ @@ -24,6 +25,7 @@ class RotTable: "TT": [35.62, 7.2, 154, 0.06, 0.6, 0]\ } + #The table that indicates what dinucleotides have dependent angles __CORRESPONDANCE = {\ "AA": "TT",\ "AC": "GT",\ @@ -55,6 +57,11 @@ class RotTable: "GC": "GC",\ "TA": "TA"\ } + + ################### + # WRITING METHODS # + ################### + # get the angles in each axis (x, y, z), considering the deviation def __init__(self): self.rot_table = {} @@ -67,6 +74,7 @@ class RotTable: def alea(self): for dinucleotide in RotTable.__SOUS_CORRESPONDANCE: for i in range(2): + #We use a unifor distribution along the desired values delta = numpy.random.uniform(low = -RotTable.__ORIGINAL_ROT_TABLE[dinucleotide][i+3], high= RotTable.__ORIGINAL_ROT_TABLE[dinucleotide][i+3]) self.rot_table[dinucleotide][i] += delta self.rot_table[RotTable.__SOUS_CORRESPONDANCE[dinucleotide]][i] += delta @@ -78,9 +86,6 @@ class RotTable: def corr(self): return self.__CORRESPONDANCE - ################### - # WRITING METHODS # - ################### #table = RotTable() #table.rot_table["AA"] --> [35.62, 7.2, -154] @@ -99,7 +104,3 @@ class RotTable: ################### -#table1 = RotTable() -#print(table1.orta()) - -# print(table1.rot_table) diff --git a/__pycache__/RotTable.cpython-37.pyc b/__pycache__/RotTable.cpython-37.pyc index d0d2bee9e71c849781de9a96c497f02788ecaaf7..a2a8357d3008572384c7dcf2386e0a1d32d1e2de 100644 Binary files a/__pycache__/RotTable.cpython-37.pyc and b/__pycache__/RotTable.cpython-37.pyc differ diff --git a/__pycache__/Traj3D.cpython-37.pyc b/__pycache__/Traj3D.cpython-37.pyc index 9f5f20ef7c01a060943e03ea5beaee567c92ae7e..cf10de94215a889844b8498bfa1adceac74c8132 100644 Binary files a/__pycache__/Traj3D.cpython-37.pyc and b/__pycache__/Traj3D.cpython-37.pyc differ diff --git a/__pycache__/croisement.cpython-37.pyc b/__pycache__/croisement.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d198ea9d256280ccf31cd22357458311486cf9b6 Binary files /dev/null and b/__pycache__/croisement.cpython-37.pyc differ diff --git a/__pycache__/individu.cpython-37.pyc b/__pycache__/individu.cpython-37.pyc index 32b398e808901aa0ca8d048b9b3c1ebb2f6c5133..49544ba734948726b642b284d58a3f5e1c39df81 100644 Binary files a/__pycache__/individu.cpython-37.pyc and b/__pycache__/individu.cpython-37.pyc differ diff --git a/__pycache__/population.cpython-37.pyc b/__pycache__/population.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c8b9251be885e62a4a09645d6eb683f983ea38da Binary files /dev/null and b/__pycache__/population.cpython-37.pyc differ diff --git a/algogenetique.py b/algogenetique.py index 2d0a1406619babfff5e1724a2757c0f92a5a6f01..9db84ff75a810c25f7869ffbfeb142dff48cf47a 100644 --- a/algogenetique.py +++ b/algogenetique.py @@ -10,47 +10,57 @@ from random import random import matplotlib.pyplot as plt import time -# Debut du decompte du temps +# Start of the time counting start_time = time.time() def main(N,tmax,pmutation, proportion): - - L=[] - lineList = [line.rstrip('\n') for line in open("plasmid_8k.fasta")] - brin = ''.join(lineList[1:]) + + #Creation of the initial population People=Population(N) + L=[] + + #Evaluating the initial population for the histogram S1=[] for individu in People.indiv: individu.evaluate() S1.append(int(individu.score)) maximum=int(max(S1)) + + #The main loop of new generations for i in range(tmax): mini=People.indiv[0].score best=People.indiv[0] People.reproduction(p = proportion, proba_mutation= pmutation) + + #Searching for the best individual in each generation for individu in People.indiv: if individu.score<mini: best=individu mini=individu.score + #Printing usefull data (generation average and their best score) S2=[individu.score for individu in People.indiv] avg = sum(S2)/len(S2) L.append(mini) print(i,"avg:",avg,"best score:", mini) + + + #Plotting all the graphs plt.subplot(221) plt.plot([i for i in range(tmax)], L) - + #Graph of the original population plt.subplot(223) plt.hist(S1, range = (0, maximum+10), bins = 20, color = 'red') S2=[individu.score for individu in People.indiv] print("Score final: ",best.score) + print("Distance finale: ", best.distance) print("Avg:", sum(S2)/len(S2)) - print("Distance final: ",best.distance) + #Graph of the final population plt.subplot(224) plt.hist(S2, range = (0,maximum+10), bins = 20, color = 'blue') plt.show() @@ -58,6 +68,8 @@ def main(N,tmax,pmutation, proportion): return(best,People) + +#Testing our solution and printing the result in 3D lineList = [line.rstrip('\n') for line in open("plasmid_8k.fasta")] brin = ''.join(lineList[1:]) best,People = main(10,1000,0.05,5) diff --git a/croisement.py b/croisement.py index 95119ecfe8ad91ea23492e9e9eab8fb3ced18b09..e9942ef5b4d0c7e628dfbd1515587c22b1486c1f 100644 --- a/croisement.py +++ b/croisement.py @@ -2,37 +2,22 @@ import numpy from RotTable import RotTable from individu import Individu -ROT_TABLE = {\ - "AA": [35.62, 7.2, -154, 0.06, 0.6, 0],\ - "AC": [34.4, 1.1, 143, 1.3, 5, 0],\ - "AG": [27.7, 8.4, 2, 1.5, 3, 0],\ - "AT": [31.5, 2.6, 0, 1.1, 2, 0],\ - "CA": [34.5, 3.5, -64, 0.9, 34, 0],\ - "CC": [33.67, 2.1, -57, 0.07, 2.1, 0],\ - "CG": [29.8, 6.7, 0, 1.1, 1.5, 0],\ - "CT": [27.7, 8.4, -2, 1.5, 3, 0],\ - "GA": [36.9, 5.3, 120, 0.9, 6, 0],\ - "GC": [40, 5, 180, 1.2, 1.275, 0],\ - "GG": [33.67, 2.1, 57, 0.07, 2.1, 0],\ - "GT": [34.4, 1.1, -143, 1.3, 5, 0],\ - "TA": [36, 0.9, 0, 1.1, 2, 0],\ - "TC": [36.9, 5.3, -120, 0.9, 6, 0],\ - "TG": [34.5, 3.5, 64, 0.9, 34, 0],\ - "TT": [35.62, 7.2, -154, 0.06, 0.6, 0]\ - } - - def croisement_un_point(parent1, parent2): '''Croise les tables de rotation des parents pour former deux enfants en respectant les symétries du problème''' ''' Retourne deux enfants''' + enfant1 = Individu(RotTable()) enfant2 = Individu(RotTable()) comp = 0 point_crois= numpy.random.random_integers(0,8) - list_dinucleotides = sorted(ROT_TABLE) + list_dinucleotides = sorted(RotTable().orta()) + + #We look at the list of sorted dinucleotides and create the crossover for doublet in list_dinucleotides: if doublet == "GA": break + + #If it have a value smaller than the generated number it wont do the crossover if comp < point_crois: enfant1.table.rot_table[doublet] = parent1.table.rot_table[doublet] correspondent_doublet1 = enfant1.table.corr()[doublet] @@ -44,6 +29,7 @@ def croisement_un_point(parent1, parent2): enfant2.table.rot_table[correspondent_doublet2] = parent2.table.rot_table[correspondent_doublet2] enfant2.table.rot_table[correspondent_doublet2][2] *= -1 + #If it have a value bigger than the generated number it will crossover else : enfant1.table.rot_table[doublet] = parent2.table.rot_table[doublet] correspondent_doublet1 = enfant1.table.corr()[doublet] @@ -62,13 +48,19 @@ def croisement_un_point(parent1, parent2): def croisement_deux_points(parent1, parent2): ''' Croise les tables de rotationd des deux parents en croisant à deux points et respectant les symétries du problème''' ''' Retourne deux enfants''' + enfant1 = Individu(RotTable()) enfant2 = Individu(RotTable()) comp = 0 point_crois1= numpy.random.random_integers(0,8) point_crois2= numpy.random.random_integers(0,8) list_dinucleotides = sorted(ROT_TABLE) + + #We look at the list of sorted dinucleotides and create the crossover for doublet in list_dinucleotides: + + #If it have a value smaller than the first generated number it wont do the crossover + #unless it have a value bigger than the second generated number if comp < min(point_crois1,point_crois2) or comp > max(point_crois1,point_crois2): enfant1.table.rot_table[doublet] = parent1.table.rot_table[doublet] correspondent_doublet1 = enfant1.table.corr()[doublet] @@ -80,6 +72,7 @@ def croisement_deux_points(parent1, parent2): enfant2.table.rot_table[correspondent_doublet2] = parent2.table.rot_table[correspondent_doublet2] enfant2.table.rot_table[correspondent_doublet2][2] *= -1 + #If it have a value is located in between the generated values it will do the crossover else : enfant1.table.rot_table[doublet] = parent2.table.rot_table[doublet] correspondent_doublet1 = enfant1.table.corr()[doublet] @@ -92,11 +85,3 @@ def croisement_deux_points(parent1, parent2): enfant2.table.rot_table[correspondent_doublet2][2] *= -1 comp += 1 return enfant1, enfant2 - -# parent1 = Individu(RotTable()) -# parent2 = Individu(RotTable()) -# print("parent1: ", parent1.table.rot_table) -# print("parent2: ", parent2.table.rot_table) -# enfant1, enfant2 = croisement_un_point(parent1, parent2) -# print("enfant1: ", enfant1.table.rot_table) -# print("enfant2: ", enfant2.table.rot_table) \ No newline at end of file diff --git a/first_plot.png b/first_plot.png index 0e536fb530ea40bc82a9395940755ad27a030609..f9294f16e9e6dc29674f763436bc6927a5b6bbb7 100644 Binary files a/first_plot.png and b/first_plot.png differ diff --git a/individu.py b/individu.py index 581d0bfb800189d20aa06b4c91ce5dd12463d203..c75d14545841b5091e248ef2b58c265fd5234ea4 100644 --- a/individu.py +++ b/individu.py @@ -8,28 +8,33 @@ P1 = 0.015 class Individu(): ''' Un individu est caractérisé par sa table de rotations (individu.table)''' + def __init__(self, table): - lineList = [line.rstrip('\n') for line in open("plasmid_8k.fasta")] - brin = ''.join(lineList[1:]) self.table = table lineList = [line.rstrip('\n') for line in open("plasmid_8k.fasta")] self.brin = ''.join(lineList[1:]) #self.brin = "AAAGGATCTTCTTGAGATCCTTTTTTTCTGCGCGTAATCTGCTGCCAGTAAACGAAAAAACCGCCTGGGGAGGCGGTTTAGTCGAA" + # (sequence used for test) self.score = None self.distance = None def evaluate(self): ''' Evalue le score d'un individu sur un nombre numb_ajout de points''' - + # The last numb_ajout dinucleotides of the "ribbon" are joined at its beginning, + # and the first numb_ajout dinucleotides are joined at the end of it. + # This "new parts" of the sequence will be compared with the real beginning and end of the the ribbon. + # If they coincide, then the chromosome is circular traj = Traj3D() numb_ajout = 50 - fisrt_seq = self.brin[0:numb_ajout] + # the first and the last numb_ajout dinucleotides respectively + first_seq = self.brin[0:numb_ajout] last_seq = self.brin[-numb_ajout:] - traj.compute(last_seq + self.brin + fisrt_seq, self.table) + # creation of the "new ribbon" + traj.compute(last_seq + self.brin + first_seq, self.table) traj_array = traj.getTraj() list_distance = [] @@ -37,6 +42,8 @@ class Individu(): begining = traj_array[0:2*numb_ajout] end = traj_array[-2*numb_ajout:] + # score calculation, comparing the new ribbon with the real sequence, + # according to the distance of the correspondent dinucleotides for i in range(numb_ajout): nuc_coordonate_beg = begining[i] @@ -47,10 +54,10 @@ class Individu(): self.score = max(list_distance) self.distance = np.linalg.norm(traj_array[numb_ajout] - traj_array[-(numb_ajout+1)], ord=2) - #return max(list_distance) def mutation(self, proba = P1): + # each dinucleotide has a probability "proba" to mutate table_rotations = self.table.rot_table for doublet in sorted(table_rotations.keys()) : for coord in range(3): @@ -65,6 +72,8 @@ class Individu(): table_rotations[doublet2][coord] = - table_rotations[doublet][coord] def mutation_with_numbers(self, proba = P1, number_of_mutations = 1): + # each individual has a probability "proba" to be mutated + # if it mutates, then a number "number_of_mutations" of chromosomes will be randomly mutated table_rotations = self.table.rot_table table_rotation_not_seen = [i for i in sorted(table_rotations.keys())] table_rotation_not_seen = table_rotation_not_seen[:8] @@ -87,6 +96,9 @@ class Individu(): def mutation_close_values(self, proba = P1, number_of_mutations = 1): + # each individual has a probability "proba" to be mutated + # if it mutates, then a number "number_of_mutations" of chromosomes will be randomly mutated + # according to the normal distribution around the current value of the dinucleotide table_rotations = self.table.rot_table table_rotation_not_seen = [i for i in sorted(table_rotations.keys())] table_rotation_not_seen = table_rotation_not_seen[:8] @@ -99,7 +111,7 @@ class Individu(): table_rotation_not_seen.remove(doublet) for coord in range(3): - value = table_rotations[doublet][coord] + np.random.normal(0, self.table.orta()[doublet][coord + 3]/15) + value = table_rotations[doublet][coord] + np.random.normal(0, self.table.orta()[doublet][coord + 3]/10) if value > self.table.orta()[doublet][coord] + self.table.orta()[doublet][coord + 3]: value = self.table.orta()[doublet][coord] + self.table.orta()[doublet][coord + 3] elif value < self.table.orta()[doublet][coord] - self.table.orta()[doublet][coord + 3]: @@ -112,18 +124,3 @@ class Individu(): else : #sur l'axe z il y a un moins table_rotations[doublet2][coord] = - table_rotations[doublet][coord] - -# individu1 = Individu(RotTable()) -# print(individu1.table.rot_table) -# individu1.mutation() - -#table = RotTable() -#test = Individu(table) -#test.evaluate() -#print(test.score) - - -# qqun=Individu(RotTable()) -# qqun.table.rot_table={'AA': [35.576558502141, 7.433901511509349, -154], 'AC': [33.22048222654215, 5.25191751302917, 143], 'AG': [26.446029097301288, 6.052240462237622, -2], 'AT': [30.47045254036881, 1.333716025628036, 0], 'CA': [34.00734209585039, 33.70710613604862, -64], 'CC': [33.61019622767888, 3.713127032109607, -57], 'CG': [29.664061041382677, 6.725155507162601, 0], 'CT': [26.446029097301288, 6.052240462237622, 2], 'GA': [36.655773481637176, 10.45337581740701, 120], 'GC': [42.26984493493484, 3.5310453395352823, 180], 'GG': [33.61019622767888, 3.713127032109607, -57], 'GT': [33.22048222654215, 5.25191751302917, 143], 'TA': [36.951508786388914, -2.5174751178033303, 0], 'TC': [36.655773481637176, 10.45337581740701, -120], 'TG': [34.00734209585039, 33.70710613604862, -64], 'TT': [35.576558502141, 7.433901511509349, -154]} -# qqun.evaluate("AAAGGATCTTCTTGAGATCCTTTTTTTCTGCGCGTAATCTGCTGCCAGTAAACGAAAAAACCGCCTGGGGAGGCGGTTTAGTCGAA") -# print(qqun.score) diff --git a/population.py b/population.py index 1a9301aef80ada02598b9a556590f604a64e93c4..2c89349ff371c58b15e405c5afa37c50eda00dc7 100644 --- a/population.py +++ b/population.py @@ -4,70 +4,69 @@ from RotTable import RotTable from croisement import croisement_un_point, croisement_deux_points import copy + class Population: + '''A class of the ensemble of individuals and the methods associated with them,such as reproduction and different types of selections''' + + + #Class initialization def __init__(self,n): self.indiv=[Individu(RotTable()) for k in range (n)] self.n = n - + + #Updates the current individuals in the population def modifier_population(self, liste_individus): """Fonction qui renvoie une nouvelle instance de population a partir d'une liste d'individus""" self.n = len(liste_individus) self.indiv = liste_individus return self + #Select a fixed number of individuals in a population def selection_p_best(self,p=None): if p==None: p=(self.n)//2 - - def tri_rapide_aux(tableau,debut,fin): - if debut < fin-1: - positionPivot=partitionner(tableau,debut,fin) - tri_rapide_aux(tableau,debut,positionPivot) - tri_rapide_aux(tableau,positionPivot+1,fin) - - def tri_rapide(tableau): - tri_rapide_aux(tableau,0,len(tableau)) - liste_individus=self.indiv - tri_rapide(liste_individus) + liste_individus.sort(key = lambda individu : individu.score) individus_selectionnes = [element for element in liste_individus[:p]] self = self.modifier_population(individus_selectionnes) - + #Select via comparing two random individuals with some randomness involved and compared def selection_duel_pondere(self,p=None): if p == None : p = (self.n)//2 - newself=[] - vu=set() + meilleur = self.indiv[0] + for individu in self.indiv : + if meilleur.score > individu.score: + meilleur = individu + newself=[meilleur] m=randrange(0,self.n) - t=randrange(0,self.n) #méthode des duels pondérée: si x=10 et y=1, y a une chance sur 11 de passer + t=randrange(0,self.n) + #méthode des duels pondérée: si x=10 et y=1, y a une chance sur 11 de passer + non_vu = [i for i in range(0, self.n)] while len(newself)<p: - while m in vu: - m=randrange(0,self.n) - while t in vu: - t=randrange(0,self.n) + m = choice(non_vu) + non_vu.remove(m) + t = choice(non_vu) + non_vu.remove(t) x=self.indiv[m] y=self.indiv[t] - vu.add(t) - vu.add(m) - p=random() - if p>x.score/(x.score+y.score): + proba=random() + if proba<x.score/(x.score+y.score): newself.append(y) else: newself.append(x) self = self.modifier_population(newself) + #Selection via comparing the player`s score randomly def selection_duel(self,p=None): if p == None : p = (self.n)//2 meilleur = self.indiv[0] for individu in self.indiv : if meilleur.score > individu.score: - #print("meilleur, individu: ", meilleur.score, individu.score) meilleur = individu - newself = [meilleur] - vu=set() + newself = [meilleur] t=randrange(0,self.n) m=randrange(0,self.n) non_vu = [i for i in range(0, self.n)] @@ -85,82 +84,72 @@ class Population: newself.append(y) self = self.modifier_population(newself) - - + #Selection using a random method to select players based on their rank in score def selection_par_rang(self,p = None): if p == None : p = (self.n)//2 liste_individus = self.indiv - n = self.n - - def echanger(tableau, i, j): - tableau[i], tableau[j] = tableau[j], tableau[i] - - def partitionner(tableau,debut,fin): - echanger(tableau,debut,randint(debut,fin-1)) - partition=debut - for i in range(debut+1,fin): - # if tableau[i] < tableau[debut]: - if tableau[i].score<tableau[debut].score: - partition+=1 - echanger(tableau,i,partition) - echanger(tableau,debut,partition) - return partition - - def tri_rapide_aux(tableau,debut,fin): - if debut < fin-1: - positionPivot=partitionner(tableau,debut,fin) - tri_rapide_aux(tableau,debut,positionPivot) - tri_rapide_aux(tableau,positionPivot+1,fin) - - def tri_rapide(tableau): - tri_rapide_aux(tableau,0,len(tableau)) - - tri_rapide(liste_individus) - individus_selectionnes = [] + n = self.n + liste_individus.sort(key = lambda individu : individu.score, reverse = True) + individus_selectionnes = [liste_individus[-1]] - for _ in range(p): + for _ in range(p-1): curseur = random()*n*(n+1)/2 - # print("curseur", curseur) j = 1 while j*(j+1)/2 < curseur : j+=1 #on doit prendre l'individu avec le jème score - # print("individus selectionés", individus_selectionnes) individus_selectionnes.append(liste_individus[j-1]) self = self.modifier_population(individus_selectionnes) - def selection_proportionelle(self,p= None): + #Selecting using a random method that takes the score into ponderation + def selection_proportionnelle(self,p= None): if p == None : p = (self.n)//2 - newself=[] + meilleur = self.indiv[0] + for individu in self.indiv : + if meilleur.score > individu.score: + meilleur = individu + newself = [meilleur] somme=0 for indiv in self.indiv: - somme=somme+indiv.score + somme+=1/indiv.score while len(newself)<p: m=m=randrange(0, self.n) x=self.indiv[m] - p=random() - if p<=x.score/somme: + proba=random() + if proba<=x.score/somme: newself.append(x) self = self.modifier_population(newself) + #The Function that makes the selection and reduces the quantity of players + #and after reproduces and mutates the remaining ones into a new population def reproduction(self,proba_mutation = None, selection=None,enfant=croisement_un_point, p = None): + liste_selections = [self.selection_p_best, self.selection_duel_pondere, self.selection_duel, self.selection_par_rang, self.selection_proportionnelle] + + #Values of variables if there are no initial conditions if proba_mutation == None : proba_mutation = 0.001 if selection == None : selection = self.selection_duel + else : + selection = liste_selections[selection] if p == None : p = (self.n)//2 + + vieille_taille = self.n selection(p) newself = [element for element in self.indiv] while len(newself)<vieille_taille: m=randrange(0,self.n) t=randrange(0,self.n) + #We have to make a deep copy so we dont lose the values of the parents x=copy.deepcopy(newself[m]) y=copy.deepcopy(newself[t]) + + #Creation of the childs couple_enfant = enfant(x,y) for child in couple_enfant : child.mutation_close_values(proba_mutation, number_of_mutations = 2) @@ -169,26 +158,11 @@ class Population: newself.append(couple_enfant[1]) self = self.modifier_population(newself) - +#Prints the current population(used for debugging) def afficher(popu): for individu in popu.indiv : print("\n individu \n") - print(individu.table.rot_table) print ("score", individu.score) - -def test(): - popu = Population(4) - print("\n POPULATION INITIALE \n") - for individu in popu.indiv : - individu.evaluate() - afficher(popu) - popu.reproduction(selection = popu.selection_duel) - print("\n REPRODUCTION \n") - afficher(popu) - -#test() - -