Report k Dawkinsovim biomorfom

 

 

Snažil som sa zistiť ako je implementovaný genóm a ako sa deje vykresľovanie. Tu je malé zhrnutie,  k čomu som došiel...

 

 

Biomorf je reprezentovaný pomocou 9 génov typu int:

                                                                                  

                                   gény 1-8 -> hodnoty z intervalu <-6,6>

                                   gén 9      -> hodnoty z intervalu <3,7>

 

9-ty gén reprezentuje hĺbku rekurzie biomorfa. Gény 1 až 8 majú vplyv na vlastnosti kreslenia biomorfa, konkrétne dĺžka čiar a uhly vetvenia. Genóm je reprezentovaný navonok pomocou veľkých písmen abecedy. Toto je len „kozmetická“ úprava. V algoritme sa pravuje s celočíselnými hodnotami.

 

Na vykresľovaní biomorfa podľa jeho genómu spolupracujú tri funkcie:

 

1)     public void phenotype(Graphics g, int[] gene,int x, int y)

2)     private void PushGene (int x1, int y1, int x2, int y2)

3)     private void tree (int x, int y, int order, int dir)

 

 

Postup vykresľovania:

 

a)     zavolá sa funkcia phenotype(...), ktorá na začiatku prepíše hodnoty genomu jedinca do polí int dx[8], dy[8]. dxdy majú rozmer daný tak aby mohli v sebe obsahovať gény 1 až 8, čiže okrem génu  reprezentujúceho stupeň rekurzie. Podľa komentára v zdrojáku sa toto deje kvôli zmesteniu sa biomorfa do danej oblasti pre vykreslenie.

b)     Funkcia phenotype zavolá následne funkciu tree(...). Táto funkcia má za úlohu na základe genómu (reprezentovaného dxdy) a stupňa rekurzie vypočítať body biomorfa, ktoré budú pospájané čiarami a vytvorí sa tak telo biomorfa. Body sa ukladajú pomocou funkcie PushGene(...).

c)     Po vypočítaní bodov sa pokračuje vo funkcii phenotype(...), kde sa vypočítané body pospájajú.

 

Toto je v skratke fungovanie vykresľovania...

V ďalšom bližšie popíšem načo som prišiel ako čo funguje. Celé to smeruje k tomu, neviem určiť čo jednotlivé gény reprezentujú...

 

 

 

  

Najprv si ozrejmíme funkciu PushGene (int x1, int y1, int x2, int y2)

 

Funkcia má ako vstup x-ovéy-ové súradnice dvoch bodov. Tieto body jednoducho uloží do polí FromPtToPt, ktoré sú typu Vector (je to použité ako dynamicky alokovaný zásobník). Keďže do poľa typu Vector sa vkladajú len veci typu Object, súradnice bodu sa vkladajú vytvorením objekty Dimension, pomocou ktorého sa súradnice bou uložia. ( tak trocha naokolo, dalo by sa aj ináč ukladať tieto body...prehľadnejšie ale asi sa to tvorcovi kódy zdalo jednoduchšie).

Do premennej MaxY sa ukladá maximálna y-ová súradnica bodu. Použije sa to na zmestenie sa obrázka do vykresľovacej plochy.

 

 

private void PushGene (int x1, int y1, int x2, int y2)

{

       if(y1 > MaxY )

                  {

                    MaxY = y1;

                  }

       else

                 if(y2 > MaxY)

                      {

                        MaxY = y2;

                      }

       FromPt.addElement(new Dimension(x1, y1));

      ToPt.addElement(new Dimension(x2, y2));

}

 

 

 

 

Funkcia  phenotype(Graphics g, int[] gene,int x, int y)

 

Vstupom funkcie sú:

            Graphics g      - reprezentuje objekt kde sa bude vykresľovať

            int[] gene         - genóm vykresľovaného jedinca jedinca

            int x, int y        - počiatočné súradnice bodu kde sa začne vykresľovanie biomorfa

 

Ako už bolo spomenuté, gény sa prepíšu do polí dxdy. Tieto sú globálne premenné a budú použité pri vyrátavaní bodov, ktoré sa pospájajú a vytvoria biomorfa. dxdy reprezentujú čiastkové prírastky x-ovejy-ovej súradnice bodov.

Pre dx  sa používajú gény 1,2,3,4 s kladným aj záporným znamienkom.

Pre dy sa používajú gény 4,5,6,1. Gén 7 sa vôbec nepoužíva pri vykresľovaní.

 

Ďalej s zavolá funkcia tree(0, 0, nOrder, nDirection) ktorá vráti v poliach FromPtToPt súradnice bodov biomorfa. nOrder je stupeň rekurzie definovaný génom 9 a nDirection je pri prvom volaní = 0.

 

V ďalšom sa len tieto body vyťahujú z poľa a spájajú čiarami. V zdrojáku je vidieť, že funkcia g.drawLine(..) je použitá dvakrát. Zmena je v x-ovej súradnici. Biomorf sa zrkadlovo dopĺňa oproti počiatočnému bodu. Z toho vyplýva že funkcia tree(..) vráti len polovicu biomorfa. Druhá sa zrkadlovo doplní...viď obr.1.

 

Obr.1 – vľavo biomorf vykreslený len jedným g.drawLine

a vpravo celý biomorf aj so zrkadlovým doplnkom

(čierny štvorček označuje počiatočný bod)

 

 

 

public void phenotype(Graphics g, int[] gene,int x, int y)            // P h e n o t y p e

     {     

       if(computed==false)

         {

                    dx[0] = -gene[1]/ 4;              // aby sa zmestil obrazok do daneho

                    dx[1] = -gene[0]/ 4;              // obdlznika na zobrazenie

                    dx[2] = gene[3] / 2;

                    dx[3] = gene[0] / 2;

                    dx[4] = gene[1] / 2;

                    dx[5] = gene[2] / 2;

                    dx[6] = -dx[2] / 2;

                    dx[7] = -dx[5] / 2;

                             

                    dy[0] = (gene[5])/2;

                    dy[1] = (gene[4]);

                    dy[2] = (gene[3]);

                    dy[3] = -(gene[4]);

                    dy[4] = -(gene[5]);

                    dy[5] = (gene[6]);

                    dy[6] = (gene[0]);

                    dy[7] = -dy[5];  

 

                   gene[8] = (gene[8] < 0) ? - gene[8] : gene[8];     // pocet iteracii je z <J,...,N>

                   gene[8] = (gene[8] < 3) ?  3 : gene[8];            // t.j. <3,...,7>

                    nOrdergene[8];

 

                    tree (0, 0, nOrder, nDirection);

         }                  

       Dimension Pt1, Pt2;

       for (int i = 0; i <FromPt.size(); i ++)    

                 {

                   Pt1 = (Dimension)FromPt.elementAt(i);

                   Pt2 = (Dimension)ToPt.elementAt(i);

                   g.drawLine(x + Pt1.width, y - MaxY + Pt1.height,x + Pt2.width, y - MaxY + Pt2.height);

                   g.drawLine (x  - Pt1.width, y - MaxY + Pt1.height,x  - Pt2.width, y - MaxY + Pt2.height);

                 }

     }

 

 

 

 

Funkcia private void tree (int x, int y, int order, int dir)

 

Vstupy funkcie:

            int x, int y        - súradnice aktuálneho bodu

            int order          - aktuálna hĺbka rekurzie

            int dir              - reprezentuje aktuálny index polí dx, dy, ktorý definuje čiastkové

  hodnoty ktoré budú použité na výpočet súradníc ďalšieho bodu

 

 

 

 

Na začiatku je počiatočný bod nastavený na (x,y)=(0,0) a dir=0 (globálna premenná). Premenná dir môže nadobúdať hodnoty <0,7>.

Nové súradnice bodu sa počítajú podľa:

 

Xnew = x + order * dx[dir];

Ynew = y + order * dy[dir];

 

Starý aj nový bod sa uložia pomocou PushGene(...) a rekurzívne sa dvakrát zavolá funkcia tree(...) so stupňom rekurzia o jednotku menším a pre dir-1 a dir+1. Dir je osetrené tak, že sa akoby točí v dvoch smeroch, t.j. ak znižovaním nadobudne hodnotu 0, tak nasledujúca hodnota bude 7.

 

 

 

 

   private void tree (int x, int y, int order, int dir)

     {

       int Xnew, Ynew;

       if(dir < 0)

         {

                    dir += NBVAR;

         }

       else

            if(dir >= NBVAR)

                 {

                   dir -= NBVAR;

                 }

      Xnew = x + order * dx[dir];

      Ynew = y + order * dy[dir];

      if( Ynew > 100 ) Ynew = 100;

      PushGene(x, y, Xnew, Ynew);

      if(order > 0)

        {

          tree (Xnew, Ynew, order - 1, dir - 1);

          tree (Xnew, Ynew, order - 1, dir + 1);

        }

       computed = true;

     }

 

 

 

  

Niekoľko mojich postrehov:

 

Pripadá mi zvláštne, že fakticky na dĺžke čiar sa podieľa aj úroveň rekurzie (vidno na Obr.1). Toto mi nepripadá ako spôsob opísaný Dawkinsom.

 

Ďalej, keďže dxdy reprezentujú čiastkové zmeny v súradniciach bodov, fakticky sa podieľajú aj na uhle a aj na dĺžke jednotlivých čiar, z čoho sa mi zdá, že nie je možné povedať že napr. gén 1 reprezentuje iba uhly a pod.

 

Skúšal som nastavovať hodnoty génu na rovnaké hodnoty a vykresľovať ako vyzerajú jednotlivé biomorfy.

 

Pre hodnoty génov 1 až 8 rovné 0 je biomorf jen bod.

Pre hodnoty génov 1 až 8 rovné -/+1 je biomorf zvislá priamka.

Pre hodnoty génov 1 až 8 rovné -/+3 vyzerajú biomorfy podľa obr.2

Pre hodnoty génov 1 až 8 rovné -/+6 vyzerajú biomorfy podľa obr.3

 

Stupeň rekurzie som kvôli prehľadnosti nechal 3. Záporná resp. kladná hodnota génu spôsobí zrkadlové prevrátenie horizontálnou rovinou.

 

Obr.2                                                      Obr. 3

 

 

Ďalej som skúšal meniť postupne len hodnotu jedného génu, pokiaľ ostatné ostali nezmenené.

Výsledok pre gén 1 je na obr.4. Kvôli prehľadnosti som nechal vykresľovať len jednu polovicu biomorfa, pretože dochádza ku križovaniu čiar. Ako je vidieť gén 1 nemení len uhol natočenia ale aj dĺžku čiary.

 

 

 

Obr. 4 – zmena hodnoty génu 1 v rozsahu <-6,6> s krokom 1

Stupeň rekurzie = 3

 

 

Ďalej na obr. 5 možno sledovať vplyv génu 5 na tvar biomorfa. Ako je vidieť, gén ovplyvňuje dĺźku aj uhol niektorých častí biomorfa.

 

 

Obr.5 - zmena hodnoty génu 5 v rozsahu <-6,6> s krokom 2

Stupeň rekurzie = 3

 

 

Podľa mňa, tak ako je to implementované v tomto aplete , jednotlivé gény majú vplyv iba na niektoré časti biomorfa, pričom regulujú dĺžku ako aj uhol. Ovplyvňovanie nastáva v určitých hĺbkach rekurzie, v ktorých je hodnota parametra dir funkcie tree zhodná s indexom daného génu. Keďže hodnoty dir sa cyklicky menia, môže mať jeden gén vplyv na viacero častí biomorfa vo rôznych hĺbkach rekurzie (viď obr.6).

 

 

Obr. 6 - zmena hodnoty génu 5 v rozsahu <-4,4> s krokom 4 + obr. pre hodnotu = 6

Stupeň rekurzie = 4

Je vidieť, že oproti obr.5, gén ovplyvňuje aj uhly a dĺžky koncových vetvení