Een berucht probleem in de moleculaire biologie is het vouwen van eiwitten. Een eiwitmolecuul bestaat uit een keten van aminozuren die zichzelf spontaan opvouwt tot een driedimensionale vorm die energetisch het gunstigst is. Deze bindingsenergie hangt af van de onderlinge positie van alle aminozuren. Dit levert zoveel mogelijkheden op dat zelfs de modernste supercomputers hier nog op stuklopen.
Om het probleem iets makkelijker te maken, gaan we een eiwitmolecuul simuleren dat zich in twee dimensies opvouwt. De begintoestand is een vierkant rooster waarin elk aminozuur een positieve of negatieve lading heeft. Het opvouwen gebeurt door schotjes tussen de hokjes te plaatsen, zodanig dat een keten door het rooster ontstaat die alle hokjes omvat. De uiteinden van het molecuul hoeven niet aan de rand van het rooster te liggen.
Overal waar een schotje tussen twee hokjes staat, is het molecuul gevouwen en raken de aminozuren elkaar. Als tussen een hokje met lading $$-3$$ en een hokje met lading $$4$$ een schotje staat, dan levert dit een bindingsenergie van $$-3 \times 4 = -12$$ op. Een aminozuur kan aan meerdere aminozuren raken, en levert dan met elke buur bindingsenergie op. Uiteraard kan, vanwege de mintekens, bindingsenergie zowel positief als negatief zijn.
Als voorbeeld staat hierboven een $$4\times4$$ rooster, waarin een eiwit met 16 aminozuren is opgevouwen tot een configuratie met bindingsenergie gelijk aan \[ \begin{multline} \phantom{xxxxxxxxxxxx}(-1 \times 2) + (2 \times -5) + (5 \times -3) + (4 \times 3) + (5\times -1) + \phantom{x}\\ (-1 \times 2) + (-4 \times 2) + (-5 \times 6) + (1 \times 2) = -58\phantom{xxxxxxxxxxxx} \nonumber \end{multline} \]
Definieer een klasse Eiwit met volgende methoden:
Een initialisatiemethode __init__ waarmee een eiwit kan aangemaakt worden met gegeven begintoestand. Deze begintoestand moet als eerste verplichte parameter aan de initialisatiemethode doorgegeven worden. Dit onder de vorm van een lijst van gehele getallen. De initialisatiemethode moet nagaan of met deze lijst een vierkant rooster kan gevormd worden waarin de getallen van links naar rechts en van onder naar boven ingevuld worden. Indien dat niet het geval is, dan moet er een AssertionError opgeworpen worden zoals aangegeven in onderstaande voorbeeld. Anders moet de begintoestand bijgehouden worden in het nieuw aangemaakte Eiwit object.
Een methode opvouwen met een optionele parameter waarmee een vouwconfiguratie voor het eiwit kan doorgeven worden onder de vorm van een lijst van tuples. Daarin is elk tuple van de vorm ($$r_1, k_1, r_2, k_2$$) en geeft aan dat er bij het opvouwen een schotje moet geplaatst worden tussen de twee aangrenzende hokjes $$(r_1, k_1)$$ en $$(r_2, k_2)$$. Hierbij staan $$r$$ en $$k$$ respectievelijk voor een rij- en kolomnummer, waarbij de nummering telkens start vanaf nul. De methode mag ervan uitgaan dat als vouwconfiguratie een lijst van tuples wordt doorgegeven, en dat elk van deze tuples bestaat uit vier gehele getallen. Voor elk tuple moet de methode wel nagaan dat deze vier getallen staan voor twee geldige posities van hokjes in het vierkant rooster, en dat het eerste hokje links van het tweede hokje staat in het rooster, of er vlak boven. Bekijk onderstaand voorbeeld om te zien hoe de methode moet reageren als geen geldige vouwconfiguratie werd opgegeven. Als er een geldige waarde voor de optionele parameter werd opgegeven, dan moet deze configuratie bijgehouden worden door het Eiwit object. Een vorige configuratie wordt hierbij eventueel overschreven. Als er geen waarde voor de optionele parameter opgegeven wordt, dan moet ingesteld worden dat het eiwit niet opgevouwen is (er zijn met andere woorden geen hokjes).
Om onmiddellijk een Eiwit object te kunnen aanmaken met gegeven begintoestand en initiƫle vouwconfiguratie, kan aan de initialisatiemethode __init__ ook een vouwconfiguratie als tweede optionele parameter doorgegeven worden. Deze heeft dezelfde vorm en betekenis als de parameter van de methode opvouwen. Indien een waarde voor deze parameter wordt opgegeven, dan moet een vouwconfiguratie ingesteld worden voor het eiwit door de methode opvouwen aan te roepen. Anders is er initieel geen vouwconfiguratie ingesteld voor het eiwit.
Een methode bindingsenergie die de bindingsenergie van het eiwit teruggeeft. Deze bindingsenergie moet berekend worden op basis van de vouwconfiguratie die ingesteld werd voor het eiwit. Indien er geen vouwconfiguratie werd ingesteld, dan moet 0 (nul) teruggegeven worden.
Een methode __str__ waarmee een stringvoorstelling van het eiwit kan uitgeschreven worden volgens het formaat aangegeven in onderstaand voorbeeld. Hierbij moeten de ladingen van de aminozuren gecentreerd over vier posities weergegeven worden in de hokjes. Indien er een vouwconfiguratie werd ingesteld, dan moeten de schotjes op de juiste plaatsen weergegeven worden.
>>> eiwit = Eiwit([-2, 5, -4, 2, 4, -1, 2])
Traceback (most recent call last):
AssertionError: ongeldige begintoestand
>>> eiwit = Eiwit([-2, 5, -4, 2, 4, -1, 2, 1, 3, 2, -5, 2, 5, -3, 6, 1])
>>> eiwit.bindingsenergie()
0
>>> print(eiwit)
+----+----+----+----+
| -2 5 -4 2 |
+ + + + +
| 4 -1 2 1 |
+ + + + +
| 3 2 -5 2 |
+ + + + +
| 5 -3 6 1 |
+----+----+----+----+
>>> eiwit.opvouwen([(1, 1, 1, 2), (2, 1, 2, 2), (3, 0, 3, 1),
... (1, 0, 2, 0), (0, 1, 1, 1), (1, 1, 2, 1),
... (0, 2, 1, 2), (2, 2, 3, 2), (1, 3, 2, 3)])
>>> eiwit.bindingsenergie()
-58
>>> print(eiwit)
+----+----+----+----+
| -2 5 -4 2 |
+ +----+----+ +
| 4 -1 | 2 1 |
+----+----+ +----+
| 3 2 | -5 2 |
+ + +----+ +
| 5 | -3 6 1 |
+----+----+----+----+
>>> eiwit.opvouwen([(1, 1, 1, 2), (2, 1, 2, 2), (4, 0, 4, 1)])
Traceback (most recent call last):
AssertionError: ongeldige configuratie
>>> eiwit.opvouwen([(1, 1, 1, 2), (2, 1, 3, 3), (3, 0, 3, 1)])
Traceback (most recent call last):
AssertionError: ongeldige configuratie
>>> eiwit = Eiwit([7, -2, -4, 3], [(0, 1, 1, 1)])
>>> eiwit.bindingsenergie()
-6
>>> print(eiwit)
+----+----+
| 7 -2 |
+ +----+
| -4 3 |
+----+----+