Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import numpy as np
- import time as t
- from numpy.random import random as np_rand
- from matplotlib import pyplot as plt
- class GBest:
- """
- Serve para contar num_fx.
- Serve para definir qual o g_best atual.
- Serve para atualizar os grupos de partículas (grupo = partícula central + orbitais).
- Atualizar significa que se tiver alguma melhor orbital melhor que a central do grupo dela, a orbital que é boa será a nova central."""
- def __init__(self, num_fx, max_fx):
- self.g_best_coords = None
- self.g_best_fitness = +float('inf')
- self.num_fx = num_fx
- self.max_fx = max_fx
- def updateGBest(self, coords, fitness):
- "Atualiza g best."
- if fitness < self.g_best_fitness:
- self.g_best_coords = coords.copy()
- self.g_best_fitness = fitness.copy()
- def updateGroups(self, particulas):
- "Vai percorrer todas as partículas e atualizar todos os grupos de centrais + orbitais."
- global num_orbitais
- global alpha_orbitais, alpha_centrais
- old_centrais = [particula for particula in particulas if type(particula) == ParticulaPrincipal]
- index_old_centrais = [particulas.index(particula) for particula in old_centrais]
- nova_pop = particulas.copy()
- for index_central, central in zip(index_old_centrais, old_centrais):
- melhor = 0
- for particula in range(len(central.orbita)):
- if central.orbita[particula].fitness < central.orbita[melhor].fitness:
- melhor = particula
- if central.orbita[melhor].fitness < central.fitness:
- # substituo a antiga central com a nova central.
- nova_pop[index_central] = ParticulaPrincipal(central.orbita[melhor], num_orbitais, alpha_centrais)
- # Transformo as partículas não melhores em orbitais para a nova central.
- for index, orbital in enumerate(central.orbita):
- if index != melhor: # não posso transformar a melhor em orbital também!
- nova_pop[nova_pop.index(central.orbita[index])] = ParticulaOrbital(orbital, nova_pop, alpha_orbitais)
- # Agora a que era central vou transformar em uma orbital. Em nova_pop vou substituir a que era melhor orbital com a antiga central (que agora é orbital)
- nova_pop[nova_pop.index(central.orbita[melhor])] = ParticulaOrbital(central, nova_pop, alpha_orbitais)
- else:
- pass # Não é necessário atualizar grupo.
- return nova_pop
- class Particula:
- def __init__(self, dim, xmin, xmax, g_best):
- global alpha_orbitais
- self.xmin = xmin
- self.xmax = xmax
- self.dim = dim
- self.coords = xmin + np_rand(dim) * (xmax - xmin)
- self.fitness = rastrigin([self.coords])[0]
- self.velocity = 0.5*np_rand(dim)*(xmax - xmin)
- self.max_velo = 0.2*(xmax - xmin)
- self.p_best_coords = self.coords
- self.p_best_fitness = self.fitness
- self.coef_velo = alpha_orbitais[0]
- self.coef_p_best = alpha_orbitais[1]
- self.coef_g_best = alpha_orbitais[2]
- self.g_best = g_best
- self.g_best.updateGBest(self.coords, self.fitness)
- def updateFitness(self):
- self.fitness = rastrigin([self.coords])[0]
- self.g_best.num_fx += 1
- if self.fitness < self.p_best_fitness:
- self.p_best_coords = self.coords.copy()
- self.p_best_fitness = self.fitness.copy()
- self.g_best.updateGBest(self.coords, self.fitness)
- def updateVelocity(self, update_coef_velo=True):
- "Atualiza a velocidade da partícula."
- if update_coef_velo:
- self.coef_velo = 1 - self.g_best.num_fx / self.g_best.max_fx
- self.velocity = self.coef_velo*self.velocity + self.coef_p_best*(self.p_best_coords - self.coords) + self.coef_g_best*(self.g_best.g_best_coords - self.coords)
- for d in range(self.dim):
- self.velocity[d] = max(self.velocity[d], -self.max_velo)
- self.velocity[d] = min(self.velocity[d], +self.max_velo)
- def move(self):
- "Movimenta a partícula já atualizando sua velocidade."
- self.updateVelocity()
- self.coords += self.velocity
- for d in range(dim):
- self.coords[d] = max(self.coords[d], self.xmin)
- self.coords[d] = min(self.coords[d], self.xmax)
- class ParticulaPrincipal(Particula):
- def __init__(self, particula, max_orbitais, alpha):
- "Transforma uma particula orbital ou sem classe em uma principal."
- self.xmin = particula.xmin
- self.xmax = particula.xmax
- self.dim = particula.dim
- self.coords, self.fitness = particula.coords, particula.fitness
- self.velocity = particula.velocity
- self.max_velo = particula.max_velo
- self.p_best_coords = particula.p_best_coords
- self.p_best_fitness = particula.p_best_fitness
- self.coef_velo = alpha[0]
- self.coef_p_best = alpha[1]
- self.coef_g_best = alpha[2]
- self.g_best = particula.g_best
- self.num_orbitais = 0
- self.max_orbitais = max_orbitais
- self.orbita = [0]*self.max_orbitais
- def addParticula(self, particula):
- "Assume que já foi verificado se pode adicionar na órbita dessa."
- # print("@", particula)
- self.orbita[self.num_orbitais] = particula
- self.num_orbitais += 1
- def removeParticula(self, particula=None, index=None):
- if not particula == None:
- index = self.orbita.index(particula)
- else:
- print("PP:remove:Argumento inválido.")
- return
- self.orbita.pop(index)
- self.num_orbitais -= 1
- class ParticulaOrbital(Particula):
- """Ao transformar uma partícula em orbital, a coordenada da nova partícula orbital será a coordenada da central mais de -2 a 2 vezes a velocidade da partícula.
- Deve receber também a lista de partículas, para assim escolher uma principal para orbitar."""
- def __init__(self, particula, particulas, alpha):
- particulas_principais_com_orbitas_vazias = [p for p in particulas if type(p) == ParticulaPrincipal and p.num_orbitais < p.max_orbitais]
- index_p_principal_escolhida = np.random.randint(0, len(particulas_principais_com_orbitas_vazias))
- self.orbiting = particulas_principais_com_orbitas_vazias[index_p_principal_escolhida]
- self.orbiting.addParticula(self)
- self.xmin = self.orbiting.xmin
- self.xmax = self.orbiting.xmax
- self.dim = self.orbiting.dim
- self.velocity = particula.velocity
- self.max_velo = particula.max_velo
- self.p_best_coords = particula.p_best_coords
- self.p_best_fitness = particula.p_best_fitness
- self.coef_velo = alpha[0]
- self.coef_p_best = alpha[1]
- self.coef_g_best = alpha[2]
- self.g_best = particula.g_best
- self.coords = self.orbiting.coords + np.random.randint(-2, 2 + 1)*particula.velocity
- self.updateFitness()
- # self.coords, self.fitness = particula.coords, particula.fitness
- def updateVelocity(self):
- Particula.updateVelocity(self)
- # Vai reescrever updateVelocity de forma que com ela seja possível implementar o movimento de órbita.
- # E se eu mudar apenas isso, script não precisa de grandes modificações, dado que self.move() vai realizar o movimento.
- #self.coef_velo = 1 - self.g_best.num_fx / self.g_best.max_fx
- # while abs((sinal := np.random.randint(-1, 1 + 1))*np.sqrt(sum((mov := np.random.rand(self.dim))**2))) >= 1 or sinal == 0:
- # pass
- # else:
- # self.coords = ( self.orbiting.coords
- # + mov
- # # + self.coef_velo*mov
- # #
- # # + self.coef_p_best*(self.p_best_coords - self.coords)
- # #
- # # + self.coef_g_best*(self.g_best.g_best_coords - self.coords)
- # )
- # # self.coef_velo*self.velocity + self.coef_p_best*(self.p_best_coords - self.coords) + self.coef_g_best*(self.g_best.g_best_coords - self.coords)
- def rastrigin(pop):
- return np.array([10*len(x) + sum([(_x**2 - 10 * np.cos(2 * np.pi * _x)) for _x in x]) for x in pop])
- g_best, pop = GBest(num_fx := 0, max_fx := 1e3), []
- xmin, xmax, dim = -5.12, +5.12, 5
- global alpha_orbitais, alpha_centrais
- alpha_orbitais = np.array([1., 1., 1.])
- alpha_centrais = np.array([1., .5, 1.])
- plot = True
- num_pop, qtd_centrais = 20, 5
- global num_orbitais
- num_orbitais = num_pop//qtd_centrais - 1
- for _ in range(0, num_pop):
- pop.append(Particula(dim, xmin, xmax, g_best)) # cria todas as partículas
- for i in range(qtd_centrais):
- index = int(np.random.randint(0, num_pop))
- while type(pop[index]) == ParticulaPrincipal:
- index = int(np.random.randint(0, num_pop))
- else:
- pop[index] = ParticulaPrincipal(pop[index], max_orbitais=num_orbitais, alpha=alpha_centrais) # estou assumindo que sempre é 3.
- for i in range(num_pop):
- if type(pop[i]) == Particula:
- pop[i] = ParticulaOrbital(pop[i], pop, alpha=alpha_orbitais) # transforma todas as que não são centrais em orbitais.
- if plot:
- plt.ion()
- tempo = 0
- while g_best.num_fx < g_best.max_fx:
- begin = t.perf_counter()
- particles = []
- p_best = []
- for i in range(num_pop):
- pop[i].move()
- pop[i].updateFitness()
- particles.append(pop[i].coords)
- p_best.append(pop[i].p_best_coords)
- pop = g_best.updateGroups(pop)
- tempo += t.perf_counter() - begin
- if plot:
- plt.clf()
- axes = plt.gca()
- axes.set_xlim([xmin, xmax])
- plt.plot([x[0] for x in particles], [x[1] for x in particles], 'bo')
- plt.plot([x[0] for x in p_best], [x[1] for x in p_best], 'ro')
- plt.plot(g_best.g_best_coords[0], g_best.g_best_coords[1], 'gx')
- plt.title("numfx %d " %g_best.num_fx + str(g_best.g_best_fitness) + " : " + str(round(tempo, 4)) + " segundos.")
- plt.pause(1e-323)
- plt.show()
- else:
- print("Parou! Tempo gasto pelo algoritmo:", tempo)
- print("G BEST:")
- print(g_best.g_best_coords, g_best.g_best_fitness)
- for p in pop:
- print(p.coords)
- if plot:
- try:
- plt.pause(999999999999)
- except Exception:
- pass
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement