Question

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.

Was it helpful?

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
   ).

OTHER TIPS

It's a strange thing to have two such a different tasks to do in one predicate. You should probably have two separate predicates, one for counting number of powers of 2 and one to count 3s. Then you can combine them in one predicate like:

check(Nums, MULT2, THREE) :-
    count2powers(Nums, MULT2),
    count3s(Nums, THREE).

After that you can decompose further and have a separate predicate to check if a number is a power of 2:

is2power(1).
is2power(N) :-
    N > 0,
    N2 is N // 2,
    N2 * 2 =:= N,
    is2power(N2).

This is basic software engineering and this way you can build your program step by step and you will be able to ask more concrete and meaningful questions than just "The whole program returns false."

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top