4
4
import sys
5
5
import random
6
6
import re
7
- from math import sqrt
8
7
from math import ceil
9
8
10
9
11
10
_password = "Abre. Soy yo! Quién va a ser si no?"
12
11
13
-
12
+ ###############################################################################
14
13
# Opciones de ejecucion
14
+ ###############################################################################
15
15
_pop_size = 100
16
16
_elite_rate = 0.2
17
17
_mutate_prob = 0.8
18
18
_max_generations = 10000
19
- _verbose = True
20
- _print_all = True
21
- _static_print = True
19
+ _verbose , _print_all , _static_print = True , False , True
22
20
_version = 0 if os .path .split (__file__ )[- 1 ] == os .path .split (sys .argv [0 ])[- 1 ] else sys .argv [0 ][- 4 ]
23
-
21
+ for arg in sys .argv [1 :]:
22
+ if re .compile ('^-[vasVAS]+' ).search (arg ):
23
+ if 'v' in arg : _verbose = True
24
+ if 'V' in arg : _verbose = False
25
+ if 'a' in arg : _print_all = True
26
+ if 'A' in arg : _print_all = False
27
+ if 's' in arg : _static_print = True
28
+ if 'S' in arg : _static_print = False
29
+ elif re .compile ('^--pop-size=[-\+\d]+' ).search (arg ): _pop_size = int (arg .split ('=' )[1 ])
30
+ elif re .compile ('^--elite-rate=[-\+\d]+' ).search (arg ): _elite_rate = float (arg .split ('=' )[1 ])
31
+ elif re .compile ('^--mutate-prob=[-\+\d]+' ).search (arg ): _mutate_prob = float (arg .split ('=' )[1 ])
32
+ elif re .compile ('^--max-generations=[-\+\d]+' ).search (arg ): _max_generations = int (arg .split ('=' )[1 ])
33
+ elif re .compile ('^--password=.+' ).search (arg ): _password = arg .split ('=' )[1 ]
34
+ elif re .compile ('^[^-]{2}.+' ).search (arg ): _password = arg
35
+ elif re .compile ('^--verbose=[\d]+' ).search (arg ): _verbose = bool (int (arg .split ('=' )[1 ]))
36
+ elif re .compile ('^--all=[\d]+' ).search (arg ): _print_all = bool (int (arg .split ('=' )[1 ]))
37
+ elif re .compile ('^--static=[\d]+' ).search (arg ): _static_print = bool (int (arg .split ('=' )[1 ]))
38
+ elif re .compile ('^--version=[-\+\d]+' ).search (arg ) and os .path .split (__file__ )[- 1 ] == os .path .split (sys .argv [0 ])[- 1 ]: _version = arg .split ('=' )[1 ]
39
+ if sum ([1 for i in [_elite_rate , _mutate_prob , _pop_size , _max_generations ] if i < 0 ]):
40
+ sys .exit ("Error: Invalid parameters" )
41
+
42
+
43
+
44
+ ###############################################################################
45
+ # Metodos aportados por el profesor (No se modifican)
46
+ ###############################################################################
24
47
25
48
def get_password_len ():
26
49
""" Return the length of the current password, for simulation purposes """
@@ -37,75 +60,53 @@ def gene_set():
37
60
return " 0123456789áéíóúabcdefghijklmnñopqrstuvwxyzÁÉÍÓÚABCDEFGHIJKLMNÑOPQRSTUVWXYZ!\" #$%&\' ()*+,-./:;<=>¿?@[\\ ]^_`{|}"
38
61
39
62
40
- def procese_options ():
41
- global _password , _pop_size , _elite_rate , _mutate_prob , _max_generations , _verbose , _print_all , _static_print , _version
42
- # if ('--verbose') in sys.argv: _verbose = True
43
- # if ('--all') in sys.argv: _print_all = True
44
- # if ('--static') in sys.argv: _static_print = True
45
- for arg in sys .argv [1 :]:
46
- if re .compile ('^-[vasVAS]+' ).search (arg ):
47
- if 'v' in arg : _verbose = True
48
- if 'V' in arg : _verbose = False
49
- if 'a' in arg : _print_all = True
50
- if 'A' in arg : _print_all = False
51
- if 's' in arg : _static_print = True
52
- if 'S' in arg : _static_print = False
53
- elif re .compile ('^--pop-size=[-\+\d]+' ).search (arg ): _pop_size = int (arg .split ('=' )[1 ])
54
- elif re .compile ('^--elite-rate=[-\+\d]+' ).search (arg ): _elite_rate = float (arg .split ('=' )[1 ])
55
- elif re .compile ('^--mutate-prob=[-\+\d]+' ).search (arg ): _mutate_prob = float (arg .split ('=' )[1 ])
56
- elif re .compile ('^--max-generations=[-\+\d]+' ).search (arg ): _max_generations = int (arg .split ('=' )[1 ])
57
- elif re .compile ('^--password=.+' ).search (arg ): _password = arg .split ('=' )[1 ]
58
- elif re .compile ('^[^-]{2}.+' ).search (arg ): _password = arg
59
- elif re .compile ('^--verbose=[\d]+' ).search (arg ):
60
- _verbose = bool (int (arg .split ('=' )[1 ]))
61
- elif re .compile ('^--all=[\d]+' ).search (arg ):
62
- _print_all = bool (int (arg .split ('=' )[1 ]))
63
- elif re .compile ('^--static=[\d]+' ).search (arg ):
64
- _static_print = bool (int (arg .split ('=' )[1 ]))
65
- elif re .compile ('^--version=[-\+\d]+' ).search (arg ) and os .path .split (__file__ )[- 1 ] == os .path .split (sys .argv [0 ])[- 1 ]:
66
- _version = arg .split ('=' )[1 ]
67
- if sum ([1 for i in [_elite_rate , _mutate_prob , _pop_size , _max_generations ] if i < 0 ]):
68
- sys .exit ("Error: Invalid parameters" )
69
-
70
-
71
- procese_options ()
72
63
64
+ ###############################################################################
65
+ # Implementación metodos solicitados por el profesor
66
+ ###############################################################################
73
67
74
68
def initial_population (pop_size , chromosome_len ):
75
69
""" Create a initial population """
76
- # return [random.sample(gene_set(), chromosome_len) for _ in range(pop_size)]
77
- # sample devuelve conjuntos de k elementos sin elementos repetidos
78
- return [[random .choice (gene_set ()) for _ in range (chromosome_len )] for _ in range (pop_size )]
70
+ population = []
71
+ for _ in range (pop_size ):
72
+ population .append ( '' .join (random .choice (gene_set ()) for _ in range (chromosome_len )))
73
+ return [[i , get_fitness (i )] for i in population ]
79
74
80
75
81
- # Implemente la función mutate() que recibe un cromosoma y lo muta cambiando aleatoriamente un único gen por otro del gene_set().
82
76
def mutate (chromosome ):
83
77
""" Mutate randomly one gen of the chromosome, which is a string with the characters of the password """
84
- chromosome [random .randint (0 , len (chromosome ) - 1 )] = random .choice (gene_set ())
78
+ pos = random .randint (0 , get_password_len () - 1 )
79
+ chromosome [0 ] = chromosome [0 ][:pos ] + random .choice (gene_set ()) + chromosome [0 ][pos + 1 :]
80
+ chromosome [1 ] = get_fitness (chromosome [0 ])
85
81
return chromosome
86
82
87
83
88
- # Implemente la función crossover() que recibe 2 cromosomas, realiza con ellos una hibridación de 1 punto aleatorio, y devuelve otro cromosoma con la hibridación realizada.
89
84
def crossover (chromosome1 , chromosome2 ):
90
85
""" Perform a one point crossover of the chromosomes """
91
86
if random .random () < 0.5 : chromosome1 , chromosome2 = chromosome2 , chromosome1
92
87
split = random .randint (0 , get_password_len () - 1 )
93
- return chromosome1 [:split ] + chromosome2 [split :]
88
+ hybrid = chromosome1 [0 ][:split ] + chromosome2 [0 ][split :]
89
+ return [hybrid , get_fitness (hybrid )]
94
90
95
91
96
92
def ga (pop_size = _pop_size , elite_rate = _elite_rate , mutate_prob = _mutate_prob , max_generations = _max_generations , fun_next_gen = None ):
97
93
""" Genetic Algorithm driving the search of the password """
98
94
pop = initial_population (pop_size , get_password_len ())
99
95
for i in range (max_generations ):
100
- pop .sort (key = get_fitness )
96
+ pop .sort (key = lambda x : x [ 1 ] )
101
97
print_generation (elite_rate , mutate_prob , the_fitest = pop [0 ], generation = i + 1 , pop = pop )
102
- if get_fitness ( pop [0 ]) == 0 :
103
- return pop [0 ]
98
+ if pop [0 ][ 1 ] == 0 :
99
+ return pop [0 ][ 0 ]
104
100
pop = fun_next_gen (pop , pop_size , elite_rate , mutate_prob )
105
101
print ("Password not found" )
106
102
return False
107
103
108
104
105
+
106
+ ###############################################################################
107
+ # Metodos propios
108
+ ###############################################################################
109
+
109
110
def _clear ():
110
111
if os .name == "nt" : os .system ("cls" )
111
112
else : os .system ("clear" )
@@ -116,58 +117,53 @@ def print_generation(elite_rate, mutate_prob, the_fitest, generation, pop):
116
117
if _verbose :
117
118
print ("Version:" , _version , "\n Password length:" , get_password_len (),
118
119
"\n pop_size:" , len (pop ), "\n elite_rate:" , elite_rate , "\n mutate_prob:" , mutate_prob ,
119
- "\n \n Generation:" , generation , "best-fitness:" , get_fitness ( the_fitest ) ,
120
- "\n " , '' . join ( the_fitest ) )
120
+ "\n \n Generation:" , generation , "best-fitness:" , the_fitest [ 1 ] ,
121
+ "\n " , the_fitest [ 0 ] )
121
122
else :
122
- print ("Generation:" , generation , " best-fitness:" , get_fitness ( the_fitest ) ,
123
- ' ' , '' . join ( the_fitest ) , sep = " " )
123
+ print ("Generation:" , generation , " best-fitness:" , the_fitest [ 1 ] ,
124
+ ' ' , the_fitest [ 0 ] , sep = " " )
124
125
if not _static_print and _verbose and not _print_all : print ("-" * 80 )
125
126
if _print_all :
126
127
print ("\n Listado ordenado de fitness de toda la poblacion:" )
127
- print (* ['{0:{width}}' .format (get_fitness ( i ) , width = 2 ) for i in pop ], sep = " " )
128
+ print (* ['{0:{width}}' .format (i [ 1 ] , width = 2 ) for i in pop ], sep = " " )
128
129
if not _static_print and _print_all : print ("-" * 80 )
129
130
130
131
131
- # def chromosome_to_string(chromosome):
132
- # """ Return the string representation of the chromosome """
133
- # return "".join(chromosome)
134
-
135
-
136
132
def roulette (players , num_winers = 1 ):
137
133
""" Return the winners of the roulette wheel selection """
138
- selection_mode = num_winers < len (players )/ 2
139
- players = players .copy ()
140
- players .sort (key = get_fitness , reverse = selection_mode )
134
+ selection_mode = num_winers < len (players )/ 2 # True si es mejor seleccionar que eliminar
135
+ players = players .copy () # Evitar modificar la lista original
136
+ players .sort (key = lambda x : x [ 1 ] , reverse = selection_mode )
141
137
winners = [] if selection_mode else players
142
138
for _ in range (num_winers if selection_mode else len (players ) - num_winers ):
143
139
domain = gauss_form (len (players ))
144
140
tirada = random .randint (1 , domain )
145
- if selection_mode :
146
- winners .append (players .pop (ceil (inverse_gauss_form (tirada ))- 1 ))
147
- else :
148
- winners .pop (ceil (inverse_gauss_form (tirada ))- 1 )
149
- return winners if len (winners ) > 1 else winners [0 ]
141
+ if selection_mode : winners .append (players .pop ( winner (tirada ) ))
142
+ else : winners .pop ( winner (tirada ) )
143
+ return winners if num_winers != 1 else winners [0 ]
150
144
151
145
152
146
def gauss_form (n ):
153
147
""" Return the sum of 1..n natural numbers """
154
148
return (n * (n + 1 )) // 2
155
149
156
150
157
- def inverse_gauss_form (x ):
151
+ def inverse_gauss_form (a ):
158
152
""" Return the inverse function of the gauss_sum """
159
- return ((8 * x + 1 )** 0.5 - 1 ) / 2
153
+ return ((8 * a + 1 )** 0.5 - 1 ) / 2
154
+
155
+
156
+ def winner (value ):
157
+ """ Return the winner of the roulette wheel selection """
158
+ return ceil ( inverse_gauss_form (value ) ) - 1
160
159
160
+ ###############################################################################
161
+ # Selección de versión
162
+ ###############################################################################
161
163
162
- # print("os.path.split(__file__)[-1] == os.path.split(sys.argv[0])[-1]", os.path.split(__file__)[-1] == os.path.split(sys.argv[0])[-1])
163
- # print(" __file__", __file__ )
164
- # print("sys.argv[0]", sys.argv[0])
165
- # print("sys.argv", sys.argv)
166
164
if os .path .split (__file__ )[- 1 ] == os .path .split (sys .argv [0 ])[- 1 ]:
167
165
if _version :
168
166
exec (open ('ga_v{}.py' .format (_version )).read ())
169
- # print("os.execv(sys.executable, sys.argv):")
170
- # os.execv(sys.executable, [sys.argv[0], [sys.argv[1:]]])
171
167
else :
172
168
print ("\n Ejecute el archivo correspondiente de la versión, o indique la versión que dese ejecutar." ,
173
169
"Ejemplos:" ,
0 commit comments