Closed josprimen closed 5 years ago
Links:
https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.ones.html (np.ones)
https://docs.scipy.org/doc/numpy-1.15.1/reference/generated/numpy.random.dirichlet.html (dirichlet)
https://stackoverflow.com/questions/45413909/should-i-use-np-absolute-or-np-abs
https://stackoverflow.com/questions/50849789/what-does-the-numpy-linalg-norm-function (norma vectorial)
https://python-para-impacientes.blogspot.com/2015/08/bucles-eficientes-con-itertools.html (itertools)
https://riptutorial.com/es/numpy/example/6745/seleccionando-una-muestra-aleatoria-de-una-matriz (np.random.choice)
https://docs.scipy.org/doc/numpy/reference/generated/numpy.ceil.html (techo)
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.T.html (Transpone)
https://docs.scipy.org/doc/numpy/reference/generated/numpy.add.html (np.add)
https://docs.python.org/2/library/copy.html (copy.copy)
https://www.pythonforbeginners.com/files/with-statement-in-python (writing files python)
En la primera implementación se encontró un error "math domain error" al calcular la 'h' en zdt3. El problema era que faltaban unos paréntesis en la parte de la 'g' y esta salía negativa. Al intentar en la 'h' hacer una raíz cuadrada de algo negativo, saltaba este error.
CF6 `import math import numpy as np
nreal = 4 nbin = 0 ncon = 2 number_obj = 2
min_realvar = [0.0, -2.0, -2.0, -2.0] max_realvar = [1.0, 2.0, 2.0, 2.0]
mysign = lambda x: 1.0 if x > 0 else -1.0
def solution(xreal):
obj = [np.infty, np.infty]
constr = [np.infty, np.infty]
sum1 = 0.0
sum2 = 0.0
for j in range(2, nreal+1):
if j%2 == 1:
yj = xreal[j-1] - 0.8*xreal[0]*math.cos(6.0*math.pi*xreal[0] + j*math.pi/nreal)
sum1 = sum1 + (yj*yj)
else:
yj = xreal[j-1] - 0.8*xreal[0]*math.sin(6.0*math.pi*xreal[0] + j*math.pi/nreal)
sum2 = sum2 + (yj*yj)
obj[0] = xreal[0] + sum1
obj[1] = (1.0 - xreal[0]) * (1.0 - xreal[0]) + sum2
constr[0] = xreal[1] - 0.8 * xreal[0] * math.sin(6.0 * xreal[0] * math.pi + 2.0 * math.pi / nreal) - mysign(
(xreal[0] - 0.5) * (1.0 - xreal[0])) * math.sqrt(math.fabs((xreal[0] - 0.5) * (1.0 - xreal[0])))
constr[1] = xreal[3] - 0.8 * xreal[0] * math.sin(6.0 * xreal[0] * math.pi + 4.0 * math.pi / nreal) - mysign(
0.25 * math.sqrt(1 - xreal[0]) - 0.5 * (1.0 - xreal[0])) * math.sqrt(
math.fabs(0.25 * math.sqrt(1 - xreal[0]) - 0.5 * (1.0 - xreal[0])))
return obj, constr
`
PRINCIPAL CF6 `import numpy as np import itertools import zdt3 import copy import cf6
class Principal:
def __init__(self, populat=100, generat=100, constr= False, bol_gen=False):
self.constr = constr
if self.constr:
self.problem = cf6
else:
self.problem = zdt3
self.population_size = populat
self.generations = generat
self.neighborhood_size = 0.3 #Probar con 0.3
self.sig = 20 #SIG para desviación estandar
self.p = len(self.problem.min_realvar)
self.pr = (1/self.p) #Operador de mutación gaussiana
self.f = 0.5 #mutación
self.cr = 0.5 #cruce
self.born = False #Para saber si es la primera
self.population = []
self.weights = []
self.distances = dict()
self.neighbors = [list() for _ in range(self.population_size)]
#self.obj = zdt3.zdt3()
self.best = [np.infty for _ in range(self.problem.number_obj)]
self.end_gen = bol_gen #Se ha acabado con todas las gen?
self.bol_gen = [] #Lista con todas las gen
def first(self): #Initialization
#self.population = [np.random.uniform(0, 1)] generalicemos
self.population = [[np.random.uniform(self.problem.min_realvar[i], self.problem.max_realvar[i])
for i in range(self.p)]
for _ in range(self.population_size)] #Generalizar el 30?
#self.weights = np.random.dirichlet(
# np.ones(self.obj.number_obj), self.population_size)
#La suma de los componentes de cada vector es 1 y vectores distribuidos uniformemente
self.weights = np.asarray(
[[(self.population_size-i)/self.population_size,
1.-((self.population_size-i)/self.population_size)]
for i in range(self.population_size)])
self.distances = {(x, y): np.linalg.norm(self.weights[x]-self.weights[y])
for x, y in itertools.product(
list(range(len(self.weights))), repeat=2)}
self.best = [np.min([self.evaluate(individual)[i] for individual in self.population])
for i in range(self.problem.number_obj)]
self.born = True
self.compute_neighbors()
def process(self):
self.first() #We have to initialize with a first population
for generation in range(self.generations):
for i in range(self.population_size):
if self.reproduce(i) != -1: #Reproduccion
obj = self.evaluate(self.population[i]) #Evaluacion
for j in range(self.problem.number_obj): #Actualizar z
if self.best[j] > obj[j]:
self.best[j] = obj[j]
#tchebycheff_son = max([self.weights[i][j] * np.abs(
# obj[j] - self.best[j])
# for j in range(self.obj.number_obj)])
for j in self.neighbors[i]: #Actualiza vecinos
obj_neighbor = self.evaluate(self.population[j])
tchebycheff_son = max([self.weights[j][k] * np.abs(
obj[k] - self.best[k])
for k in range(self.problem.number_obj)])
tchebycheff_neighbor = max([self.weights[j][k] * np.abs(
obj_neighbor[k] - self.best[k])
for k in range(self.problem.number_obj)])
if tchebycheff_son <= tchebycheff_neighbor:
self.population[j] = copy.copy(self.population[i])
if self.end_gen:
for i in range(self.population_size):
self.bol_gen.append(self.population[i])
def compute_neighbors(self):
for i in range(self.population_size):
candidates = {y: self.distances[(x, y)]
for (x, y) in self.distances.keys() if x == i}
candidates = sorted(candidates.items(), key=lambda x: x[1])
c = [candidates[x][0] for x in range(len(candidates))]
neighbors = c[:int(np.floor(
self.population_size * self.neighborhood_size))]
self.neighbors[i] = neighbors
#Darle un repaso y comparar operadores geneticos
def reproduce(self, individual):
'''print('El individuo')
print(individual)
print('Pesos individuo')
print(self.weights[individual])'''
#if np.random.random() > self.cr:
a = self.neighbors[individual]
parents = np.random.choice(a, 3, replace=False)
'''print('Padres: ')
print(parents)'''
#self.weights[individual] = self.weights[parents[0]] + self.f * (
#self.weights[parents[1]] - self.weights[parents[2]])
son = np.add(self.population[parents[0]],
self.f * (np.subtract(self.population[parents[1]],
self.population[parents[2]])))
'''print('Hijo: ')
print(son)
print('Tamaño hijo: ')
print(len(son))'''
for i in range(len(son)):
if np.random.random() < self.cr:
son[i] = self.population[individual][i]
## Gaussian Mutation##
for i in range(len(son)):
if np.random.random() < self.pr:
sigma = (self.problem.max_realvar[i] - self.problem.min_realvar[i])/self.sig
son[i] = son[i] + np.random.normal(0, sigma)
#Dentro del dominio?
for i in range(len(son)):
if son[i] < self.problem.min_realvar[i]:
son[i] = self.problem.min_realvar[i]
elif son[i] > self.problem.max_realvar[i]:
son[i] = self.problem.max_realvar[i]
self.population[individual] = copy.copy(np.ndarray.tolist(son))
return individual
def evaluate(self, individual):
if self.constr:
(v, c) = cf6.solution(individual)
return [v[j]+0.1*c[j] for j in range(cf6.number_obj)]
return zdt3.solution(individual)
`
TEST CF6 `import Principal import numpy as np import matplotlib.pyplot as plt import zdt3 import cf6
class testeo():
def test(self, problem_type):
if problem_type == 'cf6':
program = Principal.Principal(constr=True)
program.process()
values = np.array([cf6.solution(program.population[j])
for j in range(program.population_size)])
x, y = values.T
plt.scatter(x, y)
plt.show()
return program
else:
program = Principal.Principal()
program.process()
values = np.array([zdt3.solution(program.population[j])
for j in range(program.population_size)])
x, y = values.T
plt.scatter(x, y)
plt.show()
return program
#grafica.test_moec(100, 100, False)
def test_moec(self, p_size, n_gen, constr, all_gen):
m = Principal.Principal(p_size, n_gen, constr, all_gen)
m.process()
if constr:
self.last_gen_obj_c(m)
self.all_gen_obj_c(m)
else:
self.last_gen_obj(m)
self.all_gen_obj(m)
self.first_gen_obj(m)
return m
def last_gen_obj(self, moec):
with open('test/last_gen_obj_moec_' + str(moec.population_size) + '_'
+ str(moec.generations) + '.out', 'w') as f:
for i in range(moec.population_size):
obj = zdt3.solution(moec.population[i])
f.write('{:.6e}'.format(obj[0]) + '\t'
+ '{:.6e}'.format(obj[1]) + '\n')
def all_gen_obj(self, moec):
with open('test/all_gen_obj_moec_' + str(moec.population_size) + '_'
+ str(moec.generations) + '.out', 'w') as f:
for i in range(len(moec.bol_gen)):
obj = zdt3.solution(moec.bol_gen[i])
f.write('{:.6e}'.format(obj[0]) + '\t'
+ '{:.6e}'.format(obj[1]) + '\n')
def first_gen_obj(self, moec):
with open('test/first_gen_obj_moec_' + str(moec.population_size) + '_'
+ str(moec.generations) + '.out', 'w') as f:
for i in range(moec.population_size):
obj = zdt3.solution(moec.bol_gen[i])
f.write('{:.6e}'.format(obj[0]) + '\t'
+ '{:.6e}'.format(obj[1]) + '\n')
def last_gen_obj_c(self, moec):
with open('tests/last_gen_obj_cmoec_' + str(moec.population_size) + '_'
+ str(moec.generations) + '.out', 'w') as f:
for i in range(moec.population_size):
(v, c) = cf6.solution(moec.population[i])
obj = [v[j] + c[j] for j in range(cf6.number_obj)]
f.write('{:.6e}'.format(obj[0]) + '\t'
+ '{:.6e}'.format(obj[1]) + '\n')
def all_gen_obj_c(self, moec):
with open('tests/all_gen_obj_cmoec_' + str(moec.population_size) + '_'
+ str(moec.generations) + '.out', 'w') as f:
for i in range(len(moec.bol_gen)):
(v, c) = cf6.solution(moec.bol_gen[i])
obj = [v[j] + c[j] for j in range(cf6.number_obj)]
f.write('{:.6e}'.format(obj[0]) + '\t'
+ '{:.6e}'.format(obj[1]) + '\n')
`
Implementation of auxiliar methods and filling init following the given documentation of our solution.