Termin: czwartek 22 stycznia, godzina 23:59.
Pytania prosimy umieszczać w komentarzach, lub ewentualnie kierować pod adres: j.herman-izycka@mimuw.edu.pl
Rozwiązania w formie pakietu zad2_[nr_indeksu]
spakowanego w formacie zip
lub tgz
wysyłamy e-mailem do osoby prowadzącej laboratorium z kopią do wykładowcy, używając w tytule tagu [WDI-2-2014]. Aby uzyskać punkty za zadanie trzeba swoje rozwiązanie przedstawić osobiście prowadzącemu lub prowadzącej laboratoria.
Biomorfy to cyfrowe stworzenia, które kształtem mogą przypominać obiekty czy zwierzęta. Biomorfy są strukturami drzewiastymi (binarnymi), tzn. biomorf ma stawy (węzły) i segmenty (krawędzie), do każdego stawu poza zerowym (czyli poza korzeniem) wchodzi jeden segment, a wychodzą z niego dwa.
Opis historii oraz przykłady biomorfów: Opis biomorfów
Każdy biomorf ma genotyp, czyli listę 10 genów określających jego wygląd. Geny mają różny wpływ na biomorfa i są reprezentowane przez liczby całkowite albo rzeczywiste.
Opis genów
- gen 0 – głębokość, czyli liczba rozgałęzień biomorfa
- geny 1 i 2 – kąty odchylenia kolejnych segmentów od osi poprzedniego segmentu (w stopniach). Gen 1 odpowiada odchyleniom na rozgałęzieniach o nieparzystej głębokości, a gen 2 parzystej.
- geny 3 i 4 – długości segmentów odpowiednio na nieparzystej (gen3) i parzystej (gen4) głębokości (wyrażona w pikselach)
- gen 5 – wydłużenie/skrócenie segmentów. Parzyste (nieparzyste) segmenty stopnia i są długości gen4*gen5**i (gen3*gen5**i) poprzedniego parzystego (nieparzystego)
- gen 6,7,8 – geny kodujące kolor biomorfa (w notacji RGB), z zakresu 0.01-0.99
- gen 9 – gradient koloru (czyli rozjaśnienie/przyciemnienie segmentów na kolejnych głębokościach). Tak jak wydłużenie, jest to cecha multiplikatywna
Biomorfy są jednopłciowe, a ich kolejne pokolenia różnią się
od poprzedniego poprzez losową, pojedynczą mutacje – drobną zmianę jednego
z ich genów.
Opis mutacji
- gen 0 – głębokość zmienia się o +/-1
- gen 1 i 2 – odchylenie zmienia się o +/-10 stopni
- gen 3 i 4 – długość zmienia się o +/- 10 pikseli
- gen 5 – przeskalowanie o losową wartość z przedziału [0.75, 1.5]
- gen 6, 7 i 8 – przeskalowanie o losową wartość z przedziału [0.75, 1.5] (wynik skalowania spoza przedziału [0.01-0.99] powinien otrzymać wartość najbliższego krańca przedziału)
- gen 9 -przeskalowanie o losową wartość z przedziału [0.75, 1.5]
Przykład 1: Biomorf o genotypie [2, 45, 10, 50, 20, 1, 0.1, 0.1, 0.1, 2 ] , wraz z mutantami.
Przykład 2: Biomorf o genotypie [4, 120, 30, 60, 20, 1.5, 0.2, 0.2, 0.4, 1.5] wraz z mutantami
- Napisz pakiet biomorph zawierający 3 moduły do symulowania ewolucji biomorfów.
- (3pkt) Moduł mutacja będzie generował zmutowane biomorfy. Powinien
zawierać funkcjęmutuj(biomorf)
, która zwróci listę 8 biomorfów
pochodzących z losowych mutacji wejściowegobiomorfa
. - (7pkt + 3pkt) moduł rysowanie powinien zawierać funkcję
rysuj(biomorf)
rysującą przy użyciu modułuturtle
danegobiomorfa
(5 pkt),
oraz funkcjęrysuj_wszystkie(biomorf, listamutantów)
, która narysuje na środku wejściowegobiomorfa
oraz wokół wszystkie jego 8 potomnych zmutowanych biomorfów w formie obrazka 3×3 (patrz przykład 2). - (7pkt) moduł symulacja: pozwoli na symulowanie ewolucji biomorfa
korzystając z doboru (który zapewnia użytkownik) :- (4 pkt) Moduł powinien zawierać funkcję
symuluj(startowy)
, która startując od zadanego biomorfastartowy
wyświetla go oraz 8 jego losowych mutantów, a następnie pozwala
wybrać jeden z nich (wpisując numer od 1 do 9 w konsoli, biomorfy numerujemy rzędami, a w rzędzie od lewej do prawej) lub zakończyć
symulację wpisując 0 (patrz podpowiedź 1). Funkcja zwraca historię symulacji, czyli listę zawierającą kolejne pary:(lista mutantów, numer wybranego mutanta)
. - (3 pkt) Moduł powinien oferować możliwość uruchamiania jako skrypt z parametrami:
-p plik – nazwa pliku z opisem biomorfa (jeden wiersz-jeden gen)
-o output – (opcjonalny) nazwa pliku do którego należy wypisać historię symulacji (jeden wiersz – jedna para (lista mutantów, numer wybranego mutanta))
-b gen0 gen1 … gen9 – startowy biomorf zapisany jak wartości poszczególnych genów
- (4 pkt) Moduł powinien zawierać funkcję
Do rysowania należy użyć modułu turtle
Podpowiedź 1: Wczytywanie z konsoli: funkcja raw_input("Napis wyświetlany w konsoli")
zwracająca napis będący linią wpisaną przez użytkownika.
Czy można prosić o wyjaśnienie znaczenia “segmenty stopnia i są długości gen4*gen5**i (gen3*gen5**i) poprzedniego parzystego (nieparzystego)”. Być może wystarczy wstawienie jakiegoś spójnika lub relacji, żeby zdanie to było bardziej zrozumiałe. Z góry dziękuję za odpowiedź.
Czy “geny 1 i 2 – kąty odchylenia kolejnych segmentów >>od osi poprzedniego segmentu<< (w stopniach)."?
Czy w danym przykładzie, nie są to jednak kąty odchylenia od osi pionowej? Weźmy przykład pierwszy:
Biomorf ten ma genotyp: [2, 45, 10, 50, 20, 1, 0.1, 0.1, 0.1, 2 ].
W pierwszym segmencie mamy kąt odchylenia równy 45 stopni. Przyjmijmy orientację z "standard mode", czyli: załóżmy, że żółw skierowany w kierunku "90 stopni" wskazuje na górę obrazka a ustawiony na "0 stopni" – w prawo; oś pionowa oznacza oś: 270 – 90 stopni a oś pozioma: 180 – 0 stopni.
Tak więc żółw wyznaczy oś pierwszego segmentu jako 90 plus minus 45 stopni czyli odpowiednio od lewej: 45 i 135 stopni. Dalej w drugim segmencie, który jest parzysty mamy kat odchylenia równy 10. Jeśli byłby to kąt odchylenia od osi poprzedniego segmentu, kreski powinny być chyba ułożone pod kątami: 45 plus minus 10 oraz 135 plus minus 10 czyli: [35,55,125,145]. Oznaczałoby to, że skrajnie lewe segmenty powinny się ułożyć tak, że drugi segment powinien być łagodniej nachylony do osi poziomej (wyznaczonej jako 180 – 0 stopni) od segmentu pierwszego. Na załączonym przykładzie, wygląda to odwrotnie – jakby kąt odchylenia był liczony od osi pionowej (czyli od 90 stopni). Bardzo proszę o informację, w którym miejscu rozumowania popełniam błąd. Jeśli jednak jest ono poprawne – czym powinniśmy się kierować – treścią czy przykładami?
Jeśli chodzi o zdanie: “segmenty stopnia i są długości gen4*gen5**i (gen3*gen5**i) poprzedniego parzystego (nieparzystego)”, to najważniejsze jest i to jest poziom segmentu. Zaczynamy od długości gen3 i następnie na każdym kroku mnożymy go przez gen5 uzyskując ciąg: gen3*1, gen3*gen5, gen3*gen5**2, gen3*gen5**3,…
Co do pytania dotyczącego kątów, to przykład wskazuje, że Pan ma rację i kolejne kąty są liczone od pionu. Ja ze swej strony zachęcam do eksperymentowania z różnymi kodami genotyp-fenotyp. Ostatecznie takie rzeczy można uzgodnić ze sprawdzającymi podczas laboratoriów i w miarę szybko naprawić w razie niezgodności. A różne odwzorowania mogą prowadzić do różnych biomorfów.
Faktycznie, podane przykłady zostały narysowane używając genów 1 i 2 jako odchylenia od osi pionowej, a nie od poprzedniego segmentu. Pod adresem mimuw.edu.pl/~jh280468/zad2 jest poprawiony przykład, oraz dodatkowo przykład biomorfa o genotypie [4, 120, 20, 30, 20, 0.9, 0.5, 0.2, 0.2, 1.2] – kraba (pająk nie wyglądał ciekawie po tej zmianie). Myślę, że większy potencjał do stworzenia ciekawych biomorfów ma wersja z odchyleniem od poprzedniego segmentu (czyli ta z tekstu, a nie rysunków), i przy tej wersji pozostańmy, ale ja również zachęcam do zabawy genami, i ewentualnego zaprezentowania ciekawych przykładów biomorfów przy innejj interpretacji genotypu.
Jak Państwo prawidłowo zauważyli, rysunki zostały wykonane używając innej definicji genu 5. Jest on stosunkiem długości parzystego (nieparzystego) segmentu, do poprzedniego parzystego (nieparzystego). i-ty parzysty (nieparzysty) segment (numerując od 0, floor(i/2)-gi segment w ogóle) ma zatem długość gen4*gen5**i (gen4*gen5**i), czyli i*długość poprzedniego parzystego (nieparzystego). Zachęcam użycia tej definicji, bo zmiana jest niewielka, ale jeśli zdecydują się Państwo pozostać przy poprzedniej definicji, to prosimy o komentarz w kodzie.
Opis funkcji skryptu wydaje mi się bardzo niezrozumiały. Co właściwie ma robić wywołanie go z poszczególnymi parametrami? I czy “(opcjonalny)” przy parametrze -o oznacza, że napisanie go daje dodatkowe punkty poza te 20?
Parametr opcjonalny może się pojawić w wywołaniu, ale nie musi. Jego obsługa jest również wymagana do otrzymania 20pkt.
Powinna być możliwość uruchomienia skryptu w następujący sposób:
python symulacja.py -p plik_wejsciowy [-o plik_wyjsciowy ]
python symulacja.py -b gen0 gen1 … gen9 [-o plik_wyjsciowy ]
Jak widać parametry -p i -b pozwalają zdefiniować startowego biomorfa na 2 różne sposoby. Należy tę sytuację jakoś rozstrzygnąć, np. nie zezwalając na użycie obu parametrów równocześnie, lub wybierając w takiej sytuacji jednego z biomorfów. Parametr -o można łączyć zarówno z -p jak i -b. Jeśli nie jest on zdefiniowany, nie jest wypisywana historia symulacji.
Pod pojęciem “8 biomorfów pochodzących z losowych mutacji” kryje się 8 biomorfów, których nie ma dwóch takich samych mutacji, ale mogą być różne mutacje tego samego genu? To znaczy zbiór w którym są 2 mutacje (lub mniej) genów 0, 1, 2,3, 4 są dozwolone?
Mam pytanie odnośnie realizacji genu 9. Skoro kolor jest wyznaczony przez
trójkę liczb z przedziału 0.01-0.99 to w jaki sposób gradient koloru ma być multiplikatywny. Np. jak chciałabym pociemnić 2 (czyli rozjaśnić 1/2 razy) razy to ok, mogę podzielić te trzy liczby przez 2. Ale gdybym chciała rozjaśnić 2 razy a poprzednie liczby to (0.6,0.6,0.3) to wyjdę poza zakres. Co robić w takim przypadku? Po prostu przyjąć maksymalne wartości wzpółrzędnych (np. w podanym przykładzie (0.99, 0.99,0.6) czy może nic nie robić? Poza tym co ma oznaczać tu że kolor jest multiplikatywny podobnie jak wydłużenie? Przy wydłużeniu skalowaliśmy długość poprzedniego segmentu o tej samej parzystości i długości dwóch pierwszych elementów były podane, natomiast tutaj podana jest tylko jedna trójka kolorów. Czy zatem mamy skalować długość poprzedniego segmentu?
“8 biomorfów pochodzących z losowych mutacji”: Chodzi o niezależnie uzyskane mutacje. Może pojawić się mutacja tego samego genu. Nie trzeba nawet sprawdzać, czy otrzymane potomne biomorfy są różne, wystarczy że będą otrzymane niezależnie.
Kolor po przemnożeniu przez gen 9 powinien pozostać w zakresie (0.01, 0.99).
W przypadku koloru (0.6,0.6,0.3) i mnożnika 2 uzyskujemy (1.2, 1.2, 0.6), ale ponieważ 1.2 wychodzi poza zakres, to pozostawiamy kolor równy największej możliwej wartości, czyli (0.99, 0.99, 0.6). Tutaj multiplikatywność oznacza, że każdy kolejny segment ma kolor równy (gen 9) * kolor poprzedniego (z dokładnością do wychodzenia poza zakres). Parzystość segmentu nie ma tutaj znaczenia.
Mam pytanie do modułu rysowanie. Czy mamy się przejmować tym żeby na rysunku te 9 biomorfów mieściło się w swoich kwadratach (przy założeniu podziału ekranu na 9 kwadratów)? Jesli tak to czy mamy/możemy
np. dostosowywać wielkość ekranu do rozmiarów wygenerowanych biomorfów żeby się mieściły czy może raczej przeskalowywać wszystkie lub też tylko te nie mieszczące się w swoich kwadratach biomorfy, przy ustalonej wielkości ekranu.
Jaka jest namniejsza możliwa głębokość biomorfa – zero czy jeden? W sensie kiedy możemy uznać że dalsze losowe skracanie jest niemożliwe.
Jest napisane “Biomorfy są jednopłciowe, a ich kolejne pokolenia różnią się
od poprzedniego poprzez losową, pojedynczą mutacje – drobną zmianę jednego
z ich genów”. Czy to oznacza, że kazde z 8 dzieci musi się koniecznie różnić od rodzica, czy może się trafić np. mutacja identycznościowa, np. kiedy wylosujemy żeby pomniejszyć biomorf posiadający najkrótszą mozliwą głębokość, albo przypadkiem trafimy na przeskalowanie o 1. Czy może jednak w takich przypadkach należy losować aż do skutku aż mutacja nie bedzie identycznościowa?
Co do rysowania: dobrze by było, aby biomorfy nie nachodziły na siebie przy rysowaniu. W module turtle chyba ciężko jest wymusić rozmiar okna, więc lepiej przeskalować biomorfy. Najlepiej zmniejszyć je wszystkie tak samo.
Najmniejsza możliwa głębokość biomorfa to 1. W przypadku wylosowania przeskalowania=1 (co jest mało prawdopodobne), potomny biomorf może być identyczny z rodzicem, nie trzeba losować jeszcze raz.
Rozważając inny przypadek – wartość genu 6 wynosi 0,01, zaś wylosowana wartość przeskalowania jest z zakresu <1 to również otrzymamy mutację identyczną jak rodzic. Czy w takim przypadku musimy wylosować mutację raz jeszcze?
Można wylosować raz jeszcze, a można pozostawić wartość 0.01.
Chcialabym prosic o wrzucenie slajdow z wykladow o tym jak sie pisze skrypty.
Czyli te biomorfy nie moga na siebie nachodzic czy mogą jesli tak sie zmutują, czy nie? Poprzednia odpowiedz byla dla mnie niejednoznaczna.
Jesli mam juz ta funkcje symuluj.py, ktora mutuje i rysuje, to skrypt ma byc tez w niej napisany? Czy to sie robi jako osobny plik?
Biomorfy nie mogą na siebie nachodzić. Jednak kara za nachodzenie będzie symboliczna.
Rozwiązanie powinny zawierać 3 pliki: symulacja.py, rysowanie.py i mutacja.py, każdy zawierający odpowiednie funkcje. Niektóre z funkcji mogą (i muszą) być importowane przez moduł symulacja.py.
Więcej przykładów: http://www.mimuw.edu.pl/~kgogolewski/przyklady_zad2.html