Prolog: eliminate repetitions in query - prolog

I've been trying to write a simple code, that would behave in this manner:
| ?- hasCoppiesOf(X,[a,b,a,b,a,b,a,b]).
X = [a,b] ? ;
X = [a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b] ? ;
And
| ?- hasCoppiesOf([a,b,a,b,a,b,a,b], X).
X = [] ? ;
X = [a,b,a,b,a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b] ? ;
X = ...
This desire resulted in next piece of code:
hasCoppiesOf(A,[]).
hasCoppiesOf([H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf([H1|T1], X, T2).
hasCoppiesOf(A, A, B) :-
hasCoppiesOf(A, B).
hasCoppiesOf(A, [H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf(A, X, T2).
And it gives me what I want on the second query, however, the first results in:
?- hasCoppiesOf(X,[a,b,a,b,a,b,a,b]).
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
It seems to be working fine, but that repetition of the same answers bothers me. It's, probably, a simple mistake, but is there a way to make the output prettier?
And honestly, that a mystery, why Prolog treats two identical arrays as different answers.
Or maybe it's just something wrong with my system?
Edit:
The gentle guidance of the person in the comments helped me to solve this issue. However, if this question will be reading the person who wants to solve exactly the same problem - code not really working well, my apologies.

I think you just made your predicate more complex than it needs to be, probably just overthinking it. A given solution may succeed in multiple paths through the logic.
You can do this without append/3 by aligning the front end of the lists and keep the original list to "reset" on repeats:
% Empty list base cases
dups_list([], []).
dups_list([_|_], []).
% Main predicate, calling aux predicate
dups_list(L, Ls) :-
dups_list(L, L, Ls).
% Recursive auxiliary predicate
dups_list([], [_|_], []).
dups_list([], [X|Xs], [X|Ls]) :-
dups_list(Xs, [X|Xs], Ls).
dups_list([X|Xs], L, [X|Ls]) :-
dups_list(Xs, L, Ls).
Here are some results:
| ?- dups_list(X,[a,b,a,b,a,b,a,b]).
X = [a,b] ? a
X = [a,b,a,b]
X = [a,b,a,b,a,b,a,b]
no
| ?- dups_list([a,b,a,b,a,b,a,b], X).
X = [] ? ;
X = [a,b,a,b,a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b] ?
...
| ?- dups_list(A, B).
A = []
B = [] ? ;
A = [_|_]
B = [] ? ;
A = [C]
B = [C] ? ;
A = [C]
B = [C,C] ? ;
A = [C,D]
B = [C,D] ? ;
A = [C]
B = [C,C,C] ? ;
A = [C,D,E]
B = [C,D,E] ? ;
...
There may be a way to simplify the solution just a bit more, but I haven't played with it enough to determine if that's the case.

I think this is what you're trying for...
coppies(Z,Z,[]).
coppies(X,Z,[Y|Ys]):- \+member(Y,Z),coppies(X,[Y|Z],Ys).
coppies(X,Z,[Y|Ys]):- member(Y,Z),coppies(X,Z,Ys).
copies(M,[Y|Ys]):-coppies(M,[],[Y|Ys]).
Input:
copies(X,[1,2,1,2,1,2]).
Output:
X = [2, 1].
BTW I've used some different names instead..

Okay, I got your problem, you want to eliminate the repetitions.
hasCoppiesOf(A,[]).
hasCoppiesOf([H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf([H1|T1], X, T2).
hasCoppiesOf(A, A, B) :-
hasCoppiesOf(A, B),!. %Change here, place a cut after the termination.
hasCoppiesOf(A, [H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf(A, X, T2).
This is the change that you need to make.
hasCoppiesOf(A, A, B) :-
hasCoppiesOf(A, B),!.
A Cut '!' terminates the unwanted backtracking and thereby repetitions.

Related

Why are solutions in the wrong order?

I have been asked to
define a predicate subseq/2, with signature subseq(-,+),
which is true when both its arguments are lists, and its first
argument can be constructed by removing zero or more elements
from its second argument.
... with intended solution order:
?- subseq(X, [a, b, c]).
X = [a, b, c] ;
X = [a, b] ;
X = [a, c] ;
X = [a] ;
X = [b, c] ;
X = [b] ;
X = [c] ;
X = [].
My code:
subseq([], []).
subseq([], [_|_]).
subseq([X|XS], [X|YS]) :- subseq(XS, YS).
subseq([X|XS], [_|YS]) :- subseq([X|XS], YS).
My code's solution order:
?- subseq(X, [a, b, c]).
X = []
X = [a]
X = [a, b]
X = [a, b, c]
X = [a, c]
X = [b]
X = [b, c]
X = [c] ;
false.
How do I achieve the intended solution order?
In Prolog, the order of the rules is crucial. To get the desired output, simply change the order of the rules, like this:
subseq([X|XS], [X|YS]) :- subseq(XS, YS).
subseq([X|XS], [_|YS]) :- subseq([X|XS], YS).
subseq([], []).
subseq([], [_|_]).
?- subseq(X,[a,b,c]).
X = [a, b, c]
X = [a, b]
X = [a, c]
X = [a]
X = [b, c]
X = [b]
X = [c]
X = []
Little tweaks can change the order:
sub_list_forwards(Sub, Long) :-
sub_list_forwards_(Long, Sub).
sub_list_forwards_([], []).
% Either pick H, or don't
sub_list_forwards_([H|T], S) :-
(S = Sub ; S = [H|Sub]),
sub_list_forwards_(T, Sub).
Result in swi-prolog:
?- sub_list_forwards(S, [a,b,c]).
S = [] ;
S = [c] ;
S = [b] ;
S = [b, c] ;
S = [a] ;
S = [a, c] ;
S = [a, b] ;
S = [a, b, c].
Or tweak the selection line to be:
(S = [H|Sub] ; S = Sub),
... which results in the order you were given:
?- sub_list_forwards(S, [a,b,c]).
S = [a, b, c] ;
S = [a, b] ;
S = [a, c] ;
S = [a] ;
S = [b, c] ;
S = [b] ;
S = [c] ;
S = [].
Note that neither of these leave an unwanted choicepoint at the end, because they use first-argument indexing on [] vs [H|T] with 1 selection each.
Does the order matter? What would be an optimum order? It probably varies.
In general it is best to put the base case (i.e. [], []) first, for flexibility (and because they sometimes contain a cut).
This is programming, rather than mathematics, so meaningful variable names/initials are far better for readability than using the likes of X and Y continually.
Using (S = [H|Sub] ; S = Sub), produces the sensible:
?- nth1(5, L, e), sub_list_forwards([a,b,c], L).
L = [a, b, c, _, e] ;
L = [a, b, c, _, e, _] ;
L = [a, b, c, _, e, _, _] ;
L = [a, b, c, _, e, _, _, _] ;
... rather than a stack overflow, and so is preferable.

A Prolog program for permutation parity

I wrote this small program in Prolog.
odd_even_flip(odd, even).
odd_even_flip(even, odd).
% flip_one, for A = a, B = b, P = [a, .., b, ..], gives M = [b, .., a, ..]
flip_one(A, B, P, M) :-
append([A|As], [B|Bs], P),
append([B], As, L),
append([A], Bs, R),
append(L, R, M).
permutation_parity([X|L], [X|P], R) :- permutation_parity(L, P, R).
% abc
permutation_parity([X|L], [Y|P], R) :-
X \= Y,
flip_one(Y, X, [Y|P], M),
permutation_parity([X|L], M, Res),
odd_even_flip(Res, R).
permutation_parity([], [], even).
I expect it to find the parity of a permutation P of list L. The few queries that assert that a given permutation of a given list is indeed even or odd worked fine.
However, from my experience with Prolog, I would expect that permutation_parity([a, b, c], X, Y). would show me all permutations of [a, b, c] but that is not happening.
Rather, I get X = [a, b, c], Y = even. and that is all.
I tried to add member(Y, L) in the rule that follows %abc as I was thinking that will help Prolog to know how to instantiate X in permutation_parity([a, b, c], X, Y) but that helped to no avail.
If someone could help me see what I am missing it would be great. Thanks in advance.
You only need to use unification to correctly instantiate the variable X (assuming that permutation_parity/3 is called with a proper list as its first argument). So I suggest you modify your code as follows:
permutation_parity([], [], even).
permutation_parity([X|Xs], [X|Zs], P) :-
permutation_parity(Xs, Zs, P).
permutation_parity([X|Xs], Zs, P) :-
permutation_parity(Xs, Ys, Q),
flip_first([X|Ys], Zs),
odd_even_flip(Q, P).
flip_first(L0, L1) :-
append([X|Xs], [Y|Ys], L0),
append([Y|Xs], [X|Ys], L1).
odd_even_flip(odd, even).
odd_even_flip(even, odd).
Examples:
?- permutation_parity([a,b,c], Permutation, Parity).
Permutation = [c, a, b],
Parity = even ;
Permutation = [b, c, a],
Parity = even ;
Permutation = [b, a, c],
Parity = odd ;
Permutation = [c, b, a],
Parity = odd ;
Permutation = [a, c, b],
Parity = odd ;
Permutation = [a, b, c],
Parity = even.
?- permutation_parity([a,b,c], [a,c,b], Parity).
Parity = odd ;
false.
?- permutation_parity([a,b,c], Permutation, even).
Permutation = [c, a, b] ;
Permutation = [b, c, a] ;
Permutation = [a, b, c].
EDIT
perm_parity(L0, L1, P) :-
same_length(L0, L1),
permutation_parity(L0, L1, P).
The predicate same_length/2 is defined in SWI-Prolog as follows:
same_length([], []).
same_length([_|T1], [_|T2]) :-
same_length(T1, T2).
Example:
?- perm_parity(L, [a,b,c], P).
L = [b, c, a],
P = even ;
L = [c, a, b],
P = even ;
L = [b, a, c],
P = odd ;
L = [c, b, a],
P = odd ;
L = [a, c, b],
P = odd ;
L = [a, b, c],
P = even.

define a predicate solution/3 which is true when its three arguments, all lists, has the third list containing all elements of the first two arguments

solution([ ], List, List).
solution([Head|Tail], List,[Head|Result]):-
solution(Tail, List,Result).
expected output
| ?- Solution(X,Y,[a,b,c]).
X = [a,b,c]
Y = [] ? ;
X = [a,b]
Y = [c] ? ;
X = [a,c]
Y = [b] ? ;
X = [a]
Y = [b,c] ? ;
X = [b,c]
Y = [a] ? ;
X = [b]
Y = [a,c] ? ;
X = [c]
Y = [a,b] ? ;
X = []
Y = [a,b,c] ? ;
actual output
X = []
Y = [a,b,c] ? ;
X = [a]
Y = [b,c] ? ;
X = [a,b]
Y = [c] ? ;
X = [a,b,c]
Y = [] ? ;
It is not going through all the possible solutions that can be made from the predicate defined. i am expecting the output to be as shown above containing all the solutions of combining 2 lists together
Any help?
Your predicate is missing some clauses. The first clause says that if the first list is exhausted, then the result is the second list.
The second clause specifies that if the first list is not exhausted, we simply take the first element of that list as a result. This thus means that you basically implemented an append/3 predicate [swi-doc].
Based on your sample output, there is however a decision whether to take from the first list, or the second list. We thus should implement a clause like:
solution([H1|T1], L2, [H1|R]) :-
solution(T1, L2, R).
solution(L1, [H1|T2], [H1|R]) :-
solution(L1, T2, R).
If both lists are exhausted, we can return an empty list, so we can define a base-clause like:
solution([], [], []).
and thus obtain as full solution:
solution([], [], []).
solution([H1|T1], L2, [H1|R]) :-
solution(T1, L2, R).
solution(L1, [H1|T2], [H1|R]) :-
solution(L1, T2, R).
This then gives us:
?- solution(X,Y,[a,b,c]).
X = [a, b, c],
Y = [] ;
X = [a, b],
Y = [c] ;
X = [a, c],
Y = [b] ;
X = [a],
Y = [b, c] ;
X = [b, c],
Y = [a] ;
X = [b],
Y = [a, c] ;
X = [c],
Y = [a, b] ;
X = [],
Y = [a, b, c].

How to check if list 2 contains all of list 1s elements?

I'm quite new to Prolog. I got stuck with this problem:
If I have two lists, how do I check if list 1 contains all of the elements of the second list, but they don't have to be equal. So list 2 might contain more elements.
I know I can use member/2 to check if a certain element is in a list. But I don't know how to not include these members of both lists after I checked them. So for example:
If I have list A = [a,b,c,a] and list B = [a,b,c,d,e] and I start by checking if the first 'a' from list A is in list B. Obviously this returns a True, but if I check the last 'a' from list A, I should get a False returned, since list A has 2 'a's and B only 1, instead I get True returned. I really have no clue on how to fix this problem.
I would really appreciate if someone could help me :)
Thanks!
Edit: Explained my question a bit more
select/3 does exactly what we want:
is_sublist([], []).
is_sublist([], [_|_]).
is_sublist([H|T], L) :-
once(select(H, L, L2)),
is_sublist(T, L2).
We wrap it in once/1 to avoid redundant successes in cases where an element appears multiple times.
Note: you can remove once/1 to get more working behaviors:
?- is_sublist(Z,[a,b,c]). % Without once
Z = [] ;
Z = [a] ;
Z = [a, b] ;
Z = [a, b, c] ;
Z = [a, c] ;
Z = [a, c, b] ;
Z = [b] ;
Z = [b, a] ;
Z = [b, a, c] ;
Z = [b, c] ;
Z = [b, c, a] ;
Z = [c] ;
Z = [c, a] ;
Z = [c, a, b] ;
Z = [c, b] ;
Z = [c, b, a] ;
false.
This will not enumerate all possible answers in the opposite direction, so not everything is perfect:
?- is_sublist([a,b],Z). % Without once
Z = [a, b] ;
Z = [a, b, _886|_888] ;
Z = [a, _880, b|_888] ;
Z = [a, _880, _892, b|_900] ;
Z = [a, _880, _892, _904, b|_912]
…

Permutations of power set in Prolog

I am supposed to write a program in Prolog which when given a list,returns the permutation of its powerset.
one thing I forgot to mention: I already have a predicate that reverses a list: deep_reverse(List,RevList).
for example: ?-sublist_perm([a,b,c],X).
will return:(duplicates are allowed)
X = [] ;
X = [c] ;
X = [b] ;
X = [b, c] ;
X = [c, b] ;
X = [a] ;
X = [a, c] ;
X = [c, a] ;
X = [a, b] ;
X = [b, a] ;
X = [a, b, c] ;
X = [b, a, c] ;
X = [b, c, a] ;
X = [a, c, b] ;
X = [c, a, b] ;
X = [c, b, a]
You ask two things in one question: How to get all sublists and how to permutate a list:
sublist_perm(In, Out) :-
sublist(In, Temp),
permutation(Temp, Out).
sublist([], []).
sublist([_|XS], YS) :-
sublist(XS, YS).
sublist([X|XS], [X|YS]) :-
sublist(XS, YS).
See also: man page for permutation/2.
findall(X, sublist_perm([a,b,c], X), XS),
XS = [[],[c],[b],[b,c],[c,b],[a],[a,c],[c,a],[a,b],[b,a],
[a,b,c],[b,a,c],[b,c,a],[a,c,b],[c,a,b],[c,b,a]].

Resources