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 random import Random
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
rand = Random()
|
rand = Random()
|
||||||
|
|
||||||
|
|
||||||
|
class Flag(Enum):
|
||||||
|
UNSET = 1,
|
||||||
|
PARENT = 2,
|
||||||
|
ELITE = 3,
|
||||||
|
PERSIST = 4
|
||||||
|
|
||||||
|
|
||||||
class Individual(object):
|
class Individual(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.x = self.get_rand_param()
|
self.x = self.get_rand_param()
|
||||||
self.y = self.get_rand_param()
|
self.y = self.get_rand_param()
|
||||||
|
self.flag = Flag(Flag.UNSET)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_params(cls, x, y):
|
def from_params(cls, x, y):
|
||||||
|
@ -42,3 +51,13 @@ class Individual(object):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_rand_param():
|
def get_rand_param():
|
||||||
return rand.uniform(0, 1)
|
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):
|
for i in range(0, args.iter):
|
||||||
cls()
|
cls()
|
||||||
print("Epoch: %d " % i)
|
print("Epoch: %d " % i)
|
||||||
pop.advance_generation()
|
elite = round(args.pop * .1)
|
||||||
best = pop.best_fitness()
|
crossover = round(args.pop * .8)
|
||||||
best_fit.append(pop.avg_fitness())
|
pop.advance_generation(elite, crossover)
|
||||||
|
best_fit.append(pop.best_fitness().fitness())
|
||||||
#input("...")
|
#input("...")
|
||||||
sleep(args.wait)
|
sleep(args.wait)
|
||||||
|
|
||||||
|
print("Best: ")
|
||||||
|
print(pop.best_fitness())
|
||||||
|
|
||||||
plt.plot(best_fit)
|
plt.plot(best_fit)
|
||||||
plt.xlabel("Epoch")
|
plt.xlabel("Epoch")
|
||||||
plt.ylabel("Fitness")
|
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
|
from random import Random
|
||||||
|
|
||||||
rand = Random()
|
rand = Random()
|
||||||
|
@ -24,14 +24,15 @@ class Population(object):
|
||||||
(best.x, best.y, best.fitness())
|
(best.x, best.y, best.fitness())
|
||||||
return return_string
|
return return_string
|
||||||
|
|
||||||
def fitness_function(self):
|
def total_fitness(self, members=None):
|
||||||
for member in self.members:
|
|
||||||
member.fitness()
|
|
||||||
|
|
||||||
def total_fitness(self):
|
|
||||||
total = 0
|
total = 0
|
||||||
for member in self.members:
|
|
||||||
|
if members is None:
|
||||||
|
members = self.members
|
||||||
|
|
||||||
|
for member in members:
|
||||||
total += member.fitness()
|
total += member.fitness()
|
||||||
|
|
||||||
return total
|
return total
|
||||||
|
|
||||||
def avg_fitness(self):
|
def avg_fitness(self):
|
||||||
|
@ -45,33 +46,55 @@ class Population(object):
|
||||||
best_member = member
|
best_member = member
|
||||||
return best_member
|
return best_member
|
||||||
|
|
||||||
def roulette(self, divisor=1):
|
def roulette(self, members=None):
|
||||||
total = self.total_fitness() / divisor
|
total = self.total_fitness(members=members)
|
||||||
position = rand.uniform(0, total)
|
position = rand.uniform(0, total)
|
||||||
|
|
||||||
for member in self.members:
|
if members is None:
|
||||||
position -= member.fitness() / divisor
|
members = self.members
|
||||||
|
|
||||||
|
for member in members:
|
||||||
|
position -= member.fitness()
|
||||||
if position <= 0:
|
if position <= 0:
|
||||||
#print(member)
|
return member.set_flag(Flag.PARENT)
|
||||||
return member
|
|
||||||
|
|
||||||
def mutate(self, chance):
|
def mutate(self, chance):
|
||||||
for member in self.members:
|
for member in self.members:
|
||||||
if rand.random() < chance/100:
|
if rand.random() < chance/100:
|
||||||
member.mutate()
|
member.mutate()
|
||||||
|
|
||||||
def advance_generation(self):
|
def elite(self, amount):
|
||||||
# todo: elitism
|
return sorted(self.members, key=lambda x: x.fitness(),
|
||||||
# todo: don't crossover all
|
reverse=True)[:amount]
|
||||||
self.fitness_function()
|
|
||||||
parents = list()
|
def advance_generation(self, n_elite, n_crossover):
|
||||||
for i in range(0, len(self.members)):
|
|
||||||
parents.append(self.roulette())
|
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)
|
self.mutate(2)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user