Search code examples
listprologclpfdclpz

Find powers of 2 in a list Prolog


I'm trying to create a list in Prolog (SWI Prolog) and check which numbers are powers of 2 and second find how many times a specific number is in the list (in this example I'm trying to find how many times the number 3 is in the list). For a example, if you ask

?- check([0,2,3,-5,-2,1,8,7,4], MULT2, THREE).

you should see

MULT2=[2,8,4] 
THREE=1 

My first try to find a solution is to search the list with head and doing head mod 2 = 0 to find all numbers which are powers of 2, but something went wrong and I only get "false" as an answer.


Solution

  • Here's how you can find the "powers of two" in logically-pure way!

    Using 4.3.5, library(reif) and library(clpz):

    :- use_module([library(reif), library(clpz)]).
    
    power_of_two_t(I, T) :-
       L #= min(I,1),
       M #= I /\ (I-1),
       call((L = 1, M = 0), T).      % using (=)/3 and (',')/3 of library(reif)
    

    Sample query1 using meta-predicate tfilter/3 in combination with power_of_two_t/2:

    ?- tfilter(power_of_two_t, [0,2,3,-5,-2,1,8,7,4], Ps).
    Ps = [2,1,8,4].                  % succeeds deterministically
    

    Here's a more general query suggested by a comment:

    ?- tfilter(power_of_two_t, [X], Ps).
       Ps = [X], 0#=X/\_A, _A+1#=X, X in 1..sup, _A in 0..sup
    ;  Ps = [], dif(_A,0), _A#=X/\_B, _B+1#=X, X in 1..sup, _B in 0..sup
    ;  Ps = [], dif(_A,1), _A#=min(X,1), _B#=X/\_C, _C+1#=X, X#>=_A, _A in inf..1.
    

    Footnote 1: The answer sequences shown above were brushed up to indicate the determinism of calls.

    Footnote 2: To reproduce the results use call_det/2 which is defined like this:

    call_det(G_0, Det) :-
       call_cleanup(G_0, Flag = set),
       (  nonvar(Flag)
       -> Det = true
       ;  Det = false
       ).