Prolog: indicating which predicate is true in an OR rule - prolog

In SWI-Prolog I have some facts and I have rule that is composed of those facts in a disjunction like so:
father(a, b).
mother(a, c).
parent(A, X) :- father(A, X); mother(A, X).
This is all fine and all, and when I query I get this:
?- parent(a, X).
X = b ;
X = c.
I wonder if there's a way to write a rule that indicates which predicate was true for each result, like so:
?- parent(a, X).
X = b, R = father ;
X = c, R = mother.
Thank you!

Terms are an easy way to classify/categorize data, as an alternative to adding another variable, e.g.:
father(a, b).
mother(a, c).
parent(father(F), C) :- father(F, C).
parent(mother(M), C) :- mother(M, C).
Result in swi-prolog:
?- parent(P, C).
P = father(a),
C = b ;
P = mother(a),
C = c.
Here the parent has retained a categorization of father/mother rule, by creating the corresponding term.

You can also change your predicate to indicate if two persons are related, and how:
related(A, B, father(A,B)) :- father(A,B).
related(A, B, mother(A,B)) :- mother(A,B).
And maybe add a more general rule that indicates if there is a chain of relationships between to persons.
related(A, B, (R1,R2)) :- related(A,Z,R1), related(Z,B,R2).

If you don't want to rewrite your program you can trace it instead. This isn't in any way better than the other answers, it is just a different way to do it.
If I trace mother/2 and father/2, and only the exit port so I only see the success:
?- trace(mother/2, +exit), trace(father/2, +exit).
% mother/2: [exit]
% father/2: [exit]
true.
?- parent(a, X).
T [11] Exit: father(a, b)
X = b ;
T [11] Exit: mother(a, c)
X = c.
The predicates are documented here: https://www.swi-prolog.org/pldoc/man?section=debugger
There is a very nice tutorial-style overview here: https://www.swi-prolog.org/pldoc/man?section=debugoverview
I used this section in particular to answer your question: https://www.swi-prolog.org/pldoc/man?section=trace-mode-vs-point

Related

Is there a non-unifying alternative to member/2 in SWI-Prolog?

In prolog, the difference between A = B and A == B is that = tries to unify A with B, while == will only succeed if A and B are already unified.
member/2 does seem to perform unification.
Example session:
?- A = B.
A = B.
?- A == B.
false.
?- member(A, [B]).
A = B.
I have been looking but I can't find a non-unifying alternative to member/2, but not found anything. Is there something built in or do I have to invent my own thing? As I'm rather new to Prolog I don't trust myself with writing a performant version of this.
EDIT:
I came up with the following, though I don't know if the cut is correct. Without it, it seems to deliver two answers for that branch of the code (true, followed by false) though. I'd also still like to know if there is a standard library function for this.
member_eq(_, []) :-
false.
member_eq(X, [H|_]) :-
X == H,
!.
member_eq(X, [_|T]) :-
member_eq(X, T).
You may slightly modify builtin predicate member/2 to use ==/2 instead of unification:
member_not_bind(X, [H|T]) :-
member_not_bind_(T, X, H).
member_not_bind_(_, X, Y):- X==Y.
member_not_bind_([H|T], X, _) :-
member_not_bind_(T, X, H).
Sample run:
?- L=[a,b,c(E)], member_not_bind(A, L).
false.
?- A=c(E),L=[a,b,c(E)], member_not_bind(A, L).
A = c(E),
L = [a, b, c(E)].
I leave this here as it solves a related question (checking if X may unify with any item in L without actually performing the bindings)
You can use double negation like this:
member_not_bind(X, L):- \+(\+(member(X, L))).
Sample runs:
?- A=c(e),L=[a,b,c(E)], member_not_bind(A, L).
A = c(e),
L = [a, b, c(E)].
?- A=d(E),L=[a,b,c(E)], member_not_bind(A, L).
false.

The unification algorithm in Prolog

I'm trying to program the unification algorithm in Prolog to verify if two expressions can unify by returning boolean True/False:
EDIT.
I found this implementation usefull:
from: http://kti.mff.cuni.cz/~bartak/prolog/data_struct.html
unify(A,B):-
atomic(A),atomic(B),A=B.
unify(A,B):-
var(A),A=B. % without occurs check
unify(A,B):-
nonvar(A),var(B),A=B. % without occurs check
unify(A,B):-
compound(A),compound(B),
A=..[F|ArgsA],B=..[F|ArgsB],
unify_args(ArgsA,ArgsB).
unify_args([A|TA],[B|TB]):-
unify(A,B),
unify_args(TA,TB).
unify_args([],[]).```
Here is a partial implementation of something like the Martelli and Montanari unification algorithm described at https://en.wikipedia.org/wiki/Unification_(computer_science)#A_unification_algorithm. The comments for each part refer to the corresponding rewrite rule from the algorithm. Note that there is no need for an explicit conflict rule, we can just fail if no other rule applies.
% assuming a universe with function symbols g/2, p/2, q/2
% identical terms unify (delete rule)
unify(X, Y) :-
X == Y,
!.
% a variable unifies with anything (eliminate rule)
unify(X, Y) :-
var(X),
!,
X = Y.
% an equation Term = Variable can be solved as Variable = Term (swap rule)
unify(X, Y) :-
var(Y),
!,
unify(Y, X).
% given equal function symbols, unify the arguments (decompose rule)
unify(g(A, B), g(X, Y)) :-
unify(A, X),
unify(B, Y).
unify(p(A, B), p(X, Y)) :-
unify(A, X),
unify(B, Y).
unify(q(A, B), q(X, Y)) :-
unify(A, X),
unify(B, Y).
Examples:
?- unify(q(Y,g(a,b)), p(g(X,X),Y)).
false.
?- unify(q(Y,g(a,b)), q(g(X,X),Y)).
false.
?- unify(q(Y,g(a,a)), q(g(X,X),Y)).
Y = g(a, a),
X = a.
One or two things remain for you to do:
Generalize the decompose rule to deal with arbitrary terms. You might find the =.. operator useful. For example:
?- Term = r(a, b, c), Term =.. FunctorAndArgs, [Functor | Args] = FunctorAndArgs.
Term = r(a, b, c),
FunctorAndArgs = [r, a, b, c],
Functor = r,
Args = [a, b, c].
You will need to check if two terms have the same functor and the same number of arguments, and whether all corresponding pairs of arguments unify.
Find out if your professor would like you to implement the occurs check, and if yes, implement it.

(SWI)Prolog: Order of sub-goals

I have two, slightly different, implementations of a predicate, unique_element/2, in Prolog. The predicate succeeds when given an element X and a list L, the element X appears only once in the list. Below are the implementations and the results:
Implementation 1:
%%% unique_element/2
unique_element(Elem, [Elem|T]) :-
not(member(Elem, T)).
unique_element(Elem, [H|T]) :-
member(Elem, T),
H\==Elem,
unique_element(Elem, T),
!.
Results:
?- unique_element(X, [a, a, b, c, c, b]).
false.
?- unique_element(X, [a, b, c, c, b, d]).
X = a ;
X = d.
Implementation 2:
%%% unique_element/2
unique_element(Elem, [Elem|T]) :-
not(member(Elem, T)).
unique_element(Elem, [H|T]) :-
H\==Elem,
member(Elem, T),
unique_element(Elem, T),
!.
In case you didn't notice at first sight: H\==Elem and member(Elem, T) are flipped on the 2nd impl, rule 2.
Results:
?- unique_element(X, [a, a, b, c, c, b]).
X = a.
?- unique_element(X, [a, b, c, c, b, d]).
X = a ;
X = d.
Question: How does the order, in this case, affect the result? I realize that the order of the rules/facts/etc matters. The two specific rules that are flipped though, don't seem to be "connected" or affect each other somehow (e.g. a cut in the wrong place/order).
Note: We are talking about SWI-Prolog here.
Note 2: I am aware of, probably different and better implementations. My question here is about the order of sub-goals being changed.
H\==Elem is testing for syntactic inequality at the point in time when the goal is executed. But later unification might make variables identical:
?- H\==Elem, H = Elem.
H = Elem.
?- H\==Elem, H = Elem, H\==Elem.
false.
So here we test if they are (syntactically) different, and then they are unified nevertheless and thus are no longer different. It is thus just a temporary test.
The goal member(Elem, T) on the other hand is true if that Elem is actually an element of T. Consider:
?- member(Elem, [X]).
Elem = X.
Which can be read as
(When) does it hold that Elem is an element of the list [X]?
and the answer is
It holds under certain circumstances, namely when Elem = X.
If you now mix those different kinds of goals in your programs you get odd results that can only explained by inspecting your program in detail.
As a beginner, it is best to stick to the pure parts of Prolog only. In your case:
use dif/2 in place of \==
do not use cuts - in your case it limits the number of answers to two. As in
unique_element(X, [a,b,c])
do not use not/1 nor (\+)/1. It produces even more incorrectness. Consider unique_element(a,[a,X]),X=b. which incorrectly fails while X=b,unique_element(a,[a,X]) correctly succeeds.
Here is a directly purified version of your program. There is still room for improvement!
non_member(_X, []).
non_member(X, [E|Es]) :-
dif(X, E),
non_member(X, Es).
unique_element(Elem, [Elem|T]) :-
non_member(Elem, T).
unique_element(Elem, [H|T]) :-
dif(H,Elem),
% member(Elem, T), % makes unique_element(a,[b,a,a|Xs]) loop
unique_element(Elem, T).
?- unique_element(a,[a,X]).
dif(X, a)
; false. % superfluous
?- unique_element(X,[E1,E2,E3]).
X = E1, dif(E1, E3), dif(E1, E2)
; X = E2, dif(E2, E3), dif(E1, E2)
; X = E3, dif(E2, E3), dif(E1, E3)
; false.
Note how the last query reads?
When is X a unique element of (any) list [E1,E2,E3]?
The answer is threefold. Considering one element after the other:
X is E1 but only if it is different to E2 and E3
etc.
TL;DR: Read the documentation and figure out why:
?- X = a, X \== a.
false.
?- X \== a, X = a.
X = a.
I wonder why you stop so close from figuring it out yourself ;-)
There are too many ways to compare things in Prolog. At the very least, you have unification, which sometimes can compare, and sometimes does more; than you have equvalence, and its negation, the one you are using. So what does it do:
?- a \== b. % two different ground terms
true.
?- a \== a. % the same ground term
false.
Now it gets interesting:
?- X \== a. % a free variable and a ground term
true.
?- X \== X. % the same free variable
false.
?- X \== Y. % two different free variables
true.
I would suggest that you do the following: figure out how member/2 does its thing (does it use unification? equivalence? something else?) then replace whatever member/2 is using in all the examples above and see if the results are any different.
And since you are trying to make sure that things are different, try out what dif/2 does. As in:
?- dif(a, b).
or
?- dif(X, X).
or
?- dif(X, a).
and so on.
See also this question and answers: I think the answers are relevant to your question.
Hope that helps.
Here is another possibility do define unique_element/2 using if_/3 and maplist/2:
:- use_module(library(apply)).
unique_element(Y,[X|Xs]) :-
if_(Y=X,maplist(dif(Y),Xs),unique_element(Y,Xs)).
In contrast to #user27815's very elegant solution (+s(0)) this version does not build on clpfd (used by tcount/3). The example queries given by the OP work as expected:
?- unique_element(a,[a, a, b, c, c, b]).
no
?- unique_element(X,[a, b, c, c, b, d]).
X = a ? ;
X = d ? ;
no
The example provided by #false now succeeds without leaving a superfluous choicepoint:
?- unique_element(a,[a,X]).
dif(a,X)
The other more general query yields the same results:
?- unique_element(X,[E1,E2,E3]).
E1 = X,
dif(X,E3),
dif(X,E2) ? ;
E2 = X,
dif(X,E3),
dif(X,E1) ? ;
E3 = X,
dif(X,E2),
dif(X,E1) ? ;
no
Can you not define unique_element like tcount Prolog - count repetitions in list
unique_element(X, List):- tcount(=(X),List,1).

Split a list in separate lists

I have to define some more constraints for my list.
I want to split my list is separate lists.
Example:
List=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2,0],[4,0]]
I need three Lists which i get from the main list:
[[_,0],[_,0],[_,0]] and [[_,0]] and [[2,0],[4,0]]
SO I always need a group of lists between a term with [X,1].
It would be great if u could give me a tip. Don’t want the solution, only a tip how to solve this.
Jörg
This implementation tries to preserve logical-purity without restricting the list items to be [_,_], like
#false's answer does.
I can see that imposing above restriction does make a lot of sense... still I would like to lift it---and attack the more general problem.
The following is based on if_/3, splitlistIf/3 and reified predicate, marker_truth/2.
marker_truth(M,T) reifies the "marker"-ness of M into the truth value T (true or false).
is_marker([_,1]). % non-reified
marker_truth([_,1],true). % reified: variant #1
marker_truth(Xs,false) :-
dif(Xs,[_,1]).
Easy enough! Let's try splitlistIf/3 and marker_truth/2 together in a query:
?- Ls=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2,0],[4,0]],
splitlistIf(marker_truth,Ls,Pss).
Ls = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0],[4,0]],
Pss = [ [[_A,0],[_B,0],[_C,0]], [[_D,0]], [[2,0],[4,0]]] ? ; % OK
Ls = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0],[4,0]],
Pss = [ [[_A,0],[_B,0],[_C,0]], [[_D,0],[9,1],[2,0],[4,0]]],
prolog:dif([9,1],[_E,1]) ? ; % BAD
%% query aborted (6 other BAD answers omitted)
D'oh!
The second answer shown above is certainly not what we wanted.
Clearly, splitlistIf/3 should have split Ls at that point,
as the goal is_marker([9,1]) succeeds. It didn't. Instead, we got an answer with a frozen dif/2 goal that will never be woken up, because it is waiting for the instantiation of the anonymous variable _E.
Guess who's to blame! The second clause of marker_truth/2:
marker_truth(Xs,false) :- dif(Xs,[_,1]). % BAD
What can we do about it? Use our own inequality predicate that doesn't freeze on a variable which will never be instantiated:
marker_truth(Xs,Truth) :- % variant #2
freeze(Xs, marker_truth__1(Xs,Truth)).
marker_truth__1(Xs,Truth) :-
( Xs = [_|Xs0]
-> freeze(Xs0, marker_truth__2(Xs0,Truth))
; Truth = false
).
marker_truth__2(Xs,Truth) :-
( Xs = [X|Xs0]
-> when((nonvar(X);nonvar(Xs0)), marker_truth__3(X,Xs0,Truth))
; Truth = false
).
marker_truth__3(X,Xs0,Truth) :- % X or Xs0 have become nonvar
( nonvar(X)
-> ( X == 1
-> freeze(Xs0,(Xs0 == [] -> Truth = true ; Truth = false))
; Truth = false
)
; Xs0 == []
-> freeze(X,(X == 1 -> Truth = true ; Truth = false))
; Truth = false
).
All this code, for expressing the safe logical negation of is_marker([_,1])? UGLY!
Let's see if it (at least) helped above query (the one which gave so many useless answers)!
?- Ls=[[1,1],[_,0],[_,0],[_,0],[3,1],[_,0],[9,1],[2,0],[4,0]],
splitlistIf(marker_truth,Ls,Pss).
Ls = [[1,1],[_A,0],[_B,0],[_C,0],[3,1],[_D,0],[9,1],[2,0],[4,0]],
Pss = [[ [_A,0],[_B,0],[_C,0]], [[_D,0]], [[2,0],[4,0]]] ? ;
no
It works! When considering the coding effort required, however, it is clear that either a code generation scheme or a
variant of dif/2 (which shows above behaviour) will have to be devised.
Edit 2015-05-25
Above implementation marker_truth/2 somewhat works, but leaves a lot to be desired. Consider:
?- marker_truth(M,Truth). % most general use
freeze(M, marker_truth__1(M, Truth)).
This answer is not what we would like to get. To see why not, let's look at the answers of a comparable use of integer_truth/2:
?- integer_truth(I,Truth). % most general use
Truth = true, freeze(I, integer(I)) ;
Truth = false, freeze(I, \+integer(I)).
Two answers in the most general case---that's how a reified predicate should behave like!
Let's recode marker_truth/2 accordingly:
marker_truth(Xs,Truth) :- subsumes_term([_,1],Xs), !, Truth = true.
marker_truth(Xs,Truth) :- Xs \= [_,1], !, Truth = false.
marker_truth([_,1],true).
marker_truth(Xs ,false) :- nonMarker__1(Xs).
nonMarker__1(T) :- var(T), !, freeze(T,nonMarker__1(T)).
nonMarker__1(T) :- T = [_|Arg], !, nonMarker__2(Arg).
nonMarker__1(_).
nonMarker__2(T) :- var(T), !, freeze(T,nonMarker__2(T)).
nonMarker__2(T) :- T = [_|_], !, dif(T,[1]).
nonMarker__2(_).
Let's re-run above query with the new implementation of marker_truth/2:
?- marker_truth(M,Truth). % most general use
Truth = true, M = [_A,1] ;
Truth = false, freeze(M, nonMarker__1(M)).
It is not clear what you mean by a "group of lists". In your example you start with [1,1] which fits your criterion of [_,1]. So shouldn't there be an empty list in the beginning? Or maybe you meant that it all starts with such a marker?
And what if there are further markers around?
First you need to define the criterion for a marker element. This for both cases: When it applies and when it does not apply and thus this is an element in between.
marker([_,1]).
nonmarker([_,C]) :-
dif(1, C).
Note that with these predicates we imply that every element has to be [_,_]. You did not state it, but it does make sense.
split(Xs, As, Bs, Cs) :-
phrase(three_seqs(As, Bs, Cs), Xs).
marker -->
[E],
{marker(E)}.
three_seqs(As, Bs, Cs) -->
marker,
all_seq(nonmarker, As),
marker,
all_seq(nonmarker, Bs),
marker,
all_seq(nonmarker, Cs).
For a definition of all_seq//2 see this
In place of marker, one could write all_seq(marker,[_])
You can use a predicate like append/3. For example, to split a list on the first occurence of the atom x in it, you would say:
?- L = [a,b,c,d,x,e,f,g,x,h,i,j], once(append(Before, [x|After], L)).
L = [a, b, c, d, x, e, f, g, x|...],
Before = [a, b, c, d],
After = [e, f, g, x, h, i, j].
As #false has pointed out, putting an extra requirement might change your result, but this is what is nice about using append/3:
"Split the list on x so that the second part starts with h:
?- L = [a,b,c,d,x,e,f,g,x,h,i,j], After = [h|_], append(Before, [x|After], L).
L = [a, b, c, d, x, e, f, g, x|...],
After = [h, i, j],
Before = [a, b, c, d, x, e, f, g].
This is just the tip.

Prolog , Append with no repititions

Hey I'm trying to append two list with no "double" members
for example
A = [a, b, c]
B = [x, c, q]
then ->
append2(A,B,P)
P= [a,b,c,x,q]
I write this code, but it doesn't work...
not_member(_, []).
not_member(X, [Y|Ys]) :- X \= Y, not_member(X, Ys).
append2(A, [], A).
append2([], A, A).
append2([h1|ls], B, [h1|P]) :- not_member(h1, B), !, append2(ls, B, P).
append2([h1|ls], B, P) :- member(h1, P), append2(ls, B, P).
Thanks for helping :)
Assuming there are no variables in your input lists, but allowing duplicates in each list you may write:
append2(A,B,C):-
findall(Item, append2_item(A,B,Item), C).
append2_item(A,_,ItemA):-
append(HeadA, [ItemA|_], A),
\+ member(ItemA, HeadA).
append2_item(A,B,ItemB):-
append(HeadB, [ItemB|_], B),
\+ member(ItemB, HeadB),
\+ member(ItemB, A).
First clause of append2_item/3 selects (ordered) distinct items from the first list. Second clause of append2_item/3 selects (ordered) distinct items from the second list which are not present in the first list.
append2/3 just collects those elements.
Test case:
?- append2([a,b,c,a],[x,c,q,x],C).
C = [a, b, c, x, q].
Check out the pure code in my answer
to the related question "intersection and union of 2 lists"!
Telling from your requirements, predicate list_list_union/3 is just what you are looking for:
?- list_list_union([a,b,c],[x,c,q],Ls).
Ls = [a,b,c,x,q]. % succeeds deterministically
list_list_union/3 is monotone, so we get sound answers
even when using non-ground terms:
?- As = [_,_,_], Bs = [_,_,_], list_list_union(As,Bs,Ls), As = [a,b,c], Bs = [x,c,q].
As = [a,b,c], Bs = [x,c,q], Ls = [a,b,c,x,q] ; % logically sound result
false.

Resources