Related
I have the following predicates:
slow(a , 10 , b).
slow(b , 17 , c).
slow(c , 12 , d).
slow(d , 19 , e).
slow(e , 13 , f).
fast(a , 20 , c).
fast(b , 20 , d).
fast(d , 20 , f).
line(X,T,Y) :- slow(X,T,Y).
line(X,T,Y) :- fast(X,T,Y).
journey(X,N,Z) :-
line(X,L,Y),
journey(Y,M,Z),
N is L+M.
journey(X,0,X) :-
!.
I now need to create a new predicate of 2arity to find the minimum value of N defined in the journey predicate.
I've so far defined the new predicate as:
minimum(X,Y) :-
journey(X,N,Y),
write(N).
I've tried to use findall/3 and bagof/3 to make a list and find the minimum atom of that list, but I am not sure how to use them.
I'm not sure how else to go about it, so any advice would be greatly appreciated.
Thanks
(First, remove the !)
?- journey(A,N,B), false.
false. % your definition always terminates, good
?- journey(A,N,B), \+ ( journey(A,M,B), M < N ).
A = a, N = 49, B = e
; A = a, N = 50, B = f
; A = a, N = 30, B = d
; A = a, N = 10, B = b
; A = b, N = 17, B = c
; A = c, N = 31, B = e
; ... .
?- setof(N,journey(A,N,B),[N|_]).
N = 0, A = B
; N = 10, A = a, B = b
; N = 20, A = a, B = c
; N = 30, A = a, B = d
; N = 49, A = a, B = e
; N = 50, A = a, B = f
; N = 17, A = b, B = c
; ... .
?- setof(N,journey(A,N,B),[N|_]), journey(A,N,B).
... . % same as above but in general safer
I am trying to understand how to solve the following problem in Prolog. Given the following Prolog code, list all solutions in order for the query c(X,Y,Z).
a(1).
a(2).
b(a).
c(A,B,C) :- a(A),d(B,C).
c(A,B,C) :- b(A),d(B,C).
d(B,C) :- a(B),!,a(C).
d(B,_) :- b(B).
I loaded up SWI Prolog to try it out myself, but I am unsure how it reaches the conclusion:
X = Y, Y = Z, Z = 1 ;
X = Y, Y = 1,
Z = 2 ;
X = 2,
Y = Z, Z = 1 ;
X = Z, Z = 2,
Y = 1 ;
X = a,
Y = Z, Z = 1 ;
X = a,
Y = 1,
Z = 2.
Starting small, I tried to query just d(B,C). with the same code, leading to the following conclusion:
Y = Z, Z = 1 ;
Y = 1,
Z = 2.
I understand how to get the Y=1 and Z=1,2, but I am unsure how the code leads to Y=Z. If anyone could help me with the logic to reach these conclusions, that would be well appreciated!
Let's start by looking at the predicates a/1 and b/1: We expect them to produce two and one answer(s) respectively and indeed that is the case:
?- a(X).
X = 1 ? ;
X = 2
?- b(X).
X = a
Next let's look at the predicate d/2 but without the cut, that is:
d(B,C) :- a(B),a(C).
d(B,_) :- b(B).
If we query this predicate:
?- d(B,C).
Prolog will start with the first rule of the predicate d/2, that is d(B,C) :- a(B),a(C). and tries to prove the first goal a(B). That succeeds with the substitution B = 1. So Prolog goes on to prove the goal a(C). Again that succeeds with the substitution C = 1. Prolog then reports the first solution to the query:
?- d(B,C).
B = C = 1 ?
So we ask if there are any more solutions by pressing ;:
?- d(B,C).
B = C = 1 ?;
Now Prolog tries to find another solution for a(C) and finds the substitution C = 2:
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ?
Again we ask if there's more:
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
Now Prolog fails to find another solution for a(C), so it backtracks to the first goal and tries to find an alternative solution for a(B) and succeeds with the substitution B = 2. So it goes on to prove the second goal a(C) to which again the substitution C = 1 is found. So Prolog reports this new solution.
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
B = 2,
C = 1 ?
We ask for yet more solutions:
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
B = 2,
C = 1 ? ;
So Prolog looks for another solution for a(C) and finds C = 2. So it answers:
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
B = 2,
C = 1 ? ;
B = C = 2 ?
We press ; again
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
B = 2,
C = 1 ? ;
B = C = 2 ? ;
And Prolog looks for other solutions for a(C) but can't find any. So it backtracks to the goal a(B) and again fails to produce new answers here. So those are all solutions for the first rule of d/2. Prolog now goes on and tries to find a solution for the second rule d(B,_) :- b(B).. This rule only contains one goal: b(B) and Prolog finds a substitution: B = a, so it answers:
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
B = 2,
C = 1 ? ;
B = C = 2 ? ;
B = a
?-
And there are no more solutions. Let's observe that while Prolog traverses the proof tree as seen above, every time alternative substitutions can't be ruled out a choice point is created and in the course of the search for answers Prolog can backtrack to these choicepoints to look for alternative solutions. Every time an answer in the above query ended with ? Prolog still had some choice points left to explore and by pressing ; we asked it to explore them.
Now let's move our attention back to your posted version of d/2 with the cut in the first rule:
d(B,C) :- a(B),!,a(C).
d(B,_) :- b(B).
What a cut does is to prune away choice points back to where it was when the predicate that contains it was called. So it is essentially throwing away untried alternatives, thereby committing Prolog to the first substitution(s) it finds. So if we issue the query again with this version:
?- d(B,C).
Prolog again starts with the first rule, looking for a solution for a(B), successfully substituting B = 1 encountering the cut, therefore committing to this solution and then searching for a proof for a(C), again successfully substituting C = 1. Prolog then answers:
?- d(B,C).
B = C = 1 ?
indicating that there are open choice points. Again we want more:
?- d(B,C).
B = C = 1 ? ;
Prolog finds another substitution C=2 for the goal a(C) and reports:
?- d(B,C).
B = C = 1 ? ;
B = 1,
C = 2
?-
But this time the query terminates. That is because the choicepoint for an alternative solution for the goal a(B) was pruned away thereby leaving us without the solutions B = 2, C = 1 and B = C = 2. Furthermore the choicepoint that would have led to the second rule being explored was also pruned away thereby robbing us of the solution B = a. Cuts that prune away correct solutions as seen above are often referred to as red cuts in the literature.
Note that by cutting away actual solutions this program is not logically correct anymore. With the above query you asked for all solutions of the predicate d/2 but got only two of them. However, if you ask for the other solutions specifically, the respective queries still succeed:
?- d(2,1).
yes
?- d(2,2).
yes
?- d(a,_).
yes
?-
Returning to your original question, let's compare the query ?- c(X,Y,Z). with both versions of d/2. To make comparisons easier, the variables X, Y and Z are replaced with A, B and C just like they occur in the predicate definitions:
% cut-free version % version with the cut:
?- c(A,B,C). ?- c(A,B,C).
A = B = C = 1 ? ; A = B = C = 1 ? ;
A = B = 1, A = B = 1,
C = 2 ? ; C = 2 ? ;
A = C = 1,
B = 2 ? ;
A = 1,
B = C = 2 ? ;
A = 1,
B = a ? ;
A = 2, A = 2,
B = C = 1 ? ; B = C = 1 ? ;
A = C = 2, A = C = 2,
B = 1 ? ; B = 1 ? ;
A = B = 2,
C = 1 ? ;
A = B = C = 2 ? ;
A = 2,
B = a ? ;
A = a, A = a,
B = C = 1 ? ; B = C = 1 ? ;
A = a, A = a,
B = 1, B = 1,
C = 2 ? ; C = 2
A = a,
B = 2,
C = 1 ? ;
A = a,
B = C = 2 ? ;
A = B = a
For the sake of brevity I'm not going to iterate through the steps of the proof, but let's observe a few key things: Firstly, in both rules of c/3 the predicate d/2 is called by the same goal d(B,C) and we have already looked at that goal in detail for both versions. Secondly, we can observe that both rules of c/3 are taken into regard in the search for answers with both versions of the predicate by seeing all three substitutions, A = 1, A = 2 and A = a appearing in both answer-sets. So the cut doesn't prune away the choice point here. Thirdly, the three solutions of d/2 that are pruned away by the cut: B = 2, C = 1, B = 2, C = 2 and B = a are missing in the answers for all three substitutions of A in the version with the cut. And finally, the version of c/3 with the cut is also not logically correct, as the most general query does not give you all the answers but you can query for the thrown away solutions directly and Prolog will find them, e.g.:
?- c(1,2,1).
yes
?- % etc.
Try the query trace, c(X,Y,Z).
So check the exercize 3.5 description here:
%% Exercise 3.5 %%
% Binary trees are trees where all internal nodes have exactly two children.
% The smallest binary trees consist of only one leaf node. We will represent leaf nodes as
% leaf(Label) . For instance, leaf(3) and leaf(7) are leaf nodes, and therefore small binary
% trees. Given two binary trees B1 and B2 we can combine them into one binary tree using the
% functor tree/2 as follows: tree(B1,B2) . So, from the leaves leaf(1) and leaf(2) we can build
% the binary tree tree(leaf(1),leaf(2)) . And from the binary trees tree(leaf(1),leaf(2)) and
% leaf(4) we can build the binary tree tree(tree(leaf(1), leaf(2)),leaf(4)).
% Now, define a predicate swap/2 , which produces the mirror image of the binary tree that is its first argument. For example:
% ?- swap(tree(tree(leaf(1), leaf(2)), leaf(4)),T).
% T = tree(leaf(4), tree(leaf(2), leaf(1))).
% yes
And this is my implementation:
swap(tree(leaf(X), leaf(Y)), tree(leaf(Y), leaf(X))).
swap(tree(B1, leaf(Y)), tree(leaf(Y), SwapB1)) :-
dif(B1, leaf(_)),
swap(B1, SwapB1).
swap(tree(leaf(X), B2), tree(SwapB2, leaf(X))) :-
dif(B2, leaf(_)),
swap(B2, SwapB2).
swap(tree(B1, B2), tree(B2,B1)) :-
dif(B1, leaf(_)),
dif(B2, leaf(_)).
When I execute the following query swap(T1,T). I get:
?- swap(T1,T).
T1 = tree(leaf(_A), leaf(_B)),
T = tree(leaf(_B), leaf(_A)) ;
T1 = tree(tree(leaf(_A), leaf(_B)), leaf(_C)),
T = tree(leaf(_C), tree(leaf(_B), leaf(_A))) ;
T1 = tree(tree(tree(leaf(_A), leaf(_B)), leaf(_C)), leaf(_D)),
T = tree(leaf(_D), tree(leaf(_C), tree(leaf(_B), leaf(_A)))) ;
T1 = tree(tree(tree(tree(leaf(_A), leaf(_B)), leaf(_C)), leaf(_D)), leaf(_E)),
T = tree(leaf(_E), tree(leaf(_D), tree(leaf(_C), tree(leaf(_B), leaf(_A))))) .
As you can see Prolog is not considering all of the solutions for each number of leaves N. For example, for N = 4, the case T1 = tree( tree(leaf(_A) , leaf(_B)), tree(leaf(_C), leaf(_D)) ) is not being considered.
Edit: changed the case N=3 to N=4, now i think it's more clear.
I'm trying to make Prolog consider all solutions for each number of leaves N of the tree without relying on CLPFD as suggested before by user #false
Thank you for your attention!
Your problem is called fairness of enumeration. Prolog's backtracking algorithm explores the last recursive call in a goal as deeply as possible, so if you have two recursive calls in a goal, enumeration will always get "stuck" in the second one.
Here's a simpler example, just enumerating trees:
tree(leaf(_)).
tree(tree(Left, Right)) :-
tree(Left),
tree(Right).
Just like in your case, this builds trees that deepen to the right:
?- tree(Tree).
Tree = leaf(_1986) ;
Tree = tree(leaf(_1992), leaf(_1996)) ;
Tree = tree(leaf(_1992), tree(leaf(_2002), leaf(_2006))) ;
Tree = tree(leaf(_1992), tree(leaf(_2002), tree(leaf(_2012), leaf(_2016)))) ;
Tree = tree(leaf(_1992), tree(leaf(_2002), tree(leaf(_2012), tree(leaf(_2022), leaf(_2026))))) .
The fix for this is to introduce some kind of "size" measure, like the number of leaves, and to enumerate guided by the size. This is why using CLPFD arithmetic was suggested. Without arithmetic, one way of doing this is with lists.
Here is a predicate that relates trees and lists of their leaves:
tree_leaves(leaf(X), [X]).
tree_leaves(tree(Left, Right), Leaves) :-
LeftLeaves = [_ | _],
RightLeaves = [_ | _],
append(LeftLeaves, RightLeaves, Leaves),
tree_leaves(Left, LeftLeaves),
tree_leaves(Right, RightLeaves).
For example:
?- Leaves = [a, b, c], tree_leaves(Tree, Leaves).
Leaves = [a, b, c],
Tree = tree(leaf(a), tree(leaf(b), leaf(c))) ;
Leaves = [a, b, c],
Tree = tree(tree(leaf(a), leaf(b)), leaf(c)) ;
false.
As you can see, for a fixed-length list, this did enumerate all (two) possible tree structures.
So now we want to do something similar with a fair enumeration of all fixed-length lists -- this will force a fair enumeration of the corresponding trees. Lists can be enumerated fairly with the length/2 predicate:
?- length(List, N).
List = [],
N = 0 ;
List = [_2242],
N = 1 ;
List = [_2242, _2248],
N = 2 ;
List = [_2242, _2248, _2254],
N = 3 ;
List = [_2242, _2248, _2254, _2260],
N = 4 .
Therefore:
?- length(Leaves, N), tree_leaves(Tree, Leaves).
Leaves = [_2798],
N = 1,
Tree = leaf(_2798) ;
Leaves = [_2798, _2804],
N = 2,
Tree = tree(leaf(_2798), leaf(_2804)) ;
Leaves = [_2798, _2804, _2810],
N = 3,
Tree = tree(leaf(_2798), tree(leaf(_2804), leaf(_2810))) ;
Leaves = [_2798, _2804, _2810],
N = 3,
Tree = tree(tree(leaf(_2798), leaf(_2804)), leaf(_2810)) ;
Leaves = [_2798, _2804, _2810, _2816],
N = 4,
Tree = tree(leaf(_2798), tree(leaf(_2804), tree(leaf(_2810), leaf(_2816)))) ;
Leaves = [_2798, _2804, _2810, _2816],
N = 4,
Tree = tree(leaf(_2798), tree(tree(leaf(_2804), leaf(_2810)), leaf(_2816))) ;
Leaves = [_2798, _2804, _2810, _2816],
N = 4,
Tree = tree(tree(leaf(_2798), leaf(_2804)), tree(leaf(_2810), leaf(_2816))) ;
Leaves = [_2798, _2804, _2810, _2816],
N = 4,
Tree = tree(tree(leaf(_2798), tree(leaf(_2804), leaf(_2810))), leaf(_2816)) ;
Leaves = [_2798, _2804, _2810, _2816],
N = 4,
Tree = tree(tree(tree(leaf(_2798), leaf(_2804)), leaf(_2810)), leaf(_2816)) ;
Leaves = [_2798, _2804, _2810, _2816, _2822],
N = 5,
Tree = tree(leaf(_2798), tree(leaf(_2804), tree(leaf(_2810), tree(leaf(_2816), leaf(_2822))))) .
We can package this up:
fairtree(Tree) :-
length(Leaves, _N),
tree_leaves(Tree, Leaves).
And then test your swap/2 predicate with fair enumeration:
?- fairtree(Tree), swap(Tree, Swapped).
Tree = tree(leaf(_2122), leaf(_2128)),
Swapped = tree(leaf(_2128), leaf(_2122)) ;
Tree = tree(leaf(_2874), leaf(_2878)),
Swapped = tree(leaf(_2878), leaf(_2874)),
dif(_2906, _2874),
dif(_2918, _2878) ;
Tree = tree(leaf(_2122), tree(leaf(_2128), leaf(_2134))),
Swapped = tree(tree(leaf(_2134), leaf(_2128)), leaf(_2122)) ;
Tree = tree(leaf(_2922), tree(leaf(_2932), leaf(_2936))),
Swapped = tree(tree(leaf(_2936), leaf(_2932)), leaf(_2922)),
dif(_2974, _2932),
dif(_2986, _2936) ;
Tree = tree(leaf(_2690), tree(leaf(_2700), leaf(_2704))),
Swapped = tree(tree(leaf(_2700), leaf(_2704)), leaf(_2690)),
dif(_2732, _2690) ;
Tree = tree(tree(leaf(_2122), leaf(_2128)), leaf(_2134)),
Swapped = tree(leaf(_2134), tree(leaf(_2128), leaf(_2122))) ;
Tree = tree(tree(leaf(_2934), leaf(_2938)), leaf(_2942)),
Swapped = tree(leaf(_2942), tree(leaf(_2938), leaf(_2934))),
dif(_2980, _2934),
dif(_2992, _2938) ;
Tree = tree(tree(leaf(_2702), leaf(_2706)), leaf(_2710)),
Swapped = tree(leaf(_2710), tree(leaf(_2702), leaf(_2706))),
dif(_2738, _2710) ;
Tree = tree(leaf(_2122), tree(leaf(_2128), tree(leaf(_2134), leaf(_2140)))),
Swapped = tree(tree(tree(leaf(_2140), leaf(_2134)), leaf(_2128)), leaf(_2122)) ;
Tree = tree(leaf(_2970), tree(leaf(_2980), tree(leaf(_2990), leaf(_2994)))),
Swapped = tree(tree(tree(leaf(_2994), leaf(_2990)), leaf(_2980)), leaf(_2970)),
dif(_3042, _2990),
dif(_3054, _2994) ;
Tree = tree(leaf(_2738), tree(leaf(_2748), tree(leaf(_2758), leaf(_2762)))),
Swapped = tree(tree(tree(leaf(_2758), leaf(_2762)), leaf(_2748)), leaf(_2738)),
dif(_2800, _2748) ;
Tree = tree(leaf(_2724), tree(leaf(_2734), tree(leaf(_2744), leaf(_2748)))),
Swapped = tree(tree(leaf(_2734), tree(leaf(_2744), leaf(_2748))), leaf(_2724)),
dif(_2776, _2724) .
(For whatever it's worth, the canonical definition of swap is much shorter and simpler than yours. Two clauses are enough.)
Bad usage of dif/2
First some remarks on the goal dif(B1, leaf(_)). With this you intend to express that it should only be true if B1 is not a leaf. But what you said is that B1 should be different to a very particular leaf structure whose argument does not occur anywhere else. In other words, there is no term for B1 that makes this goal fail.
(Both Scryer and SWI have here a bug with the anonymous variable. So let's use _A instead.)
?- B1 = leaf(2), dif(B1, leaf(_A)).
B1 = leaf(2), dif:dif(leaf(2),leaf(_A)).
That is certainly not what you intend. What you meant was that this dif should be true for all _A. Or otherwise, that the functor of B1 must be different to leaf/1. There is no common way to express this idiomatically. But in your case, just consider which trees are not leaves! Certainly, they must look like tree(_,_). So you can replace that goal and all others by B1 = tree(_,_).
Mirroring a tree
Then for your definition of swap/2: It fails for swap(leaf(1),T). That might give you a clue. In general it is very often an error to try to specialize a program into too many separate cases. Instead, try to keep it as simple as possible. For that take the definition of a tree as a starting template, and fill in the remainder:
is_tree(leaf(_)).
is_tree(tree(L, R)) :-
is_tree(L),
is_tree(R).
% Version 0, too general w.r.t. the second argument, but otherwise fine
swap_v0(leaf(_), _).
swap_v0(tree(L,R), _) :-
swap_v0(L, _),
swap_v0(R, _).
Counterexample:
?- swap_v0(leaf(_), anything).
true. % unexpected
Evidently, this definition is too general, this anything is pointless. So we need to specialize the program. Let's do this very slowly:
swap_v1(leaf(E), leaf(E)).
swap_v1(tree(L,R), tree(_,_)) :-
swap_v1(L, _),
swap_v1(R, _).
Still too general, I will leave the rest to you.
Enumerating infinite answers/solutions
Prolog is very good at enumerating one infinite set that is described with infinitely many answers:
?- length(L, N).
L = [], N = 0
; L = [_A], N = 1
; L = [_A,_B], N = 2
; L = [_A,_B,_C], N = 3
; L = [_A,_B,_C,_D], N = 4
; L = [_A,_B,_C,_D,_E], N = 5
; ... .
It is only because of the finite space limit here on SO that we cannot have the entire sequence of answers. (Just kidding, it's because we have finite machines, always the cheap ones.) But just tell me a number and I will tell you were this number will appear. That's essentially what a fair enumeration is about.
But now consider that we want to have one further list:
?- length(L, N), length(K, M).
L = [], N = 0, K = [], M = 0
; L = [], N = 0, K = [_A], M = 1
; L = [], N = 0, K = [_A,_B], M = 2
; L = [], N = 0, K = [_A,_B,_C], M = 3
; L = [], N = 0, K = [_A,_B,_C,_D], M = 4
; L = [], N = 0, K = [_A,_B,_C,_D,_E], M = 5
; ... .
So here we have two infinite sets but only one is enumerated in a fair manner. That is the problem with chronological backtracking. We need to reformulate such queries in such a manner that only a single infinite sequence of answers will be produced.
Same problem with enumerating is_tree/2. Except that here it is a bit more confusing if you attempt to follow Prolog's execution step-by-step. Don't try it, yes there are tracers out there, but you will not understand this with the help of them. Instead, try to find some size-like norm such that for each such size, Prolog will enumerate all corresponding trees with finitely many answers. Like the number of leaves. Or, even better the list of all leaves. That is, for each such list, Prolog will enumerate all corresponding trees. Here is such a definition:
tree_leaves(T, Es) :-
Es = [_|Ls],
phrase(tree(T, Ls,[]), Es).
tree(leaf(E), Ls,Ls) --> [E].
tree(tree(L,R), [_|Ls0],Ls) -->
tree(L, Ls0,Ls1),
tree(R, Ls1,Ls).
Now all trees can be enumerated like so:
?- length(Es, N), tree_leaves(T, Es).
Es = [_A], N = 1, T = leaf(_A)
; Es = [_A,_B], N = 2, T = tree(leaf(_A),leaf(_B))
; Es = [_A,_B,_C], N = 3, T = tree(leaf(_A),tree(leaf(_B),leaf(_C)))
; Es = [_A,_B,_C], N = 3, T = tree(tree(leaf(_A),leaf(_B)),leaf(_C))
; Es = [_A,_B,_C,_D], N = 4, T = tree(leaf(_A),tree(leaf(_B),tree(leaf(_C),leaf(_D))))
; Es = [_A,_B,_C,_D], N = 4, T = tree(leaf(_A),tree(tree(leaf(_B),leaf(_C)),leaf(_D)))
; Es = [_A,_B,_C,_D], N = 4, T = tree(tree(leaf(_A),leaf(_B)),tree(leaf(_C),leaf(_D)))
; Es = [_A,_B,_C,_D], N = 4, T = tree(tree(leaf(_A),tree(leaf(_B),leaf(_C))),leaf(_D))
; Es = [_A,_B,_C,_D], N = 4, T = tree(tree(tree(leaf(_A),leaf(_B)),leaf(_C)),leaf(_D))
; Es = [_A,_B,_C,_D,_E], N = 5, T = tree(leaf(_A),tree(leaf(_B),tree(leaf(_C),tree(leaf(_D),leaf(_E)))))
; ... .
Test your code
With tree_leaves/2 you can now also test your definition of swap/2! The following must never succeed
?- any(Es), tree_leaves(T, Es), reverse(Es, EsR),
\+ ( swap(T, TS),
tree_leaves(TS, EsS),
EsS == EsR
).
Let's say that I want to find two numbers where the sum of these are 8, are from 1-9 and must be different(it is obvious that these numbers are (7,1),(6,2),etc).So I wrote.
dif_list([H|T]):- \+ member(H,T),dif_list(T).
dif_list([]).
check1_9([H|T]):-H>=1,H=<9,check1_9(T).
check1_9([]).
find_number([A,B],N) :- N =:= A+B,dif_list([A,B]),check1_9([A,B]).
Afterwards I will ask prolog
?-find_number([A,B],8).
ERROR: =:=/2: Arguments are not sufficiently instantiated
My goal is that prolog will print for me the results.For example:
?-find_number([A,B],8).
A = 7,
B = 1 ;
A = 6,
B = 2 ;
...
The best way to handle this kind of problem in Prolog is to use the CLP(FD) library:
:- [library(clpfd)].
sum_of(A, B, Sum) :-
A #> 0,
B #> 0,
A + B #= Sum.
?- sum_of(A, B, 8), label([A, B]).
A = 1,
B = 7 ;
A = 2,
B = 6 ;
A = 3,
B = 5 ;
A = B, B = 4 ;
A = 5,
B = 3 ;
A = 6,
B = 2 ;
A = 7,
B = 1.
?-
If you want the addends to be unique, you can further constrain it:
sum_of(A, B, Sum) :-
A #> 0,
B #>= A,
A + B #= Sum.
There's really no need to use a list to manage the variables A and B, but you can if you wish: sum_of([A,B], Sum).
Prolog is not that declarative: there are indeed answer set programming (ASP) or constraint logic programming (clp) languages where you can simply define a set of constraints and a finite domain solver aims to solve it (but these will take considerable time).
I would suggest that you define your program as follows:
find_number(A,B,N) :-
member(A,[1,2,3,4,5,6,7,8,9]),
member(B,[1,2,3,4,5,6,7,8,9]),
N is A+B,
A \= B.
Here member/2 will instantiate A and B to values that are provided by the list, so 1..9, next you use is/2 to calculate the sum and verify that the sum is equal to N. You can only call N is A+B if A and B are given a proper value. Finally we say A \= B (A is not equal to B).
When you run this predicate, it produces:
?- find_number(A,B,8).
A = 1,
B = 7 ;
A = 2,
B = 6 ;
A = 3,
B = 5 ;
A = 5,
B = 3 ;
A = 6,
B = 2 ;
A = 7,
B = 1 ;
false.
You can however also query with A and B already filled in, or one of them filled in, or where the sum is left open. So:
?- find_number(A,2,8).
A = 6 ;
false.
or:
?- find_number(A,2,N).
A = 1,
N = 3 ;
A = 3,
N = 5 ;
A = 4,
N = 6 ;
A = 5,
N = 7 ;
A = 6,
N = 8 ;
A = 7,
N = 9 ;
A = 8,
N = 10 ;
A = 9,
N = 11 ;
false.
my game is about picking the max set of elements from a given list that their sum is N
example : L=[1,1,2,2,3,2,4,5,6], N = 6 , Sub List would be equal to [1,1,2,2]
I need a hint using constraint logic programming.
There is a library for Constrained Logic Programming in SWI-Prolog. It's called clpfd.
:-use_module(library(clpfd)).
Let's say that you'll have a variable for the length of the subsequence. Its domain goes from zero (corresponding to the empty subsequence) to the length of the list. In order to get the longest sequence first, values should be tried starting with the highest.
...
length(List, M),
L in 0..M,
labeling([max(L)],[L]),
...
Next, L can be used to build a list of L variables that would correspond to indices of elements from List. As these indices must be in ascending order, chain/2 can be used to create #</2 constraints between any two consecutive indices.
...
length(Indices, L),
Indices ins 1..M,
chain(Indices, #<),
...
Using these indices, a list with elements from List can be constructed. nth1/3 is useful here, but with a minor trick.
...
nth1a(List, N, E):-
nth1(N, List, E).
...
maplist(nth1a(List), Indices, SubSequence),
...
And the sum of that list must be N:
...
sum(SubSequence, #=, N)
...
As only the longest sequence is needed, once/1 can be used to stop after first solution is found.
Some example queries:
?- longest_subsequence([1,1,4,4,6], 9, S).
S = [1, 4, 4].
?- longest_subsequence([1,1,4,4,6], 11, S).
S = [1, 4, 6].
?- longest_subsequence([1,1,4,4,6], 21, S).
false.
As I am not sure if that's a homework or not, I won't post the full code here.
In this answer we use clpfd and a little lambda:
:- use_module([library(clpfd),
library(lambda)]).
Based on meta-predicate maplist/4 and the constraints (ins)/2 and sum/3 we define:
zs_selection_len_sum(Zs, Bs, L, S) :-
same_length(Zs, Bs),
Bs ins 0..1,
maplist(\Z^B^X^(X #= Z*B), Zs, Bs, Xs),
sum(Bs, #=, L),
sum(Xs, #=, S).
Sample queries using labeling/2 with option max/1:
?- zs_selection_len_sum([1,1,4,4,6],Bs,L,8), labeling([max(L)],Bs).
Bs = [1,1,0,0,1], L = 3
; Bs = [0,0,1,1,0], L = 2
; false.
?- zs_selection_len_sum([1,1,3,4,5],Bs,L,7), labeling([max(L)],Bs).
Bs = [1,1,0,0,1], L = 3
; Bs = [0,0,1,1,0], L = 2
; false.
?- zs_selection_len_sum([1,1,2,2,3,2,4,5,6],Bs,L,6), labeling([max(L)],Bs).
Bs = [1,1,0,1,0,1,0,0,0], L = 4
; Bs = [1,1,1,0,0,1,0,0,0], L = 4
; Bs = [1,1,1,1,0,0,0,0,0], L = 4
; Bs = [0,0,1,1,0,1,0,0,0], L = 3
; Bs = [0,1,0,0,1,1,0,0,0], L = 3
; Bs = [0,1,0,1,1,0,0,0,0], L = 3
; Bs = [0,1,1,0,1,0,0,0,0], L = 3
; Bs = [1,0,0,0,1,1,0,0,0], L = 3
; Bs = [1,0,0,1,1,0,0,0,0], L = 3
; Bs = [1,0,1,0,1,0,0,0,0], L = 3
; Bs = [1,1,0,0,0,0,1,0,0], L = 3
; Bs = [0,0,0,0,0,1,1,0,0], L = 2
; Bs = [0,0,0,1,0,0,1,0,0], L = 2
; Bs = [0,0,1,0,0,0,1,0,0], L = 2
; Bs = [0,1,0,0,0,0,0,1,0], L = 2
; Bs = [1,0,0,0,0,0,0,1,0], L = 2
; Bs = [0,0,0,0,0,0,0,0,1], L = 1
; false.