Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to swap three by three elements in a prolog list?

I'm doing an exercise in Prolog and I'm stuck. I need to swap three adjacent items in a list with another three elements.

That is:

| ?- swap([c,g,g,a,t,t,g,c,a,a], X).

X = [a,t,t,c,g,g,g,c,a,a]
X = [g,c,a,a,t,t,c,g,g,a]
X = [c,g,g,g,c,a,a,t,t,a]
X = [c,a,a,a,t,t,g,c,g,g]
.
.
.

This is what I have so far:

swap([H1, H2, H3, H4, H5, H6|T1], X) :-
     X = [H4, H5, H6, H1, H2, H3|T1];
     swap([H2, H3, H4, H5, H6|T1], X);
     swap([H1, H2, H3, H4, H5|T1], X).

And the output for this is:

| ?- swap([c,g,g,a,t,t,g,c,a,a], X).

X = [a, t, t, c, g, g, g, c, a, a] ;
X = [t, t, g, g, g, a, c, a, a] ;
X = [t, g, c, g, a, t, a, a] ;
X = [g, c, a, a, t, t, a] ;
X = [c, a, a, t, t, g] ;
X = [c, a, a, a, t, t] ;
X = [g, c, a, g, a, t, a] ;
X = [c, a, a, a, t, g] ;
X = [c, a, a, g, a, t] ;
X = [t, g, c, g, g, a, a, a] ;
X = [g, c, a, g, a, t, a] ;
X = [c, a, a, a, t, g] ;
X = [c, a, a, g, a, t] ;
X = [g, c, a, g, g, a, a] ;
X = [c, a, a, g, a, g] ;
X = [c, a, a, g, g, a] ;
X = [t, t, g, c, g, g, c, a, a] ;
X = [t, g, c, g, g, t, a, a] ;
X = [g, c, a, g, t, t, a] ;
X = [c, a, a, t, t, g] ;
X = [c, a, a, g, t, t] ;
X = [g, c, a, g, g, t, a] ;
X = [c, a, a, g, t, g] ;
X = [c, a, a, g, g, t] ;
X = [t, g, c, c, g, g, a, a] ;
X = [g, c, a, g, g, t, a] ;
X = [c, a, a, g, t, g] ;
X = [c, a, a, g, g, t] ;
X = [g, c, a, c, g, g, a] ;
X = [c, a, a, g, g, g] ;
X = [c, a, a, c, g, g] ;
false.

The only problem that I have is that with every recursion I lose some part of the list and I don't know how to put it back.

like image 209
RobertM Avatar asked Dec 13 '22 09:12

RobertM


1 Answers

It seems you are interested in describing RNA-sequences. Triples, that sounds much like anticodons. To make those sequences more readable, use:

:- set_prolog_flag(double_quotes, chars).

which permits you to write "attac" in place of [a,t,t,a,c]. See this how to get also compact answers.

Now for the swap. The easiest way is to first sketch what you want:

... Triple1 ... Triple2 ...  is the OldSequence

... Triple2 ... Triple1 ...  is the NewSequence

Where the ... are the same for both sequences. All of this can be readily translated using DCGs.

tripleswap(OldSequence, NewSequence) :-
   dif(T1,T2),
   phrase( ( seq(A), triple(T1), seq(B), triple(T2), seq(C) ), OldSequence),
   phrase( ( seq(A), triple(T2), seq(B), triple(T1), seq(C) ), NewSequence).

seq([]) --> [].
seq([B|Bs]) --> [B], seq(Bs).

triple([A,B,C]) --> [A,B,C].

Whenever you distrust a DCG-definition, just try it out with phrase/2. Like

?- phrase(triple(T1), Bs).
T1 = Bs, Bs = [_A,_B,_C].

The non-terminal triple//1 describes a sequence of 3 elements (presumably nucleotides).

seq//1 is an arbitrarily long sequence.

There are solutions with better termination conditions, but they are less readable and often require certain assumptions that are difficult to maintain in the general case. Here is such a simple improvement:

samelength([], []).
samelength([_|Xs], [_|Ys]) :-
   samelength(Xs, Ys).

and add samelength(OldSequence, NewSeqence) as the first goal. Now, tripleswap/2 terminates iff samelength/2 terminates. So one of the arguments should be a list of fixed length.

Also note that I think that "cccccc" has no swap. That's why I added dif(T1,T2).

?- tripleswap("cggattgcaa", Bs).
      Bs = "attcgggcaa"
   ;  Bs = "ttgacggcaa"
   ;  Bs = "tgcatcggaa"
   ;  Bs = "gcaattcgga"
   ;  Bs = "caaattgcgg"
   ;  Bs = "cttgggacaa"
   ;  Bs = "ctgctggaaa"
   ;  Bs = "cgcattggaa"
   ;  Bs = "ccaattggga"
   ;  Bs = "cgtgcgataa"
   ;  Bs = "cggcatgata"
   ;  Bs = "cgcaatggat"
   ;  Bs = "cgggcaatta"
   ;  Bs = "cggcaagatt"
   ;  Bs = "cggacaattg"
   ;  false.

BTW, dcgs are used in Molecular Biology since the 1980s. Start with

David B. Searls, Investigating the Linguistics of DNA with Definite Clause Grammars, NACLP 1989

and other work by the same author as well as Ross Overbeek around that time. All of this happened in the dawn of the Human Genome Project.

like image 81
false Avatar answered Dec 28 '22 15:12

false