2017-02-02 9 views
5

Chciałem zrobić prosty program, aby poprawić moją wiedzę na temat tego typu programowania. Znalazłem naprawdę użyteczną bibliotekę, pyeasyGA, a wraz z nią próbowałem zrobić prosty program używając graphics.py, który z losowo wygenerowanej sekwencji "przebiegów" tworzy sekwencję, która zbiega się do punktu.Programowanie genetyczne grafiki pyeasyGA i Zelle na Pythonie

Tak to działa:

def create_individual(data): 
    a = [(randint(0,5),randint(0,5)) for n in range(len(data))] 
    print(a) 
    return a 

funkcja ta tworzy sekwencję podań od graphics.py biblioteka pozwala przenieść obiekt, nadając mu ile pikseli chcesz go przenieść. To moja "osoba".

celu obliczenia sprawności, że stosuje się następująco:

def fitness(individual, data): 
    totX=0 
    totY=0 
    for elem in individual: 

     totX+=elem[0] 
     totY+=elem[1] 

    tot = (totX,totY) 

    return distEuclidea(arrivo, tot) 

def distEuclidea(p1,p2): 
    x1 = p1[0] 
    y1 = p1[1] 
    x2 = p2[0] 
    y2 = p2[1] 

    return ((x2-x1)**2+(y2-y1)**2)**(1/2) 

ten oblicza odległości od wybranego punktu przybycia.

Po tych przejściach program generuje wiele pokoleń i zabiera osobę o najniższej sprawności, ale nie działa.

Nie ewoluuje. Każda sekwencja przebiegów wydaje się być generowana losowo.

Czy ktoś może mi pomóc?

Here's the full code

EDIT:

Program wydaje się działać. Jedynym problemem były małe generacje liczb.

+1

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. –

+0

Używam 3.x, a odległość jest poprawnie obliczana –

Odpowiedz

3

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.

enter image description here

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.

+0

Próbowałem zrobić każdy prostokąt przesunąć do punktu. Funkcja "ruch" tłumaczy obiekt dwiema wartościami. Każda osoba jest tablicą N punktu. Każdy punkt to deltax i deltay, które tłumaczą obiekt. Funkcja fitness podsumowuje każdy składnik tej tablicy, aby uzyskać ostateczną deltę i ostateczne opóźnienie dla każdej osoby. Przynajmniej kontroluję odległość od tej delty od punktu przybycia –

+0

Dlaczego nie używasz zwrotnicy? –

+0

@RobertoAureli funkcja łączenia kolidowała ze sposobem, w jaki odzyskiwam poszczególne osoby w następnym cyklu tworzenia, więc go wyłączyłem. Ponownie, posiadanie odpowiedniego haka do pyeasyga do wizualizacji prawdopodobnie pozwoliłoby na włączenie tej funkcji. – cdlane