Revamp algorithm
- Implement variable elitism and crossover - Don't crossover all members
This commit is contained in:
parent
8956dfefed
commit
985fac54a2
|
@ -1,14 +1,23 @@
|
|||
from math import pow, sin, pi, cos
|
||||
from math import pow, sin, pi
|
||||
from random import Random
|
||||
from enum import Enum
|
||||
|
||||
rand = Random()
|
||||
|
||||
|
||||
class Flag(Enum):
|
||||
UNSET = 1,
|
||||
PARENT = 2,
|
||||
ELITE = 3,
|
||||
PERSIST = 4
|
||||
|
||||
|
||||
class Individual(object):
|
||||
|
||||
def __init__(self):
|
||||
self.x = self.get_rand_param()
|
||||
self.y = self.get_rand_param()
|
||||
self.flag = Flag(Flag.UNSET)
|
||||
|
||||
@classmethod
|
||||
def from_params(cls, x, y):
|
||||
|
@ -42,3 +51,13 @@ class Individual(object):
|
|||
@staticmethod
|
||||
def get_rand_param():
|
||||
return rand.uniform(0, 1)
|
||||
|
||||
def set_flag(self, flag):
|
||||
if self.flag is Flag.UNSET:
|
||||
self.flag = flag
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def reset_flag(self):
|
||||
self.flag = Flag.UNSET
|
||||
|
|
12
src/main.py
12
src/main.py
|
@ -22,13 +22,17 @@ pop = Population(args.pop)
|
|||
for i in range(0, args.iter):
|
||||
cls()
|
||||
print("Epoch: %d " % i)
|
||||
pop.advance_generation()
|
||||
best = pop.best_fitness()
|
||||
best_fit.append(pop.avg_fitness())
|
||||
elite = round(args.pop * .1)
|
||||
crossover = round(args.pop * .8)
|
||||
pop.advance_generation(elite, crossover)
|
||||
best_fit.append(pop.best_fitness().fitness())
|
||||
#input("...")
|
||||
sleep(args.wait)
|
||||
|
||||
print("Best: ")
|
||||
print(pop.best_fitness())
|
||||
|
||||
plt.plot(best_fit)
|
||||
plt.xlabel("Epoch")
|
||||
plt.ylabel("Fitness")
|
||||
plt.savefig("fig.png")
|
||||
plt.show()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from individual import Individual
|
||||
from individual import Individual, Flag
|
||||
from random import Random
|
||||
|
||||
rand = Random()
|
||||
|
@ -24,14 +24,15 @@ class Population(object):
|
|||
(best.x, best.y, best.fitness())
|
||||
return return_string
|
||||
|
||||
def fitness_function(self):
|
||||
for member in self.members:
|
||||
member.fitness()
|
||||
|
||||
def total_fitness(self):
|
||||
def total_fitness(self, members=None):
|
||||
total = 0
|
||||
for member in self.members:
|
||||
|
||||
if members is None:
|
||||
members = self.members
|
||||
|
||||
for member in members:
|
||||
total += member.fitness()
|
||||
|
||||
return total
|
||||
|
||||
def avg_fitness(self):
|
||||
|
@ -45,33 +46,55 @@ class Population(object):
|
|||
best_member = member
|
||||
return best_member
|
||||
|
||||
def roulette(self, divisor=1):
|
||||
total = self.total_fitness() / divisor
|
||||
def roulette(self, members=None):
|
||||
total = self.total_fitness(members=members)
|
||||
position = rand.uniform(0, total)
|
||||
|
||||
for member in self.members:
|
||||
position -= member.fitness() / divisor
|
||||
if members is None:
|
||||
members = self.members
|
||||
|
||||
for member in members:
|
||||
position -= member.fitness()
|
||||
if position <= 0:
|
||||
#print(member)
|
||||
return member
|
||||
return member.set_flag(Flag.PARENT)
|
||||
|
||||
def mutate(self, chance):
|
||||
for member in self.members:
|
||||
if rand.random() < chance/100:
|
||||
member.mutate()
|
||||
|
||||
def advance_generation(self):
|
||||
# todo: elitism
|
||||
# todo: don't crossover all
|
||||
self.fitness_function()
|
||||
parents = list()
|
||||
for i in range(0, len(self.members)):
|
||||
parents.append(self.roulette())
|
||||
def elite(self, amount):
|
||||
return sorted(self.members, key=lambda x: x.fitness(),
|
||||
reverse=True)[:amount]
|
||||
|
||||
def advance_generation(self, n_elite, n_crossover):
|
||||
|
||||
for member in self.members:
|
||||
member.reset_flag()
|
||||
|
||||
# elitism
|
||||
for member in self.elite(n_elite):
|
||||
member.flag = Flag.ELITE
|
||||
|
||||
potential_parents = [member for member in self.members if member.flag
|
||||
is Flag.UNSET]
|
||||
# parent
|
||||
for ind in range(0, n_crossover):
|
||||
while not self.roulette(members=potential_parents):
|
||||
pass
|
||||
|
||||
# persist
|
||||
[member.set_flag(Flag.PERSIST) for member in self.members
|
||||
if member.flag is Flag.UNSET]
|
||||
|
||||
parents = [member for member in self.members if member.flag is
|
||||
Flag.PARENT]
|
||||
|
||||
for ind in range(0, len(parents), 2):
|
||||
if ind is len(parents) - 1:
|
||||
parents[ind].set_flag(Flag.PERSIST)
|
||||
else:
|
||||
parents[ind], parents[ind + 1] = parents[ind]\
|
||||
.crossover(parents[ind + 1])
|
||||
|
||||
children = list()
|
||||
for i in range(0, len(parents) - 1, 2):
|
||||
one, two = self.members[i].crossover(parents[i + 1])
|
||||
children.append(one)
|
||||
children.append(two)
|
||||
self.members = children
|
||||
self.mutate(2)
|
||||
|
|
Loading…
Reference in New Issue
Block a user