Uważam, że twoja funkcja fitness jest najtrudniejsza do zrozumienia. Zamiast tego uśrednij rogi lub znajdź centrum, sumuje rogi, a następnie znajduje dystans. Jaka jest interpretacja geometryczna?
Również twój kod odnosi się do ga.logGenerations, który nie jest częścią aktualnego wydania pyeasyga 0.3.1.
Poniżej znajduje się moje przybliżenie do tego, o czym myślę, że prosisz. Jeśli jest to chybione, należy poszerzyć swoje wyjaśnienia z przykładami i/lub schematów:
from time import sleep
from random import randint
from itertools import cycle
from graphics import *
from pyeasyga import pyeasyga
NUMBER_OF_RECTANGLES = 4 # make one more than what you want to see
NUMBER_OF_POINTS = 2
arrivo = (90, 90)
colori = ["red", "green", "blue", "cyan", "magenta", "yellow"]
X, Y = 0, 1
def distEuclidea(p1, p2):
x1, y1 = p1
x2, y2 = p2
return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5
def create_individual(colors):
color = next(colors)
while color in rectangles and rectangles[color] is None: # skip over deleted rectangle
color = next(colors)
if color in rectangles:
rectangle = rectangles[color]
p1, p2 = rectangle.getP1(), rectangle.getP2()
points = [[p1.getX(), p1.getY()], [p2.getX(), p2.getY()]]
else:
points = [[randint(0, 20), randint(0, 20)] for _ in range(NUMBER_OF_POINTS)]
rectangle = Rectangle(*[Point(x, y) for x, y in points])
rectangle.setOutline(color)
rectangle.draw(win)
rectangles[color] = rectangle
return [color, points]
def fitness(individual, colors):
_, points = individual
rectangle = Rectangle(*[Point(x, y) for x, y in points])
center = rectangle.getCenter()
return distEuclidea(arrivo, (center.getX(), center.getY()))
def mutate(individual):
_, points = individual
mutate_index = randint(0, NUMBER_OF_POINTS - 1)
points[mutate_index][X] += randint(-1, 1)
points[mutate_index][Y] += randint(-1, 1)
def is_point_inside_rectangle(point, rectangle):
p1, p2 = rectangle.getP1(), rectangle.getP2()
return min(p1.getX(), p2.getX()) < point.getX() < max(p1.getX(), p2.getX()) and \
min(p1.getY(), p2.getY()) < point.getY() < max(p1.getY(), p2.getY())
win = GraphWin("Genetic Graphics", 500, 500)
win.setCoords(0, 0, 100, 100)
rectangles = {}
color_generator = cycle(colori[0:NUMBER_OF_RECTANGLES])
arrivoC = Circle(Point(*arrivo), 1)
arrivoC.setFill("orange")
arrivoC.draw(win)
number_of_rectangles = NUMBER_OF_RECTANGLES
while True:
ga = pyeasyga.GeneticAlgorithm(color_generator, \
elitism=False, \
maximise_fitness=False, \
crossover_probability=0.0, \
population_size=number_of_rectangles)
ga.create_individual = create_individual
ga.fitness_function = fitness
ga.mutate_function = mutate
ga.run()
for member in ga.last_generation():
my_fitness, (my_color, my_points) = member
if rectangles[my_color] is None:
continue # skip over deleted rectangle
rectangle = Rectangle(*[Point(x, y) for x, y in my_points])
rectangle.setOutline(my_color)
rectangle.draw(win)
rectangles[my_color] = rectangle
if is_point_inside_rectangle(arrivoC.getCenter(), rectangle):
rectangles[my_color] = None # delete finished rectangle
number_of_rectangles -= 1
if number_of_rectangles < 2:
break
sleep(0.1)
for value in rectangles.values():
if value is not None:
value.undraw() # delete unfinished rectangle
win.getMouse()
win.close()
Powyższy kod jest szorstki (np nie zawsze zachować punkty generycznych domen i prostokąty niezależne od graphics.py Punkty i prostokąty), ale powinien dać ci coś do eksperymentowania.
tworzy prostokąty w lewym dolnym rogu okna, że genetyczne mutuje algorytm kierunku celu w prawym górnym rogu, zrzucając obecnie prostokąty, gdy docierają do celu.
Częścią złożoności mojego kodu jest to, że pyeasyga nie zapewnia funkcjonalnego haka do wizualizacji tego, co dzieje się z każdym pokoleniem. Lepszym rozwiązaniem może być podklasa pyeasyga, aby dodać taki hak, aby uprościć logikę kodu.
Nikt z nas nie może uruchomić twojego kodu, ponieważ nie mamy "grafiki". Ale widzę problem, jeśli używasz Pythona 2.7: wykładnikiem funkcji 'distEuclidea' jest int przez int, co daje int; konkretnie, '1/2 == 0' w Pythonie 2.7, więc wszystko, co fitness ma zawsze "1", niezależnie od indywidualnego wektora projektowego. Zmień na "1/2.0". Jeśli używasz Pythona 3.X, '1/2 == 0.5' zgodnie z oczekiwaniami. –
Używam 3.x, a odległość jest poprawnie obliczana –