So I've been trying to teach myself prolog and I think I'm coming along nicely. However, I'm sort of stuck at this one method I'm trying to make.
toN(N,A) A is equal to the integer values between 0 and N-1, generated in ascending order.
so
toN(5,A) would be
A = 0;
A = 1;
A = 2;
A = 3;
A = 4.
I'm still new to prolog so I'm not exactly sure how to do this with multiple values. I had something like this:
toN(N,A) :- 0 < N, Nx is N-1, toN(Nx,A).
toN(N,A) :- 0 =< N, Nx is N-1, A = Nx.
However this just returns false. Nothing else. It seems perfectly fine to me
Check if the Prolog implementation that you are using supports clpfd!
:- use_module(library(clpfd)).
The implementation of toN/2 gets declarative and super-concise:
toN(N,A) :-
A #>= 0,
A #< N,
labeling([up],[A]).
You'll find more labeling options in the clpfd manual: SWI-Prolog clpfd, SICStus Prolog clpfd.
Something like this should generate the sequence of integers between any two arbitrary endpoints:
sequence(X,Y,X) :- % to generate the integers between X and Y,
integer(X) , % - the starting point must be bound
integer(Y) , % - the endpoint must be bound
range(X,Y,Z) % - then we just invoke the worker
. %
range(X,X,X) . % hand back the last item in the sequence if X and Y have converged.
range(X,Y,X) :- % otherwise, return an item
X =\= Y . % - if X and Y haven't converged.
range(X,Y,Z) :- % otherwise,
X < Y , % - if X < Y ,
X1 is X+1 , % - increment X
range(X1,Y,Z) % - and recurse down.
. %
range(X,Y,Z) :- % otherwise
X > Y , % - if X > Y
X1 is X-1 , % - decrement X
range(X1,Y,Z) % - and recurse down
. %
With that general-purpose tool, you can simply say:
to_n(N,A) :- sequence(0,N,A).
Your implementation does not fail: by backtracking it yields numbers from -1 to N-1
?- toN(5,A).
A = -1 ? ;
A = 0 ? ;
A = 1 ? ;
A = 2 ? ;
A = 3 ? ;
A = 4 ? ;
no
To eliminate the -1 you should just replace =< by < in your second clause as #false commented above.
An alternative implementation, maybe more readable, would be
Edit: inserted condition N>=0 in answer to #false comment below.
toN(N,A) :-
N >= 0,
toN(0,N,A).
toN(K,N,K).
toN(K,N,A) :-
K < N-1,
Kn is K+1,
toN(Kn,N,A).
Related
I am trying to print all the even numbers from 1 to 10 using Prolog, and here is what I have tried:
printn(10,0):- write(10),!.
printn(X,Sum):-
( X mod 2 =:= 0 -> Sum is X+Sum, Next is X+1, nl, printn(Next);
Next is X+1, printn(Next) ).
but it returns false.
You don't need to create the list with the numbers from the beginning, it is better to examine numbers once:
print(X,Y):-print_even(X,Y,0).
print_even(X, X, Sum):-
( X mod 2 =:= 0 -> Sum1 is X+Sum;
Sum1 = Sum
), print(Sum1).
print_even(X, Y, Sum):-
X<Y, Next is X+1,
( X mod 2 =:= 0 -> Sum1 is X+Sum, print_even(Next, Y, Sum1);
print_even(Next, Y, Sum)
).
Keep in mind that in Prolog Sum is Sum+1 always fails you need to use a new variable e.g Sum1.
Example:
?- print(1,10).
30
true ;
false.
The most useful way of obtaining Prolog output is to capture the solution in a variable, either individually through backtracking, or in a list. The idea of "printing", which carries over from using other languages allows for formatting, etc, but is not considered the best way to express a solution.
In Prolog, you want to express your problem as a relation. For example, we might say, even_with_max(X, Max) is true (or succeeds) if X is an even number less than or equal to Max. In Prolog, when reasoning with integers, the CLP(FD) library is what you want to use.
:- use_module(library(clpfd)).
even_up_to(X, Max) :-
X in 1..Max,
X mod 2 #= 0, % EDIT: as suggested by Taku
label([X]).
This will yield:
3 ?- even_up_to(X, 10).
X = 2 ;
X = 4 ;
X = 6 ;
X = 8 ;
X = 10.
If you then want to collect into a list, you can use: findall(X, even_up_to(X), Evens).
What error do you have? Here is my solution:
Create list [1...10]
Filter it, excluding odd numbers
Sum elements of the list
Code:
sumList([], 0).
sumList([Head|Tail], Sum) :-
sumList(Tail, Rest),
Sum is Head + Rest.
isOdd(X) :-
not((X mod 2) =:= 0).
sumOfEvenNums(A, B, Out) :-
numlist(A, B, Numbers),
exclude(isOdd, Numbers, Even_numbers),
sumList(Even_numbers, Out).
Now you can call sumOfEvenNums(1, 10, N)
In ECLiPSe, you can write with iterator:
sum_even(Sum):-
( for(I,1,10),fromto(0,In,Out,Sum)
do
(I mod 2 =:= 0 -> Out is In + I;Out is In)
)
With library(aggregate):
evens_upto(Sum) :-
aggregate(sum(E), (between(1, 10, E), E mod 2 =:= 0), Sum).
Thanks to #CapelliC for the inspiration.
I want to write the equivalent psudo-function in prolog:
function underhundred(X){
if (X >= 0 && X <=100) return 1;
else return 0;
}
I tried writing this but it does not compile:
underhundred(X,L) :- L is (X => 0, X =< 100 -> L = 1; L = 0) .
What would be the proper way of writing this without using prolog between predicate?
If you indeed want to use the goals L=1 and L=0 and X is an integer, use clpfd!
:- use_module(library(clpfd)).
Reification works like a charm!
?- X in 0..100 #<==> L.
L in 0..1, X in 0..100#<==>L.
What if X gets instantiated?
?- X in 0..100 #<==> L, X=(-7).
L = 0, X = -7. % out of bounds: -7 < 0 =< 100
?- X in 0..100 #<==> L, X=55.
L = 1, X = 55. % within bounds: 0 =< 55 =< 100
?- X in 0..100 #<==> L, X=111.
L = 0, X = 111. % out of bounds: 0 =< 100 < 111
A Prolog query succeeds or fails. If it succeeds it will return the bindings it made to be true.
You can write this predicate using clpfd as:
:-use_module(library(clpfd)).
under_hundred_clpfd(X):-
X in 0..100.
(You might prefer a name such as between_0_100?, if you literally want under 100 then you can use X in inf..99).
Some queries:
?-under_hundred_clpfd(5).
true.
?-under_hundred_clpfd(101).
false.
?-under_hundred_clpfd(X).
X in 0..100.
A traditional way to write this is:
under_hundred(X):-
X>=0,
X=<100.
But this way does not work for uninstantiated variables.
?-under_hundred(X).
ERROR: >/2: Arguments are not sufficiently instantiated
So like you say you might have to put a between/3 or length/2 goal to get a solution or similar construct.
underhundred(X):-
length(_,X),
X>=0,
X=<100.
This is not a very good solution as on back tracking it will get into an infinite loop. between/3 behaves better but you don't want it :).
If the main point of the question is how to write an if-then-else construct in Prolog, then a reasonable answer along the lines of the proposed definition is:
underhundred(X,L) :-
( X >= 0, X =< 100 )
-> L = 1
; L = 0.
This will only be useful if underhundred(X,L) is called after X has been sufficiently instantiated.
I am very new to prolog and I am trying to code a simple program which will display the first 100 integers.
is_integer(0).
is_integer(X) :-
is_integer(Y),
( Y >= 100, ! ; X is Y + 1 ).
It works well but when we ask if 2.1 is an integer then it replies "true". This is because 2.1 is between 0 and 100.
But I want a program which will strictly display the first 100 Integers only.Could someone help me with this please.
Thanks!
I think this matches your style in the question if you don't want to use predefined functions like between(0, 100, X):
between0_100(X) :-
(var(X) -> true ; X >= 0), % either X is unbound or >= 0.
between0_100(0, X).
between0_100(X, X).
between0_100(X, Y) :-
Z is X + 1, % increment X
Z =< 100, % and test if it is <= 100
between0_100(Z, Y). % recurse
?- between0_100(X).
X = 0 ;
X = 1 ;
X = 2 ;
…
X = 98 ;
X = 99 ;
X = 100 ;
false.
?- between0_100(2.1).
false
What do you mean by "display"?
The (very standard) predicate between/3 is defined along the lines of:
between(Lower, Upper, N) is true when N >= Lower and N =< Upper. If N is an integer, it will succeed or fail, and throw an error if it is not an integer. If N is a free variable it will enumerate solutions by backtracking. I am quite certain you can find reasonable implementations of between/3 elsewhere on StackOverflow.
Or do you mean that you type in:
?- first_100_ints.
And you get:
0
1
2
3
4
...
99
?
You could do this as follows:
first_100_ints :-
next_int(0, 100).
next_int(X, Upper) :-
( X < Upper
-> format('~d~n', [X]),
succ(X, X1),
next_int(X1, Upper)
; true
).
This is one "cheap" way to do it. But keep in mind that this is not how you would want to write a Prolog program, normally. One somewhat better way would be to use the built-ins between/3 and forall/3:
?- forall(between(0, 99, X), format('~d~n', [X])).
This is equvalent to:
?- \+ (between(0, 99, X), \+ format('~d~n', [X])).
which reads something along the lines of, "There is no number between 0 and 99 (inclusive) for which you cannot print out the number". See here.
There are other things you can do, depending on what your exact goal is.
I second #Kay's answer. If it is possible, don't use side-effects and use the prolog-toplevel instead!
If your Prolog implementation offers clpfd, you could do it like this:
:- use_module(library(clpfd)).
?- X in 0..100, indomain(X).
X = 0. ;
X = 1 ;
X = 2 ;
% % ... lots of more answers ...
X = 99 ;
X = 100 ;
false. % query terminates universally
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).
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 ;
}