I am coding in Prolog. I want to find all distinct partitions of a list. I look at a list as a set here. Each partition is a set of sets in which none is empty, the union of all of them is the main set, and the pairwise intersection of them is empty.
Asked
Active
Viewed 1,883 times
2 Answers
6
First, we define an auxiliary predicate list_taken_rest/3:
list_taken_rest([], [], []).
list_taken_rest([X|Xs], [X|Ys], Zs) :-
list_taken_rest(Xs, Ys, Zs).
list_taken_rest([X|Xs], Ys, [X|Zs]) :-
list_taken_rest(Xs, Ys, Zs).
Let's look at a query of list_taken_rest/3 with the first argument being the list [a,b,c]. As answers we get alternative ways of parting the element of [a,b,c] between Xs and Ys:
?- list_taken_rest([a,b,c], Xs, Ys).
Xs = [a,b,c], Ys = []
; Xs = [a,b], Ys = [c]
; Xs = [a,c], Ys = [b]
; Xs = [a], Ys = [b,c]
; Xs = [b,c], Ys = [a]
; Xs = [b], Ys = [a,c]
; Xs = [c], Ys = [a,b]
; Xs = [], Ys = [a,b,c].
Next, we define the predicate list_partitioned/2, building on list_taken_rest/3.
As we "walk along" the list [X|Xs]:
- A single partition is
[X|Ys]gets built. - That partition contains
Xas the first element and some other items ofXsinYs. - All items in
Xsthat were not taken intoYsend up being inZs. - We proceed similarly until
Xs = []holds.
list_partitioned([], []). list_partitioned([X|Xs], [[X|Ys]|Pss]) :- list_taken_rest(Xs, Ys, Zs), list_partitioned(Zs, Pss).
Done! Let's use list_partitioned/2 in some queries!
?- list_partitioned([1,2,3,4], Pss). % query #1
Pss = [[1,2,3,4]]
; Pss = [[1,2,3],[4]]
; Pss = [[1,2,4],[3]]
; Pss = [[1,2],[3,4]]
; Pss = [[1,2],[3],[4]]
; Pss = [[1,3,4],[2]]
; Pss = [[1,3],[2,4]]
; Pss = [[1,3],[2],[4]]
; Pss = [[1,4],[2,3]]
; Pss = [[1,4],[2],[3]]
; Pss = [[1],[2,3,4]]
; Pss = [[1],[2,3],[4]]
; Pss = [[1],[2,4],[3]]
; Pss = [[1],[2],[3,4]]
; Pss = [[1],[2],[3],[4]].
?- list_partitioned([1,1,1], Pss). % query #2
Pss = [[1,1,1]]
; Pss = [[1,1],[1]]
; Pss = [[1,1],[1]] % (redundant answer)
; Pss = [[1],[1,1]]
; Pss = [[1],[1],[1]].
Note that list_partitioned/2 doesn't care about sets at all:
- If
Lsis a set (like in query #1), all answers will be solutions. - If
Lscontains duplicates (like in query #2), we get some redundant answer(s).
repeat
- 18,496
- 4
- 54
- 166
-
1Thank a lot. It works perfectly. Can you please add an explanation to your code? – sinderela May 15 '15 at 07:45
2
part([Single], [[Single]]).
part([First|Others], [[First] | Result]) :-
part(Others, Result).
part([First|Others], Result) :-
part(Others, Temp),
addElement(First, Temp, Result).
/* addElement(E, L, R) iff R is the same list of lists as L, except one of its sublist has an extra E in front */
addElement(Element, [FirstList | OtherLists],
[ [Element|FirstList] | OtherLists]).
addElement(Element, [FirstList | OtherLists],
[ FirstList | Temp] )
:- addElement(Element, OtherLists, Temp).
Execution:
?- part([a,b,c,d],X).
X = [[a], [b], [c], [d]] ;
X = [[a], [b], [c, d]] ;
X = [[a], [b, c], [d]] ;
X = [[a], [c], [b, d]] ;
X = [[a], [b, c, d]] ;
X = [[a, b], [c], [d]] ;
X = [[b], [a, c], [d]] ;
X = [[b], [c], [a, d]] ;
X = [[a, b], [c, d]] ;
X = [[b], [a, c, d]] ;
X = [[a, b, c], [d]] ;
X = [[b, c], [a, d]] ;
X = [[a, c], [b, d]] ;
X = [[c], [a, b, d]] ;
X = [[a, b, c, d]] ;
false.
Michel Billaud
- 1,758
- 11
- 14