Beginner - add multiples of 3 and 5 - prolog

I'm trying to find the sum of all positive multiples of 3 and 5 below 1000. After adding the portion that's supposed to remove the multiples of 3 from the sum of the multiples of 5, gprolog will keep spitting out "No" for the query ?- sigma(1000,N).
The problem apparently lies in sigma5, but I can't quite spot it:
sigma(Num, Result) :- sigma3(Num, 3, Result3),
sigma5(Num, 5, Result5),
Result is Result3 + Result5.
sigma3(Num, A, Result) :- A < Num,
Ax is A+3,
sigma3(Num, Ax, ResultX),
Result is ResultX + A.
sigma3(Num, A, Result) :- A >= Num,
Result is 0.
sigma5(Num, A, Result) :- A < Num,
mod3 is A mod 3,
0 \= mod3,
Ax is A+5,
sigma5(Num, Ax, ResultX),
Result is ResultX + A.
sigma5(Num, A, Result) :- A < Num,
mod3 is A mod 3,
0 == mod3,
Ax is A+5,
sigma5(Num, Ax, ResultX),
Result is ResultX.
sigma5(Num, A, Result) :- A >= Num,
Result is 0.
What's the problem with my code?

As integers are involved, consider using finite domain constraints. For example, with SWI-Prolog:
?- use_module(library(clpfd)).
true.
?- findall(N, (N mod 3 #= 0 #\/ N mod 5 #= 0, N in 0..999, indomain(N)), Ns),
sum(Ns, #=, Sum).
Ns = [0, 3, 5, 6, 9, 10, 12, 15, 18|...],
Sum = 233168.

Prolog has never been popular for it's arithmetic capabilities.
This is due to the need to represent 'term constructors' for symbolic processing, without undue evaluation, so when actual arithmetic is required we must explicitly allocate the 'space' (a variable) for the result, instead that 'passing down' an expression. This lead to rather verbose and unpleasant code.
But using some popular extension, like CLP(FD), available in GProlog as well as SWI-Prolog, we get much better results, not readily available in other languages: namely, a closure of the integer domain over the usual arithmetic operations. For instance, from the SWI-Prolog CLP(FD) library, a 'bidirectional' factorial
n_factorial(0, 1).
n_factorial(N, F) :- N #> 0, N1 #= N - 1, F #= N * F1, n_factorial(N1, F1).
?- n_factorial(X, 3628800).
X = 10 .
Anyway, here is a simple minded solution to the original problem, similar to what you attempted, but using an accumulator to compute result. This simple trick allows writing a tail recursive procedure, that turns out in better efficiency.
sigma(Num, Result) :-
sigma(1, Num, 0, Result).
sigma(N, M, Acc, Tot) :-
( N < M, !,
( (0 is N mod 3 ; 0 is N mod 5)
-> Sum is Acc + N
; Sum is Acc
),
N1 is N + 1,
sigma(N1, M, Sum, Tot)
; Tot is Acc
).
Test:
?- sigma(1000, X).
X = 233168 .

mod3 is A mod 3,
(as well all the other occurrences of mod3) should be Mod3 since it is a variable.
with that fix, the program runs correctly (at least for N=1000)
btw here is my solution (using higher-order predicates):
sum(S):-
findall(X,between(1,999,X),L), % create a list with all numbers between 1 and 999
include(div(3),L,L3), % get the numbers of list L which are divisible by 3
include(div(5),L,L5), % get the numbers of list L which are divisible by 5
append(L3,L5,LF), % merge the two lists
list_to_set(LF,SF), % eliminate double elements
sumlist(SF,S). % find the sum of the members of the list
div(N,M):-
0 is M mod N.
it's less efficient of course but the input is too small to make a noticeable difference

This all seems very complicated to me.
sum_of( L , S ) :-
L > 0 ,
sum_of( 0 , L , 0 , S )
.
sum_of( X , X , S , S ) . % if we hit the upper bound, we're done.
sum_of( X , L , T , S ) :- % if not, look at it.
X < L , % - backtracking once we succeeded.
add_mult35( X , T , T1 ) , % - add any multiple of 3 or 5 to the accumulator
X1 is X + 1 , % - next X
sum_of( X1 , L , T1 , S ) % - recurse
.
add_mult35( X , T , T ) :- % no-op if X is
X mod 3 =\= 0 , % - not a multiple of 3, and
X mod 5 =\= 0 , % - not a multiple of 5
!. %
add_mult35( X , T , T1 ) :- % otherwise,
T1 is T + X % increment the accumulator by X
.
This could be even more concise than it is.
Aside from my code probably being extraordinarily horrible (it's actually longer than my C solution, which is quite a feat on it's own),
ANSI C:
int sum_multiples_of_three_and_five( int lower_bound , int upper_bound )
{
int sum = 0 ;
for ( int i = lower_bound ; i <= upper_bound ; ++i )
{
if ( 0 == i % 3 || 0 == i % 5 )
{
sum += i ;
}
}
return sum ;
}

Related

Prolog, given N and find all numbers not divisible by 3 and 5 and these numbers must be smaller than N

I have problem with find a solution to the problem.
Divisible/2 predicate examines whether a number N is divisible by one of numbers in the list
divisible([H|_],N) :- N mod H =:= 0.
divisible([H|T],N) :- N mod H =\= 0, divisible(T,N).
I need to build a predicate find that will find Number < N that are not divisible by the list of numbers
example input/output:
?- find(5, [3,5],Num).
output is :
Num = 4; Num = 2; Num = 1. False
Here N is 5 and list of number is [3,5]
Current Code:
findNum(1, LN, Num) :- \+ divisible(LN,1),
Num is 1.
findNum(Rank, LN, Num) :- Rank > 1,
Num1 is Rank - 1,
( \+ divisible(LN,Num1) -> Num is Num1;
findNum(Num1,LN, Num) ).
It only prints Num = 4; It never prints 2 and 1 for some reasons
And I am not sure where goes wrong..
Any help is appreciated...
Done three different ways
Using recursion
find_rec(0,_,[]) :- !.
find_rec(N0,Possible_divisors,[N0|Successful_divisors]) :-
divisible(Possible_divisors,N0),
N is N0 - 1,
find_rec(N,Possible_divisors,Successful_divisors).
find_rec(N0,Possible_divisors,Successful_divisors) :-
\+ divisible(Possible_divisors,N0),
N is N0 - 1,
find_rec(N,Possible_divisors,Successful_divisors).
Example run
?- find_rec(5,[3,5],Num).
Num = [5, 3] ;
false.
Using partition
find_par(N,Possible_divisors,Successful_divisors) :-
findall(Ns,between(1,N,Ns),List),
partition(partition_predicate(Possible_divisors),List,Successful_divisors,_).
partition_predicate(L,N) :-
divisible(L,N).
Example run
?- find_par(5,[3,5],Num).
Num = [3, 5].
Using conditional ( -> ; )
find_con(0,_,[]) :- !.
find_con(N0,Possible_divisors,Result) :-
(
divisible(Possible_divisors,N0)
->
Result = [N0|Successful_divisors]
;
Result = Successful_divisors
),
N is N0 - 1,
find_con(N,Possible_divisors,Successful_divisors).
Example run
?- find_con(5,[3,5],Num).
Num = [5, 3].
It would be nice to see some test cases for divisible/2 to quickly understand how it works.
:- begin_tests(divisible).
divisible_test_case_generator([13,1],13).
divisible_test_case_generator([20,10,5,4,2,1],20).
divisible_test_case_generator([72,36,24,18,12,9,8,6,4,3,2,1],72).
divisible_test_case_generator([97,1],97).
divisible_test_case_generator([99,33,11,9,3,1],99).
test(1,[nondet,forall(divisible_test_case_generator(List,N))]) :-
divisible(List,N).
:- end_tests(divisible).
Running of tests
?- make.
% c:/users/groot/documents/projects/prolog/so_question_177 compiled 0.00 sec, 0 clauses
% PL-Unit: divisible ..... done
% All 5 tests passed
true.
Some feedback about your code.
Typically the formatting of a predicate starts a new line after :-
When using a ; operator, it is better to put it on a line by itself so that it is very obvious, many programmers have spent hours looking for bugs because a ; was seen as a , and not understood correctly.
findNum(1, LN, Num) :-
\+ divisible(LN,1),
Num is 1.
findNum(Rank, LN, Num) :-
Rank > 1,
Num1 is Rank - 1,
(
\+ divisible(LN,Num1)
->
Num is Num1
;
findNum(Num1,LN, Num)
).
Where the bug is in your code is here for the <true case>
->
Num is Num1
you did not recurse for the next value like you did for the <false case>
;
findNum(Num1,LN, Num)
Try to modify the findNum predicate into:
findNum(Rank, LN, Num) :- Rank > 1,
Num1 is Rank - 1,
\+ divisible(LN,Num1) -> Num is Num1.
findNum(Rank, LN, Num) :- Rank > 1,
Num1 is Rank - 1,
findNum(Num1,LN, Num).
For me, it gives the requested answer.

Cannot do simple Prolog

I have multiple recursions in Prolog but when i do similar recursion to pow in result block it says:
is/2: Arguments are not sufficiently instantiated.
pow(_,0,1):-!.
pow(X,N,XN):-
N>0,
N1 is N - 1,
pow(X, N1, XN1),
XN is XN1 * X.
result(_,0,_):-!.
result(X, N, Res):-
N2 is N - 1,
N1 is 2*N - 1,
pow(X, N1, Numer),
pow(-1, N2, One),
writeln('before'),
result(X, N2, RS1),
writeln('after'),
writeln('RS1: ' + RS1),
Res is RS1+One*(Numer/N1).
It's probably for the reason that because
result(_,0,_):-!.
is true for any 3rd (and 1st) argument where 2nd one is 0, so in
result(X, N2, RS1)
the RS1 variable cannot be computed when N2 is 0. (It's just like to ask a question to find x when 0 * x = 0 is given, for example.)
If you fix the value for RS1 when N2=0, e.g. using a conditional like this
(N2 =:= 0 -> RS1 is 1; result(X, N2, RS1)),
it will work.
A common pattern in Prolog is the use of helper predicates with an accumulator.
Xn is repeated multiplication. It's shorthand for 1 * X * X ..., repeated n times, correct? And that gives you the prolog predicate you need.
Try something like this:
% ---------------------------------------------------------
% pow/3 — Our public predicate to raise X to the Nth power,
% unifying the result with R
% ---------------------------------------------------------
pow( X , N , R ) :-
pow(X,N,1,R)
.
% --------------------------------------------------------------
% pow/4 — Our private helper predicate
%
% It also raised X to the Nth power, but uses an accumulator, T,
% in which to accumulate the result.
% --------------------------------------------------------------
pow( _ , 0 , R , R ) . % Once we hit the 0th power, we're done: just unify the accumulator with R.
pow( X , N , T , R ) :- % To evaluate X to the Nth power...
N > 0, % 0. For non-negative, integral values of N.
T1 is T * X, % 1. Multiple the accumulator by X
N1 is N-1, % 2. Decrement the power N by 1
pow(X,N1,T1,R) % 3. Recursively evaluate X to the N-1th power
. % Easy!

Prolog count list elements higher than n

I'm kinda new to Prolog so I have a few problems with a certain task. The task is to write a tail recursive predicate count_elems(List,N,Count) condition List_Element > N, Count1 is Count+1.
My approach:
count_elems( L, N, Count ) :-
count_elems(L,N,0).
count_elems( [H|T], N, Count ) :-
H > N ,
Count1 is Count+1 ,
count_elems(T,N,Count1).
count_elems( [H|T], N, Count ) :-
count_elems(T,N,Count).
Error-Msg:
ERROR: toplevel: Undefined procedure: count_elems/3 (DWIM could not correct goal)
I'm not quite sure where the problem is. thx for any help :)
If you want to make a tail-recursive version of your code, you need (as CapelliC points out) an extra parameter to act as an accumulator. You can see the issue in your first clause:
count_elems(L, N, Count) :- count_elems(L,N,0).
Here, Count is a singleton variable, not instantiated anywhere. Your recursive call to count_elems starts count at 0, but there's no longer a variable to be instantiated with the total. So, you need:
count_elems(L, N, Count) :-
count_elems(L, N, 0, Count).
Then declare the count_elem/4 clauses:
count_elems([H|T], N, Acc, Count) :-
H > N, % count this element if it's > N
Acc1 is Acc + 1, % increment the accumulator
count_elems(T, N, Acc1, Count). % check the rest of the list
count_elems([H|T], N, Acc, Count) :-
H =< N, % don't count this element if it's <= N
count_elems(T, N, Acc, Count). % check rest of list (w/out incrementing acc)
count_elems([], _, Count, Count). % At the end, instantiate total with accumulator
You can also use an "if-else" structure for count_elems/4:
count_elems([H|T], N, Acc, Count) :-
(H > N
-> Acc1 is Acc + 1
; Acc1 = Acc
),
count_elems(T, N, Acc1, Count).
count_elems([], _, Count, Count).
Also as CapelliC pointed out, your stated error message is probably due to not reading in your prolog source file.
Preserve logical-purity with clpfd!
Here's how:
:- use_module(library(clpfd)).
count_elems([],_,0).
count_elems([X|Xs],Z,Count) :-
X #=< Z,
count_elems(Xs,Z,Count).
count_elems([X|Xs],Z,Count) :-
X #> Z,
Count #= Count0 + 1,
count_elems(Xs,Z,Count0).
Let's have a look at how versatile count_elems/3 is:
?- count_elems([1,2,3,4,5,4,3,2],2,Count).
Count = 5 ; % leaves useless choicepoint behind
false.
?- count_elems([1,2,3,4,5,4,3,2],X,3).
X = 3 ;
false.
?- count_elems([1,2,3,4,5,4,3,2],X,Count).
Count = 0, X in 5..sup ;
Count = 1, X = 4 ;
Count = 3, X = Count ;
Count = 5, X = 2 ;
Count = 7, X = 1 ;
Count = 8, X in inf..0 .
Edit 2015-05-05
We could also use meta-predicate
tcount/3, in combination with a reified version of (#<)/2:
#<(X,Y,Truth) :- integer(X), integer(Y), !, ( X<Y -> Truth=true ; Truth=false ).
#<(X,Y,true) :- X #< Y.
#<(X,Y,false) :- X #>= Y.
Let's run above queries again!
?- tcount(#<(2),[1,2,3,4,5,4,3,2],Count).
Count = 5. % succeeds deterministically
?- tcount(#<(X),[1,2,3,4,5,4,3,2],3).
X = 3 ;
false.
?- tcount(#<(X),[1,2,3,4,5,4,3,2],Count).
Count = 8, X in inf..0 ;
Count = 7, X = 1 ;
Count = 5, X = 2 ;
Count = 3, X = Count ;
Count = 1, X = 4 ;
Count = 0, X in 5..sup .
A note regarding efficiency:
count_elems([1,2,3,4,5,4,3,2],2,Count) left a useless choicepoint behind.
tcount(#<(2),[1,2,3,4,5,4,3,2],Count) succeeded deterministically.
Seems you didn't consult your source file.
When you will fix this (you could save these rules in a file count_elems.pl, then issue a ?- consult(count_elems).), you'll face the actual problem that Count it's a singleton in first rule, indicating that you must pass the counter down to actual tail recursive clauses, and unify it with the accumulator (the Count that gets updated to Count1) when the list' visit is done.
You'll end with 3 count_elems/4 clauses. Don't forget the base case:
count_elems([],_,C,C).

Finding the k'th occurence of a given element

I just started in Prolog and have the problem:
(a) Given a list L, an object X, and a positive integer K, it returns
the position of the K-th occurrence of X in L if X appears at least K
times in L otherwise 0.
The goal pos([a,b,c,b],b,2,Z) should succeed with the answer Z = 4.
So far I have:
pos1([],H,K,F).
pos1([H],H,1,F).
pos1([H|T],H,K,F):- NewK is K - 1, pos1(T,H,NewK,F), F is F + 1.
pos1([H|T],X,K,F):- pos1(T,X,K,F).
But I can't figure out why I'm getting:
ERROR: is/2: Arguments are not sufficiently instantiated
Any help would be much appreciated!
Use clpfd!
:- use_module(library(clpfd)).
We define pos/4 based on (#>)/2, (#=)/2, if_/3, dif/3, and (#<)/3:
pos(Xs,E,K,P) :-
K #> 0,
pos_aux(Xs,E,K,1,P).
pos_aux([X|Xs],E,K,P0,P) :-
P0+1 #= P1,
if_(dif(X,E),
pos_aux(Xs,E,K,P1,P),
if_(K #< 2,
P0 = P,
(K0+1 #= K,
pos_aux(Xs,E,K0,P1,P)))).
Sample query as given by the OP:
?- X = b, N = 2, pos([a,b,c,b],X,N,P).
X = b, N = 2, P = 4. % succeeds deterministically
How about the following more general query?
?- pos([a,b,c,b],X,N,P).
X = a, N = 1, P = 1
; X = b, N = 1, P = 2
; X = b, N = 2, P = 4 % (exactly like in above query)
; X = c, N = 1, P = 3
; false.
Let's take a high-level approach to it, trading the efficiency of the resulting code for the ease of development:
pos(L,X,K,P):-
numerate(L,X,LN,1), %// [A1,A2,A3...] -> [A1-1,A2-2,A3-3...], where Ai = X.
( drop1(K,LN,[X-P|_]) -> true ; P=0 ).
Now we just implement the two new predicates. drop1(K,L,L2) drops K-1 elements from L, so we're left with L2:
drop1(K,L2,L2):- K<2, !.
drop1(K,[_|T],L2):- K1 is K-1, drop1(K1,T,L2).
numerate(L,X,LN,I) adds an I-based index to each element of L, but keeps only Xs:
numerate([],_,[],_).
numerate([A|B],X,R,I):- I1 is I+1, ( A=X -> R=[A-I|C] ; R=C ), numerate(B,X,C,I1).
Testing:
5 ?- numerate([1,b,2,b],b,R,1).
R = [b-2, b-4].
6 ?- pos([1,b,2,b],b,2,P).
P = 4.
7 ?- pos([1,b,2,b],b,3,P).
P = 0.
I've corrected your code, without changing the logic, that seems already simple enough.
Just added a 'top level' handler, passing to actual worker pos1/4 and testing if worked, else returning 0 - a debatable way in Prolog, imo is better to allow to fail, I hope you will appreciate how adopting this (see comments) simplified your code...
pos(L,X,K,F):- pos1(L,X,K,F) -> true ; F=0.
% pos1([],H,K,F). useless: let it fail
% pos1([H],H,1,F). useless: already handled immediatly bottom
pos1([H|T],H,K,P):- K==1 -> P=1 ; NewK is K - 1, pos1(T,H,NewK,F), P is F + 1.
pos1([_|T],X,K,P):- pos1(T,X,K,F),P is F+1.
I hope you're allowed to use the if/then/else construct. Anyway, yields
7 ?- pos([a,b,c,b],b,2,Z).
Z = 4.
8 ?- pos([a,b,c,b],b,3,Z).
Z = 0.
Something like this. An outer predicate (this one enforces the specified constraints) that invokes an inner worker predicate:
kth( L , X , K , P ) :-
is_list( L ) , % constraint: L must be a list
nonvar(X) , % constriant: X must be an object
integer(K) , K > 0 % constraint: K must be a positive integer
kth( Ls , X , K , 1 , P ) % invoke the worker predicate with its accumulator seeded to 1
. % easy!
is_list/2 ensures you've got a list:
is_list(X) :- var(X) , !, fail .
is_list([]).
is_list([_|_]).
The predicate that does all the work is this one:
kth( [] , _ , _ , _ , 0 ) . % if we hit the end of the list, P is 0.
kth( [X|Ls] , X , K , K , K ) :- ! . % if we find the Kth desired element, succeed (and cut: we won't find another Kth element)
kth( [_|Ls] , X , K , N , P ) :- % otherwise
N < K , % - if we haven't got to K yet ...
N1 is N+1 , % - increment our accumulator , and
kth(Ls,X,K,N1,P) % - recurse down.
. % easy!
Though the notion of returning 0 instead of failure is Not the Prolog Way, if you ask me.

Prolog: Decrementing variable in argument

I am new to Prolog and was tasked with a Fibonnaci predicate fib( N, F) where N is the number in sequence, and F is the value. What I came up with does not work, but the solution I found seems identical to me... I cannot understand the difference.
My version:
/* MY VERSION, DOES NOT WORK */
fib( 0, 0).
fib( 1, 1).
fib(N,F) :-
N > 1,
fib(N-1,F1),
fib(N-2,F2),
plus(F1,F2,F).
The working version:
/* FOUND SOLUTION, DOES WORK */
fib( 0, 0).
fib( 1, 1).
fib(N,F) :-
N > 1,
N1 is N-1,
N2 is N-2,
fib(N1,F1),
fib(N2,F2),
plus(F1,F2,F).
Obviously the problem has something to do with me using "N-1" and "N-2" as arguments rather than assigning those values to new variables first. But I don't get it... because in other recursive Prolog codes, I have successfully done just that (decremented a variable right in the argument slot). Does this make sense?
Thanks!
Below is an example where the "N-1" did work.
line( N, _, _) :-
N =:= 0.
line( N, M, Char) :-
N > 0,
N mod M =\= 1,
write( Char), write( ' '),
line( N-1, M, Char).
line( N, M, Char) :-
N > 0,
N mod M =:= 1,
write( Char), write( '\n'),
line( N-1, M, Char).
square( N, Char) :-
N > 0,
line( N*N, N, Char).
A new version of fib/2 which also works!
/* NEW VERSION, CHANGED TRIVIAL CASES TO EVALUATE N */
fib( N, 0) :-
N =:= 0.
fib( N, 1).
N =:= 1.
fib(N,F) :-
N > 1,
fib(N-1,F1),
fib(N-2,F2),
plus(F1,F2,F).
In prolog,
1 - 2
Doesn't actually do any arithmetic (I know, right?), it creates a structure:
-(1, 2)
And is is a predicate that evaluates that structure:
is(X, -(1, 2))
Will unify X with -1.
Also apparently < and > (and those like it) are like is in that they evaluate expressions.
So that means that the difference between your fib predicate and your line predicate is that
fib(0, 0).
is using unification, ie, testing whether the terms themselves are equal:
foo(0).
?- foo(1 - 1).
false
Whereas a test like =:= tests for numerical equality:
foo(X) :- X =:= 0.
?- foo(1 - 1).
yes
I'd probably write the predicate somthing like the following.
fib/2 is the outer 'public' interface. N is the position in the sequence (zero-relative). F gets unified with the value of the Fibonacci sequence at that position.
fibonacci/5 is the inner 'core' that does the work.
The 1st argument is the counter
The 2nd argument is the limit
The 3rd/4th arguments are the sliding frame required to compute the next item in the sequence. It should be noted that there is not required for a Fibonacci sequence start start with { 1 , 1 }. Any two integers will do.
The 5th argument gets unified with the desired result.
Each clause in the core works as follows:
If N is 0, F is unified with '1'.
If N is 1, F is unified with '1'.
If the limit has been reached, we're done. Unify F with the sum of the preceding two elements in the sequence.
If counter is less than the limit, compute the next element in the sequence and recurse, sliding the oldest value out from the sliding window.
Here's the code:
fib( N , F ) :-
N >= 0 ,
fibonnaci( 0 , N , 1 , 1 , F ).
fibonacci( 0 , 0 , F , _ , F ).
fibonacci( 1 , 1 , _ , F , F ).
fibonacci( Limit , Limit , X , Y , F ) :-
F is X + Y
.
fibonacci( Current , Limit , X , Y , F ) :-
Current < Limit ,
Next is Current + 1 ,
Z is X + Y ,
fibonacci( Next , Limit , Y , Z , F )
.

Resources