I am new on prolog and I want to list the n-ary partitions of a number in prolog using backtracking. The result must be something like this:
?- nary(3,9,P).
P = [9] ? ;
P = [3,3,3] ? ;
P = [3,3,1,1,1] ? ;
P = [3,1,1,1,1,1,1] ? ;
P = [1,1,1,1,1,1,1,1,1] ? ;
no
Do you have any ideas of how to do it?
Lots of thanks.
Assuming that you mean n-ary partitions as described in Characterizing the Number of m-ary Partitions Modulo m:
... These are partitions of an integer n wherein each part is a power of a fixed integer m >= 2. ... As an example, note that there are five 3-ary partitions of n=9: 9, 3+3+3, 3+3+1+1+1, 3+1+1+1+1+1+1, 1+1+1+1+1+1+1+1+1. ...
Note, that in the linked Paper the m corresponds to the n in your question. Building on base_limit_powers/3 from this answer, I propose to keep using DCGs and CLP(FD). Let's start with a name for the predicate and the DCG, e.g. nary_partitions_of/3 (Note that I swapped the second and third arguments of your predicate nary/3 to more easily obtain a nice declarative name) and partitions_//4.
The second argument is a list (Partitions), consisting of powers of the first argument (N), that add up to the number that is the third argument (Int). The first number has to be greater or equal to 2 per definition (see above), hence the sum has to be as well. Since you want the powers in the list in descending order, the predicate reverse/2 from library(lists) can be used to reorder the list of powers as described by base_limit_powers/3 and have partitions_//4 start with the largest number. Because of N and Int being larger than 1 the list of powers is not empty and its corresponding reversed list can be written in head and tail notation ([FRP|RPs], read F irst of R eversed P owers and rest of R eversed P ower s), thereby providing easy access to the first (and largest) number (FRP) that is to be used as second argument of partitions_//4. At the time partitions_//4 is called (using phrase/2), the list Partitions is yet to be described, therefore the sum of its numbers is still 0. Putting all this together the relation nary_partitions_of/3 can be defined like so:
nary_partitions_of(N,Partitions,Int) :-
N #> 1,
Int #> 1,
base_limit_powers(N,Int,Powers),
reverse(Powers,[FRP|RPs]),
phrase(partitions_([FRP|RPs],FRP,0,Int),Partitions).
Then the n-ary partitions can be described by a DCG like so:
partitions_(_Powers,_Last,Int,Int) --> % If the sum and the integer are equal
[]. % the list is finished
partitions_(Powers,Last,Sum0,Int) --> % otherwise
{Sum0 #< Int}, % the sum is smaller than the integer and
{P #=< Last}, % the power to be added is less or equal to the last power in the partition and
{member(P,Powers)}, % the power is from the list of powers and
{Sum1 #= Sum0 + P}, % adds to the sum of powers so far and
[P], % the power is in the list of partitions and
partitions_(Powers,P,Sum1,Int). % the remainder of the partition-list is described recursively
With this definition your example query produces the desired answers:
?- nary_partitions_of(3,P,9).
P = [9] ? ;
P = [3,3,3] ? ;
P = [3,3,1,1,1] ? ;
P = [3,1,1,1,1,1,1] ? ;
P = [1,1,1,1,1,1,1,1,1] ? ;
no
Due to the use of CLP(FD) you can also use nary_partitions_of/3 to ask different types of questions, e.g. to check if a given list is a partition of some N and Int, however this query loops after producing the answers:
?- nary_partitions_of(N,[9],Int).
Int = N = 9 ? ;
Int = 9,
N = 3 ? ;
% loop here
But due to the use of CLP(FD) that can be remedied by constraining the range of N like so:
?- N in 2..5, nary_partitions_of(N,[9],Int).
Int = 9,
N = 3 ? ;
no
?- N in 2..5, nary_partitions_of(N,[3,3,3],Int).
Int = 9,
N = 3 ? ;
no
?- N in 2..5, nary_partitions_of(N,[3,3,1,1,1],Int).
Int = 9,
N = 3 ? ;
no
?- N in 2..5, nary_partitions_of(N,[3,3,1,1],Int).
Int = 8,
N = 3 ? ;
no
?- N in 2..5, nary_partitions_of(N,[3,3,4],Int).
no
You can also look for n-ary partitions of some number, e.g. 9 without specifying N:
?- N in 2..6, nary_partitions_of(N,P,9).
N = 4,
P = [4,4,1] ? ;
N = 6,
P = [6,1,1,1] ? ;
N = 5,
P = [5,1,1,1,1] ? ;
N = 4,
P = [4,1,1,1,1,1] ? ;
P = [1,1,1,1,1,1,1,1,1],
N in 3..6, % residual goal
N^2#=_A, % residual goal
_A in 10..36 ? ; % residual goal
.
.
.
However this leads to some residual goals in the answers (see CLP(FD) documentation for details). You can again remedy this by constraining N, this time also labeling it:
?- N in 2..6, nary_partitions_of(N,P,9), label([N]).
N = 4,
P = [4,4,1] ? ;
N = 6,
P = [6,1,1,1] ? ;
N = 5,
P = [5,1,1,1,1] ? ;
N = 4,
P = [4,1,1,1,1,1] ? ;
N = 4,
P = [1,1,1,1,1,1,1,1,1] ? ;
N = 5,
P = [1,1,1,1,1,1,1,1,1] ? ;
N = 6,
P = [1,1,1,1,1,1,1,1,1] ? ;
N = 3,
P = [9] ? ;
N = 3,
P = [3,3,3] ? ;
N = 3,
P = [3,3,1,1,1] ? ;
N = 3,
P = [3,1,1,1,1,1,1] ? ;
N = 3,
P = [1,1,1,1,1,1,1,1,1] ? ;
N = 2,
P = [8,1] ? ;
N = 2,
P = [4,4,1] ? ;
N = 2,
P = [4,2,2,1] ? ;
N = 2,
P = [4,2,1,1,1] ? ;
N = 2,
P = [4,1,1,1,1,1] ? ;
N = 2,
P = [2,2,2,2,1] ? ;
N = 2,
P = [2,2,2,1,1,1] ? ;
N = 2,
P = [2,2,1,1,1,1,1] ? ;
N = 2,
P = [2,1,1,1,1,1,1,1] ? ;
N = 2,
P = [1,1,1,1,1,1,1,1,1] ? ;
no
I came up with this, where the nary partitions are either the number in a list, or it expanded (spand). Then the spand process takes the first number evenly divisible by the partition size, splits the list on it, inserts the partition, and either completes there OR spands the newly constructed complete list on backtracking.
This was about the only way I could get your backtracking request without the backtracking undoing the previous expansion and turning 1,1,1 back into 3. I haven't been able to split the list on the first evenly divisible element without leaving any choicepoints in a nicer way, but there probably is a nicer way.
spand(In, Psize, Out) :-
once((append(Left, [Elem|Right], In), % first divisible element, e.g. 3
0 is Elem mod Psize)),
length(Parts, Psize), % make the partition list, e.g. [1,1,1]
Pt is Elem / Psize,
maplist(=(Pt), Parts),
append(Left, Parts, Temp),
( append(Temp, Right, Out) % choicepoint for backtracking
; append(Temp, Right, Out_),
spand(Out_, Psize, Out)).
nary(Psize, Target, Parts) :-
Parts = [Target]
;
spand([Target], Psize, Parts).
e.g.
?- nary(3, 9, Parts).
Parts = [9] ;
Parts = [3, 3, 3] ;
Parts = [1, 1, 1, 3, 3] ;
Parts = [1, 1, 1, 1, 1, 1, 3] ;
Parts = [1, 1, 1, 1, 1, 1, 1, 1, 1] ;
false
e.g.
?- nary(2, 24, Parts).
Parts = [24] ;
Parts = [12, 12] ;
Parts = [6, 6, 12] ;
Parts = [3, 3, 6, 12] ;
Parts = [3, 3, 3, 3, 12] ;
Parts = [3, 3, 3, 3, 6, 6] ;
Parts = [3, 3, 3, 3, 3, 3, 6] ;
Parts = [3, 3, 3, 3, 3, 3, 3, 3] ;
false
Your example is too short to see if [6, 6, 12] -> [3, 3, 6, 12] or [6, 6, 6, 6]. Depth first or Breadth first.
Related
Before our Prolog final exam soon, I got some practice questions and I am stuck on one:
For each integer n > 0,
let Ln := {s ∈ {0, 1}+ | s ends in a string from 1(0 + 1)n−1}
be the set of bit-strings whose n-th to the last bit is 1. That is, Ln is described by the regular expression (0 + 1)∗1(0 + 1)n−1.
Define a DCG for the 3-ary predicate s/3 such that s(n,s,[]) is true exactly if s encodes a string in Ln.
I tried for a while to get this, but I am unsure what to do, does anyone have a solution?
Here's a DCG for (0 + 1)*:
zero_or_one -->
[0].
zero_or_one -->
[1].
many_zero_or_one -->
[].
many_zero_or_one -->
zero_or_one,
many_zero_or_one.
Let's try to make it look like the regular expression you showed, just for funzies. I will not define operators and instead "parse" the regex to something that Prolog can read without new operator definitions (I am not even sure if you can make it work just with redefining operators, maybe it isn't possible). So I will define a +//2 for "or" and *//1 for "0 or more repetitions" and n//2 for "n repetitions".
+(A, B) --> [A] | [B].
*(P) --> [] | call(P), *(P).
n(P, N) --> { length(L, N) }, n_1(L, P).
n_1([], _) --> [].
n_1([_|L], P) --> call(P), n_1(L, P).
With those available I can write a query that roughly resembles your problem statement:
?- length(L, _), phrase(( *(+(0,1)), [1], n(+(0,1), 1) ), L).
L = [1, 0] ;
L = [1, 1] ;
L = [0, 1, 0] ;
L = [0, 1, 1] ;
L = [1, 1, 0] ;
L = [1, 1, 1] ;
L = [0, 0, 1, 0] ;
L = [0, 0, 1, 1] ;
L = [0, 1, 1, 0] . % it goes on
Note that here I set the n to be equal to 2, so in n//2 I am using 2 - 1 = 1.
EDIT: I noticed that the *//1 I defined is just a special case of n//2. So you can actually do this:
?- phrase(n(+(0,1), N), L).
N = 0,
L = [] ;
N = 1,
L = [0] ;
N = 1,
L = [1] ;
N = 2,
L = [0, 0] ;
N = 2,
L = [0, 1] ;
N = 2,
L = [1, 0] ;
N = 2,
L = [1, 1] ;
N = 3,
L = [0, 0, 0] .
In other words, you can leave the N argument a free variable and you will get strings of increasing length, with the length in N.
Eg:
List[1,2,3,4,5,6] with N equal to 6 should print true because there are exactly 3 values that add upto 6. 1+2+3.
List[2,5,7,9] with N equal to 12 should print false as there are no 3 elements that add upto 12.
Let's maybe start with a more general predicate that describes the relation between a list, a sublist of said list and the sum of numbers in the sublist. To make it obvious which argument is what, it is opportune to chose a descriptive name for the predicate, say sum_ofsub_fromlist/3. Now let's observe that if the first argument is the sum of the numbers in the sublist, then successively subtracting those numbers from the sum yields zero, e.g.: X=A+B → X-A-B=0. So there will be a base case that contains 0 as the sum and [] as the sublist (rule 1) and a recursive rule that subtracts the elements of the sublist from the sum (rule 2). And since a sublist does not contain all elements of the list it's taken from in general, there will be a recursive rule for skipping elements of the list that do not occur in the sublist (rule 3). This rule is only needed as long as there are still elements in the sublist, so a constraint would be beneficial, that prevents this rule from succeeding once the sublist is empty. These ideas can be realized in Prolog like so:
sum_ofsub_fromlist(0,[],_L). % rule 1
sum_ofsub_fromlist(X,[A|Bs],[A|As]) :- % rule 2
X0 is X-A,
sum_ofsub_fromlist(X0,Bs,As).
sum_ofsub_fromlist(X,Bs,[_A|As]) :- % rule 3
dif(Bs,[]), % constraint: sublist not empty
sum_ofsub_fromlist(X,Bs,As).
You can query this predicate to assure yourself that it delivers all sublists for the given sum in your examples:
?- sum_ofsub_fromlist(6,S,[1,2,3,4,5,6]).
S = [1, 2, 3] ;
S = [1, 5] ;
S = [2, 4] ;
S = [6] ;
false.
?- sum_ofsub_fromlist(12,S,[2,5,7,9]).
S = [5, 7] ;
false.
Building on this you can then write a calling predicate that only succeeds for sublists of length three:
sum_oftriple_fromlist(S,T,L) :-
T=[_,_,_], % T has to be a triple
sum_ofsub_fromlist(S,T,L).
This predicate yields the answers you desire:
?- sum_oftriple_fromlist(6,T,[1,2,3,4,5,6]).
T = [1, 2, 3] ;
false.
?- sum_oftriple_fromlist(12,T,[2,5,7,9]).
false.
Note that the predicate is also working with negative numbers:
?- sum_oftriple_fromlist(6,T,[-5,-3,-1,2,4,7,8,9]).
T = [-5, 2, 9] ;
T = [-5, 4, 7] ;
T = [-3, 2, 7] ;
false.
?- sum_oftriple_fromlist(-6,T,[-6,-5,-4,-3,-2,-1,2,4]).
T = [-6, -4, 4] ;
T = [-6, -2, 2] ;
T = [-5, -3, 2] ;
T = [-3, -2, -1] ;
false.
However, due to the use of is/2, the predicate only works if the first and the third arguments are ground:
?- sum_oftriple_fromlist(S,T,[1,2,3,4,5,6]).
ERROR: is/2: Arguments are not sufficiently instantiated
Exception: (7) sum_ofsub_fromlist(_G918, [_G1016, _G1019, _G1022], [1, 2, 3, 4, 5, 6]) ?
?- sum_oftriple_fromlist(6,T,[A,B,C,D,E,F]).
ERROR: is/2: Arguments are not sufficiently instantiated
Exception: (7) sum_ofsub_fromlist(6, [_G2121, _G2124, _G2127], [_G1945, _G1948, _G1951, _G1954, _G1957, _G1960]) ?
If that's fine with you, you can stop here. Alternatively, you could opt to make the predicate more versatile by using CLP(FD). Just apply these minor changes to your code:
:- use_module(library(clpfd)). % <- new
sum_oftriple_fromlist(S,T,L) :-
T=[_,_,_],
sum_ofsub_fromlist(S,T,L).
sum_ofsub_fromlist(0,[],_L).
sum_ofsub_fromlist(X,[A|Bs],[A|As]) :-
X0 #= X-A, % <- change
sum_ofsub_fromlist(X0,Bs,As).
sum_ofsub_fromlist(X,Bs,[_A|As]) :-
dif(Bs,[]),
sum_ofsub_fromlist(X,Bs,As).
Now the above queries deliver answers:
?- sum_oftriple_fromlist(S,T,[1,2,3,4,5,6]).
S = 6,
T = [1, 2, 3] ;
S = 7,
T = [1, 2, 4] ;
S = 8,
T = [1, 2, 5] ;
. % another
. % seventeen
. % results here
The second query, however, yields residual goals (see documentation for details) as results:
?- sum_oftriple_fromlist(6,T,[A,B,C,D,E,F]).
T = [A, B, C],
_G2424+A#=6,
C+B#=_G2424 ;
T = [A, B, D],
_G2424+A#=6,
D+B#=_G2424 ;
.
.
.
To get actual numbers, you have to restrict the range of the numbers and subsequently label the variables in the list:
?- L=[A,B,C,D,E,F], sum_oftriple_fromlist(6,T,L), L ins 1..6, label(L).
L = [1, 1, 4, 1, 1, 1],
A = B, B = D, D = E, E = F, F = 1,
C = 4,
T = [1, 1, 4] ;
L = [1, 1, 4, 1, 1, 2],
A = B, B = D, D = E, E = 1,
C = 4,
F = 2,
T = [1, 1, 4] ;
.
.
.
Possibly you are only interested in lists where every number only appears once:
?- L=[A,B,C,D,E,F], all_distinct(L), sum_oftriple_fromlist(6,T,L), L ins 1..6, label(L).
L = [1, 2, 3, 4, 5, 6],
A = 1,
B = 2,
C = 3,
D = 4,
E = 5,
F = 6,
T = [1, 2, 3] ;
L = [1, 2, 3, 4, 6, 5],
A = 1,
B = 2,
C = 3,
D = 4,
E = 6,
F = 5,
T = [1, 2, 3] ;
.
.
.
Or maybe you don't even want to restrict the sum:
?- L=[A,B,C,D,E,F], all_distinct(L), sum_oftriple_fromlist(S,T,L), L ins 1..6, label(L).
L = [1, 2, 3, 4, 5, 6],
A = 1,
B = 2,
C = 3,
D = 4,
E = 5,
F = S, S = 6, % sum = 6
T = [1, 2, 3] ;
.
.
.
L = [1, 2, 4, 3, 5, 6],
A = 1,
B = 2,
C = 4,
D = 3,
E = 5,
F = 6,
S = 7, % sum = 7
T = [1, 2, 4] ;
.
.
.
As you can see the CLP(FD) version of the predicate resembles a true relation as opposed to the non-CLP(FD) version. And of course your example queries yield the same answers with both versions.
Your code only considers the first 3 items in the list, and not any other combinations.
The most natural way to structure a solution involving a list is to base your recursion on the structure of the list. So:
If the first element of the list (say, X) is to be included in the 3 values that sum to N, we need to find a way to find 2 values in the rest of the list that sum to N-X.
If it isn't, just try to solve the problem using the rest of the list.
Note that you may need a "helper" version of your predicate that allows you to add other parameters. In this case, knowing how many values you need to add up would be helpful.
I don't understand why my code doesn't work.
An inverse permutation is a permutation in which each number and the number of the place which it occupies are exchanged. For example [3,8,5,10,9,4,6,1,7,2] -> [8,10,1,6,3,7,9,2,5,4]
inv_perm3(X,[F],length(X)):-
length([F]) == 1,
!,
nth0(F,X,length(X)).
inv_perm3(X,[F|M],N):-
nth0(F,X,N), %nth0(?Index, List, Elem)
F is F+1,
N1 is N+1,
inv_perm3(X,M,N1).
inv_perm(A,B):-
inv_perm3(A,B,1).
I get false in every input, I test it like this: inv_perm( [2,3,1], X ).
it's way simpler... a hint
?- X=[3,8,5,10,9,4,6,1,7,2],same_length(Y,X),nth1(I,X,V),nth1(V,Y,I).
X = [3, 8, 5, 10, 9, 4, 6, 1, 7|...],
Y = [_358, _364, 1, _376, _382, _388, _394, _400, _406|...],
I = 1,
V = 3 ;
X = [3, 8, 5, 10, 9, 4, 6, 1, 7|...],
Y = [_358, _364, _370, _376, _382, _388, _394, 2, _406|...],
I = 2,
V = 8 ;
...
while I've shown only 1 element of both lists, you should use forall/2 to check all elements, or findall/3 to relate both lists. Findall would allow to generate the inverse, while forall just would check for correctness
I got two expressions to list all lists of bits using Prolog:
bit(0).
bit(1).
bitlist1([]).
bitlist1([B|Bs]) :-
bit(B),
bitlist1(Bs).
bitlist2([]).
bitlist2([B|Bs]) :-
bitlist2(Bs),
bit(B).
I can't quite see if they are logically equivalent and even if they both really list ALL bit lists.
As I'm using SWI-Prolog I got the following outputs:
?- bitlist1(Bs).
Bs = [] ;
Bs = [0] ;
Bs = [0, 0] ;
Bs = [0, 0, 0] ;
Bs = [0, 0, 0, 0] ;
Bs = [0, 0, 0, 0, 0] ;
Bs = [0, 0, 0, 0, 0, 0] ;
Bs = [0, 0, 0, 0, 0, 0, 0] ;
Bs = [0, 0, 0, 0, 0, 0, 0, 0] ;
Bs = [0, 0, 0, 0, 0, 0, 0, 0, 0] ;
Bs = [0, 0, 0, 0, 0, 0, 0, 0, 0|...] ;
...
?- bitlist2(Bs).
Bs = [] ;
Bs = [0] ;
Bs = [1] ;
Bs = [0, 0] ;
Bs = [1, 0] ;
Bs = [0, 1] ;
Bs = [1, 1] ;
Bs = [0, 0, 0] ;
Bs = [1, 0, 0] ;
Bs = [0, 1, 0] ;
Bs = [1, 1, 0] ;
Bs = [0, 0, 1] ;
Bs = [1, 0, 1] ;
Bs = [0, 1, 1] ;
Bs = [1, 1, 1] ;
Bs = [0, 0, 0, 0] ;
...
bitlist1 starts listing all bit lists containing only zeros and starts listing all others afterwards but this actually can't be seen as Prolog lists an endless stream of bit lists containing only zeros.
bitlist2 lists all combinations of 0 and 1 of every length and afterwards continues with the bit lists with the length higher length.
So they are logically equivalent imo, only the output order of the bit lists differ.
Maybe anyone can confirm my guess or explain why the two expressions aren't logically equivalent? Would be great.
Citing Vannoord
The problem whether two expressions are logically equivalent is undecidable for any `interesting' logic.
Then, because of incompleteness of Prolog search, you should somewhat restrict your proof criteria. I would state the equivalence arise from the fact that
for any given N, it's not possible to find a length(L, N), bitlist1(L), bitlist2(L) that fail.
Indeed
2 ?- length(L,N), bitlist1(L), bitlist2(L).
L = [],
N = 0 ;
L = [0],
N = 1 ;
L = [1],
N = 1 ;
L = [0, 0],
N = 2 ;
L = [0, 1],
N = 2 ;
L = [1, 0],
N = 2 ;
L = [1, 1],
...
On a logical level, both predicates are equivalent, since "," in a rule is interpreted as logical conjunction which is commutative(the easiest way to check this is by looking at the truth tables for A & B -> C and B & A -> C, but also sequent calculus or some other proof calculus does the job).
For pure prolog programs, the set of answers of logically equivalent predicates is the same. Since prolog uses depth first search as a search strategy, one predictae might not terminate in case the others do:
?- bitlist1([a|Xs]).
false.
?- bitlist2([a|Xs]).
^CAction (h for help) ? abort
% Execution Aborted
The reason is that prolog tries to prove the goals one after each other. In the case of bitlist1, the first goal is bit(B) where prolog can immediatly decide that bit(a) does not hold. In the case of bitlist2, prolog first tries to prove bitlist2(Bs) and recursively does this for the tail of the Bs list which leads to an infinite recursion. So even if both predicates are logically equivalent, they behave differently.
For your problem of looking at the solutions, you could try to enumerate the lists in increasing length:
?- length(X,_), bitlist1(X).
X = [] ;
X = [0] ;
X = [1] ;
X = [0, 0] ;
X = [0, 1] ;
X = [1, 0] ;
X = [1, 1] ;
X = [0, 0, 0] ;
X = [0, 0, 1] ;
X = [0, 1, 0] .
?- length(X,_), bitlist2(X).
X = [] ;
X = [0] ;
X = [1] ;
X = [0, 0] ;
X = [1, 0] ;
X = [0, 1] ;
X = [1, 1] ;
X = [0, 0, 0] ;
X = [1, 0, 0] ;
X = [0, 1, 0] .
the length predicate gives the relation between a list and its length. We now rely on the fact that length(X,_) produces lists of free variables of increasing length. Then the goal bitlist(1/2) will be called on a fixed size list and prolog will find all solutions for that size before backtracking and trying the next larger list.
Please note that this trick only reorders solutions, but does not change termination in general:
?- X=[a|Xs], length(X,_), bitlist2(X).
^CAction (h for help) ? abort
% Execution Aborted
This still fails because prolog needs to check all lists X not to start with a, but the check is only done after the recursive goal.
I'm not sure you should be discussing pure logical meaning of a predicate and then demonstrating it with an actual Prolog program.
Your first predicate, for example, will actually never run out of 0. There is no "afterwords", or the "afterwords in the search tree is surely never going to be visited. This is of course if you use it for generating answers; using it for validating does not exhibit this behaviour.
In pure logic, order of operations is irrelevant, since everything is an idempotent function. So as long as you have no cuts or side effects, A, B and B, A are equivalent.
I'd like to define a members predicate.
members(A, B) means that all members of the list A are members of list B.
top(N) defines how long A can be.
This is my try:
top(5).
members([X], L):-
member(X, L).
members([X| Xs], L):-
member(X, L),
members(Xs, L),
length(Xs, M),
top(N),
M < N.
I'd like to use it as follow:
members(L, [1,2,3]).
The problem with my implementation is that if I ; to get new answers, I'll finish with an ERROR: Out of local stack
?- members(I, [1,2,3]).
I = [1] ;
I = [2] ;
I = [3] ;
I = [1, 1] ;
I = [1, 2] ;
I = [1, 3] ;
I = [1, 1, 1] ;
I = [1, 1, 2] ;
I = [1, 1, 3] ;
I = [1, 1, 1, 1] ;
I = [1, 1, 1, 2] ;
I = [1, 1, 1, 3] ;
I = [1, 1, 1, 1, 1] ;
I = [1, 1, 1, 1, 2] ;
I = [1, 1, 1, 1, 3] ;
;ERROR: Out of local stack
How can I change my code to prevent this out of memory?
As already mentioned, your problem is that you do the length check after the recursive call, meaning that the recursion is unbounded. Unfortunately, just moving the length check above the recursive call like this...
members([X], L):-
member(X, L).
members([X|Xs], L):-
length(Xs, M),
top(N), M < N,
member(X, L),
members(Xs, L).
...is not so good as we get this:
L = [3, 1, 2, 3, 3] ;
L = [3, 2, 2, 3, 3] ;
L = [3, 3, 2, 3, 3] ;
L = [3, 1, 3, 3, 3] ;
L = [3, 2, 3, 3, 3] ;
L = [3, 3, 3, 3, 3] ;
ERROR: Out of global stack
While this gets us the answer, it's not that useful as it can't be put inside a larger predicate since it breaks. It breaks because we have only pushed the problem further along. Here's why:
The problem is that you are constructing the list in a top-down manner. In other words, we define the list like this: List = [Head|Tail] where we stipulate some constraints on Head and state that Tail is made up of a list of elements defined by the same constraints and bounded by a base case. This means that while we are in the middle of the recursive call, we actually only have access to Head - we cannot access the contents of Tail as it is only constructed once the interpreter has gone all the way down and reached the base case (i.e. members([X], L) :-) and then has successively added each Tail to its Head until the final List is constructed.
It may look like we have access to the length, since the length/2 call is sitting there in the middle of the recursive predicate, however since the variable being passed into length/2 for the list is at this stage not bound to anything, Prolog waits until it has finished the recursive calls beneath this point before calculating the length. The problem of course is that the length check is what is bounding the recursion, so it will just continue until it runs out of memory.
While top-down recursion tends to be the default way of constructing Prolog predicates, as this example shows, sometimes we need access to the data structure we are creating. The solution is to use bottom-up recursion. This is implemented in Prolog by means of an accumulator predicate, which starts with an empty list and proceeds to build the list up one by one, by passing the accumulator list (which is a fully ground list) through the recursive predicate. Here's how I would write an accumulator predicate for this problem:
members(I,L) :-
members_accumulator([],I,L).
members_accumulator(Tail,I,L) :-
length(Tail, M),
top(N),
M < N,
member(X, L),
members_accumulator([X|Tail],I,L).
members_accumulator(I,I,_).
We need two predicates, as the first is a wrapper around the accumulator which passes the empty list to the accumulator predicate. The base case no longer has anything to do with the empty list - all it has to do is state that the final accumulator list is actually the final list that we're after (which has been threaded through the accumulator predicate just for this purpose). Also, in this case, the accumulator predicates need to be in this order otherwise there will be one choice point that evaluates as false right at the end.
Getting ones head around recursion in Prolog and when you need to use bottom-up recursion rather than top-down is a non-trivial feat. I didn't really have a solid grasp on it at all until I had a good read through The Art of Prolog. There should also be plenty of info about accumulators online.
Here is an alternate implementation which does'nt require calculating the length of the list. Here N is the length of list A. This solution gives all the answers without going out of stack.
members([X],L,1) :- member(X,L).
members([H|T],L,N) :- N>1 , member(H,L) , N1 is N-1, members(T,L,N1).
Example execution:
?- members(L,[1,2,3],5).
L = [1, 1, 1, 1, 1] ;
L = [1, 1, 1, 1, 2] ;
L = [1, 1, 1, 1, 3] ;
L = [1, 1, 1, 2, 1] ;
...
L = [3, 3, 3, 1, 2] ;
L = [3, 3, 3, 3, 1] ;
L = [3, 3, 3, 3, 2] ;
L = [3, 3, 3, 3, 3] ;
No
You do the check for the depth after the recursion. So the depth of the recursion is not limited, only the resulting lists are discarded as too long.
Use meta-predicate maplist/2,
lambdas, and membership predicate memberd/2 and simply write:
:- use_module(library(lambda)).
members(As,Bs,N) :-
length(Xs,N),
append(As,_,Xs),
maplist(Bs+\A^memberd(A,Bs), As).
Sample query with abbreviated answer sequence:
?- members(As,[1,2,3],5).
As = [ ] ;
As = [ 1] ; As = [ 2] ; As = [ 3] ;
As = [ 1,1] ; As = [ 1,2] ; /* ... */ As = [ 3,3] ;
As = [ 1,1,1] ; As = [ 1,1,2] ; /* ... */ As = [ 3,3,3] ;
As = [ 1,1,1,1] ; As = [ 1,1,1,2] ; /* ... */ As = [ 3,3,3,3] ;
As = [1,1,1,1,1] ; As = [1,1,1,1,2] ; /* ... */ As = [3,3,3,3,3] ;
false.
Above query universally terminates.
Let's look at the size of the solution set:
?- setof(As,members(As,[1,2,3],5),Ass), length(Ass,N_Solutions).
Ass = [[],[1],[1,1],[1,1,1],[1,1,1|...],[1,1|...],[1|...],[...|...]|...],
N_Solutions = 364.
?- 364 =:= 1 + 3 + 3^2 + 3^3 + 3^4 + 3^5.
true.