I'm looking for a predicate that works as this:
?- subset([1,2,3], X).
X = [] ;
X = [1] ;
X = [2] ;
X = [3] ;
X = [1, 2] ;
X = [1, 2, 3] ;
X = [2, 3] ;
...
I've seen some subset implementations, but they all work when you want to check if one list is a subset of the another, not when you want to generate the subsets. Any ideas?
Here goes an implementation:
subset([], []).
subset([E|Tail], [E|NTail]):-
subset(Tail, NTail).
subset([_|Tail], NTail):-
subset(Tail, NTail).
It will generate all the subsets, though not in the order shown on your example.
As per commenter request here goes an explanation:
The first clause is the base case. It states that the empty list is a subset of the empty list.
The second and third clauses deal with recursion. The second clause states that if two lists have the same Head and the tail of the right list is a subset of the tail of the left list, then the right list is a subset of the left list.
The third clause states that if we skip the head of the left list, and the right list is a subset of the tail of the left list, then the right list is a subset of the left list.
The procedure shown above generates ordered sets. For unordered sets you might use permutation/3:
unordered_subset(Set, SubSet):-
length(Set, LSet),
between(0,LSet, LSubSet),
length(NSubSet, LSubSet),
permutation(SubSet, NSubSet),
subset(Set, NSubSet).
On http://www.probp.com/publib/listut.html you will find an implementation of a predicate called subseq0 that does what you want to:
subseq0(List, List).
subseq0(List, Rest) :-
subseq1(List, Rest).
subseq1([_|Tail], Rest) :-
subseq0(Tail, Rest).
subseq1([Head|Tail], [Head|Rest]) :-
subseq1(Tail, Rest).
A short explanation: subseq0(X, Y) checks whether Y is a subset subsequence of X, while subseq1(X, Y) checks whether Y is a proper subset subsequence of X.
Since the default representation of a set is a list with unique elements, you can use it to get all subsets as in the following example:
?- subseq0([1,2,3], X).
X = [1, 2, 3] ;
X = [2, 3] ;
X = [3] ;
X = [] ;
X = [2] ;
X = [1, 3] ;
X = [1] ;
X = [1, 2] ;
false.
Set is a collection of distinct objects by definition. A subset procedure shouldn't care about the order of elements in the set(in the arguments). A proper solution(swi prolog) may look like:
subset(_, []).
subset([X|L], [A|NTail]):-
member(A,[X|L]),
subset(L, NTail),
not(member(A, NTail)).
For the question ?- subset([1,2,3], E) it will generate:
E = [] ;
E = [1] ;
E = [1, 2] ;
E = [1, 2, 3] ;
E = [1, 3] ;
E = [2] ;
E = [2, 3] ;
E = [3] ;
E = [3, 2] ;
false.
Hope it will help!
we can also test by deleting subset's item from the super set.
% to delete : an item can be deleted it its in the head or in the tail of a list
delete(I,[I|L],L).
delete(I,[H|L],[H|NL]) :- delete(I,L,NL).
% an [] is an item of an set.A set is a subset of we can recursively delete its head item from the super set.
subset(_,[]).
subset(S,[I|SS]) :- delete(I,S,S1), subset(S1,SS).
example:
subset([a,b,c],S).
S = []
S = [a]
S = [a, b]
S = [a, b, c]
S = [a, c]
S = [a, c, b]
S = [b]
S = [b, a]
S = [b, a, c]
S = [b, c]
S = [b, c, a]
S = [c]
S = [c, a]
S = [c, a, b]
S = [c, b]
S = [c, b, a]
subset([a,b,a,d,e],[a,e]).
1true
append([],L,L).
append([H|T],L,[H|L1]):-append(T,L,L1).
subset([X|T],[X|L]) :-subset(T,L).
subset([X|T],[G|L]) :-subset([X],L),append(L2,[X|L3],[G|L]),append(L2,L3,L4),subset(T,L4).
subset([],_).
----------------------------------------------
?- subset([1,2],[1,2]).
yes
?- subset([1,2],[2,1]).
yes
?- subset([1,1],[1,2]).
no
?- subset(D,[1,2]).
D = [1,2] ;
D = [1] ;
D = [2,1] ;
D = [2] ;
D = '[]' ;
no
Related
I received this problem and I can't get it done, I don't know what I've done wrong, can someone help me ?
Write a predicate to add a value v after 1-st, 2-nd, 4-th, 8-th, … element in a list.
% add(L:list, E:Number, P:Number, C:number, H:List)
% add(i,i,i,i,o)
add([],_,_,_,[]).
add([_|T],E,P,C,[HR|TR]) :-
P =:= C,
HR is E,
C is C+1,
P is P*2,
add(T,E,P,C,TR).
add([H|T],E,P,C,[H|TR]) :-
P =\= C,
C is C+1,
add(T,E,P,C,TR).
Here's another possibility to define such a predicate. Whenever you are describing lists it is worthwhile to consider using DCGs since they yield easily readable code. First let's observe that there's only need for three arguments, namely the list, the element to be inserted and the list with the element already inserted at the desired positions. The arguments P and C are only needed for bookkeeping purposes so it's opportune to hide them inside the predicate. And since we're already about to redesign the predicates interface let's also give it a more descriptive name that reflects its relational nature, say list_e_inserted/3:
list_e_inserted(L,E,I) :-
phrase(inserted(L,E,1,1),I). % the DCG inserted//4 describes the list I
inserted([],_E,_P,_C) --> % if the list L is empty
[]. % the list I is empty as well
inserted([H|T],E,P,P) --> % if P and C are equal
{P1 is P*2, C1 is P+1}, % P is doubled and C is increased
[H,E], % H is in the list I, followed by E
inserted(T,E,P1,C1). % the same holds for T,E,P1,C1
inserted([H|T],E,P,C) --> % if P and C are
{dif(P,C), C1 is C+1}, % different C is increased
[H], % H is in the list I
inserted(T,E,P,C1). % the same holds for T,E,P,C1
Now let's see the predicate at work:
?- list_e_inserted([],10,I).
I = [].
?- list_e_inserted([1],10,I).
I = [1, 10] ;
false.
?- list_e_inserted([1,2],10,I).
I = [1, 10, 2, 10] ;
false.
?- list_e_inserted([1,2,3],10,I).
I = [1, 10, 2, 10, 3] ;
false.
?- list_e_inserted([1,2,3,4],10,I).
I = [1, 10, 2, 10, 3, 4, 10] ;
false.
The predicate also works in the other direction:
?- list_e_inserted(L,E,[1,10,2,10,3,4,10,5]).
L = [1, 2, 3, 4, 5],
E = 10 ;
false.
And the most general query also yields the desired solutions:
?- list_e_inserted(L,E,I).
L = I, I = [] ;
L = [_G23],
I = [_G23, E] ;
L = [_G23, _G35],
I = [_G23, E, _G35, E] ;
L = [_G23, _G35, _G47],
I = [_G23, E, _G35, E, _G47] ;
L = [_G23, _G35, _G47, _G53],
I = [_G23, E, _G35, E, _G47, _G53, E] ;
.
.
.
The main problem is that when a variable in Prolog gets instantiated you can't change the value e.g increase the value so you need to use a new variable:
add([],_,_,_,[]).
add([H|T],E,P,C,[H,E|TR]) :-
P =:= C,
C1 is C+1,
P1 is P*2,
add(T,E,P1,C1,TR).
add([H|T],E,P,C,[H|TR]) :-
P =\= C,
C1 is C+1,
add(T,E,P,C1,TR).
Example:
?- add([1,2,3,4],10,1,1,L).
L = [1, 10, 2, 10, 3, 4, 10] ;
false.
I would like to solve a simple problem, but even through I tried many different approaches, I couldn't find a solution for it. I am using SICStus Prolog (if that matters), and I want to get all sublists/subsets (I don't know which term is correct for this) of a list, which contains elements in succession. For example, if I have the list [1, 2, 3, 4], calling the sl/2 predicate as sl([1, 2, 3, 4], R)., the expected result is:
? - sl([1, 2, 3, 4], R).
R = [] ? ;
R = [1] ? ;
R = [1, 2] ? ;
R = [1, 2, 3] ? ;
R = [1, 2, 3, 4] ? ;
R = [2] ? ;
R = [2, 3] ? ;
R = [2, 3, 4] ? ;
R = [3] ? ;
R = [3, 4] ? ;
R = [4] ? ;
no
The best result I could reach until now is:
sl([], []).
sl([X|Xs], [X|Ys]) :-
sl(Xs, Ys).
sl([_|Xs], Ys) :-
sl(Xs, Ys).
But this also gives me the following unwanted results in addition:
R = [1,2,4] ? ;
R = [1,3,4] ? ;
R = [1,3] ? ;
R = [1,4] ? ;
R = [2,4] ? ;
How should I modify my predicates so I can get the desired result?
When writing a predicate in Prolog, you need to think about what the predicate means, or what relation it is defining. The reason your predicate gives non-solutions is that you are mixing meanings in your predicate clauses. They don't all really mean the same thing.
You have the predicate sl/2 which is intended to mean "sublist" (or "subsequence") but, more than that, means a sublist per the description you provided, which is a contiguous sublist (cannot have any "gaps" in it).
Now we can break down your clauses:
sl([], []).
This says the empty list is a contiguous sublist of the empty list. This is true, so is a valid fact.
sl([X|Xs], [X|Ys]) :-
sl(Xs, Ys).
This says that [X|Ys] is a contiguous sublist of [X|Xs] if Ys is a contiguous sublist of Xs. This relation is not true. What would really be true here would be: [X|Ys] is a contiguous sublist of [X|Xs] if Ys is a contiguous prefix sublist of Xs. That is, not only does Ys need to be a sublist of Xs, but it needs to be only from the start of the list and not somewhere within this list. This is a clue that you'll need another predicate since the meaning of the relation is different.
Your final clause says that Ys is a sublist of [_|Xs] if Ys is a sublist of Xs. This appears to be true.
If we simply adjust to the above updated definitions, we get:
subseq([], []).
subseq([_|Xs], Ys) :-
subseq(Xs, Ys).
subseq([X|Xs], [X|Ys]) :-
prefix_subseq(Xs, Ys).
prefix_subseq(_, []).
prefix_subseq([X|Xs], [X|Ys]) :-
prefix_subseq(Xs, Ys).
I offered the prefix_subseq/2 definition above without explanation, but I think you can figure it out.
This now yields:
| ?- subseq([a,b,c,d], R).
R = [a] ? a
R = [a,b]
R = [a,b,c]
R = [a,b,c,d]
R = [b]
R = [b,c]
R = [b,c,d]
R = [c]
R = [c,d]
R = [d]
R = []
(1 ms) yes
An interesting, compact way of defining your sublist (or subsequence) would be using the append/2 predicate:
subseq(L, R) :- append([_, R, _], L).
This says that L is the result of appending lists _, R, and _. The minor flaw in this simple implementation is that you'll get R = [] more than once since it satisfies the append([_, R, _], L) rule in more than one way.
Taking a fresh look at the definition, you can use a DCG to define a subsequence, as a DCG is perfect for dealing with sequences:
% Empty list is a valid subsequence
subseq([]) --> ... .
% Subsequence is any sequence, followed by sequence we want, followed by any sequence
subseq(S) --> ..., non_empty_seq(S), ... .
% Definition of any sequence
... --> [] | [_], ... .
% non-empty sequence we want to capture
non_empty_seq([X]) --> [X].
non_empty_seq([X|T]) --> [X], non_empty_seq(T).
And you can call it with phrase/2:
| ?- phrase(subseq(S), [a,b,c,d]).
S = [] ? ;
S = [a] ? ;
S = [a,b] ? ;
S = [a,b,c] ? ;
S = [a,b,c,d] ? ;
S = [b] ? ;
S = [b,c] ? ;
S = [b,c,d] ? ;
S = [c] ? ;
S = [c,d] ? ;
S = [d] ? ;
no
We can reswizzle this definition a little and make use of a common seq//1 definition to make it more compact:
subseq([]) --> seq(_) .
subseq([X|Xs]) --> seq(_), [X], seq(Xs), seq(_).
% alternatively: seq(_), seq([X|Xs]), seq(_).
seq([]) --> [].
seq([X|Xs]) --> [X], seq(Xs).
Is there a simple way of getting all the combinations of a list without doubles. Without doubles I mean also no permutations of each other. So no [a,b,c] and [c,a,b] or [c,b,a].
So for the input [a,b,c] the output would be:
[a]
[b]
[c]
[a,b]
[a,c]
[b,c]
[a,b,c]
I can only find solutions WITH the doubles (permutations)
The solution to this problem is rather simple: there is evidently only one combination out of the empty set: the empty set:
combs([],[]).
Furthermore for each element, you can decide whether you add it or not:
combs([H|T],[H|T2]) :-
combs(T,T2).
combs([_|T],T2) :-
combs(T,T2).
Since you pick (or drop) in the order of the list, this guarantees you that you later will not redecide to pick a. If you feed it [a,b,c], it will never generate something like [b,a,c], because once it has decided to pick/drop a, it cannot add b and re-decide on a.
Running this gives:
?- combs([a,b,c],L).
L = [a, b, c] ;
L = [a, b] ;
L = [a, c] ;
L = [a] ;
L = [b, c] ;
L = [b] ;
L = [c] ;
L = [].
In case you want to generate it the opposite way (have more of a test to first drop elements, instead of adding them, you can simply swap the recursive statements):
combs([],[]).
combs([_|T],T2) :-
combs(T,T2).
combs([H|T],[H|T2]) :-
combs(T,T2).
In that case the result will be:
?- combs([a,b,c],L).
L = [] ;
L = [c] ;
L = [b] ;
L = [b, c] ;
L = [a] ;
L = [a, c] ;
L = [a, b] ;
L = [a, b, c].
EDIT
Given you want to exclude the empty list, either you can do it simply by adding another check in your call:
?- combs([a,b,c],L),L \= [].
You can define this in a function like:
combs_without_empty1(LA,LB) :-
combs_without_empty1(LA,LB),
LB \= [].
Or by rewriting the comb/2 function. In that case you better use an accumulator that counts the current amount of selected elements:
combs_without_empty(L,C) :-
combs_without_empty(L,0,C).
The combs_without_empty/3 is a bit more complicated. In case the list contains only one element, one should check if N is greater than zero. If that is the case, we can choose whether to add the element or not. If N is zero, we have to include it. So:
combs_without_empty([A],_,[A]).
combs_without_empty([_],N,[]) :-
N > 0.
We also have to implement a recursive part that will increment N given we select an element:
combs_without_empty([_|T],N,T2) :-
combs_without_empty(T,N,T2).
combs_without_empty([H|T],N,[H|T2]) :-
N1 is N+1,
combs_without_empty(T,N1,T2).
Putting it all together gives:
combs_without_empty(L,C) :-
combs_without_empty(L,0,C).
combs_without_empty([A],_,[A]).
combs_without_empty([_],N,[]) :-
N > 0.
combs_without_empty([_|T],N,T2) :-
combs_without_empty(T,N,T2).
combs_without_empty([H|T],N,[H|T2]) :-
N1 is N+1,
combs_without_empty(T,N1,T2).
Which produces:
?- combs_without_empty([a,b,c],L).
L = [c] ;
L = [b, c] ;
L = [b] ;
L = [a, c] ;
L = [a] ;
L = [a, b, c] ;
L = [a, b] ;
false.
A clean solution without ancillary checks for empty list would be simply to exclude empty lists from the rules. The base case should be a single element combination:
comb_without_empty([H|_], [H]). % Simple case of one element comb
comb_without_empty([_|T], C) :- % Combinations of the tail w/o head
comb_without_empty(T, C).
comb_without_empty([H|T], [H|C]) :- % Combinations of the tail including head
comb_without_empty(T, C).
| ?- comb_without_empty([a,b,c], L).
L = [a] ? a
L = [b]
L = [c]
L = [b,c]
L = [a,b]
L = [a,c]
L = [a,b,c]
(1 ms) no
| ?-
I am a new learner for prolog. Here is the question of our workshop, I have no idea where start it.
Would really appreciate any help with this.
sublist(Xs, Ys)
This holds when Xs is a list containing some of the elements of Ys, in the same order they appear in the list Ys. This should work whenever Ys is a proper list. For example:
sublist([a,c,e],[a,b,c,d,e]) should succeed.
sublist([a,e,c],[a,b,c,d,e]) should fail.
sublist([a,X,d],[a,b,c,d,e]) should have the two solutions X=b and X=c.
sublist(X,[a,b,c]) should have the eight solutions X=[]; X=[c]; X=[b]; X=[b,c]; X=[a]; X=[a,c]; X=[a,b]; and X=[a,b,c].
My implementation:
sublist([], []).
sublist([H| Rest1], [H| Rest2]) :-sublist(Rest1, Rest2).
sublist(H, [_ | Rest2]) :-sublist(H, Rest2).
Examples:
?- sublist(X,[a,b,c]).
X = [a, b, c] ;
X = [a, b] ;
X = [a, c] ;
X = [a] ;
X = [b, c] ;
X = [b] ;
X = [c] ;
X = [].
?- sublist([a,c,e],[a,b,c,d,e]) .
true ;
false.
?- sublist([a,e,c],[a,b,c,d,e]) .
false.
?- sublist([a,X,d],[a,b,c,d,e]).
X = b ;
X = c ;
false.
Please note that a sublist needs its elements to be consecutive in the original list.
With that definition it would be easier to define a sublist through defining auxiliary predicates prefix and suffix, examples are taken from Shapiro's book:
prefix([], _).
prefix([X|Xs], [X,Ys]) :-
prefix(Xs, Ys).
suffix(Xs, Xs).
suffix(Xs, [_|Ys]) :-
suffix(Xs, Ys).
– and then it is just a matter of defining a sublist as either a suffix of a prefix:
sublist(Xs, Ys) :-
prefix(Ps, Ys),
suffix(Xs, Ps).
Result:
?- sublist(X, [1,2,3]).
X = [] ;
X = [1] ;
X = [] ;
X = [1, 2] ;
X = [2] ;
X = [] ;
X = [1, 2, 3] ;
X = [2, 3] ;
X = [3] ;
X = [] ;
false.
– or as a prefix of a suffix:
sublist(Xs, Ys) :-
prefix(Xs, Ss),
suffix(Ss, Ys).
Result:
?- sublist(X, [1,2,3]).
X = [] ;
X = [] ;
X = [] ;
X = [] ;
X = [1] ;
X = [2] ;
X = [3] ;
X = [1, 2] ;
X = [2, 3] ;
X = [1, 2, 3] ;
But one could also do a recursive definition:
sublist(Xs, Ys) :-
prefix(Xs, Ys).
sublist(Xs, [_|Ys]) :-
sublist(Xs, Ys).
Result:
?- sublist(X, [1,2,3]).
X = [] ;
X = [1] ;
X = [1, 2] ;
X = [1, 2, 3] ;
X = [] ;
X = [2] ;
X = [2, 3] ;
X = [] ;
X = [3] ;
X = [] ;
false.
I am currently using this in my Prolog program:
sublist(X, L) :- append(_, S, L), append(X, _, S).
It will correctly list the sublists of a list if I call it like so,
?- sublist(A, [1, 2, 3]).
A = [] ;
A = [1] ;
A = [1, 2] ;
A = [1, 2, 3] ;
A = [] ;
A = [2] ;
A = [2, 3] ;
A = [] ;
A = [3] ;
A = [] ;
false.
I am looking to make a new function that will try all the shorter substrings first, so that it will come up with something more like
[1] ; [2] ; [3] ; [1, 2] ; [2, 3] ; [1, 2, 3].
Taking out the empty lists isn't vital, but would be preferred.
How about one of the following? Using SWI-Prolog we define the following rules:
Version 1
sublist_of([X|Xs], [E|Es]) :-
append(Ruler, _, [E|Es]), % ensure we get answers in ascending lengths
same_length(Ruler, [X|Xs]),
append([_,[X|Xs],_], [E|Es]).
Version 2
sublist_of__ver2([X|Xs], [E|Es]) :-
append(Ruler, _, [E|Es]), % ensure we get answers in ascending lengths
same_length(Ruler, [X|Xs]),
append([_,[X|Xs],_], [E|Es]).
Version 3a
sublist_of__ver3a([X|Xs], [E|Es]) :-
len1_len2_len12([X|Xs], _, [E|Es]),
append([_,[X|Xs],_], [E|Es]).
len1_len2_len12([], Ys, Zs) :-
same_length(Ys, Zs).
len1_len2_len12([_|Xs], Ys, [_|Zs]) :-
len1_len2_len12(Xs, Ys, Zs).
Version 3b
sublist_of__ver3b(Xs, Es) :-
Xs = [_|_],
len1_len2_len12(Xs, _, Es),
append([_,Xs,_], Es).
Sample query as given by the OP:
?- sublist_of__ver2(Xs, [1,2,3,4]).
Xs = [1 ]
; Xs = [ 2 ]
; Xs = [ 3 ]
; Xs = [ 4]
; Xs = [1,2 ]
; Xs = [ 2,3 ]
; Xs = [ 3,4]
; Xs = [1,2,3 ]
; Xs = [ 2,3,4]
; Xs = [1,2,3,4]
; false.
I swapped arguments order, for readability - please forgive me :)
sublist(L, S) :-
length(L, N),
between(1, N, M),
length(S, M),
append([_,S,_], L).
yields
?- sublist([a,b,c],S).
S = [a] ;
S = [b] ;
S = [c] ;
S = [a, b] ;
S = [b, c] ;
S = [a, b, c] ;
false.
with Sicstus-prolog it's easy with sublist(?X,+List). inside library(lists3).
code
% sublist(?Sub, +List)
% is true when all members of Sub are members of List
:- sublist(?,+) is nondet.
sublist(List, List).
sublist(Sub, [Head|Tail]) :- sublist_(Tail, Head, Sub).
:- sublist_/3 is nondet.
sublist_(Sub, _, Sub).
sublist_([Head|Tail], _, Sub) :- sublist_(Tail, Head, Sub).
sublist_([Head|Tail], X, [X|Sub]) :- sublist_(Tail, Head, Sub).
result
?- sublist(Y,[1,2,3]).
Y = [1,2,3] ? ;
Y = [2,3] ? ;
Y = [3] ? ;
Y = [] ? ;
Y = [2] ? ;
Y = [1,3] ? ;
Y = [1] ? ;
Y = [1,2] ? ;
no