Twitter: @grzegg
Kategoria: java, Tagi: - - - - - .

Java [14] – Zadania: Model Malthusa, dobór naturalny

Tym razem ćwiczenia podsumowujące pierwszą część kursu. Przykłady dotyczą kilku zjawisk związanych z biologią, należy więc najpierw zrozumieć problem, a później przystąpić do projektowania i pisania programów. Biorąc pod uwagę, że wielu czytelników tej strony nie ma wiele spólnego z tą dziedziną, starałem się opisać zagadnienia w miarę przystępnie a stosowane modele i algorytmy są dość proste.

Ta strona jest częścią materiałów do kursu “Programowanie w Javie z elementami bioinformatyki dla poczatkujących”. Pozostałe materiały znajdziesz tutaj

Malthus, czyli wzrost wykładniczy i arytmetyczny

Thomas Malthus był angielskim ekonomistą i demografem, który pod koniec XVII wieku opublikował pracę An Essay on the Principle of Population. Zawarł w niej stwierdzenie, że populacja ludzka wzrasta w postępie geometrycznym, natomiast produkcja żywności w postępie arytmetycznym. Ponieważ wzrost arytmetyczny w dłuższej perspektywie nie nadąża za geometrycznym, wg. autora sytuacja taka prowadzi nieuchronnie do klęski głodu.

Opisany przez Malthusa związek miedzy populacją i żywnością nie jest oczywiście ograniczony do ludzi, ale może być podstawą stworzenia uproszczonego modelu wzrostu populacji z uwzględnieniem ograniczeń związanych z zasobami środowiska (niekoniecznie tylko żywności). Można w ten sposób na przykład symulować wzrost populacji zwierząt zasiedlających wyspę, czy rozwój bakterii w pożywce w warunkach laboratoryjnych. Tworząc odpowiedni model należy oczywiście wziąć pod uwagę specyfikę symulowanego układu: populacja – środowisko. Zauważ, że założenie o wzroście zasobów żywności, związane z postępem w rolnictwie, rzadko będzie miało rację bytu w modelach odnoszących się do warunków naturalnych czy rozwijających się w szalce drobnoustrojów.

Zadanie

Zadanie polega na stworzeniu symulacji wzrostu populacji i zasobów żywnościowych aż do chwili, kiedy zacznie brakować pożywienia. Zakładamy, że pokolenia nie zachodzą na siebie – liczebność populacji i ilość żywności zmienia się w kolejnych krokach co sezon. Program powinien na bieżąco wyświetlać zmieniające się parametry. Rozwiązania pojawią się mniej więcej za tydzień.

Założenia i wzory

Jak wynika z tezy Malthusa, będziemy mieli do czynienia z dwoma rodzajami wzrostu:

Wzrost arytmetyczny polega na tym, że ilość (żywności) wzrasta o pewną stałą wartość. Tak więc ilość pożywienia w kolejnym sezonie będzie równa:

Gdzie:
Z – ilość żywności, i – kolejny sezon, a – przyrost żywności w kolejnym sezonie (stała)

Z kolei dla wzrostu geometrycznego (wykładniczego) populacji obliczając jej wielkość w kolejnym sezonie mnożymy liczbę osobników w poprzednim sezonie o pewną stałą, która uwzględnia przyrost osobników (współczynnik wzrostu populacji):

Gdzie:
N – ilość osobników, i – kolejny sezon, R – współczynnik wzrostu populacji

Stała używana we wzorze może uwzględniać pojawienie się nowych osobników i śmierć części osobników populacji. Oczywiście, jeśli chcielibyśmy stworzyć bardziej realistyczny model należałoby uwzględnić takie czynniki jak dojrzewanie, przerwy między wydaniem kolejnych potomków, czy stosunek płci.

Ponieważ w programie uwzględniamy zależność między populacją a zasobami zakładamy, że każdy osobnik zużywa określoną ilość pożywienia (zasobów środowiska), którą możemy określić jakąś stałą (np. c). Populacja może się rozrastać dopóki ilość zużywanych zasobów nie przekracza zasobów istniejących w danym pokoleniu. Jeśli będzie większa, dochodzi do zatrzymania wzrostu o czym powinien poinformować program.

Dobór naturalny

Tematem tego zadania będzie symulacja doboru naturalnego. Będziemy symulować ten proces na poziomie genetycznym a dokładniej jako zmiany częstości występowania dwu alleli jednego genu. Będziemy brali pod uwagę trzy genotypy: AA, Aa, oraz aa. Można sobie wyobrazić na przykład, że gen odpowiada za barwę sierści: czarną (genotyp AA), szarą (Aa) i białą (aa). Każdy z nich może mieć inne dostosowanie (w) co oznacza, że trzymając się powyższego przykładu barwa sierści ma wpływ na możliwość przetrwania albo zwabienie partnera. W skrócie – im większa wartość w tym więcej osobniki o danym genotypie pozostawiają przeciętnie potomstwa. Dostosowanie jest wartością wynikającą z porównania konkurujących osobników (genotypów), aby wartości miały biologiczny sens, powinny mieścić się między 0 a 1, przy czym, przynajmniej dla jednego z genotypów dostosowanie powinno wynosić 1.

W kolejnych pokoleniach dochodzi do losowego krzyżowania się osobników a to jak wiele powstaje osobników o poszczególnych genotypach wynika z tego jak dużo jest poszczególnych alleli w populacji a dokładnie z ich częstości, czyli frekwencji. Frekwencja danego allelu to liczba kopii tego allelu podzielona przez liczbę wszystkich alleli, może więc przyjmować wartości między 0 a 1.
Frekwencje alleli, oznaczane są zwyczajowo literami p (dla allelu A) i q (a).
Częstość genotypów (liczba osobników o danym genotypie/liczba wszystkich osobników), które powstają w kolejnym pokoleniu, można wyliczyć ze wzorów znanych z prawa Hardy’ego-Weinberga:

Gdzie: PAA – frekwencja genotypu AA, PAa – frekwencja genotypu Aa, Paa – frekwencja genotypu aa, p – frekwencja allelu A, q – frekwencja allelu a.

Pamiętaj, że suma frekwencji alleli jak też suma frekwencji wszystkich genotypów powinna wynosić 1.

Ponieważ, jak napisałem powyżej, genotypy mogą mieć różne wartości dostosowania a więc różna będzie ilość zostawionego przez nich potomstwa, będzie w takiej sytuacji mogło dochodzić do zmian częstości alleli w kolejnych pokoleniach. Zmianę częstości występowania allelu a opisuje wzór:


Gdzie: Δq – zmiana częstości allelu a (q) między pokoleniami, p – częstość allelu A, q -częstość allelu a, Ws – średnie dostosowanie, wAA – dostosowanie genotypu AA, wAa – dostosowanie genotypu Aa, waa – dostosowanie genotypu aa.

Z powyższych oznaczeń zagadkowe pozostaje średnie dostosowanie (Ws). Wyliczamy je ze wzoru:

Oznaczenia jak wyżej

Frekwencja allelu w kolejnym pokoleniu będzie więc wynosić:

Odpowiednie wartości dla drugiego allelu łatwo wyliczyć pamiętając, że p + q = 1.

W zależności od wprowadzonych wartości frekwencje alleli mogą się zachowywać w różny sposób. Może dojść do wyeliminowania jednego z alleli, albo frekwencja może zmierzać do tego stanu ale go nie osiągnąć, może też powstać stan równowagi.

Nieco szerzej temat jest omówiony w moich prezentacjach do kursu „Genetyka”, ale jeśli temat wydaje się interesujący to z pewnością warto zajrzeć do bardziej fachowej literatury.

Zadanie

Napisać program, który prześledzi zmiany frekwencji alleli i genotypów w populacji w kolejnych pokoleniach. Użytkownik podaje wartości dostosowania poszczególnych genotypów, początkowe frekwencje alleli oraz maksymalną liczbę pokoleń.
Program ma obliczać (i drukować na ekranie) te wartości oraz frekwencje genotypów w kolejnych pokoleniach aż frekwencja jednego z alleli osiągnie 1 (co oznacza, że drugi został wyeliminowany a więc dalsze zmiany nie są możliwe) lub liczba pokoleń osiągnie wartość dopuszczoną przez użytkownika lub wystąpi stan równowagi (brak zmian frekwencji alleli w kolejnych pokoleniach).
Działanie programu można skonfrontować np. z wynikami uzyskanymi w programie populus. Wybierz z menu: Model -> Quantative-Genetic Models: -> Population & Quantative Genetics, wpisz odpowiednie dane i porównaj wyniki.

Ta strona jest częścią materiałów do kursu “Programowanie w Javie z elementami bioinformatyki dla poczatkujących”. Pozostałe materiały znajdziesz tutaj

1 comment to Java [14] – Zadania: Model Malthusa, dobór naturalny

  • Karolina

    Nie zaglądałam do odpowiedzi, uparłam się, że zrobię sama :) I strasznie się cieszę, bo programy działają jak trzeba, a moje podejście okazało się zupełnie inne :)

    Zad. 1.
    package petle;

    import java.util.Scanner;

    public class WzorstPopulacji {

    public static void main(String[] args) {

    Scanner skaner = new Scanner(System.in);

    System.out.println(„Podaj początkową wartość populacji: „);
    int populacja = skaner.nextInt();

    System.out.println(„Podaj początkową wartość zasobów żywieniowych [kg]: „);
    long zasoby = skaner.nextLong();

    System.out.println(„Podaj współczynnik wzrostu populacji: „);
    int wzrostPopulacji = skaner.nextInt();

    System.out.println(„Podaj przyrost ilości żywności w kolejnym sezonie [kg]: „);
    long wzrostZasoby = skaner.nextLong();

    System.out.println(„Podaj ilość zużywanych przez osobnika zasobów w sezonie [kg]: „);
    int zuzywanie = skaner.nextInt();

    System.out.println(„Sezon: 1 ” + „liczba osobnikow: ” + populacja + ” zasoby: ” + zasoby + ” kg” + ” nadmiar ” +
    „zasobów: ” + (zasoby – (zuzywanie*populacja)) + ” kg”);

    for (int i = 2; i < 100000000; i++){

    long x = zasoby – (zuzywanie*populacja);

    long y = populacja;

    zasoby = (x) + wzrostZasoby;

    populacja = populacja * wzrostPopulacji;

    long oIleWzroslaPopulacja = populacja – y;

    long nadmiarZasobow = zasoby – (zuzywanie*populacja);

    if ((populacja*zuzywanie) < x) {

    System.out.println("Sezon: " + i + " liczba osobników: " + populacja + " wzrost populacji o: " + oIleWzroslaPopulacja +
    " zasoby: " + zasoby + " kg" + " nadmiar zasobów: " + nadmiarZasobow + " kg");
    } else
    break;
    }
    }
    }

    Zad. 2.
    package petle;
    import java.util.Scanner;
    public class DoborNaturalny {

    public static void main(String[] args) {

    Scanner skaner = new Scanner(System.in);

    System.out.println("Wpisz wartość dopasowania typu AA (wartość powinna mieścić się od 0 do 1): ");
    double WAA = skaner.nextDouble();

    System.out.println("Wpisz wartość dopasowania typu Aa (wartość powinna mieścić się od 0 do 1): ");
    double WAa = skaner.nextDouble();

    System.out.println("Wpisz wartość dopasowania typu aa (wartość powinna mieścić się od 0 do 1): ");
    double Waa = skaner.nextDouble();

    System.out.println("Podaj frekwencję allelu A (wartość powinna mieścić się od 0 do 1): ");
    double p = skaner.nextDouble();

    double q = 1-p;

    System.out.println("Podaj liczbę pokoleń, przez które chcesz śledzić zmiany genotypu: ");
    int pokolenia = skaner.nextInt();

    System.out.println("Pokolenie: " + 1 + ", frekwencja allelu A: " + p + ", frekwencja allelu a: " + q + "," +
    " frekwencja genutypu AA: " + (p*p) + ", frekwencja genotypu Aa: " + (p*q) + ", frekwencja genotypu " +
    "aa: " + (q*q));

    for(int i=2; i<=pokolenia; i++) {

    double Ws = (p*p)*WAA + 2*p*q*Waa + (q*q)*Waa;

    double zmianaQ = ((p*q)/Ws)*(q*(Waa-WAa)-p*(WAA-WAa));

    double a = q;

    q = a + zmianaQ;
    p = 1 – q;

    double PAA = p*p;
    double PAa = p*q;
    double Paa = q*q;

    System.out.println("Pokolenie: " + i + ", frekwencja allelu A: " + p + ", frekwencja allelu a: " + q + "," +
    " frekwencja genutypu AA: " + PAA + ", frekwencja genotypu Aa: " + PAa + ", frekwencja genotypu " +
    "aa: " + Paa);
    if ((p==1) || (q==1) || (p==q))
    break;

    }

    }
    }

Leave a Reply