Depending on faliure to prove in prolog - prolog

Consider this code
:- use_module(library(clpfd)).
p(1).
p(3).
p(5).
p(7).
predecessor(A, B) :- A #= B - 1. % is true for pairs
q(X) :- predecessor(P, X), \+ p(P).
If I query ?- p(X) I correctly get the results
?- p(X).
X = 1 ;
X = 3 ;
X = 5 ;
X = 7.
But if I query ?- q(X) then I get false.
I realize that \+ is really not negation but faliure to prove, but what if not being able to prove something is sufficient for another predicate being true?
I wanted to give a reasonable use case / example which is why I resorted to using clpfd. Even without using it, I have another example which I can present:
likes(betty, butter).
likes(betty, jam) :- fail.
dislikes(betty, Item) :- \+ likes(betty, Item).
This example too, has a shortcoming that likes(betty, jam) :- fail. isn't really doing anything. But I hope I'm able to get my point across.
Is there a way in prolog to define this dependence?

You have to specifically define the "negative universe" of possibilities if you want Prolog to provide solutions in that space.
For instance, \+ p(X) cannot tell you specific values of X because the possible X that meet this criteria have not been defined. You're asking Prolog to invent what X might possibly be, which it cannot do.
You could define the universe of all possible values, then you can define what \+ p(X) means:
:- use_module(library(clpfd)).
p(1).
p(3).
p(5).
p(7).
predecessor(A, B) :- A #= B - 1. % is true for pairs
q(X) :- predecessor(P, X), P in 0..9, label([P]), \+ p(P).
Then you get:
2 ?- q(X).
X = 1 ;
X = 3 ;
X = 5 ;
X = 7 ;
X = 9 ;
X = 10.
3 ?-
Here we've told Prolog that the possible universe of P to choose from is defined by P in 0..9. Then the call \+ p(P) can yield specific results. Unfortunately, using \+, you still have to apply label([P]) before testing \+ p(P), but you get the idea.
In your other example of likes, it's the same issue. You defined:
likes(betty, butter).
likes(betty, jam) :- fail.
As you indicated, you wouldn't normally include likes(betty, jam) :- fail. since failure would already occur due to lack of a successful fact or predicate. But your inclusion is really an initial attempt to define the universe of possible choices. Without that definition, Prolog cannot "invent" what to pick from to test for a dislike. So a more complete solution would be:
person(jim).
person(sally).
person(betty).
person(joe).
food(jam).
food(butter).
food(eggs).
food(bread).
likes(betty, butter).
Then you can write:
dislikes(Person, Food) :-
person(Person),
food(Food),
\+ likes(Person, Food).

Related

How is it that a clause that requires a ground term works, but that term isn't ground outside of the clause?

I'd like to test whether a term has only one solution.
(Understanding that this might be done in different ways) I've done the following and would like to understand why it doesn't work, if it can be made to work, and if not, what the appropriate implementation would be.
First, I have an "implies" operator (that has seemed to work elsewhere):
:- op(1050,xfy,'==>').
'==>'(A,B) :-·forall(call(A), call(B)).
next I have my singleSolution predicate:
singleSolution(G) :- copy_term(G,G2), (call(G), call(G2)) ==> (G = G2).
Here I'm trying to say: take a term G and make a copy of it, so I can solve them independently. Now if solving both independently implies they are equal, then there must be only one solution.
This works in some simple cases.
BUT.
I have a predicate foo(X,Y,Z) (too large to share) which solves things properly, and for which singleSolution can answer correctly. However, X,Y,Z are not fully ground after singleSolution(foo(X,Y,Z)) is called, even though they would be after directly calling foo(X,Y,Z).
I don't understand that. (As a sanity test: I've verified that I get the same results under swi-prolog and gprolog.)
EDIT: Here is an example of where this fails.
increasing([]).
increasing([_]).
increasing([X,Y|T]) :- X < Y, increasing([Y|T]).
increasingSublist(LL,L) :-·
sublist(L,LL),
length(L, Len),
Len > 1,
increasing(L).
then
| ?- findall(L, singleSolution(increasingSublist([1,2],L)),R).
R = [_]
yes
But we don't know what L is.
This seems to work, but I'm not sure if it's logically sound :)
It uses call_nth/2, a nonstandard but common predicate. It abuses throw to short-circuit the computation. Using bagof/3 instead of findall/3 lets us keep the Goal argument bound (and it will fail where findall/3 would succeed if it finds 0 solutions).
only_once(Goal) :-
catch(bagof(_, only_once_(Goal), _), too_many, fail).
only_once_(Goal) :-
call_nth(Goal, N),
( N > 1
-> throw(too_many)
; true
).
Testing it (on SWI):
?- only_once(member(X, [1])).
X = 1.
?- only_once(member(a, [a, b])).
true.
?- only_once(member(X, [a, b])).
false.
?- only_once(between(1,inf,X)).
false.
Unfortunately, I don't think call_nth/2 is supported in GNU Prolog.
Another possible solution:
single_solution(G) :-
copy_term(G, H),
call(G),
!,
( ground(H)
-> true
; \+ ( call(H), G \= H ) % There is no H different from G
).
p(a).
p(a).
q(b).
q(c).
Examples:
?- single_solution( p(X) ).
X = a.
?- single_solution( q(X) ).
false.
?- single_solution( member(X, [a,a,a]) ).
X = a.
?- single_solution( member(X, [a,b,c]) ).
false.
?- single_solution( repeat ).
true.
?- single_solution( between(1,inf,X) ).
false.
?- single_solution( between(1,inf,5) ).
true.
Here is an another approach I came up with after #gusbro commented that forall/2 doesn't bind variables from the calling goal.
single_solution(G) :-·
% duplicate the goal so we can solve independently
copy_term(G,G2),
% solve the first goal at least / at most once.
G, !,
% can we solve the duplicate differently?
% if so, cut & fail. Otherwise, succeed.
(G2, G2 \= G, !, fail; true).

Is it possible to write an inconsistent Prolog program using only pure Prolog, cut and `false`?

This one tickled my interest in theory:
Is it possible to write an inconsistent Prolog program, i.e. a program that answers both false and true depending on how it is queried, using only pure Prolog, the cut, and false?
For example, one could query p(1) and the Prolog Processor would says false. But when one queries p(X) the Prolog Processor would give the set of answers 1, 2, 3.
This can be easily achieved with "computational state examination predicates" like var/1 (really better called fresh/1) + el cut:
p(X) :- nonvar(X),!,member(X,[2,3]).
p(X) :- member(X,[1,2,3]).
Then
?- p(1).
false.
?- p(X).
X = 1 ;
X = 2 ;
X = 3.
"Ouch time" ensues if this is high-assurance software. Naturally, any imperative program has no problem going off the rails like this on every other line.
So. can be done without those "computational state examination predicates"?
P.S.
The above illustrates that all the predicates of Prolog are really carrying a threaded hidden argument of the "computational state":
p(X,StateIn,StateOut).
which can be used to explain the behavour of var/1 and friends. The Prolog program is then "pure" when it only calls predicates that neither consult not modify that State. Well, at least that seems to be a good way to look at what is going on. I think.
Here's a very simple one:
f(X,X) :- !, false.
f(0,1).
Then:
| ?- f(0,1).
yes
| ?- f(X,1).
no
| ?- f(0,Y).
no
So Prolog claims there are no solutions to the queries with variables, although f(0,1) is true and would be a solution to both.
Here is one attempt. The basic idea is that X is a variable iff it can be unified with both a and b. But of course we can't write this as X = a, X = b. So we need a "unifiable" test that succeeds without binding variables like =/2 does.
First, we need to define negation ourselves, since it's impure:
my_not(Goal) :-
call(Goal),
!,
false.
my_not(_Goal).
This is only acceptable if your notion of pure Prolog includes call/1. Let's say that it does :-)
Now we can check for unifiability by using =/2 and the "not not" pattern to preserve success while undoing bindings:
unifiable(X, Y) :-
my_not(my_not(X = Y)).
Now we have the tools to define var/nonvar checks:
my_var(X) :-
unifiable(X, a),
unifiable(X, b).
my_nonvar(X) :-
not(my_var(X)).
Let's check this:
?- my_var(X).
true.
?- my_var(1).
false.
?- my_var(a).
false.
?- my_var(f(X)).
false.
?- my_nonvar(X).
false.
?- my_nonvar(1).
true.
?- my_nonvar(a).
true.
?- my_nonvar(f(X)).
true.
The rest is just your definition:
p(X) :-
my_nonvar(X),
!,
member(X, [2, 3]).
p(X) :-
member(X, [1, 2, 3]).
Which gives:
?- p(X).
X = 1 ;
X = 2 ;
X = 3.
?- p(1).
false.
Edit: The use of call/1 is not essential, and it's interesting to write out the solution without it:
not_unifiable(X, Y) :-
X = Y,
!,
false.
not_unifiable(_X, _Y).
unifiable(X, Y) :-
not_unifiable(X, Y),
!,
false.
unifiable(_X, _Y).
Look at those second clauses of each of these predicates. They are the same! Reading these clauses declaratively, any two terms are not unifiable, but also any two terms are unifiable! Of course you cannot read these clauses declaratively because of the cut. But I find this especially striking as an illustration of how catastrophically impure the cut is.

Prolog - why does the following code generate the solution X=root forever?

black(root).
black(v1).
black(v3).
black(v4).
edge(root,root).
edge(v1,root).
edge(v2,v1).
edge(v3,v1).
edge(v4,v3).
edge(v5,v2).
edge(v5,v4).
edge(v6,v5).
foo(root).
foo(X) :- edge(X,Y), black(Y), foo(Y).
Then I type foo(X) and only get X=root.
I really can't figure out why. We get the first root because of the first part of foo. Then we are supposed to go the the second part, we then proceed to find the edge (root,root). black(root) returns true and so does foo(root) so we get another root solution. Why don't we then go to the edge (v1,root)? What am I missing?
Here is a fragment that is responsible for non-termination called a failure-slice. You need to modify the remaining part somehow in order to avoid that loop.
black(root).
black(v1) :- false.
black(v3) :- false.
black(v4) :- false.
edge(root,root).
edge(v1,root) :- false.
edge(v2,v1) :- false.
edge(v3,v1) :- false.
edge(v4,v3) :- false.
edge(v5,v2) :- false.
edge(v5,v4) :- false.
edge(v6,v5) :- false.
foo(root) :- false.
foo(X) :- edge(X,Y), black(Y), foo(Y), false.
The easiest way to solve this is to reuse closure0/3.
edgeb(X, Y) :-
edge(X, Y),
black(Y).
foo(X) :-
closure0(edgeb, X, root).
... or change your facts. The failure-slice above showed us that the edge(root,root). was part of the problem. What, if we just remove that very fact? Or turn it into
edge(root,root) :- false.
Now foo(X) terminates:
?- foo(X).
X = root
; X = v1
; X = v2
; X = v3
; X = v4
; X = v5
; false.
To avoid hammering ; or SPACE so many times, your carpal tunnels recommend:
?- foo(X), false.
false.
By that we have proven that your program will terminate always. There cannot be any special case lurking around.
Because looking for the 3rd solution starts with retrying foo(Y) when Y=root, and you've already established there are at least 2 distinct ways to prove foo(root). (But, as #WillemVanOnsem points out, it is much worse than that.)

Prolog predicate where two items are associated but not equivalent

I haven't programmed in Prolog for years and am struggling with a simple block of test code (I'm trying to solve a logic puzzle for fun...):
aboard(jack, blackbird).
aboard(jim, blackbird).
aboard(donna, blackbird).
aboard(david, north_star).
aboard(sandy, north_star).
shipmates(A, B) :- A \= B, aboard(A, X), aboard(B, X).
shipmates1(A, A) :- !, fail.
shipmates1(A, B) :- aboard(A, X), aboard(B, X).
The shipmates and shipmates1 rules are two different attempts to accomplish the following: I want to pair all passengers who are on the same ship but are not equivalent to each other.
For example, I want shipmates(jack, jack). to be false.
When I query this with fully-qualified arguments, I get the expected answers:
3 ?- shipmates(jack, david).
false.
4 ?- shipmates(jack, jack).
false.
5 ?- shipmates(jack, jim).
true.
However, when I want all of Donna's shipmates, it doesn't seem to work:
6 ?- shipmates(donna, X).
false.
I was expecting:
X = jack ;
X = jim ;
NOTE: I get the same wrong results with shipmates1.
So please take pity on a very amateur Prolog programmer (who is not doing homework for a class!) What very obvious thing am I doing wrong?
Version: SWI-Prolog (threaded, 64 bits, version 8.0.2)
Try:
shipmates(A, B) :-
aboard(A, X),
aboard(B, X),
A \= B.
By calling the aboard/2 predicate before the A \= B goal, you ensure that both A and B will be instantiated, thus making the comparison meaningful.

PROLOG - clause returns true for constants, but won't find solution for variable?

After many years of abstinence of the PROLOG programming language, I'm trying to get into it again.
And promptly there, something confused me.
(I am using SWI prolog 6.4.1. on windows)
Consider the following defined:
father(jack, clara).
father(jack, sophie).
mother(angela,clara).
mother(angela,sophie).
parent(A, B) :- father(A, B).
parent(A, B) :- mother(A, B).
sibling( A, B ) :-
A \= B,
parent(P, A),
parent(P, B).
Now, if I "ask" the interpreter:
sibling(clara, sophie).
true is the answer.
But if I try to get the siblings of e.g. clara:
sibling(clara, X).
The answer is just false.
Just as
findall( X, sibling(clara, X ), L ).
returns an empty list.
Why?
To prove sibling(clara, X), you first need to prove clara \= x. But that doesn't work because it reduces to \+ clara = X, were \+ is the infamous negation as failure: Prolog tries to prove clara = X, which succeeds, and concludes that clara \= X must therefore be false.
You should either reorder your program to do the \= check last instead of first, or use dif(clara, X).

Resources