How to bi-unify a term's operator in Prolog? - prolog

I just asked the question in How to unify a term's operator in Prolog? and got good answers.
However, it doesn't completely solve my problem, i.e. =.. only works for single-side.
For example,
test(Expr) :-
1 + 2 = Expr.
test(Expr) :-
1 * 2 = Expr.
?- E =.. [Op, X, Y], test(E). % E can not be a variable!
ERROR: Arguments are not sufficiently instantiated
I hope the query returns
Op = (+),
X = 1,
Y = 2;
Op = (*),
X = 1,
Y = 2.
Very thanks.

expr_op_x_y(Expr, Op, X, Y) :-
when((nonvar(Expr) ; nonvar(Op)), Expr =.. [Op, X, Y]).
?- expr_op_x_y(Expr, Op, X, Y).
when((nonvar(Expr);nonvar(Op)),Expr=..[Op,X,Y]).
?- expr_op_x_y(Expr, Op, X, Y), Op = (+).
Expr = X+Y, Op = (+).
?- expr_op_x_y(Expr, Op, X, Y), Expr = 1+2.
Expr = 1+2, Op = (+), X = 1, Y = 2.
This could also be called a boomy univ for entirely historical reasons.

Related

Boolean unification in Prolog?

I am struggling alreay for a long time with the
following problem. I want to make the usual unification
of Prolog more smart.
Basically I want that certain variables understand that
for example 0 = ~1 and 1 = ~0. This doesn't work normally:
?- op(300, fy, ~).
true.
?- X = ~Y, Y = 0.
X = ~0,
Y = 0.
I know that that CLP(B) can do it:
Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.7)
:- use_module(library(clpb)).
true.
?- sat(X=:= ~Y), Y = 0.
X = 1,
Y = 0.
But I require something more lightweight than loading a full CLP(B) library. Any ideas?
It seems that SWI-Prologs when/2 does the job. I am using
the Quine algorithm from here to partially evaluate a boolean expression.
I can then define a Boolean let/2 predicate:
let(X, Y) :-
eval(Y, H),
term_variables(H, L),
( L== [] -> X = H;
cond(L, R),
when(R, let(X, H))).
cond([X], nonvar(X)) :- !.
cond([X,Y|Z], (nonvar(X);T)) :-
cond([Y|Z], T).
The above predicate will reevaluate the expression assigned
to the variable X when ever some variable inside the expression
changes. The expression is associate with the variable X through when/2. Since we see when/2 in the top-level, we see the associated expression:
?- let(X, ~Y).
when(nonvar(Y), let(X, ~Y))
?- let(X, Y+Z).
when((nonvar(Y); nonvar(Z)), let(X, Y+Z))
And we can also do our use case and even more:
?- let(X, ~Y), Y = 0.
X = 1,
Y = 0.
?- let(X, Y+Z), Y = 0.
Y = 0,
when(nonvar(Z), let(X, Z))
?- let(X, Y+Z), Y = 0, Z = 1.
X = 1,
Y = 0,
Z = 1

Given a few facts in prolog. I can't seem to create a rule which returns the variables don't have a relationship with given variable

The facts are listed below. I can't seem to create the proper rule called notneighbors which returns all the letters that are not neighbor to the given letter. Or don't have a neighborletters(X,Y) relationship with given letter.
neighborletters(a,b,beggining_letters).
neighborletters(b,a,beggining_letters).
neighborletters(j,k,middle_letters).
neighborletters(k,j,middle_letters).
neighborletters(x,y,last_letters).
neighborletters(y,x,last_letters).
So far I have come up with the below rule and many other variations of it.
notneighbor(X,Y):-
neighborletters(A,B, _),
neighborletters(B,A, _),
X \= A,
Y \= B.
but whenever I do a query with the above rule.
?- notneighbor(a, X).
I get a boolean false instead of the desired returns
j
k
x
y
In your query, notneighbor(a, X), the second argument is not instantiated. Therefore, the last goal in your rule, Y \= B, is false as a variable can always be unified with any term. Try instead:
neighbor_letters(a, b, beggining_letters).
neighbor_letters(b, a, beggining_letters).
neighbor_letters(j, k, middle_letters).
neighbor_letters(k, j, middle_letters).
neighbor_letters(x, y, last_letters).
neighbor_letters(y, x, last_letters).
not_neighbor(X, Y):-
neighbor_letters(X, _, _),
neighbor_letters(Y, _, _),
X \== Y,
\+ neighbor_letters(Y, X, _),
\+ neighbor_letters(X, Y, _).
This will give you:
| ?- not_neighbor(a, X).
X = j ? ;
X = k ? ;
X = x ? ;
X = y
yes
This definition for the not_neighbor/2 predicate can also return pairs of letters that are not neighbors:
| ?- not_neighbor(X, Y).
X = a
Y = j ? ;
X = a
Y = k ? ;
X = a
Y = x ? ;
X = a
Y = y ? ;
...
Still an issue with it, however, it returns duplicated answers. E.g.
| ?- not_neighbor(b, y).
yes
| ?- not_neighbor(y, b).
yes
Is that a problem? If yes, can you solve it continuing from here?

Predicate in prolog which is true if M and N differ more than X

First of all I am completely new to prolog and I am trying to write a predicate length(M,X,N) which is true, if M differs from N more than X.
I wrote the following testcase which is true if M(=dec.5) and N(=dec.2) differ more than X(=dec.2). And it is true in this case because 5 and 2 have a difference of 3 which is more than 2:
?- length(s(s(s(s(s(0))))), s(s(0)), s(s(0))).
true .
I know that prolog works recursively so I am wondering if I can construct such a predicate with conditions (for example <,>) like in languages like C, or if there is another way to do this in prolog. Sorry for this simple question but I just started with prolog.
You could construct predicates for greater or less. For example:
greater_than(s(_), 0).
greater_than(s(X), s(Y)) :-
greater_than(X, Y).
And similarly:
less_than(0, s(_)).
less_than(s(X), s(Y)) :-
less_than(X, Y).
If you want to find the absolute difference, you could do something like this:
abs_diff(0, 0, 0).
abs_diff(s(X), 0, s(X)).
abs_diff(0, s(X), s(X)).
abs_diff(s(X), s(Y), D) :-
abs_diff(X, Y, D).
Those concepts should help kick start some ideas for how to solve the rest of the problem.
This answer follows up on #lurker's fine answer and improves the determinism of the auxiliary predicate abs_diff/3 by utilizing
first argument clause indexing.
Introducing x_y_dist/3:
x_y_dist(0, Y, Y).
x_y_dist(s(X), Y, Z) :-
y_sx_dist(Y, X, Z).
y_sx_dist(0, X, s(X)).
y_sx_dist(s(Y), X, Z) :-
x_y_dist(X, Y, Z).
Sample query:
?- x_y_dist(X, Y, s(s(0))). % |X-Y| = 2
( X = 0 , Y = s(s(0)) % |0-2| = 2
; X = s(s(0)) , Y = 0 % |2-0| = 2
; X = s(0) , Y = s(s(s(0))) % |1-3| = 2
; X = s(s(s(0))) , Y = s(0) % |3-1| = 2
; X = s(s(0)) , Y = s(s(s(s(0)))) % |2-4| = 2
; X = s(s(s(s(0)))) , Y = s(s(0)) % |4-2| = 2
; X = s(s(s(0))) , Y = s(s(s(s(s(0))))) % |3-5| = 2
; X = s(s(s(s(s(0))))), Y = s(s(s(0))) % |5-3| = 2
; X = s(s(s(s(0)))) , Y = s(s(s(s(s(s(0)))))) % |4-6| = 2
; .........
)
Try this:
?- length(s(s(s(s(s(0))))), s(s(0)), s(s(0))).
length(s(_),0,0).
length(s(M),s(X),s(N)) :- length(M,X,N).
Do keep in mind that Prolog's predicates do not return values - so they don't return true or false. They either succeed or they don't. The interpreter is just telling you if your program succeeds or not.

#< Symbol In Prolog

I want to know what #< means in Prolog?
I encountered this symbol in this line of code while reading about the Bridge and Torch Problem:
select_one_or_two(L, [Sel1,Sel2], L2) :-
select(Sel1, L, NewL),
select(Sel2, NewL, L2),
Sel1 #< Sel2.
The comparative operators that start with # are more general than the ones that don't. With operators such as </2, you can only compare numeric values and expressions (involving literal numerics and variables that are instantiated with numeric values). So, with </2 you can do this:
?- X = 2, Y = 3, X + Y < 2*Y.
X = 2,
Y = 3.
?- X = 2, Y = 3, X + Y > 2*Y.
false.
?-
But you will get an error in the following cases if the expressions don't evaluate to a known numeric:
?- Y = 3, X + Y < 2*Y.
ERROR: </2: Arguments are not sufficiently instantiated
Or:
?- a < b.
ERROR: </2: Arithmetic: `a/0' is not a function
However, using #</2 you can compare lots of different types of objects in prolog. The comparison evaluation follows the rules described in the link that #Ankur gave. To understand these rules, you'll need to know what Prolog terminology means, such as term, functor, atom, etc (see, for example, Prolog Terms)
Looking at some examples:
?- a #< b.
true.
?- a(1) #< a(2).
true.
?- b(1) #< a(2).
false.
?- 20 #< a.
true.
These are pretty straight-forward, following the rules. Here's a more interesting case (from above):
?- Y = 3, X + Y #< 2*Y.
false.
Why would X + Y be considered "not less than" 2*Y? Prolog would internally look at this as:
`+(X,3) #< *(2,3).`
(Note Y is instantiated to 3.) These are compound terms (they aren't individual atoms or variables). If we look through the comparison rules, the matching rule is:
Compound terms are first checked on their arity, then on their functor
name (alphabetically) and finally recursively on their arguments,
leftmost argument first.
The arity of both terms is 2. The functor names are + and * respectively. Those are different. And in teh ASCII collating sequence, + comes after *. Therefore it is not true that + "is less than" *, and therefore not true that +(X,3) #< *(2,3). Thus, it is not true that Y = 3, X + Y #< 2 * Y.
Note also that #</2 doesn't evaluate numeric expressions. So even with X and Y instantiated as values, you will get:
?- X = 2, Y = 3, X + Y #< 2*Y.
false.
Whereas, when we had </2 here, this is true, since the expression X + Y < 2*Y, when evaluated, is true. When variables are simply unified, it understands that, however, so you would have:
| ?- X #< Y.
yes
But on the other hand:
| ?- X = 2, Y = 1, X #< Y.
no
In this case X #< Y is seen as 2 #< 1 due to the unification of X with 2 and Y with 1 and the numeric rule kicks in.
Having said all that, the use of #</2 in the predicate select_one_or_two enables that predicate to be usable on lists of all sorts of objects, not just numbers or fully instantiated numeric expressions. If it had used </2, then the following would work:
?- select_one_or_two([2,1,3], X, Y).
X = [2, 3],
Y = [1] ;
X = [1, 2],
Y = [3] ;
X = [1, 3],
Y = [2] ;
false.
But the following fails:
?- select_one_or_two([b,a,c], X, Y).
ERROR: </2: Arithmetic: `b/0' is not a function
?-
However, with the #< operator, it works:
?- select_one_or_two([b,a,c], X, Y).
X = [b, c],
Y = [a] ;
X = [a, b],
Y = [c] ;
X = [a, c],
Y = [b] ;
false.

Solving CNF using Prolog

While learning Prolog, I tried to write a program solving CNF problem (the performance is not an issue), so I ended up with the following code to solve (!x||y||!z)&&(x||!y||z)&&(x||y||z)&&(!x||!y||z):
vx(t).
vx(f).
vy(t).
vy(f).
vz(t).
vz(f).
x(X) :- X=t; \+ X=f.
y(Y) :- Y=t; \+ Y=f.
z(Z) :- Z=t; \+ Z=f.
nx(X) :- X=f; \+ X=t.
ny(Y) :- Y=f; \+ Y=t.
nz(Z) :- Z=f; \+ Z=t.
cnf :-
(nx(X); y(Y); nz(Z)),
(x(X); ny(Y); z(Z)),
(x(X); y(Y); z(Z)),
(nx(X); ny(Y); z(Z)),
write(X), write(Y), write(Z).
Is there any simpler and more direct way to solve CNF using this declarative language?
Consider using the built-in predicates true/0 and false/0 directly, and use the toplevel to display results (independently, instead of several subsequent write/1 calls, consider using format/2):
boolean(true).
boolean(false).
cnf(X, Y, Z) :-
maplist(boolean, [X,Y,Z]),
(\+ X; Y ; \+ Z),
( X ; \+ Y ; Z),
( X ; Y ; Z),
( \+ X ; \+ Y ; Z).
Example:
?- cnf(X, Y, Z).
X = true,
Y = true,
Z = true .
EDIT: As explained by #repeat, also take a serious look at CLP(B): Constraint Solving over Booleans.
With CLP(B), you can write the whole program above as:
:- use_module(library(clpb)).
cnf(X, Y, Z) :-
sat(~X + Y + ~Z),
sat(X + ~Y + Z),
sat(X + Y + Z),
sat(~X + ~Y + Z).
Please see the answer by #repeat for more information about this.
Look up "lean theorem prover" (such as leanTAP or leanCoP) for simple, short theorem provers in Prolog. Those are designed to use Prolog features to the best possible advantage. Although provers like that use first-order logic, CNF is a subset of that. There are dedicated SAT solvers for Prolog as well, such as this one.
Use clpb!
:- use_module(library(clpb)).
To check if some Boolean expression is satisfiable, use sat/1:
% OP: "(!x||y||!z) && (x||!y||z) && (x||y||z) && (!x||!y||z)"
?- sat((~X + Y + ~Z)*(X + ~Y + Z)*(X + Y + Z)*(~X + ~Y + Z)).
sat(X=\=X*Y#Z).
No concrete solution(s) yet... but a residue that's a lot simpler than the term we started with!
To get to concrete truth values, use labeling/1:
?- sat(X=\=X*Y#Z), labeling([X,Y,Z]).
X = 0, Y = 0, Z = 1
; X = 0, Y = 1, Z = 1
; X = 1, Y = 0, Z = 0
; X = 1, Y = 1, Z = 1.

Resources