Skip to content

Commit 91513ef

Browse files
committed
Antes de opciones por atributo de entrada
1 parent d695d80 commit 91513ef

File tree

5 files changed

+127
-91
lines changed

5 files changed

+127
-91
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
/.vscode
2-
/trabajo2.pdf
2+
/trabajo2.pdf
3+
/__pycache__
4+
.gitignore

ga.py

+53-90
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,20 @@
11
# -*- coding: utf-8 -*-
22

3-
# import math
3+
import os
4+
import sys
45
import random
6+
from math import sqrt
7+
from math import ceil
8+
9+
# Opciones de ejecucion
10+
verbose = False
11+
print_all = False
12+
if ('-v' or '--verbose') in sys.argv: verbose = True
13+
if ('-a' or '--all') in sys.argv: print_all = True
514

6-
import ga_aux
715

816
_password = "Abre. Soy yo! Quién va a ser si no?"
9-
# _password = "El módulo estandariza un conjunto básico de herramientas rápidas y eficientes en memoria que son útiles por sí mismas o en combinación. Juntos, forman un álgebra iteradora que permite construir herramientas especializadas de manera sucinta y eficiente en Python puro."
10-
# _password = "Este módulo implementa una serie de bloques de construcción de iteradores inspirados en construcciones de APL, \"Haskell\" y SML. Cada uno ha sido refundido en una forma adecuada para Python. El módulo estandariza un conjunto básico de herramientas rápidas y eficientes en memoria que son útiles por sí mismas o en combinación. Juntos, forman un álgebra iteradora que permite construir herramientas especializadas de manera sucinta y eficiente en Python puro. Por ejemplo, SML proporciona una herramienta de tabulación: que produce una secuencia . El mismo efecto se puede lograr en Python combinando map() y count() para formar .tabulate(f)f(0), f(1), ...map(f, count()) Estas herramientas y sus contrapartes integradas también funcionan bien con las funciones de alta velocidad en el módulo del operador. Por ejemplo, el operador de multiplicación se puede mapear a través de dos vectores para formar un producto de punto eficiente: .sum(map(operator.mul, vector1, vector2))Iteradores infinitos: "
11-
12-
''' Settings for the genetic algorithm
13-
aptitud:
14-
- proportional: Probabilidad de supervivencia proporcional al valor de la función fitness
15-
- ranked: Probabilidad de supervivencia proporcional a pa posicion en el ranking
16-
muestreo:
17-
- ruleta: Seleccion por ruleta
18-
- torneo: Seleccion por n torneos
19-
- elitista: Seleccion por elitismo (Mantener a los mejores para evitar perderlos)
20-
mutacion:
21-
- intercambio: Intercambia dos genes
22-
- incremento: Incrementa un gen
23-
- decremento: Decrementa un gen
24-
cruzamiento: (crossover)
25-
- 1_punto: Cruza un punto
26-
- 2_puntos: Cruza dos puntos
27-
- random: Cruza aleatoriamente
28-
29-
'''
17+
# _password = "Python Random module is an in-built module of Python which is used to generate random numbers. These are pseudo-random numbers means these are not truly random. This module can be used to perform random actions such as generating random numbers, print random a value for a list or string, etc."
3018

3119

3220
def get_password_len():
@@ -35,9 +23,7 @@ def get_password_len():
3523

3624

3725
def get_fitness(guess):
38-
""" Return the number of caracters in guess string mismatching the same position of the password """
39-
# El objeto zip produce tuplas de n-longitud, donde n es el número de iterables pasados como argumentos posicionales a zip().
40-
# El elemento i-ésimo en cada tupla viene del argumento i-ésimo iterable a zip(). Esto continúa hasta que el argumento más corto se agota.
26+
""" Return the number of caracters in guess string mismathing the same position of the password """
4127
return sum(1 for expected, actual in zip(_password, guess) if expected != actual)
4228

4329

@@ -49,105 +35,82 @@ def gene_set():
4935
def initial_population(pop_size, chromosome_len):
5036
""" Create a initial population """
5137
# return [random.sample(gene_set(), chromosome_len) for _ in range(pop_size)]
38+
# sample devuelve conjuntos de k elementos sin elementos repetidos
5239
return [[random.choice(gene_set()) for _ in range(chromosome_len)] for _ in range(pop_size)]
5340

5441

5542
# Implemente la función mutate() que recibe un cromosoma y lo muta cambiando aleatoriamente un único gen por otro del gene_set().
5643
def mutate(chromosome):
5744
""" Mutate randomly one gen of the chromosome, which is a string with the characters of the password """
58-
chromosome[random.randint(0, len(chromosome) - 1)
59-
] = random.choice(gene_set())
45+
chromosome[random.randint(0, len(chromosome) - 1)] = random.choice(gene_set())
6046
return chromosome
6147

6248

6349
# 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.
6450
def crossover(chromosome1, chromosome2):
6551
""" Perform a one point crossover of the chromosomes """
66-
p = random.randint(0, get_password_len() - 1)
67-
return chromosome1[:p] + chromosome2[p:]
68-
69-
70-
"""
71-
• pop_size el tamaño de la población (por defecto 100) que se mantiene fijo entre generaciones
72-
• elite_rate la proporción de la población que se consideran buenas soluciones y que se usan para construir la siguiente población (por defecto es el 20%)
73-
• mutate_prob la proporción de candidatos que mutan (por defecto es el 80%) de la población entera (incluida la élite). Los candidatos que no se mutan, se cruzan con otro
74-
• max_generations el número máximo de generaciones que permitimos iterar en el
75-
algoritmo (pode defecto 10.000)
76-
"""
52+
if random.random() < 0.5: chromosome1, chromosome2 = chromosome2, chromosome1
53+
split = random.randint(0, get_password_len() - 1)
54+
return chromosome1[:split] + chromosome2[split:]
7755

7856

79-
def ga(pop_size=1000, elite_rate=0.2, mutate_prob=0.8, max_generations=10000):
57+
def ga(pop_size=100, elite_rate=0.2, mutate_prob=0.8, max_generations=10000, fun_next_gen=None):
8058
""" Genetic Algorithm driving the search of the password """
8159
pop = initial_population(pop_size, get_password_len())
8260
for i in range(max_generations):
8361
pop.sort(key=get_fitness)
84-
ga_aux.clear()
85-
print("Password length:", get_password_len(), "\n\nGeneration:",
86-
i, "fitness:", get_fitness(pop[0]), "\n", chromosome_to_string(pop[0]))
87-
if get_fitness(pop[0]) == 0: return pop[0]
88-
# pop = next_generation_roulette(pop, elite_rate, mutate_prob)
89-
pop = next_generation(pop, elite_rate, mutate_prob)
62+
print_generation(pop_size, elite_rate, mutate_prob, the_fitest=pop[0], generation=i, pop=pop)
63+
if get_fitness(pop[0]) == 0:
64+
return pop[0]
65+
pop = fun_next_gen(pop, pop_size, elite_rate, mutate_prob)
9066
print("Password not found")
9167
return False
9268

9369

94-
def next_generation(pop, elite_rate, mutate_prob):
95-
""" Return the next generation """
96-
pop_size = len(pop)
97-
# Selecciona la elite
98-
pop = pop[:int(pop_size * elite_rate)]
99-
# Cruzar elite hasta completar la población
100-
while len(pop) < pop_size:
101-
pop.append(crossover(random.choice(pop), random.choice(pop)))
102-
# Mutar al mutate_prob de la poblacion
103-
pop = [pop[i] if random.random() > mutate_prob else mutate(pop[i]) for i in range(len(pop))]
104-
return pop
105-
106-
107-
def next_generation_roulette(pop, elite_rate, mutate_prob):
108-
""" Return the next generation """
109-
pop_size = len(pop)
110-
# Selecciona la elite
111-
split = int(pop_size * elite_rate)
112-
elite, non_elite = pop[:split], pop[split:]
113-
# Mutar entre los no elite
114-
non_elite = [non_elite[i] if random.random() > mutate_prob else mutate(non_elite[i]) for i in range(len(non_elite))]
115-
# Cruzar para generar descendencia. Se cruza por parejas en orden para cruzar individuos de similar fitness
116-
progeny = [crossover(pop[i], pop[i+1]) for i in range(0, pop_size, 2)]
117-
return elite + roulette_wheeling(non_elite + progeny, num_winers=pop_size - len(elite))
70+
def _clear():
71+
if os.name == "nt": os.system("cls")
72+
else: os.system("clear")
73+
74+
75+
def print_generation(pop_size, elite_rate, mutate_prob, the_fitest, generation, pop):
76+
if not print_all: _clear()
77+
print("Password length:", get_password_len(), "\npop_size:", len(pop),
78+
"\nelite_rate:", elite_rate, "\nmutate_prob:", mutate_prob,
79+
"\n\nGeneration:", generation, "fitness:", get_fitness(the_fitest),
80+
"\n", chromosome_to_string(the_fitest), "\n")
81+
if verbose:
82+
print("Listado ordenado de fitness de toda la poblacion:")
83+
print(*['{0:{width}}'.format(get_fitness(i), width=2) for i in pop], sep=" ")
84+
85+
86+
def chromosome_to_string(chromosome):
87+
""" Return the string representation of the chromosome """
88+
return "".join(chromosome)
11889

11990

12091
def roulette_wheeling(players, num_winers):
12192
""" Return the winners of the roulette wheel selection """
122-
# Ordenar de modo que los mejores tengan mayor valor de indice
123-
players.sort(key=get_fitness, reverse=True)
124-
winners = []
125-
for _ in range(num_winers):
126-
domain = gauss_sum(len(players))
93+
selection_mode = num_winers < len(players)/2
94+
players.sort(key=get_fitness, reverse=selection_mode)
95+
winners = [] if selection_mode else players
96+
for _ in range(num_winers if selection_mode else len(players) - num_winers):
97+
domain = gauss_form(len(players))
12798
tirada = random.randint(1, domain)
128-
winners.append(players.pop(int(inverse_gauss_sum(tirada))-1))
99+
if selection_mode:
100+
winners.append(players.pop(ceil(inverse_gauss_form(tirada))-1))
101+
else:
102+
winners.pop(ceil(inverse_gauss_form(tirada))-1)
129103
return winners
130104

131105

132-
def gauss_sum(n):
106+
def gauss_form(n):
133107
""" Return the sum of 1..n natural numbers """
134108
return (n*(n+1)) // 2
135109

136110

137-
def inverse_gauss_sum(x):
111+
def inverse_gauss_form(x):
138112
""" Return the inverse function of the gauss_sum """
139-
# indice = (math.sqrt(8*tirada+1) - 1) / 2
140113
return ((8*x+1)**0.5 - 1) / 2
141114

142115

143-
def chromosome_to_string(chromosome):
144-
""" Return the string representation of the chromosome """
145-
return "".join(chromosome)
146-
147-
148-
# def clear():
149-
# if os.name == "nt": os.system("cls")
150-
# else: os.system("clear")
151-
152-
153-
gpassword = ga()
116+
print("\nEjecute el archivo correspondiente de cada versión.\n> python3 ga_v?.py\n")

ga_v1.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import random
4+
5+
from ga import ga, crossover, mutate
6+
7+
8+
def next_generation(pop, pop_size, elite_rate, mutate_prob):
9+
""" Return the next generation """
10+
pop = pop[:int(pop_size * elite_rate)] # Selecciona la elite
11+
while len(pop) < pop_size: # Cruzar elite hasta completar la población
12+
couple = random.sample(pop, 2)
13+
pop.append(crossover(couple[0], couple[1]))
14+
# Mutar la poblacion segun la probabilidad de mutate_prob
15+
pop = [mutate(pop[i]) if random.random() < mutate_prob else pop[i]
16+
for i in range(len(pop))]
17+
return pop
18+
19+
20+
gpassword = ga(pop_size=100, elite_rate=0.2, mutate_prob=0.01,
21+
fun_next_gen=next_generation)

ga_v2.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import random
4+
5+
from ga import ga, crossover, mutate, roulette_wheeling
6+
7+
8+
def next_generation(pop, pop_size, elite_rate, mutate_prob):
9+
""" Return the next generation """
10+
split = int(pop_size * elite_rate) # Selecciona la elite
11+
elite, non_elite = pop[:split], pop[split:]
12+
# Mutar entre los no elite
13+
non_elite = [non_elite[i] if random.random() > mutate_prob else mutate(non_elite[i]) for i in range(len(non_elite))]
14+
# Cruzar para generar descendencia. Se cruza por parejas en orden para cruzar individuos de similar fitness
15+
progeny = [crossover(pop[i], pop[i+1]) for i in range(0, pop_size, 2)]
16+
return elite + roulette_wheeling(non_elite + progeny, num_winers=pop_size - len(elite))
17+
18+
19+
gpassword = ga(pop_size=100, elite_rate=0.2, mutate_prob=0.8,
20+
fun_next_gen=next_generation)

ga_v3.py

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import random
4+
5+
from ga import ga, crossover, mutate, roulette_wheeling
6+
7+
8+
# def next_generation(pop, pop_size, elite_rate, mutate_prob):
9+
# """ Return the next generation """
10+
# split = int(pop_size * elite_rate)
11+
# elite, non_elite = pop[:split], pop[split:] # Selecciona la elite
12+
# progeny = [mutate(i.copy()) if random.random() < mutate_prob
13+
# else crossover(i, elite[random.randint(0, len(elite) - 1)])
14+
# for i in elite]
15+
# return elite + progeny + roulette_wheeling(non_elite, num_winers=pop_size - len(elite) - len(progeny))
16+
17+
18+
def next_generation(pop, pop_size, elite_rate, mutate_prob):
19+
""" Return the next generation """
20+
split = int(pop_size * elite_rate)
21+
elite, non_elite = pop[:split], pop[split:] # Selecciona la elite
22+
progeny = []
23+
for i in elite:
24+
if random.random() < mutate_prob: mutate(i)
25+
else: progeny.append(crossover(i, elite[random.randint(0, len(elite) - 1)]))
26+
return elite + roulette_wheeling(non_elite + progeny, num_winers=pop_size - len(elite))
27+
28+
29+
gpassword = ga(pop_size=100, elite_rate=0.8, mutate_prob=0.2,
30+
fun_next_gen=next_generation)

0 commit comments

Comments
 (0)