11 May 2010

The importance of differentiation

As I said in the previous post, I was using Python to test some genetic algorithms.
Actually, I did this test:
Given a grid of size NxN with F pieces of food randomly distributed in it, try to build an agent which moves inside the space to get all the food. The agent has a DNA which consists in a set of directions: North, South, West and East. These are the D steps that it will try to do starting from the location (0, 0).
Well, I did this program in Python in 195 lines of code (and still I didn't make my best to avoid verbose code). About 100 are comments. This gives an idea about how fast to write in Python is.

Anyway, I tried a simulation with these parameters:

  • Grid is 3x3, that is 9 cells.
  • 3 food pieces in the space.
  • The max number of steps is 7. This is sufficient to reach all the 3 pieces of food on a 9-cells grid.
  • The population is of 5 agents, every agent is tested on a copy of the grid, so no race condition.
  • 100 tests for each variation.
  • 10000 maximum ages of evolution.
So, each of the 100 tests will have a maximum of 10000 ages. If you can't get the food within this range, the test fails, else it pass.

Now, the test is on how the population is built: in the first age, the 5 agents are randomly built.
But from the second, the genetic algorithm apply:
  1. calculate the fitness of the 5 agents;
  2. cross the 2 most fitting agents, and produce 2 new agents;
  3. keep the most fitting agent in the set;
  4. mutate the most fitting agent;
  5. mutate the second most fitting agent OR the the least fitting agent;
The mutation is of ONE base of the DNA. Which is rather limited mutation.
Of course, the fit function calculates how much food do you get with that DNA sequence.

Now, it seems logical that keeping the most fitting agents in the set is better, because it provides higher probability that a single mutation will give the optimum. But this isn't true at all (and this isn't a news :D), because a single mutation often isn't enough to push the most fitting agents toward a better direction.
For example, if the food has a total value of 10 (4 + 5 + 1), an agent may use a DNA of length 7 to get food for a value of 9. Which is pretty good in nature, but it's the optimal solution.
The problem is that if the 1 food is far, while the 4 and 5 foods are near the origin, the agent may have a DNA which is totally wrong and just can't reach the last piece of food with a single mutation.

It may happen that all the 5 agents in the population will evolve toward a local optimum, which is the  DNA of the fittest, which can reach only 9 food.

Now, we can introduce more mutations, OR we can just keep an high variation in the DNA by not discarding the least-fittest agent.

In fact, with this test program I show that this is a better strategy. Here a test result:

('Executed ', 100, ' tests with passing rate ', 100.0, ' and total iterations: ', 10249)
('Executed ', 100, ' tests with passing rate ', 68.0, ' and total iterations: ', 320407)

As you see, leaving the least-fit agent in the population, will produce a 100% hit in 10249 ages (being 100 tests, we have an average of 102 ages to get all the food).
While discarding the least-fit agent and keeping all the best ones, won't always succeed, as the hit ratio is 68% - giving a limit of 10000 iterations - and with a total number of iterations that is 32 times higher.

Without the limit of 10000, some configuration won't evolve and the problem will be unsolved.

This is done with DNA long 7. Reducing it to 6, will show that the least-fitting method is anyway faster and more efficient. Actually 6 is the lowest-limit to get 3 foods in the space. In fact, the least-fit method will achieve the solution more than the best-fit method.

EDIT: I fixed the code, now (again) it runs happily with a limit of 10000 iterations.

Here with a DNA long 6

('Executed ', 100, ' tests with passing rate ', 100.0, ' and total iterations: ', 26707, ' with limit ', 10000)
('Executed ', 100, ' tests with passing rate ', 70.0, ' and total iterations: ', 300610, ' with limit ', 10000)


Here with a DNA long 5
('Executed ', 100, ' tests with passing rate ', 77.0, ' and total iterations: ', 247228, ' with limit ', 10000)

('Executed ', 100, ' tests with passing rate ', 50.0, ' and total iterations: ', 500384, ' with limit ', 10000)


Stay --sync

Here 50 with a limit of 1000:
('Executed ', 50, ' tests with passing rate ', 88.0, ' and total iterations: ', 8772, ' with limit ', 1000)
('Executed ', 50, ' tests with passing rate ', 72.0, ' and total iterations: ', 14335, ' with limit ', 1000)

And with limit of 2000:
('Executed ', 50, ' tests with passing rate ', 96.0, ' and total iterations: ', 10352, ' with limit ', 2000)
('Executed ', 50, ' tests with passing rate ', 58.0, ' and total iterations: ', 42208, ' with limit ', 2000)

Here with DNA size set to 5, again with 1000 iterations:
('Executed ', 50, ' tests with passing rate ', 74.0, ' and total iterations: ', 15166, ' with limit ', 1000)
('Executed ', 50, ' tests with passing rate ', 52.0, ' and total iterations: ', 24182, ' with limit ', 1000)

And with 2000 iterations:
('Executed ', 50, ' tests with passing rate ', 88.0, ' and total iterations: ', 15563, ' with limit ', 2000)
('Executed ', 50, ' tests with passing rate ', 58.0, ' and total iterations: ', 42197, ' with limit ', 2000)

I had to reduce the test size and the limit as the testing time was growing a bit too much... Don't try this at home XD

This is because the program randomly hangs when returning from a function :\ This bug is annoying as it stops me from doing really large tests (because an hang won't produce any result...).
I'm trying to figure out the problem, but it's quite rare and debugging 10000 tests isn't joyful :P

10 commenti:

  1. Ciao leggo ogni tanto il tuo blog e trovo cose interessanti alle volte (la ricetta del pesce spasa o della vera programmatrice :) )
    Non ho letto tutto il testo, ma che tecnica di programmazione algortmica ai deciso di utilizzare per risolvere questo problema? a naso una tecnica buona sembra backtracking...
    ReplyDelete
  2. Ciao :)
    Bhe ho usato la programmazione genetica! L'algoritmo prevede una funzione di fitness per tenere un insieme di soluzioni parziali, ma vengono portate avanti tutte assieme...

    Il backtracking non credo possa essere applicato in questo caso, perche' bisognerebbe sapere a priori quando una soluzione non e' piu' adatta, ma non c'e' modo di saperlo proprio in virtu' dell'approccio statistico alla soluzione del problema.

    Anzi, lo scopo di questo post era di mostrare come una differenziazione genetica alta (cioe' includere anche le soluzioni che all'inizio sembrano pessime) invece porta alla soluzione ottima piu' velocemente, perche' evita piu' facilmente i massimi locali :)
    ReplyDelete
  3. Non conosco questo approccio, mi sono letto il wiki, e sono rimasto davvero entusiasta.
    Pensavo fosse una classe di problemi, come quelli di "computational geometry" o di bio-informatica, ma devo dire che questo approccio di trovare le soluzioni è un po' "metafisico" :)
    Portare avanti soluzioni pessime direi che è stupido, ma se questa tecnica riesce adirittura a portare a soluzioni ottime è fantastico. Sono nuovo di agoritmi probabilistici, ma devo dire che non è niente male questo metodo.
    Questa tecnica la affronterò il prossimo corso di algoritmi, quindi ti ringrazio di avermela introdotta :)
    ReplyDelete
  4. Yeah :D Prego! No comunque il sistema, in natura, e' auto-bilanciato... Ma naturalmente non e' conveniente mantenere un insieme di soluzioni troppo ampio, durante questo genere di simulazione.

    Bhe, non e' neanche detto che la soluzione sia ottima! Anzi spesso non lo e'!!
    L'algoritmo genetico e' usato per trovare UNA soluzione tra le tante... Per avere l'ottimo, e' necessario che si stabilisca cos'e' "l'ottimo".

    Prendiamo l'esempio che ho portato nel post: diciamo che data una griglia NxN e dato un punto P, noi possiamo calcolare il numero ottimo di passi per raggiungere il punto P dal punto di partenza O, diciamo con Opt = f(O, P, N).

    Se nell'algoritmo genetico si specificasse che avere un numero Opt di passi e' un requisito fondamentale, allora la simulazione va avanti finche' non trova l'ottimo (uno dei tanti, magari).
    Ma ovviamente questo significa restringere i vincoli di fitness, quindi richiede piu' tempo la ricerca di una soluzione ottima.

    Nella programmazione genetica, dove gli algoritmi genetici vengono usati per creare programmi, solitamente si crea una procedura per generare il programma, poi si stabilisce cosa deve fare il programma (esempio, ricreare la funzione XOR), e si da un limite sulla dimensione del programma.
    S'e' visto che generalmente, l'approccio genetico tende ad usare tutto lo spazio disponibile, quindi creare programmi lunghi anche per una funzione semplice... Non e' certo l'ottimo! Significa fare molti piu' calcoli del necessario :) Ma e' piu' facile trovare una soluzione che vada bene nei casi che ci interessano, anziche' trovare una soluzione che va bene, ma rispecchia qualche criterio "particolarmente filosofico"...

    ... Questo per dire, ad esempio, che nessuno ci garantisce che la Natura abbia fatto le cose nel miglior modo possibile :D sicuramente e' un modo che funziona! Ma e' il migliore?
    ReplyDelete
  5. Ciao,
    mi son riletto i tuoi ottimi commenti. Sto preparando l'esame di algoritmi e mi è venuto in mente questo post.
    Volevo chiederti se posso, ma su che testo hai studiato le tecniche di progettazione di algoritmi. E se hai affrontato problemi NP che testi hai usato.
    Solo perchè affronterò tali argomenti tra meno di un mese :) Grazie
    ReplyDelete
  6. Algoritmi l'ho studiato sul Cormen-Leiserson-Rivest-Stain, introduction to algorithm. E' molto bello, anche se devo ammettere che capire appieno la parte sulla programmazione dinamica ci ho messo parecchio tempo (ma a quanto pare e' un'ottica difficile da raggiungere. Ho qualche post in proposito se ti interessasse).

    Problemi NP... Ne ho affrontati, ma non sono facili e non ho consigli particolari su che testo usare. Se possono interessarti, la teoria della complessita' l'ho studiata principalmente sull'Hopcroft, automata theory & co.
    Inoltre una parte sostanziosa su "Teoria della computabilita' e della complessita", Toffalori, Mancini e altri.
    Ma non trattano di algoritmi nella stessa maniera.

    Tra l'altro, son tutti argomenti che mi piacciono molto :) Benche' non li abbia mai approfonditi piu' di tanto.

    HIH
    Ciao!
    ReplyDelete
  7. Hia usato Cormen pure te, questo libro dicono sia uno dei migliori. Fino all'anno scorso lo usava il docente del corso di Algoritmi, ma quest'anno ha preferito cambiare ed usarne uno più abbordabile e secondo me più didattico ma con molto formalismo come Cormen.
    Comunque Cormen è valido, ma certe volte è un mattone mamma mia :)
    a meno del Master Theorem che senza di sto libro non ne venivo fuori.
    Ho cercato come da tuo consiglio il libro di Toffalori, davvero niente male. Ho trovato il giusto libro pieno di formalismo che mi serviva, e poi tratta l'approccio della macchina di Turing che il mio libro non affrontava.

    Io tra tutte le tecniche di algoritmi che è visto fin'ora la programmazione dinamica è quella che mi ha sorpreso di più.
    Un codice di poche righe e alle volte anche molto elegante, risolve problemi anche molto complessi, una cosa meravigliosa :)
    prima però bisogna trovare e dimostrare la sottostruttura ottima e qua sono "cazzi" :)
    Forse anche la greedy e la ricerca locale sono carine ma non so, la prog dinamica è quella più affascinante, una tabella e degli indici e tanto ingegno.

    Davvero belli gli algoritmi :)

    Ciao e grazie delle dritte, davvero bel libro
    ReplyDelete
  8. Figurati!

    Bah, la programmazione dinamica e' interessante, ma alla fine - nella maggiorparte dei casi pratici - si puo' risolvere in modo comunque decente con la memoizzazione. Anzi, esistono decine di librerie ed estensioni ai linguggi che fanno proprio quello :)
    Gli algoritmi, in generale, son belli da studiare perche' son soluzioni intelligenti a grossi problemi... E' un po' come meccanica, che in qualche modo e' sempre bella ed ingegnosa.

    Ciao
    ReplyDelete
  9. Ciao,
    scusami se ri-commento in questo post, ma chiedo una cosa che continua con le altre risposte.

    Visto che mi hai consigliato un libro che mi è stato davvero utile ultimamente, "Teoria della complessità e computabilità",
    vorrei chiederti se percaso conosci qualche libro in Italiano che tratta gli argomenti:
    - ricerca locale stocastica
    - ricerca locale (dinamica, iterativa, combo di iterativa-perturbatica, costruttiva, sistematica, ecc..)
    - algoritmi popolosi/genetici

    praticamente io sto seguendo delle slide del libro "Stochastic local Search", ma essendo troppo riassuntive e non avendo il libro, vorrei sapere se conosci qualcosa in Italiano.

    Non so mi hai consigliato bene, se conosci qualcosa ti ringrazio.

    Ciau
    ReplyDelete
  10. Mmmh no, nessun libro che sia specifico su quegli argomenti, mi spiace!
    Al piu' posso consigliarti l'intramontabile "Intelligenza artificiale", di Russel e Norvig, ma e' abbastanza generico su tanti argomenti... Nel senso che e' un bel librazzo che parla piu' o meno di tutto, ne parla anche bene, ma non approfondisce.

    Cercalo su google e dai un occhio all'indice, cosi' ti fai una idea...

    Piu' di questo non so dirti, purtroppo neanche io ho affrontato questi argomenti nel dettaglio.

    Ciauz!
    ReplyDelete