Search code examples
prolog

Prolog write the is_progression predicate to check that the sequence of elements of a numerical list is a geometric progression


Write the is_progression predicate to check that the sequence of elements of a numerical list is a geometric progression.


Solution

  • Well, a geometric progression is a series of non-zero numbers, where each term after the first is the result of multiplying the previous by some fixed value (their common ration), correct? SO

    1, 2, 4, 8, 16, ... is a geometric progression where the common ratio is 2.

    We can define that in Prolog easily:

    progression( X , _ , X ) .
    progression( X , R , N ) :- progression1(X,R,N) .
    
    progression1( X , R , N ) :- N  is X*R .
    progression1( X , R , N ) :- X1 is X*R , progression1(X1,R,N) .
    

    This successively yields the desired geometric progression.

    To test whether a given list represents a geometric progression then, is a matter of traversing the list and testing the ratio between adjacent elements of the list.

    Something like this:

    progression( [A,B|Cs] , R ) :-  % A geometric progression has to have a least to values
        number(A),                  % - both of which must be numeric
        number(B),                  %
        R is B / A ,                % - compute the expected ratio
        progression_( [B|Cs] , R )  % - invoke the helper, discarding the 1st element
        .                           % Easy!
    
    progression_( []       , _ ) .  % is the source list exhausted? If so, we're done.
    progression_( [_]      , _ ) .  % is the source list of length 1? If so, we're done.
    progression_( [A,B|Cs] , R ) :- % otherwise...
        B =:= A * R ,               % - if the current item (B)  is identical to the previous item times the ratio
        progression_([B|Cs], R ) .  % - discard the previous item and recurse down.
    

    If you don't care what the common ratio might be, you can simplify things down to:

    progression( [A,B|Cs] ) :- progression1( [A,B|Cs] ) .
    
    progression1( []         ) .
    progression1( [_]        ) .
    progression1( [_,_]      ) .
    progression1( [A,B,C|Ds] ) :-
        number(A),
        number(B),
        number(C),
        B / A =:= C / B ,
        progression1( [B,C|Ds] )
        .
    

    Note that these solutions treat a sequence of two numbers, say [1, 2] as being a [very short] geometric progression.