Proper Subset - Prolog - prolog

I am attempting to write a program that takes two lists as input and checks for proper subset. I started with:
proper([A],[]).
proper([],[A]).
proper([A|T1],[A|T2]) :- proper(T1,T2).
This works perfectly fine for inputs in the exact same order. for instance:
?- proper([a,b,c],[a,b,c,d]).
Yes
But doesn't for inputs such as:
?- proper([a,b,c],[b,d,a,c]).
No
After looking through the site I found this previously asked question:
Subset function in prolog
Which lead me to modify my code as such:
proper([A],[]).
proper([],[A]).
proper([A|T1],[A|T2) :- member(A,T2), proper(T1,T2).
proper([H1|T1], [H2|T2]) :- \+ member(H1, T2).
This works fine for subsets but not for proper subsets. Which I think my problem is arising from my understanding of how the second clause of proper/4 works. Any and all help is greatly appreciated.
Edit:
Realized I was trying to determine if the first list was a proper subset of the second and the second was a proper subset of the first. Cleaned up the code to be more precise.
proper([],_).
proper([A|T1],[A|T2) :- member(A,T2), proper(T1,T2).
proper([H1|T1], [H2|T2]) :- \+ member(H1, T2).

If I understand correctly, the first two declarations in your last attempt would mean that, both a list with 1 element is a proper subset of an empty list (false), and that an empty list is a proper subset of a list with one element (true); the first one should be problematic, because proper([1], []) will succeed as well as proper([],[1]), but the proper subset relation is asymmetric.
I believe the reason that your second attempt doesn't filter out identical subsets is that you have no declaration that requires A to be smaller than B.
Here are some possible solutions I came up with. I use smaller_set/2 a couple times for increased clarity and concision.
smaller_set(A, B) :-
length(A, LA),
length(B, LB),
LA < LB.
def_proper_subset/2 tries to capture the standard definition of a subset.
def_proper_subset(A, B) :-
smaller_set(A, B), % if A < B then there's some _e in B that isn't in A.
forall(member(_e, A), member(_e, B)).
An example with recursive definition, based on removeing each matching element of A and B. It assures that A < B by only succeeding if A runs out of elements before B.
rec_proper_subset1([], [_|_]).
rec_proper_subset1([_e|A], B) :-
select(_e, B, C), % C is B with _e removed. Only true if _e is in B.
rec_proper_subset1(A, C).
This one uses an auxiliarry predicate to check membership once the main predicate has already assured that A < B.
rec_proper_subset2(A, B) :-
smaller_set(A, B),
rec_proper_subset2_(A, B).
rec_proper_subset2_([], _).
rec_proper_subset2_([_e|A], B) :-
member(_e, B),
rec_proper_subset2_(A, B).
Edit:
You'll need to use list_to_set/2, sort/2, or something similar if you want to be sure that your lists don't have any duplicate elements. But these kinds of solutions will also work to find sub lists.
I think def_proper_subset/2 is a kind of crappy solution, because it will only work to check that A is a subset of B but can't generate a subset of B in A. The other two are able to thought.
(I screwed up and forgot to include the ground definition for rec_proper_subset2/2, but I have now fixed it).

Related

Merging two ordered lists ProLog

Hey so this is my code so far. I am only a begginer in prolog but i need it for school
firstElement([_|_], [Elem1|List1], [Elem2|List2]):-
Elem1 =< Elem2, merge([Elem1] , List1, [Elem2|List2]);
merge([], [Elem2], List2).
merge([Head|Tail], [Elem1|List1], [Elem2|List2]):-
Elem1 =< Elem2,!, add(Elem1,[Head|Tail],[Head|Tail1]),
merge([Head|Tail1], List1, [Elem2|List2]);
add(Elem2,[Head|Tail],[Head|Tail1]),
merge([Head|Tail1], [Elem1|List1], List2).
merge([Head|Tail], [], [Elem2|List2]):-
add(Elem2,[Head|Tail],[Head|Tail1]).
merge([Head|Tail], [Elem1|List1], []):-
add(Elem1,[Head|Tail],[Head|Tail1]).
merge([Head|Tail], [], []).
add(X,[],[X]).
add(X,[Y|Tail],[Y|Tail1]):-
add(X,Tail,Tail1).
I found out that everytime it gets out of a merge it keeps forgetting the last number so it gets back to nothing in the end.
I think you’ve gotten very mixed up here with your code. A complete solution can be had without helpers and with only a few clauses.
First let us discuss the two base cases involving empty lists:
merge(X, [], X).
merge([], X, X).
You don’t quite have these, but I see some sort of recognition that you need to handle empty lists specially in your second and third clauses, but I think you got confused and overcomplicated them. There’s really three scenarios covered by these two clauses. The case where both lists are empty is a freebie covered by both of them, but since that case would work out to merge([], [], []), it’s covered. The big idea here is that if you exhaust either list, because they were sorted, what you have left in the other list is your result. Think about it.
This leaves the interesting case, which is one where we have some items in both lists. Essentially what you want to do is select the smaller of the two, and then recur on the entire other list and the remainder of the one you selected the smaller value from. This is one clause for that:
merge([L|Ls], [R|Rs], [L|Merged]) :-
L #< R,
merge(Ls, [R|Rs], Merged).
Here’s what you should note:
The “result” has L prepended to the recursively constructed remainder.
The recursive call to merge rebuilds the entire second list, using [R|Rs].
It should be possible to build the other clause by looking at this.
As an intermediate Prolog user, I would be naturally a bit suspicious of using two clauses to do this work, because it’s going to create unnecessary choice points. As a beginner, you will be tempted to erase those choice points using cuts, which will go badly for you. A more intermediate approach would be to subsume both of the necessary clauses into one using a conditional operator:
merge([L|Ls], [R|Rs], [N|Ns]) :-
( L #< R ->
N = L, merge(Ls, [R|Rs], Ns)
; —- other case goes here
).
An expert would probably build it using if_/3 instead:
#<(X,Y,true) :- X #< Y.
#<(X,Y,false) :- X #>= Y.
merge([L|Ls], [R|Rs], [N|Ns]) :-
if_(#<(L,R),
(N = L, merge(Ls, [R|Rs], Ns)),
( -- other case here )).
Anyway, I hope this helps illustrate the situation.

Prolog - remove the non unique elements

I have a predicate to check if the element is member of list and looks the following:
member(X,[X|_]).
member(X,[_|T]) :- member(X,T).
When I called: ?- member(1,[2,3,1,4])
I get: true.
And now I have to use it to write predicate which will remove all non unique elements from list of lists like the following:
remove([[a,m,t,a],[k,a,w],[i,k,b,b],[z,m,m,c]],X).
X = [[t],[w],[i,b,b],[z,c]]
How can I do that?
Using library(reif) for
SICStus|SWI:
lists_uniques(Xss, Yss) :-
maplist(tfilter(in_unique_t(Xss)), Xss, Yss).
in_unique_t(Xss, E, T) :-
tfilter(memberd_t(E), Xss, [_|Rs]),
=(Rs, [], T).
Remark that while there is no restriction how to name a predicate, a non-relational, imperative name often hides the pure relation behind. remove is a real imperative, but we only want a relation. A relation between a list of lists and a list of lists with only unique elements.
An example usage:
?- lists_uniques([[X,b],[b]], [[X],[]]).
dif(X, b).
So in this case we have left X an uninstantiated variable. Therefore, Prolog computes the most general answer possible, figuring out what X has to look like.
(Note that the answer you have accepted incorrectly fails in this case)
Going by your example and #false's comment, the actual problem seems to be something like removing elements from each sublist that occur in any other sublist. My difficulty conceptualizing this into words has led me to build what I consider a pretty messy and gross piece of code.
So first I want a little helper predicate to sort of move member/2 up to lists of sublists.
in_sublist(X, [Sublist|_]) :- member(X, Sublist).
in_sublist(X, [_|Sublists]) :- in_sublist(X, Sublists).
This is no great piece of work, and in truth I feel like it should be inlined somehow because I just can't see myself ever wanting to use this on its own.
Now, my initial solution wasn't correct and looked like this:
remove([Sub1|Subs], [Res1|Result]) :-
findall(X, (member(X, Sub1), \+ in_sublist(X, Subs)), Res1),
remove(Subs, Result).
remove([], []).
You can see the sort of theme I'm going for here though: let's use findall/3 to enumerate the elements of the sublist in here and then we can filter out the ones that occur in the other lists. This doesn't quite do the trick, the output looks like this.
?- remove([[a,m,t,a],[k,a,w],[i,k,b,b],[z,m,m,c]], R).
R = [[t], [a, w], [i, k, b, b], [z, m, m, c]].
So, it starts off looking OK with [t] but then loses the plot with [a,w] because there is not visibility into the input [a,m,t,a] when we get to the first recursive call. There are several ways we could deal with it; a clever one would probably be to form a sort of zipper, where we have the preceding elements of the list and the succeeding ones together. Another approach would be to remove the elements in this list from all the succeeding lists before the recursive call. I went for a "simpler" solution which is messier and harder to read but took less time. I would strongly recommend you investigate the other options for readability.
remove(In, Out) :- remove(In, Out, []).
remove([Sub1|Subs], [Res1|Result], Seen) :-
findall(X, (member(X, Sub1),
\+ member(X, Seen),
\+ in_sublist(X, Subs)), Res1),
append(Sub1, Seen, Seen1),
remove(Subs, Result, Seen1).
remove([], [], _).
So basically now I'm keeping a "seen" list. Right before the recursive call, I stitch together the stuff I've seen so far and the elements of this list. This is not particularly efficient, but it seems to get the job done:
?- remove([[a,m,t,a],[k,a,w],[i,k,b,b],[z,m,m,c]], R).
R = [[t], [w], [i, b, b], [z, c]].
This strikes me as a pretty nasty problem. I'm surprised how nasty it is, honestly. I'm hoping someone else can come along and find a better solution that reads better.
Another thing to investigate would be DCGs, which can be helpful for doing these kinds of list processing tasks.

Removing unique elements from list in prolog

I am attempting to remove unique elements from a list in Prolog.
Output should look something like:
?- rem_Uniq([3,3,1,7,a,c,c],D).
D = [3, c].
Here is my current code.
rem_Uniq(L1,L2).
rem_Uniq([L1|RL1], [L1|D]) :-
member(L1,RL1),
rem_Uniq(RL1,D).
rem_Uniq([L1|RL1], D) :-
remove(L1[L1|RL1], O),
rem_Uniq(O, D).
Currently it just returns true no matter what I do (whether I enter I list containing unique variables or not).
Anyone have any ideas or suggestions on what I am doing wrong?
D is the set of elements of the list which appears only one time.
In Prolog "an element which appears only one time in a list" can be translate by
select(X, L, L_X),
\+member(X, L_X)
In Prolog exist predicates that collect element with a certain property setof/3 and bagof/3.
bagof collect all the elements, setof keeps only one element.
So you can write
rem_uniq(In, Out) :-
setof(X, In_X^(select(X, In, In_X),\+member(X, In_X)), Out).
[EDIT]
Now we want only elements that are duplicated in a list. If I remove one of these elements of the list, it will remain other elements of the same value in the list so it can be translated in Prolog by
select(X, In, In_X),
member(X, In_X)
(we say that select(X, In, In_X),member(X, In_X) succeed).
Now the code can be written
rem_uniq(In, Out) :-
setof(X, In_X^(select(X, In, In_X),member(X, In_X)), Out).
For example
?- rem_uniq([3,3,1,7,a,c,c],D).
D = [3,c].
Note that setof will fail if there no elements available
?- rem_uniq([3,1,7,a,c],D).
false.
Well, your first problem is your first clause:
rem_Uniq(L1,L2).
This literally says "Any two things are rem_Uniq to each other." This is what's giving rise to always getting true with no unifications. You probably meant this:
rem_Uniq([], []).
Your second problem is that this is not valid syntax:
remove(L1[L1|RL1], O),
Specifically, L1[L1|RL1], I am unclear what you meant there. I think you meant this delete(L1, [L1|RL1], O).
Now, algorithmically, I think you're a little confused. In clause #2, you prepend L1 to D in the result, which is to say, after knowing that L1 is present in RL1 and using the recursive call to remove it from D. But then in clause #3, you just remove it from [L1|RL1] to make O, which you then remove uniques from.
Each clause of a recursive predicate should represent a case you have to worry about. I don't really see what these clauses mean. The first one should be, in case where the list is empty. The second one should be the case where the list is not empty. What you seem to be trying to do here is something like, in the case where the list is not empty and contains the head element, and the case where it is not empty and does not contain the head element, but the distinction between having or not having that element is (or ought to be) meaningless to your library routine. In other words, delete/3 in one non-empty recursive case should be totally sufficient for this problem:
rem_uniq([], []).
rem_uniq([X|Xs], [X|UniqueXs]) :-
delete(X, Xs, XsWithoutX),
rem_uniq(XsWithoutX, UniqueXs).
So, I think you have a little confusion about when and why you should have multiple clauses, and I think your choice of variable names may have made life harder on yourself. But that's just my guess.
Hope this helps!

What exactly is member(b,X)?

Today I came across this query:
?- member(b,X).
The program was:
member(X,[X|_]).
member(X,[_|T]) :-
member(X,T),
!.
When I ran the query, I got these answers:
?- member(b,X).
X = [b|_G1560] ;
X = [_G1559, b|_G1563].
What exactly is that? What does this query do?
The query member(b,X) generates lists containing b. As the second argument is not instantiated, you have a (theoretically) infinite number of solutions. The first solution will have b in the first position, the second solution will have b in the second position and so on. Moreover, if you look closely to any of the solutions, you see that it represents any list with a b on that position. For example, the first solution is [b| _]. As the list tail is not instantiated (see the member/2 predicate base case), this solution unifies with any list with b in the head position.
If you want to make the member/2 deterministic, i.e. if you want to use the predicate only to check if a term is a member of a list, you will need to add a cut in the base clause, not in the recursive clause as #false noted:
member(Head, [Head| _]) :-
!.
member(Head, [_| Tail]) :-
member(Head, Tail).
The resulting predicate is usually named memberchk/2 and available as such as a library predicate.

Prolog: Related predicates with permuted arguments

Is there a way to declare the following in Prolog without being caught in an endless recursion?
left([X,Y], Z) :- left([Z,X], Y); left([Y,Z], X).
The semantics is that the list represents a vector given by two points and the second argument is a third point lying left of the vector.
A related question is, how one can declare the relation of "left" and "right" given by:
left([X,Y], Z) :- right([Y,X], Z).
without getting an endless recursion.
Unfortunately, you cannot do this directly in Prolog. You can express commutative relationships by introducing a predicate that enumerates the permutations for the fact, so for example:
left_of(A, B, C) :- left(A, B, C).
left_of(A, B, C) :- left(C, A, B).
left_of(A, B, C) :- left(B, C, A).
left(a, b, c).
Now the query should be
?- left_of(A, B, C).
Similarly, you should define right_of in terms of left.
Several things worth noting:
Keep the three arguments separate, as shown. It is good practice not to introduce unnecessary structures.
Prefer explicit clauses, instead of ;. It makes your code far more obvious. The ; is really easy to miss when reading the code; if you use it, put it at the beginning of the line, not in the middle somewhere or at the end
Prolog implementations that support tabling do not have this problem.

Resources