Prolog, error with exclusive OR - prolog

i am new to prolog, and i want to make a simple expert system that uses prepositions, and i am struggling to use exclusive OR. Here is my program so far:
/*facts*/
a.
b.
c.
/*rules*/
e :- c.
d :- a, \+e.
f :- xor(b, d). /*here is where it gives me an error*/
/*query*/
?- f.
/*error*/
ERROR: f/0: Undefined procedure: (xor)/2
Exception: (8) b xor d ? no debug
?-

I don't think this is the better way to solve your problem, but anyway...
?- X is 1 xor 0.
X = 1.
?- X is 1 xor 1.
X = 0.
so
:- meta_predicate xor(0,0).
% reify arguments and apply usual boolean
xor(A, B) :-
( call(A) -> X=1 ; X=0 ),
( call(B) -> Y=1 ; Y=0 ),
1 is X xor Y.
and now
?- xor(true,false).
true.
?- xor(true,true).
false.
?- xor(true,1 is 7-6).
false.

Related

Why is my prolog program stucked in endless recursion

I have the following experimental code
s(a,b).
s(b,c).
s(c,b).
r(a).
r(c).
r(d).
p(X,Y) :- s(X,Y), not(r(Y)).
q(X,Y) :- q(Y,X), r(X).
q(X,Y) :- p(Y,X), s(X,Y).
t(X,Y) :- r(X), q(X,Y).
Querying for t(X,Y) will result in a endless recursion blowing up the stack. But I can actually think of X=c,Y=b being the solution because
t(c,b) <- r(c), q(c,b)
q(c,b) <- q(b,c), r(c)
q(b,c) <- p(c,b), s(b,c)
p(c,b) <- s(c,b), not(r(b))
Can someone explain to me, why prolog doesn't come to this solution and gets caught in an endless recursion around q(c,b) and q(b,c)
Many thanks!
In SWI-Prolog, you can solve the problem using tabled execution.
:- table q/2.
s(a,b).
s(b,c).
s(c,b).
r(a).
r(c).
r(d).
p(X,Y) :- s(X,Y), not(r(Y)).
q(X,Y) :- q(Y,X), r(X).
q(X,Y) :- p(Y,X), s(X,Y).
t(X,Y) :- r(X), q(X,Y).
Examples:
?- t(X,Y).
X = c,
Y = b ;
false.
?- q(X,Y).
X = c,
Y = b ;
X = b,
Y = c.

Pure Prolog Peano Number Apartness

Lets assume there is pure_2 Prolog with dif/2 and pure_1 Prolog without dif/2. Can we realize
Peano apartness for values, i.e. Peano numbers, without using dif/2? Thus lets assume we have Peano apartness like this in pure_2 Prolog:
/* pure_2 Prolog */
neq(X, Y) :- dif(X, Y).
Can we replace neq(X,Y) by a more pure definition, namely from pure_1 Prolog that doesn't use dif/2? So that we have a terminating neq/2 predicate that can decide inequality for Peano numbers? So what would be its definition?
/* pure_1 Prolog */
neq(X, Y) :- ??
Using less from this comment:
less(0, s(_)).
less(s(X), s(Y)) :- less(X, Y).
neq(X, Y) :- less(X, Y); less(Y, X).
I had something else in mind, which is derived from two of the Peano Axioms, which is also part of Robinson Arithmetic. The first axiom is already a Horn clause talking about apartness:
∀x(0 ≠ S(x))
∀x∀y(S(x) = S(y) ⇒ x = y)
Applying contraposition to the second axiom gives.
The axiom is now a Horn clause talking about apartness:
∀x∀y(x ≠ y ⇒ S(x) ≠ S(y))
Now we have everything to write some Prolog code.
Adding some symmetry we get:
neq(0, s(_)).
neq(s(_), 0).
neq(s(X), s(Y)) :- neq(X, Y).
Here are some example queries. Whether the predicate leaves a choice
point depends on the Prolog system. I get:
SWI-Prolog 8.3.15 (some choice point):
?- neq(s(s(0)), s(s(0))).
false.
?- neq(s(s(0)), s(0)).
true ;
false.
Jekejeke Prolog 1.4.6 (no choice point):
?- neq(s(s(0)), s(s(0))).
No
?- neq(s(s(0)), s(0)).
Yes
Just removing the unwanted choicepoint (in swi-prolog) from user502187's answer:
neq(0, s(_)).
neq(s(N), M) :-
% Switch args, to use first-arg indexing
neq_(M, s(N)).
neq_(0, s(_)).
neq_(s(N), s(M)) :-
% Switch args back, to fix choicepoint
neq(M, N).
Results in swi-prolog:
?- neq(s(s(0)), s(0)).
true.
?- neq(s(0), s(s(0))).
true.
?- neq(N, M).
N = 0,
M = s(_) ;
N = s(_),
M = 0 ;
N = s(s(_)),
M = s(0) ;
N = s(0),
M = s(s(_)) ;
N = s(s(0)),
M = s(s(s(_))) ;
N = s(s(s(_))),
M = s(s(0)) ;

Prolog membership predicate without dif or when

The following prolog logic
memberd(X, [X|_T]).
memberd(X, [Y| T]) :- dif(X,Y), memberd(X, T).
will produce
?- memberd(a, [a, b, a]).
true
?- memberd(X, [a, b, a]).
X = a ;
X = b ;
false.
?- memberd(X, [a, b, a, c, a, d, b]).
X = a ;
X = b ;
X = c ;
X = d ;
false.
is there prolog logic that can be used to produce the same result without using when() or dif() function or anything from a loaded prolog library. Just using pure logic?
To answer your question literally, just use:
?- setof(t, member(X, [a,b,a]), _).
X = a
; X = b.
However, some answers will be suboptimal:
?- setof(t,member(a,[a,X]),_).
true
; X = a. % redundant
... whereas memberd/2 answers in perfection:
?- memberd(a,[a,X]).
true
; false.
In fact, if you use library(reif) with
memberd(E, [X|Xs]) :-
if_(E = X, true, memberd(E, Xs) ).
you get the best answer possible:
?- memberd(a,[a,X]).
true.

Prolog - using negation (declarative approach) to define member/2 to only succeed once for each number

I'm trying to write an alternative definition to member/2 which will won't return repetitions of numbers (i.e. will only succeed once for each element). I've currently got this code working using the cut procedurally:
once_member(X,[H|T]) :-
member(H,T),
!,
once_member(X,T).
once_member(H,[H|_]).
once_member(X,[_|T]) :-
once_member(X,T).
However, I'm aware that you can also use negation in a declarative approach to do this but I can't work out how to do it. If anyone could point me in the right direction that'd be great.
It is very simple using dif/2:
once_member(X, [X|_]).
once_member(X, [Y|T]) :-
dif(X, Y),
once_member(X, T).
1 ?- once_member(A, [1,2,3,3,4]).
A = 1 ;
A = 2 ;
A = 3 ;
A = 4 ;
false.
2 ?- X = a, once_member(X,[A,b]).
X = A, A = a ;
false.
3 ?- once_member(X,[A,b]), X = a.
X = A, A = a ;
false.

Predicate that pick elements which are on list twice not less not more

I'm trying to write a predicate twice(El,L) which will return true. when El is on list exactly twice. Here is what I have:
twice(El,L) :- select(El,L,L1), member(El,L1), \+ twice(El,L1).
It works nice for twice(2,[1,2,2,3,4])
but for twice(X,[1,1,2,2,3,3]) it doubles every number X = 1 ; X = 1 ; X = 2... How could I avoid this without using any accumulator?
You want to describe a sequence of elements. For such, there is a special formalism in Prolog called Definite Clause Grammars. Before using the formalism, let's try to figure out how a sequence with E occurring exactly twice looks like:
First, is a possibly empty sequence which does not contain E
then, there is one occurrence of E
then again a possibly empty sequence without E
then, there is the second occurrence of E
then again a possibly empty sequence without E.
Now, to put this into the DCG formalism
twice(E, L) :-
phrase(twice_occurring(E), L). % Interface
twice_occurring(E) -->
seq_without(E), % 1.
[E], % 2.
seq_without(E), % 3.
[E], % 4.
seq_without(E). % 5.
seq_without(_E) -->
[].
seq_without(E) -->
[X],
{dif(X,E)},
seq_without(E).
Or, more compactly by using all//1 and avoiding auxiliary definitions:
twice(E, L) :-
phrase(( all(dif(E)), [E], all(dif(E)), [E], all(dif(E)) ), L).
There is essentially only one drawback with these definitions: On current systems, they are not optimally implemented. See this if you want to know more.
Stay both logically pure and efficient by using if_/3 and
(=)/3 by #false. It goes like this:
list_member1x([X|Xs],E) :-
if_(X=E, maplist(dif(E),Xs), list_member1x(Xs,E)).
list_member2x([X|Xs],E) :-
if_(X=E, list_member1x(Xs,E), list_member2x(Xs,E)).
twice(E,Xs) :-
list_member2x(Xs,E).
That's it. Let's run some queries!
?- twice(E,[1,2,3,4,5,2,3,4]).
E = 2 ;
E = 3 ;
E = 4 ;
false.
Now something a little more general:
?- twice(X,[A,B,C,D]).
A=X , B=X , dif(C,X), dif(D,X) ;
A=X , dif(B,X), C=X , dif(D,X) ;
A=X , dif(B,X), dif(C,X), D=X ;
dif(A,X), B=X , C=X , dif(D,X) ;
dif(A,X), B=X , dif(C,X), D=X ;
dif(A,X), dif(B,X), C=X , D=X ;
false.
Here are the queries the OP gave:
?- twice(2,[1,2,2,3,4]).
true.
?- twice(E,[1,1,2,2,3,3]).
E = 1 ;
E = 2 ;
E = 3 ;
false.
Edit
As an alternative, use meta-predicate tcount/3 in combination with (=)/3 like this:
twice(E,Xs) :- tcount(=(E),Xs,2).
Try:
twice(E,L) :-
append(B1,[E|A1],L),
\+ member(E,B1),
append(B2,[E|A2],A1),
\+ member(E,B2),
\+ member(E,A2).
Addendum
In case that the list of number could be (partially) unbound, following variant solves the issues. It uses "dif" instead of "\=", "+". In addition, it is a few optimized ("append" and "member" have been joined to a single "appendchk"):
appendchk(L,L).
appendchk([E|Q2],[H|R]) :-
dif(H,E),
appendchk([E|Q2],R).
notmember(_,[]).
notmember(X,[H|Q]) :-
dif(X,H),
notmember(X,Q).
twice(E,L) :-
appendchk([E|A1],L),
appendchk([E|A2],A1),
notmember(E,A2).
Examples:
twice(1,[1,2,3,4,2,3,2]).
false
twice(2,[1,2,3,4,2,3,2]).
false
twice(3,[1,2,3,4,2,3,2]).
true
twice(X,[1,2,3,4,2,3,2]).
X = 3
false
twice(X,[A,B]).
A = B, B = X
twice(X,[A,B,C]).
A = B, B = X,
dif(X, C)
A = C, C = X,
dif(B, X)
B = C, C = X,
dif(A, X)
Here is how we can declare, courtesy library(aggregate), the required constraint:
twice(El, L) :-
aggregate(count, P^nth1(P,L,El), 2).
Where list' elements are restricted to integers, library(clpfd) reification hint hosts another solution:
twice(El, L) :- vs_n_num(L,El,2).
% aggregate(count, P^nth1(P,L,El), 2).

Resources