Prolog syntax - using function results - prolog

I am trying to perform a sum operation on every result of :
combination(0,_,[]).
combination(K,L,[X|Xs]) :-
K > 0,
el(X,L,R),
K1 is K-1,
combination(K1,R,Xs).
el(X,[X|L],L).
el(X,[_|L],R) :- el(X,L,R).
For example, the user will enter is_sum_equal_10 ([1,2,3,4,5,6,7]) and the result will be true if the sum of any of the permutations equals 10.
I am struggling with putting it all together, can someone please help me define the is_sum_equal_10 rule that uses the combination rule for each permutation?

OK, well it's pretty easy to write really, you just need a rule to say if a particular combination sums to 10, and then another extra one to count up through the different sizes of combination lists (which is required due to the way you wrote combination with the K that you need to decrease as you check the rule).
1 ?- [user].
|: combination(0,_,[]).
|: combination(K,L,[X|Xs]) :- K > 0,
|: el(X,L,R), K1 is K-1, combination(K1,R,Xs).
|: el(X,[X|L],L).
|: el(X,[_|L],R) :- el(X,L,R).
|:
|: totals_10([],10).
|: totals_10([X|Xs],T) :- N is T+X, totals_10(Xs,N).
|:
|: is_comb_sum_equal_10(Numbers,_,R) :- combination(R,Numbers,C), totals_10(C,0).
|: is_comb_sum_equal_10(Numbers,N,R) :- Rnext is R+1, Rnext =< N,
|: is_comb_sum_equal_10(Numbers,N,Rnext).
|:
|: is_sum_equal_10(Numbers) :- length(Numbers,N), is_comb_sum_equal_10(Numbers,N,0).
|:
% user://1 compiled 0.13 sec, 1,824 bytes
true.
2 ?- is_sum_equal_10([2,3,5]).
true .
3 ?- is_sum_equal_10([2,235,124,3,3347,5,2373]).
true .
4 ?- is_sum_equal_10([2,235,124,3,3347,6,2373]).
false.
5 ?- is_sum_equal_10([1,1,1,1,1,-1,1,1,1,1,12]).
false.
6 ?- is_sum_equal_10([1,1,1,1,1,-1,1,1,1,1,11]).
true ;
false.
Since you don't care about the actual list or how big it is in the is_sum_equal_10 thing, you can just sum the combinations as you go along, and even better, check the sum is correct as a rule for the base case. I think it's a bit neater if you subtract from the desired total to get to 0 at the base rather than adding up and checking at the end against the value you want. This gives you a very simple single ruleset to look for a certain sum.
7 ?- [user].
|: is_subset_sum(0,[]).
|: is_subset_sum(N,[_|Xs]) :- is_subset_sum(N,Xs).
|: is_subset_sum(N,[X|Xs]) :- R is N-X, is_subset_sum(R,Xs).
|:
% user://2 compiled 0.03 sec, 540 bytes
true.
8 ?- is_subset_sum(10,[3,5,6]).
false.
9 ?- is_subset_sum(10,[123,4,1,77,3,2,34]).
true .
10 ?- is_subset_sum(11,[0,2,4,6,8,10,12,14,16,18,20,22]).
false.
This approach is of course both much easier to understand, and a lot more efficient.

Related

finding players in the same the team in prolog

I'm trying to solve a prolog question. I'm trying to print the players who is playing in Arsenal. I couldn't solve the problem.
player(rick,arsenal)
player(tom,dortmund)
player(paul,bayern)
player(tim,liverpool)
player(john,arsenal)
player(andrew,arsenal)
the output has to be:
?- sameteam(????)
X= [rick,john,andrew]
First, your facts need to be terminated with a "." to be correct Prolog syntax
player(rick,arsenal).
player(tom,dortmund).
player(paul,bayern).
player(tim,liverpool).
player(john,arsenal).
player(andrew,arsenal).
In "relational database fashion", let's first collect the ground atoms (in the sense of "logic atoms", i.e. "facts") that match the condition "plays at arsenal".
Fire up your preferred Prolog, and then:
?- [user].
|: player(rick,arsenal).
|: player(tom,dortmund).
|: player(paul,bayern).
|: player(tim,liverpool).
|: player(john,arsenal).
|: player(andrew,arsenal).
|: ^D% user://2 compiled 0.00 sec, 6 clauses
true.
?- player(Who,arsenal).
Who = rick ;
Who = john ;
Who = andrew.
Now we just need to "collect them into a list" and we can do that easily using setof/3:
?- setof(Who,player(Who,arsenal),Players).
Players = [andrew, john, rick].
This is all bog-standard "asking the database" work.
We can pack the above into a predicate for easier usage:
?- [user].
|: sameteam(Players) :- setof(Who,player(Who,arsenal),Players).
|: ^D% user://3 compiled 0.00 sec, 1 clauses
true.
?- sameteam(Players).
Players = [andrew, john, rick].

PROLOG Stack overflow recursive multiply

multiply(A,0,0).
multiply(A,B,C) :- D is B-1, multiply(A,D,E), C is E+A.
After using this rule once and Prolog returns an answer, if I want it to continue searching (prompts A = 5 ? and I hit ;), Prolog crashes. I don't understand why? Would anyone be able to explain. Thank you.
The problem is,
multiply(A,B,C) :- D is B-1, multiply(A,D,E), C is E+A.
This code does not have the constraint B > 0 that would prevent the stack overflow from occurring.
You can modify the code as,
multiply(A,B,C) :- B > 0, D is B-1, multiply(A,D,E), C is E+A.
Also, this line multiply(A,0,0). gives a singleton warning, so you can possibly change it into multiply(_,0,0)
Note : I wrote the constraint B > 0 thinking that you call the predicate as multiply(5,1,A).
Here is how you can make an endless loop easily:
?- [user].
|: loop(0).
|: loop(X) :- X0 is X - 1, loop(X0).
|: ^D% user://1 compiled 0.01 sec, 2 clauses
true.
?- loop(3).
true ;
After you redo (when you press ;) you backtrack into the second clause with a 0.
Then X0 becomes -1, you go into the recursive loop(X0), and from here on the first clause will never again match.
Try for example querying:
?- loop(-1).
Your version of the infinite loop is not tail-recursive, which means that it will use up the stack eventually. Here is a minimal example:
?- [user].
|: out_of_stack(0, 0).
|: out_of_stack(X, Y) :- X0 is X - 1, out_of_stack(X0, Y0), Y is Y0 + 1.
|: ^D% user://1 compiled 0.01 sec, 2 clauses
true.
?- out_of_stack(3, R).
R = 3 ;
ERROR: Stack limit (1.0Gb) exceeded
ERROR: Stack sizes: local: 1.0Gb, global: 19Kb, trail: 1Kb
ERROR: Stack depth: 11,183,864, last-call: 0%, Choice points: 3
ERROR: Possible non-terminating recursion:
ERROR: [11,183,864] user:out_of_stack(-11183853, _5046)
ERROR: [11,183,863] user:out_of_stack(-11183852, _5066)
So this is what is happening and why Prolog crashes.
To get rid of the problem, do as other have suggested. The other solution is to use 0, s(0), s(s(0)), ... to represent natural numbers.

How to return two values from a basic predicate(?) in Prolog?

I just started going over Prolog about an hour ago and have already stumbled into a slight problem I am unsure about. I am writing a predicate (or function?) that takes a list and returns the min and max values. Right now, I am just looking at one of the special cases when the list has 1 item. For example, if you query minmax([5], X, Y). I want the predicate to return X=5 Y=5. I have this code:
minmax([X], X, X).
but it is returning X = Y, Y = 5. I know it is a true statement and trivial, but is there a way I can return X=5,Y=5 ???
It is returning what you think it is. X is 5 as is Y. The values are unified and so the interpreter shows the message X=Y, Y=5. You need to get out the Prolog textbook and read up on unification of terms.
You could just as easily say
foo(A,B) :- A = 5 , B is (A+A)/2 .
and query it:
?- foo(X,Y).
and get the same result. In the Prolog universe, there is only ever a single instance of the integer 5.
X=Y, Y=5 means that X and Y are now both equal to 5. It's just a different way of saying that; you really shouldn't care. If you print both values, you'll just get 5:
?- [user].
|: print_stuff :-
|: X = Y,
|: Y = 5,
|: write('X = '), writeln(X),
|: write('Y = '), writeln(Y).
|: % user://1 compiled 0.02 sec, 2 clauses
true.
?- print_stuff.
X = 5
Y = 5
true.

SWI Prolog Database

is there a way I can query a SWI Prolog database to check if it doesn't contain an element?
I have tried using "not" but doesn't seem to work with this version of Prolog.
maybe you're looking for clause/2. A dummy session sample
1 ?- [user].
|: a(1).
|: a(2).
|: a(X) :- b(X).
|: b(3).
|: b(4).
% user://1 compiled 0.03 sec, 6 clauses
true.
2 ?- clause(a(X),Body).
X = 1,
Body = true ;
X = 2,
Body = true ;
Body = b(X).
3 ?- clause(b(X),Body).
X = 3,
Body = true ;
X = 4,
Body = true.
4 ?- clause(c(X),Body).
false.
you can see that c/1 is not defined...
Anyway, SWi-Prolog database is a complex beast, and it offers much more control about its contents.

Unification of expanded terms, double negation

I need to introduce a predicate that will let me negate atoms. So far I have neg(Premise) :- \+ Premise., which gives me following results:
?- assert(a).
true.
?- a.
true.
?- neg(a).
false.
?- neg(neg(a)).
true.
That makes sense and all is dandy, until I tried unification. For instance
[a,_] = [a,123]. returns true.
while
[a,_] = [neg(neg(a)),123]. returns false..
How can I solve this so that the neg(neg(X)) part is being evaluated or otherwise unified with X (since they both are logically equivalent)? So basically, I need X=neg(a), a=neg(X). to succeed.
Edit I found an explanation as to why not(not(<expression>)) is not equivalent to <expression> in prolog. Since <expression> succeeds, not(<expression>) fails. When a goal fails the variables it instantiated get uninstantiated. (source, slide 14).
I'm still not sure how to get around this though.
Reification of truth value will work on your simple case:
4 ?- [user].
|: reify(P, V) :- call(P) -> V = 1 ; V = 0.
% user://1 compiled 0.03 sec, 2 clauses
true.
5 ?- reify(true, V), reify(\+ \+ true, U), V = U.
V = U, U = 1.
using your symbols:
6 ?- [user].
|: a.
|: neg(P) :- \+ P.
% user://2 compiled 0.02 sec, 3 clauses
true.
7 ?- reify(a, V), reify(neg(neg(a)), U), V = U.
V = U, U = 1.
not sure how well this will merge with your code.

Resources