gap> ######################### BEGIN COPYRIGHT MESSAGE ######################### GBNP - computing Gröbner bases of noncommutative polynomials Copyright 2001-2010 by Arjeh M. Cohen, Dié A.H. Gijsbers, Jan Willem Knopper, Chris Krook. Address: Discrete Algebra and Geometry (DAM) group at the Department of Mathematics and Computer Science of Eindhoven University of Technology.

For acknowledgements see the manual. The manual can be found in several formats in the doc subdirectory of the GBNP distribution. The acknowledgements formatted as text can be found in the file chap0.txt.

GBNP is free software; you can redistribute it and/or modify it under the terms of the Lesser GNU General Public License as published by the Free Software Foundation (FSF); either version 2.1 of the License, or (at your option) any later version. For details, see the file 'LGPL' in the doc subdirectory of the GBNP distribution or see the FSF's own site: http://www.gnu.org/licenses/lgpl.html gap> ########################## END COPYRIGHT MESSAGE ##########################

gap> ### filename = "exampleColagen.g" gap> ### authors Cohen & Gijsbers

gap> ### THIS IS A GAP PACKAGE FOR COMPUTING NON-COMMUTATIVE GROBNER BASES gap> <#GAPDoc Label="ExampleColagen">
The cola gene puzzle

A prize question appearing in the January 2005 issue of the Dutch journal "Natuur en Techniek" asked for a DNA change of cows so that they could produce Cola instead of milk. A team of genetic manipulators has tools to perform the following five DNA string operations. (Here the strings before and after the equality sign can be interchanged at will.)

operation 1: TCAT = T;

operation 2: GAG = AG;

operation 3: CTC = TC;

operation 4: AGTA = A;

operation 5: TAT = CT.

The first question is to show how they can transform the milk gene TAGCTAGCTAGCT to the cola gene CTGACTGACT.

A second question is to show that mad cow disease related retro virus CTGCTACTGACT can be avoided at all times. Can this be guaranteed?

We answer these questions using the trace functions of the Gröbner basis package GBNP in Section .

First load the package and set the standard infolevel to 0 and the time infolevel to 0 to minimize the printing of data regarding the computation (for more information about the info level, see Chapter ).

gap> LoadPackage("GBNP","0",false);; gap> SetInfoLevel(InfoGBNP,0); gap> SetInfoLevel(InfoGBNPTime,0);

We introduce the free algebra ALG on the generators corresponding to the four letters in the DNA code and express the milk gene and cola gene as monomials in this algebra.

gap> ALG:=FreeAssociativeAlgebraWithOne(Rationals, "A", "C", "G", "T");; gap> g:=GeneratorsOfAlgebra(ALG);; gap> A:=g[2];; gap> C:=g[3];; gap> G:=g[4];; gap> T:=g[5];;

gap> milk := T*A*G*C*T*A*G*C*T*A*G*C*T;; gap> cola := C*T*G*A*C*T*G*A*C*T;;

We next enter the set K of binomials x-y corresponding to the five operations x = y listed above. We enter the binomials as members of ALG and let KNP be the corresponding set of NP polynomials.

gap> rule1 := T*C*A*T - T;; gap> rule2 := G*A*G - A*G;; gap> rule3 := C*T*C - T*C;; gap> rule4 := A*G*T*A - A;; gap> rule5 := T*A*T - C*T;; gap> K := [rule1,rule2,rule3,rule4,rule5];; gap> KNP := List(K,x-> GP2NP(x));;

We stipulate how the variables will be printed and print KNP. See .

gap> GBNP.ConfigPrint("A","C","G","T"); gap> PrintNPList(KNP); TCAT - T GAG - AG CTC - TC AGTA - A TAT - CT

Now calculate the usual Gröbner basis with .

gap> GB := SGrobner(KNP);;

Compare milk and cola after taking their strong normal forms with respect to GB using . We oberve that they have the same normal form and so there is a way to transform the milk gene into the cola gene.

gap> milkNP := GP2NP(milk);; gap> colaNP := GP2NP(cola);; gap> milkRed := NP2GP(StrongNormalFormNP(milkNP,GB),ALG); (1)*T gap> colaRed := NP2GP(StrongNormalFormNP(colaNP,GB),ALG); (1)*T

But this information does not yet show us how to perform the transformation. To this end we calculate the Gröbner basis with trace information, using the function .

gap> GTrace := SGrobnerTrace(KNP);;

The full trace can be printed with , but we only print the relations (and no trace) by invoking .

gap> PrintNPListTrace(GTrace); CT - T GA - A AGT - AT ATA - A TAT - T TCA - TA

In order to display a proof that milk-cola belongs to the ideal we use , The result is a record, p say, containing milk-cola in the field p.pol (the normal form will be subtracted from the argument milk-cola to obtain p.pol, but the normal form is zero because the argument belongs to the ideal generated by K). The other field of the record p is p.trace, the traced polynomial, which is best displayed by use of .

gap> p := StrongNormalFormTraceDiff(CleanNP(GP2NP(milk-cola)),GTrace);; gap> NP2GP(p.pol,ALG); (1)*(T*A*G*C)^3*T+(-1)*(C*T*G*A)^2*C*T gap> PrintTracePol(p); - TGATGAG(1) + TAGG(1)ATAT - TATATAGG(1) - TGAG(1)GACT + TGATGACG(1) - G( 1)GACTGACT - TAGCG(1)ATAT - TATAGG(1)AGT + TATATAGCG(1) + TGACG(1)GACT + CG( 1)GACTGACT - TAGG(1)AGTAGT + TAGTAGTAGG(1) + TATAGCG(1)AGT + TAGCG( 1)AGTAGT + TAGTAGG(1)AGCT - TAGTAGTAGCG(1) + TAGG(1)AGCTAGCT - TAGTAGCG( 1)AGCT - TAGCG(1)AGCTAGCT - TATG(2)TAT - TG(2)TATGAT - TGATGAG(3)AT + TAGG( 3)ATATAT - TATATAGG(3)AT - TGAG(3)ATGACT - G(3)ATGACTGACT - TATAGG( 3)ATAGT - TAGG(3)ATAGTAGT + TAGTAGTAGG(3)AT + TAGTAGG(3)ATAGCT + TAGG( 3)ATAGCTAGCT - TATG(4)T + TG(4)TAT + TATGG(4)T - TG(4)TGAT + TATATG(4)T + TGG( 4)TGAT - TG(4)TATAT + TATG(4)TAGT + TG(4)TAGTAGT + TAGG(5)ATAT - TATATAGG( 5) - TATAGG(5)AGT - TAGG(5)AGTAGT

In order to give a precise answer to the first question we need to work a little on p.trace. To do so, we introduce the following function, which creates the NP polynomial corresponding to the i-th term in the expression p.trace of p.pol as a linear combination of members of KNP. It is used to obtain the list EvalList of polynomials for all i.

gap> EvalTracePol := function(i,p,KNP) > local x,pi; > pi := p.trace[i]; > x := BimulNP(pi[1],KNP[pi[2]],pi[3]); > return [x[1],pi[4]*x[2]]; > end;;

gap> lev := Length(p.trace);; gap> EvalList := List([1..lev], y -> CleanNP(EvalTracePol(y,p,KNP)));;

In order to find the rewrite from the milk gene to the cola gene as required for an answer to the first question, we match leading terms recursively.

gap> UnusedIndices := Set([1..lev]);; gap> RunningTerm := milkNP[1][1];; gap> stepno := 0;; gap> NP2GP(milkNP,ALG); (1)*(T*A*G*C)^3*T gap> while Length(UnusedIndices) > 0 do > i := 0; > notfnd := true; > while i < lev and notfnd do > i := i+1; > if EvalList[i][1][1] = RunningTerm and i in UnusedIndices then > notfnd := false; > RemoveSet(UnusedIndices, i); > RunningTerm := EvalList[i][1][2]; > stepno := stepno+1; > elif EvalList[i][1][2] = RunningTerm and i in UnusedIndices then > notfnd := false; > RemoveSet(UnusedIndices, i); > RunningTerm := EvalList[i][1][1]; > stepno := stepno+1; > fi; > od; > if i = lev and notfnd = true then Print("error not fnd in"); fi; > Print(" -(",stepno,")- "); > PrintNP([[p.trace[i][1]],[1]]); > Print(" K[",p.trace[i][2],"]\n "); > PrintNP([[p.trace[i][3]],[1]]); > Print(" --> "); > PrintNP([[EvalList[i][1][2]],[1]]); > od;; -(1)- TAGC K[1] AGCTAGCT --> TAGCTAGCTAGCT -(2)- TAG K[3] ATAGCTAGCT --> TAGTCATAGCTAGCT -(3)- TAG K[1] AGCTAGCT --> TAGTAGCTAGCT -(4)- TAGTAGC K[1] AGCT --> TAGTAGCTAGCT -(5)- TAGTAG K[3] ATAGCT --> TAGTAGTCATAGCT -(6)- TAGTAG K[1] AGCT --> TAGTAGTAGCT -(7)- TAGTAGTAGC K[1] 1 --> TAGTAGTAGCT -(8)- TAGTAGTAG K[3] AT --> TAGTAGTAGTCAT -(9)- TAGTAGTAG K[1] 1 --> TAGTAGTAGT -(10)- TAG K[1] AGTAGT --> TAGTAGTAGT -(11)- TAG K[3] ATAGTAGT --> TAGTCATAGTAGT -(12)- TAGC K[1] AGTAGT --> TAGCTAGTAGT -(13)- TAG K[5] AGTAGT --> TAGCTAGTAGT -(14)- T K[4] TAGTAGT --> TATAGTAGT -(15)- TATAG K[1] AGT --> TATAGTAGT -(16)- TATAG K[3] ATAGT --> TATAGTCATAGT -(17)- TATAGC K[1] AGT --> TATAGCTAGT -(18)- TATAG K[5] AGT --> TATAGCTAGT -(19)- TAT K[4] TAGT --> TATATAGT -(20)- TATATAG K[1] 1 --> TATATAGT -(21)- TATATAG K[3] AT --> TATATAGTCAT -(22)- TATATAGC K[1] 1 --> TATATAGCT -(23)- TATATAG K[5] 1 --> TATATAGCT -(24)- TATAT K[4] T --> TATATAT -(25)- T K[4] TATAT --> TATATAT -(26)- TAG K[5] ATAT --> TAGCTATAT -(27)- TAGC K[1] ATAT --> TAGCTATAT -(28)- TAG K[3] ATATAT --> TAGTCATATAT -(29)- TAG K[1] ATAT --> TAGTATAT -(30)- T K[4] TAT --> TATAT -(31)- TAT K[4] T --> TATAT -(32)- TAT K[2] TAT --> TATAGTAT -(33)- TATG K[4] T --> TATGAT -(34)- T K[4] TGAT --> TATGAT -(35)- T K[2] TATGAT --> TAGTATGAT -(36)- TG K[4] TGAT --> TGATGAT -(37)- TGATGA K[1] 1 --> TGATGAT -(38)- TGATGA K[3] AT --> TGATGATCAT -(39)- TGATGAC K[1] 1 --> TGATGACT -(40)- TGA K[1] GACT --> TGATGACT -(41)- TGA K[3] ATGACT --> TGATCATGACT -(42)- TGAC K[1] GACT --> TGACTGACT -(43)- 1 K[1] GACTGACT --> TGACTGACT -(44)- 1 K[3] ATGACTGACT --> TCATGACTGACT -(45)- C K[1] GACTGACT --> CTGACTGACT gap> NP2GP(colaNP,ALG); (1)*(C*T*G*A)^2*C*T

And now the second question regarding the retro virus.

gap> retro := C*T*G*C*T*A*C*T*G*A*C*T;;

We compute the Strong Normal Form of retro with respect to GB. As it is TGT, distinct to T, the strong normal form of milk, there is no transformation from milk to retro. gap> NP2GP(StrongNormalFormNP(CleanNP(GP2NP(retro)),GB), ALG); (1)*T*G*T

Of course, here too we can verify the reduction, by computing with input the NP polynomial corresponding to retro and with respect to K; it is called retroTrace. The symbol G in expression like G(2) are not to be confused with the single symbols G representing the DNA element.

gap> retroTrace := StrongNormalFormTraceDiff(CleanNP(GP2NP(retro)),GTrace);; gap> PrintTracePol(retroTrace); TGG(1) - TGC^2G(1) - TGTAG(1) + TGTACG(1) + TGTAGG(1)AT + TGTATGAG( 1) + TGTAG(1)GACT - TGTAGCG(1)AT - TGTATGACG(1) + TGG(1)ACTGACT - TGTACG( 1)GACT + G(1)GCTACTGACT - TGCG(1)ACTGACT - CG(1)GCTACTGACT + TGTATG( 2)TAT + TGG(3)AT + TGCG(3)AT - TGTAG(3)AT + TGTAGG(3)ATAT + TGTATGAG( 3)AT + TGTAG(3)ATGACT + TGG(3)ATACTGACT + G(3)ATGCTACTGACT + TGTG( 4)T + TGTATG(4)T - TGTG(4)TAT - TGTATGG(4)T + TGCG(5) + TGG(5)AT - TGTAG( 5) + TGTAGG(5)AT
<#/GAPDoc>