Search code examples
listrotationprologelementgreatest-common-divisor

Shifting both directions elements of a list, and GCD of them. Prolog


i got trouble when trying to solve 2 problems in Prolog.

Here is the first one: I need to calculate de gcd of the elements of a list

Expectations:

gdc([3, 9, 6], G).

G=3

This is how i try to do it:

gdcs(1, _, 1) :- !.
gdcs(_, 1, 1) :- !.
gdcs(0, B, B) :- !.
gdcs(B, 0, B) :- !.
gdcs(X, X, X) :- !.
gdcs(A, B, L) :- A < B, !, L1 = B mod A, gdc(A, L1, L).
gdcs(A, B, L) :- L1 = A mod B, gdcs(B, L1, L).
gdc([], 0).
gdc([H|T], C) :- gdc(T, D), gdcs(D, H, C).

The problem is that it works only when i introduce only 0 or 1, for other numbers, it doesn't work.

The second one: Rotate a list in Prolog, this is what i need:

rot([1, 2, 1, 4, 5, 3, 5], Dir, Nr, Res). // Dir = direction(lft,rght), Nr = nr. of elements to shift, Res = List of elements

Res=[1, 4, 5, 3, 5, 1, 2]  // in this case Dir = lft, Nr = 1.

This one i have no idea how to implement, found on the internet how to use only one direction, but this one, i can't figure.


Solution

  • The gcd(a,b,c) = gcd(gcd(a,b),c). It means that for calculating gcd of more than 2 elements, you can first calculate gcd for two first elements, and then use it as an element in a recursive call list:

    % GCD calculation for two numbers
    gcd2(A, 0, A).
    gcd2(A, B, C) :- 
        A > B, 
        A1 is mod(A,B),
        gcd2(A1, B, C).
    gcd2(A, B, C) :- gcd2(B,A,C).
    
    
    % GCD of a list (the list contains at least two elements)
    gcd([A,B], G) :- gcd2(A,B,G).
    gcd([A,B|T], G) :-
        gcd2(A,B,A1),
        gcd([A1|T], G).
    

    As for rotation... Ok the rotation effectively is splitting of the list in certain position, and then glueing it in opposite order. The position for the left rotation is exactly the number of rotations required, while the right is the length of the list minus the number. The solution is divided to the split rule, and two different rotations:

    % splitAt (List, Position, Leftpart, Rightpart)
    splitAt([],_,[], []).
    splitAt(L, 0, [], L).
    splitAt([H|T], N, [H|Tleft], Right) :-
        N1 is N-1,
        splitAt(T, N1, Tleft, Right).
    
    
    rotateLeft(L, N, Res) :- 
        splitAt(L, N, Left, Right),
        append(Right, Left, Res).
    
    
    rotateRight(L, N, Res) :-
        length(L, Len),
        N1 is Len-N,
        splitAt(L, N1, Left, Right),
        append(Right, Left, Res).
    
    % rot(list, Dir, Nr, Res)
    rot(L, lft, N, Res) :- rotateLeft(L, N, Res).
    rot(L, rght, N, Res) :- rotateRight(L, N, Res).