I'm working on Problem 26 from 99 Prolog Problems:
P26 (**) Generate the combinations of K distinct objects chosen from
the N elements of a list
Example:
?- combination(3,[a,b,c,d,e,f],L).
L = [a,b,c] ;
L = [a,b,d] ;
L = [a,b,e] ;
So my program is:
:- use_module(library(clpfd)).
combination(0, _, []).
combination(Tot, List, [H|T]) :-
length(List, Length), Tot in 1..Length,
append(Prefix, [H], Stem),
append(Stem, Suffix, List),
append(Prefix, Suffix, SubList),
SubTot #= Tot-1,
combination(SubTot, SubList, T).
My query result starts fine but then returns a Global out of stack error:
?- combination(3,[a,b,c,d,e,f],L).
L = [a, b, c] ;
L = [a, b, d] ;
L = [a, b, e] ;
L = [a, b, f] ;
Out of global stack
I can't understand why it works at first, but then hangs until it gives Out of global stack error. Happens on both SWISH and swi-prolog in the terminal.
if you try to input, at the console prompt, this line of your code, and ask for backtracking:
?- append(Prefix, [H], Stem).
Prefix = [],
Stem = [H] ;
Prefix = [_6442],
Stem = [_6442, H] ;
Prefix = [_6442, _6454],
Stem = [_6442, _6454, H] ;
...
maybe you have a clue about the (main) problem. All 3 vars are free, then Prolog keeps on generating longer and longer lists on backtracking. As Boris already suggested, you should keep your program far simpler... for instance
combination(0, _, []).
combination(Tot, List, [H|T]) :-
Tot #> 0,
select(H, List, SubList),
SubTot #= Tot-1,
combination(SubTot, SubList, T).
that yields
?- aggregate(count,L^combination(3,[a,b,c,d,e],L),N).
N = 60.
IMHO, library(clpfd) isn't going to make your life simpler while you're moving your first steps into Prolog. Modelling and debugging plain Prolog is already difficult with the basic constructs available, and CLP(FD) is an advanced feature...
I can't understand why it works at first, but then hangs until it gives Out of global stack error.
The answers Prolog produces for a specific query are shown incrementally. That is, the actual answers are produced lazily on demand. First, there were some answers you expected, then a loop was encountered. To be sure that a query terminates completely you have to go through all of them, hitting SPACE/or ; all the time. But there is a simpler way:
Simply add false at the end of your query. Now, all the answers are suppressed:
?- combination(3,[a,b,c,d,e,f],L), false.
ERROR: Out of global stack
By adding further false goals into your program, you can localize the actual culprit. See below all my attempts: I started with the first attempt, and then added further false until I found a terminating fragment (failure-slice).
combination(0, _, []) :- false. % 1st
combination(Tot, List, [H|T]) :-
length(List, Length), Tot in 1..Length, % 4th terminating
append(Prefix, [H], Stem), false, % 3rd loops
append(Stem, Suffix, List), false, % 2nd loops
append(Prefix, Suffix, SubList),
SubTot #= Tot-1, false, % 1st loops
combination(SubTot, SubList, T).
To remove the problem with non-termination you have to modify something in the remaining visible part. Evidently, both Prefix and Stem occur here for the first time.
The use of library(clpfd) in this case is very suspicious. After length(List, Length), Length is definitely bound to a non-negative integer, so why the constraint? And your Tot in 1..Length is weird, too, since you keep on making a new constrained variable in every step of the recursion, and you try to unify it with 0. I am not sure I understand your logic overall :-(
If I understand what the exercise is asking for, I would suggest the following somewhat simpler approach. First, make sure your K is not larger than the total number of elements. Then, just pick one element at a time until you have enough. It could go something like this:
k_comb(K, L, C) :-
length(L, N),
length(C, K),
K =< N,
k_comb_1(C, L).
k_comb_1([], _).
k_comb_1([X|Xs], L) :-
select(X, L, L0),
k_comb_1(Xs, L0).
The important message here is that it is the list itself that defines the recursion, and you really don't need a counter, let alone one with constraints on it.
select/3 is a textbook predicate, I guess you should find it in standard libraries too; anyway, see here for an implementation.
This does the following:
?- k_comb(2, [a,b,c], C).
C = [a, b] ;
C = [a, c] ;
C = [b, a] ;
C = [b, c] ;
C = [c, a] ;
C = [c, b] ;
false.
And with your example:
?- k_comb(3, [a,b,c,d,e,f], C).
C = [a, b, c] ;
C = [a, b, d] ;
C = [a, b, e] ;
C = [a, b, f] ;
C = [a, c, b] ;
C = [a, c, d] ;
C = [a, c, e] ;
C = [a, c, f] ;
C = [a, d, b] ;
C = [a, d, c] ;
C = [a, d, e] ;
C = [a, d, f] ;
C = [a, e, b] ;
C = [a, e, c] . % and so on
Note that this does not check that the elements of the list in the second argument are indeed unique; it just takes elements from distinct positions.
This solution still has problems with termination but I don't know if this is relevant for you.
Related
We want now to evaluate if any word in our language which is only made with the letters {a,b}, is a palindrome or not. I did code the program below, but I want it to accept only letters a or letters b and none other, if we input any other letters then it’s false. Example : [a,b,a] is correct, [b,a,b] is correct but [b,b,a] or [a,b,a,b] is incorrect.
Here is what I tried to do, but I just want prolog to return true if the word is a palindrome with only the letters a or b and not any other letters. I hope someone will help me.
reverse(X,Y) :- reverse(X,[],Y).
reverse([],X,X).
reverse([X|Y],Z,T) :- reverse(Y,[X|Z],T).
langage6([]).
langage6(L):-
reverse(L, L).
I'd just include a test for the letters while having the elements at hand:
letter(a).
letter(b).
reverseletter([],X,X).
reverseletter([X|Y],Z,T) :-
letter(X),
reverseletter(Y,[X|Z],T).
langage6(L):-
reverseletter(L, [], L).
Tested with SWISH:
?- langage6([a,b,a]).
true.
?- langage6([b,a,b]).
true.
?- langage6([b,b,a]).
false.
?- langage6([b,a,b,a]).
false.
This code can be used as a generator as well:
?- langage6(L).
L = []
L = [a]
L = [b]
L = [a, a]
L = [b, b]
L = [a, a, a]
L = [a, b, a]
L = [b, a, b]
L = [b, b, b]
L = [a, a, a, a]
L = [a, b, b, a]
...
You need to check, whether the word is over the alphabet? In this case, this could be a solution:
langage6(L):-
word_in_alphabet(L),
reverse(L, L).
word_in_alphabet([]).
word_in_alphabet([a|Xs]) :- word_in_alphabet(Xs).
word_in_alphabet([b|Xs]) :- word_in_alphabet(Xs).
Can anyone help me with the following task: I need to define a predicate eq_set, which succeeds if the sets S1 and S2 are equal when it comes to the number of their elements.
But it works only if they are exactly the same number and order. I want to create a code that shows all varieties and doesn't take order into account. Can you help me,please?
I wrote:
eq_set([],[]).
eq_set([H|T],[H|T1]) :-
eq_set(T,T1).
But it works only if they are exactly the same number and order. I want to create a code that shows all varieties and doesn't take order into account.
The closest translation I have of the assignment, which is in Bulgarian, is: "Define the predicate eq_set, which succeeds if the sets (S1, S2) coincide.
You call them "sets" but the data structure you are using is a list. It is easiest to just sort the two lists:
eq_set(A, B) :-
% prerequisites: A and B are lists without duplicates
sort(A, S),
sort(B, S).
If you want something more complicated (for some reason) you need to be more specific.
With this definition:
?- eq_set([a,b,c], [a,b]).
false. % OK
?- eq_set([a,b,c], [a,b,c]).
true. % OK
?- eq_set([a,c,b], [a,b,c]).
true. % OK
?- eq_set([a,a,b], [a,b,b]).
true. % Not sure....
It really really depends on how the predicate is going to be used.
Assuming that a "set" is indeed a Prolog list without duplicates but not in any particular order; then two sets in that presentation "coincide" if they are permutations of each other. In other words, it would be enough to define eq_set/2 as:
eq_set(A, B) :-
my_permutation(A, B).
and just use the textbook definition of permutation/2 which uses the textbook definition of select/3 (See "The Art of Prolog (Second Edition)" by Sterling and Shapiro, pp 67-9):
my_permutation([], []).
my_permutation(Xs, [Y|Ys]) :-
my_select(Y, Xs, Xs0),
my_permutation(Xs0, Ys).
my_select(X, [X|Xs], Xs).
my_select(X, [Y|Ys], [Y|Zs]) :-
my_select(X, Ys, Zs).
(I renamed those just to make sure I am not using the standard library definitions; SWI-Prolog has both select/3 and permutation/2 in the autoloaded library(lists); the definitions are basically the same, but they do some run-time type-checking on the arguments.)
Here is how you can use it:
?- eq_set([1,2,3], [2,3,1]).
true ;
false.
?- eq_set([1,2,3], S).
S = [1, 2, 3] ;
S = [1, 3, 2] ;
S = [2, 1, 3] ;
S = [2, 3, 1] ;
S = [3, 1, 2] ;
S = [3, 2, 1] ;
false.
?- eq_set([1,2,3], [1,2]).
false.
?- eq_set(A, B).
A = B, B = [] ;
A = B, B = [_4480] ;
A = B, B = [_4480, _4492] ;
...
I am not sure how useful the last query is. You can force it to enumerate solutions in order of increasing size of the "set", like this:
?- length(S1, _), eq_set(S1, S2), numbervars(S1).
S1 = S2, S2 = [] ;
S1 = S2, S2 = [A] ;
S1 = S2, S2 = [A, B] ;
S1 = [A, B],
S2 = [B, A] ;
S1 = S2, S2 = [A, B, C] ;
S1 = [A, B, C],
S2 = [A, C, B] ;
S1 = [A, B, C],
S2 = [B, A, C] ;
S1 = [A, B, C],
S2 = [B, C, A] ;
S1 = [A, B, C],
S2 = [C, A, B] ;
S1 = [A, B, C],
S2 = [C, B, A] ;
S1 = S2, S2 = [A, B, C, D] .
(Don't worry about the numbervars, it is just there to give readable names to all the free variables in the sets. Keep in mind that unifying two free variables makes them the same variable.)
This is a starting point, but maybe it is already good enough. The most glaring omission is that it doesn't require the arguments to be lists without duplicates. One way to define this would be to require that each element is different from all other elements. Since "is different" is commutative, you can define it like this:
is_set([]).
is_set([X|Xs]) :-
all_different(Xs, X),
is_set(Xs).
all_different([], _).
all_different([Y|Ys], X) :-
dif(X, Y),
all_different(Ys, X).
This uses dif/2 which is a widely available predicate (but does your Prolog have it?).
We would have maybe used maplist for that last one:
is_set([]).
is_set([X|Xs]) :-
maplist(dif(X), Xs).
is_set(Xs).
You are pretty close in your solution.
We have two cases
1) The first list argument is bigger
2) The second list argument is bigger
If you already know which one is bigger, you can just do
%in case the left one is longer
eq_set_left(_,[]).
eq_set_left(X,[H|T]):-member(H,X), eq_set_left(X,T).
So a very simple solution and yet very optimal could be this:
%in case the right one is longer
eq_set_right([],_).
eq_set_right([H|T], X):- member(H,X), eq_set_right(T,X).
%in case the left one is longer
eq_set_left(_,[]).
eq_set_left(X,[H|T]):-member(H,X), eq_set_left(X,T).
%both cases, equal length is also included here
eq_set(X,Y):- eq_set_left(X,Y).
eq_set(X,Y):- eq_set_right(X,Y).
eq_set(X, Y) is true if either X is subset of Y, Y is subset of X or they are equal
A set is defined as a collection of distinct things where order is not important, which is to say that sets {a,b,c} and {b,a,c} are identical.
From that, one could say that two sets are identical if neither set contains an element that is not also found in the other (or conversely, two sets are not identical if either set contains an element not found in the other.
From that, one could simply say:
eq_set(Xs,Ys) :-
findall( (Xs,Ys) , ( member(X,Xs), \+ member(X,Ys) ), [] ),
findall( (Xs,Ys) , ( member(Y,Ys), \+ member(Y,Xs) ), [] )
.
Or if you don't want to use the built-in findall/3,
eq_set(Xs,Ys) :-
a_not_in_b( Xs , Ys , [] ) ,
a_not_in_b( Ys , Xs , [] ) .
a_not_in_b( [] , [] , [] ) .
a_not_in_b( [A|As] , Bs , Xs ) :- member(A,Bs) , a_not_in_b( As, Bs, Xs ) .
a_not_in_b( [A|As] , Bs , Xs ) :- a_not_in_b( As, Bs, [A|Xs] ) .
One should note that both of these has roughly O(N2) performance. If the sets in question are large, you might want to first sort each set and then merge the two sorted lists to identify those elements that are not common to both sets:
eq_set(Xs,Ys) :-
sort(Xs,X1),
sort(Ys,Y1),
X1 == Y1.
The thing I wanted to do was generate all combinations of elements from a given list. E.g.: From [a,b,c], I might want:
[]
[a]
[b]
[c]
[a,a]
[a,b]
[a,c]
[b,a]
...
And so on. Perhaps there is a magical prolog one-liner that does this. If so, I would love to hear it.
However, my question is less about solving this particular problem and more of a request that someone explain some subtleties of Prolog's search algorithm for me.
So here's what I did first to solve the above problem:
members([], _).
members([X|Xs], List) :-
member(X,List),
members(Xs, List).
This works great but returns all possible results, and not in a great order:
[]
[a]
[a,a]
[a,a,a]
Okay, that's no problem. I really just want all combinations up to a certain length. So I decided to first get the ones that have exactly a particular length:
membersWithLength(Members, List, Bound) :-
L = Bound,
length(Members, L), members(Members, List).
This works great, e.g. for length 2:
[a,a]
[a,b]
[a,c]
...
And so on. Now my attempt to use clpfd to leverage the above function to get all lists up to a certain length went awry:
:- use_module(library(clpfd)).
membersLessThan(Members, List, Bound) :-
L in 0..Bound, % I also tried L #=< Bound
membersWithLength(Members, List, L).
Kind of works. Finds the right results (lists with length less than Bound).
But after it finds them, it loops continuously searching for more results. E.g. for length 2:
[]
[a]
[b]
[c]
[a,a]
[a,b]
...
[c,c]
Hangs looking for more solutions.
I guess this is the heart of my question. Can someone explain why (according to the trace) prolog continues to check larger and larger lists as possible solutions, even though they are all doomed to failure? And can someone tell me if there's a way to help prolog avoid this doomed journey?
I ultimately used the following code to solve the problem, but I was disappointed that I couldn't figure out how to use clpfd's integer constraints to constrain the size of the lists.
membersLessThan_(Members, List, Bound) :-
numlist(0,Bound,ZeroToBound),
member(L, ZeroToBound),
membersWithLength(Members, List, L).
Here is all the relevant code on SWISH: http://swish.swi-prolog.org/p/allcombos.pl
With you original implementation of members, if you want to enumerate all the answers you can do:
length(L, _), members(L, [a,b,c]).
which gives you the answers:
L = [] ;
L = [a] ;
L = [b] ;
L = [c] ;
L = [a, a] ;
L = [a, b] ;
L = [a, c] ;
L = [b, a] ;
L = [b, b] ;
L = [b, c] ;
L = [c, a] ;
L = [c, b] ;
L = [c, c] ;
L = [a, a, a] ;
L = [a, a, b] ;
L = [a, a, c] ;
L = [a, b, a]
This is a common idiom for iterative deepening, which allows you to list all the answers fairly. I don't think clpfd can help you in this case.
EDIT
I see that in the title you explicitly ask about CLPFD. The reason your code doesn't work is that when you do
L in 0..Bound
you are not actually enumerating those values. For the next predicates, L is still unbound and carries a constraint. So membersWithLength will keep looping trying new lengths, and once the length it's instantiated, it will see that the constraint fails and try again. You can see it in these examples:
L in 0..2, length(X, L)
loops like in your code, because length keeps trying. If you want to limit it, L has to be instantiated before calling length. You can use label for that. This next example doesn't loop:
L in 0..2, label([L]), length(X, L)
listMem(L, K, LK): LK is the list L with element K inserted in it somewhere.
I am having trouble writing this function, but my attempt goes as so:
My idea was to add K to L, then sort it and check if that sorted was the same as LK, unfortunately it doesn't work so well. I am having doubts of my use of the append predicate.
listMem(L, K, LK) :- append(L, K, Y), sort(Y, LK).
Since it seems you are missing the difference between a function and a Prolog predicate:
?- select(E, [a,b,c], L).
E = a,
L = [b, c] ;
E = b,
L = [a, c] ;
E = c,
L = [a, b] ;
false.
?- select(x, L, [a,b,c]).
L = [x, a, b, c] ;
L = [a, x, b, c] ;
L = [a, b, x, c] ;
L = [a, b, c, x] ;
false.
?- select(x, [a,b,c], L).
false.
In a sense, "select" as a word means less than what select/3 does, but, as CapelliC pointed out, what you are looking for is indeed select/3. You can see how it is implemented in any Prolog textbook or check out the library implementation of an open-source Prolog implementation.
I'm writing a permutation function [a,b]-->[[[a], [b]], [[a, b]]
I have this so far, but it doesn't work.
perm([],[]).
perm(L,[H|T]) :- append(V,[H|U],L), append(V,U,W), perm(W,T).
Given your example, it looks like you might actually be wanting the powerset, not the permutation, of the given list.
For instance, the powerset of [a,b] is the set {[a,b], [a], [b], []}.
To compute the powerset of a list of items in Prolog, look at this answer by #gusbro. If this helps you, also please upvote that answer.
If you want all solutions of the powerset of a list L at once, you can wrap the call to powerset/2 in a findall/3 call like this:
?- findall(S, powerset(L, S), Ss).
If, on the other hand, you're after the partitions (as you've mentioned in one of your earlier edits), consider the following:
partition(L, PL) :-
partition(L, [], PL).
partition([], [], []).
partition([X|Xs], As, R) :-
% add X into the new partition...
append(As, [X], NewAs),
partition(Xs, NewAs, R).
partition(L, [A|As], [[A|As]|R]) :-
% ...or, collect the current non-empty partition
partition(L, [], R).
The predicate partition/2 takes a list and returns all partitions, as you've described. For example:
?- partition([a,b,c],L).
L = [[a, b, c]] ;
L = [[a, b], [c]] ;
L = [[a], [b, c]] ;
L = [[a], [b], [c]] ;
false.
Really? It seems to work in SWI-Prolog:
?- [user].
|: perm([],[]).
|: perm(L,[H|T]) :- append(V,[H|U],L), append(V,U,W), perm(W,T).
|: % user://1 compiled 0.00 sec, 3 clauses
true.
?- perm([a,b,c], X).
X = [a, b, c] ;
X = [a, c, b] ;
X = [b, a, c] ;
X = [b, c, a] ;
X = [c, a, b] ;
X = [c, b, a] ;
false.
?- perm([a,b,c,d], X).
X = [a, b, c, d] ;
/* trimming 22 solutions */
X = [d, c, b, a] ;
false.
This also yields the number of answers you'd expect: 3! = 6, 4! = 24. What's not working for you?
Quick note: Prolog doesn't offer functions, but relations.
In this case, perm/2 will hold true when the arguments are one the permutation of the other.
I find this definition more readable than your.
perm([], []).
perm([E|Es], P) :-
perm(Es, Q),
select(E, P, Q).
It's almost the same as that of permutation/2 SWI-Prolog, but hides a bug...