====== Skládání proteinů: Popis úlohy ======
===== Sekvence aminokyselin =====
Pro skládání proteinů použijeme zjednodušený svět ve formě 2D pravoúhlé mřížky, kde se vyskytují pouze dva druhy aminokyselin: hydrofóbní (označené jako 1) a hydrofilní (označené jako 0). Mějme následující sekvenci aminokyselin, kde jsou hydrofóbní aminokyseliny označeny červené a hydrofilní modře:
{{ :courses:a4b99rph:cviceni:folding1.gif?200 |Protein 1}}
Takovouto sekvenci budeme reprezentovat jako seznam nul a jedniček:
>>> a = [0, 1, 1, 1, 1, 0]
===== Protein = Složená sekvence aminokyselin =====
Představte si sekvenci aminokyselin, z níž máme složit protein, jako řetěz. Každý jeho článek se může ohnout o násobek 90 stupňů, ale vzdálenosti mezi články řetězu zůstávají stejné. Řetěz nemůže protínat sám sebe a lze jej skládat jen v rovině (tj. v naší 2D mřížce). Složený řetěz pak tvoří linii "kroutící se" ve čtvercové mřížce, kde každá aminokyselina leží v nějakém vrcholu mřížky. Taková linie se někdy označuje jako [[https://en.wikipedia.org/wiki/Self-avoiding_walk|sobě se vyhýbající procházka]].
Pro popis pozic mřížky můžeme použít komplexní čísla (kde souřadnice pozice bude určena reálnou a imaginární složkou), např.:
>>> a = 3+2j
>>> a.real
3.0
>>> a.imag
2.0
Podobně pro určení směru v mřížce můžeme použít komplexní čísla jednotkové velikosti: ''1'' (východ), ''1j'' (sever), ''-1'' (západ) a ''-1j'' (jih).
===== Konfigurace proteinu =====
Konfigurací budeme nazývat předpis pro složení řetězce aminokyselin. Budeme-li mít sekvenci aminokyselin
>>> a = [0, 1, 1, 1, 1, 0]
můžeme k ní přiřadit např. konfiguraci
>>> c = [1, 1, 1, 1, 1]
což odpovídá přímé "vodorovné" linii (viz obrázek výše), pokud se domluvíme na následujících vlastnostech a interpretaci konfigurace:
* Konfigurace je sekvence jednotkových komplexních čísel a je nutně o jeden element kratší než sekvence aminokyselin.
* První aminokyselina je umístěna v počátku (''0 + 0j'').
* Umístění dalších aminokyselin se řídí jednotlivými prvky konfigurační sekvence, a to tak, že se k pozici předchozí aminokyseliny přičte první dosud nepoužitý prvek konfigurace. Pro příklad nahoře tedy
* druhá aminokyselina leží na pozici ''1 + 0j'' (protože ''(0 + 0j) + 1 = (1 + 0j)'',
* třetí aminokyselina leží na pozici ''2 + 0j'' (protože ''(1 + 0j) + 1 = (2 + 0j)'',
* atd.
===== Pozice aminokyselin podle konfigurace =====
Připomeňme, že první aminokyselina je zakotvená v počátku ''(0 + 0j)''. Jistě jste si všimli, že pozice dalších aminokyselin je dána kumulativním součtem konfigurační sekvence. S využitím funkce ''accumulate'' z modulu ''itertools'' tak lze poměrně snadno získat pozici všech aminokyselin:
>>> from itertools import accumulate
>>> p = [0] # Začni s pozici první aminokyseliny
>>> p.extend(accumulate(c))
>>> p
[0, 1, 2, 3, 4, 5]
Jiný příklad: pro konfiguraci ''c = [1, 1, 1j, 1, 1]'' dostáváme
>>> c = [1, 1, 1j, 1, 1]
>>> p = [0] # Začni s pozici první aminokyseliny
>>> p.extend(accumulate(c))
>>> p
[0, 1, 2, (2+1j), (3+1j), (4+1j)]
Taková konfigurace je vidět na následujícím obrázku:
{{ :courses:a4b99rph:cviceni:folding2.gif?200 |Protein 2}}
===== Ohýbání konfigurace =====
Jednu konfiguraci můžeme změnit v jinou např. tak, že ji za nějakou aminokyselinou ohneme po nebo proti směru hodinových ručiček. Komplexní aritmetika zjednodušuje výpočty. Pokud např. chceme ohnout pravou část původní konfigurace ''c'' o 90 stupňů, můžeme ji po prvcích vynásobit sekvencí ''f'', která je takto ohnutá:
>>> c = [1, 1, 1, 1, 1]
>>> f = [1, 1, 1j, 1j, 1j]
>>> c2 = [a*b for a, b in zip(c, f)] # Součin sekvencí c a f po prvcích
>>> c2
[1, 1, 1j, 1j, 1j]
Pozice aminokyselin pak spočteme již známým způsobem:
>>> p2 = [0]
>>> p2.extend(accumulate(c2))
>>> p2
[0, 1, 2, (2+1j), (2+2j), (2+3j)]
{{ :courses:a4b99rph:cviceni:folding3.gif?100 |Protein 3}}
V již ohnuté konfiguraci ''c2'' můžeme znovu ohnout např. poslední dva elementy o dalších 90 stupňů. Výsledek vypadá takto:
>>> f2 = [1, 1, 1, 1j, 1j]
>>> c3 = [a*b for a, b in zip(c2, f2)]
>>> c3
[1, 1, 1j, (-1+0j), (-1+0j)]
>>> p3 = [0]
>>> p3.extend(accumulate(c3))
>>> p3
[0, 1, 2, (2+1j), (1+1j), 1j]
{{ :courses:a4b99rph:cviceni:folding4.gif?100 |Protein 4}}
Sekvencí několika ohnutí/skladů jsme získali výslednou konfiguraci ''c3''. Jak dobrá ale tato konfigurace je?
===== Volná energie proteinu =====
Protože protein existuje ve vodním prostředí, hydrofóbní aminokyseliny (1) mají tendenci zůstávat pohromadě v kompaktních útvarech. Každé možné složení sekvence aminokyselin (možný protein) je asociováno s volnou energií. A protože v přírodě často systémy zaujímají stavy s nejnižší energií, optimální složení (které máte najít a které může být více než jedno) odpovídá konfiguraci s nejmenší volnou energií.
**Volná energie** se v naší úloze počítá jako součet vzdáleností mezi každými dvěma hydrofóbními aminokyselinami, přičemž použijeme Euklidovskou vzdálenost. Neformálně řečeno, vaším úkolem je najít takovou konfiguraci, díky které budou hydrofóbní aminokyseliny "co nejblíže u sebe".
V posledním příkladu jsme našli konfiguraci ''c3'', jíž odpovídají pozice aminokyselin ''p3'' na posledním obrázku. Tato konfigurace má volnou energii:
\( E = 1 + 1 + 1 + 1 + \sqrt{2} + \sqrt{2} \)
Vaším úkolem je tedy pro nějakou vstupní sekvenci aminokyselin ''a'' najít takovou konfiguraci ''c'', která minimalizuje volnou energii.