How to make prolong understand a connection by other relationship - prolog

My DataBase =>
fact(a).
fact(b).
likes(a, rain).
likes(a, snow).
likes(b, X) :- not(likes(a, X)).
human(X) :-
not(likes(X, rain)),
fact(X).
alien(X) :-
likes(X, snow),
fact(X).
Prolog question =>
?- human(X)
no
The logic here is
likes(a, rain),
so by rule
not(likes(b, rain)) is True AND fact(b) is True
human(b) is No
human(X) is No
Should be Yes but it doesnt make the connection
How can I make with prolong this check so it understands that it should return b ?

A lowercase x is a constant, so it looks for not(likes(x, rain)), which indeed holds, but fact(x) does not hold since there is no clause fact(x), only for a and b.
As for human(X) (so as a variable), not(likes(X, rain)) will not succeed, since there is an X that likes rain: a likes rain, hence likes(X, rain) can be unfied, and therefore not(likes(X, rain)) fails. The fact that there is a b that does not like rain, is not relevant. Negation in Prolog is not constructive, it is implemented as finite failure: something is not true if all attempts to proof that it is true fail and these attempts are finite (otherwise we get stuck in an infinite loop).
You can however swap the fact(X) and not(likes(X, rain)) clauses:
human(X) :-
fact(X),
\+ likes(X, rain).
If you then call human(X), it will succeed with X = b. This works since it will first unify X with a, but that will fail for the \+ likes(a, rain) clause, but then it will retry by unfying X with b, and this will succeed.

I just altered the order of the predicate and it seems to work know:
human(X) :-
fact(X),
\+ likes(X, rain).
?- human(X).
X = b.
The reason behind this is that before unification of X you ask for likes(X, rain) and you want it to be false. So prolog searches for likes(X, rain), finds likes(a, rain) returns true, negates it and will therefore fail. Resolve the issue by adressing fact(X) first, so it will ask for this particular X and not just any value.

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).

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.)

Depending on faliure to prove in 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).

Can't show the second answer in Prolog

sisters(mary,catherine).
sisters(catherine,mary).
brothers(john,simone).
brothers(simone,john).
marriage(john,mary,2010).
marriage(mary,john,2010).
marriage(kate,simone,2009).
marriage(simone,kate,2009).
marriage(catherine,josh,2011).
marriage(josh,catherine,2011).
birth(mary,johnny).
birth(mary,peter).
birth(catherine,william).
birth(kate,betty).
givebirthyear(mary,peter,2015).
givebirthyear(mary,johnny,2012).
givebirthyear(catherine,william,2012).
givebirthyear(kate,betty,2011).
siblings(X,Y) :-
birth(Parent,X),
birth(Parent,Y).
cousins(X,Y) :-
birth(Xparent,X),
birth(Yparent,Y),
sisters(Xparent,Yparent).
cousins(X,Y) :-
X \= Y,
birth(Xmom,X),
birth(Ymom,Y),
marriage(Xmom,Xdad,_),
marriage(Ymom,Ydad,_),
brothers(Xdad,Ydad).
I don' know what's happening in my code. When I input
cousins(betty,johnny).
and
cousins(william,johnny).
The prolog says true. But when I entered
cousins(S,johnny).
THe prolog says S = william but didn't show me that S = betty. I don't really know what's happening. Need help.
Here is the prolog result I got.
?- cousins(S,johnny).
S = william ;
false.
?- cousins(betty,johnny).
true.
?- cousins(william,johnny).
true .
The problem
The reason this happens is because
X \= Y,
actually means:
\+(X = Y).
now \+ or not in Prolog has some weird behaviour compared to the logical not. \+ means negation as finite failure. This means that \+(G) is considered to be true in case Prolog queries G, and can not find a way to satisfy G, and that G is finite (eventually the quest to satisfy G ends).
Now if we query \+(X = Y), Prolog will thus aim to unify X and Y. In case X and Y are (ungrounded) variables, then X can be equal to Y. As a result X \= Y fails in case X and Y are free variables.
So basically we can either use another predicate that for instance puts a constraint on the two variables that is triggered when the variables are grounded, or we can reorder the body of the clause, such that X and Y are already grounded before we call X \= Y.
If we can make for instance the assumption that X and Y will be grounded after calling birth/2, we can reorder the clause to:
cousins(X,Y) :-
birth(Xmom,X),
birth(Ymom,Y),
X \= Y,
marriage(Xmom,Xdad,_),
marriage(Ymom,Ydad,_),
brothers(Xdad,Ydad).
Prolog has however a predicate dif/2 that puts a constraint on the two variables, and from the moment the two are grounded, it will fail if the two are equal. So we can use it like:
cousins(X,Y) :-
dif(X,Y),
birth(Xmom,X),
birth(Ymom,Y),
marriage(Xmom,Xdad,_),
marriage(Ymom,Ydad,_),
brothers(Xdad,Ydad).
Making things simpler
That being said, I think you make the program too complex. We can start with a few definitions:
two people are slibings/2 if they are brothers/2 or sisters/2.
slibings(X,Y) :-
brothers(X,Y).
slibings(X,Y) :-
sisters(X,Y).
It is however possible that brothers/2 and sisters/2 do not provide all information. Two people are also slibings if they have the same mother (we will assume that people do not divorce here, or at least not give birth to other children after they remarry).
slibings(X,Y) :-
dif(X,Y),
birth(Mother,X),
birth(Mother,Y).
a parent/2 of a person is the mother of the person or the father (the person that married the mother).
So we can write:
parent(Mother,X) :-
birth(Mother,X).
parent(Father,X) :-
birth(Mother,X),
marriage(Father,Mother,_).
based on your example, the marriage/3 predicate is bidirectional: in case marriage(X,Y,Z)., then there is also a fact marriage(Y,X,Z)..
And now we can define:
two people are cousins if there parents are slibings:
cousins(X,Y) :-
parent(MF1,X),
parent(MF2,Y),
slibings(MF1,MF2).
and that's it.

Prolog Predicate to return true when two people have same hobby

I want to write a Prolog predicate that returns true when two people have the same hobby, without using negation. I have the following database:
likes(john,movies).
likes(john,tennis).
likes(john,games).
likes(karl,music).
likes(karl,running).
likes(peter,swimming).
likes(peter,movies).
likes(jacob,art).
likes(jacob,studying).
likes(jacob,sleeping).
likes(mary,running).
likes(mary,sleeping).
likes(sam,art).
likes(sam,movies).
I came up with the following predicate:
same_hobby(X,Y) :-
likes(X,Z),
likes(Y,Z).
However, this predicate is also true when X equals Y and I do not want this to be the case. Can anyone help me find a solution? A small explanation would also be greatly appreciated.
You can simply use the predicate dif/2 , that is, dif(Term1, Term2) that means that Term1 have to differ from Term2, otherwise it will fail.
Your rule will become:
same_hobby(X,Y) :-
likes(X,Z),
likes(Y,Z),
dif(X,Y).
Cause dif/2 is a completely pure predicate, you can also write this as
same_hobby(X,Y) :-
dif(X,Y),
likes(X,Z),
likes(Y,Z).
That means that, if X differs from Y then reduce the goal likes(X,Z), likes(Y,Z), fail otherwise.
You can use the predicate dif/2 to state that X and Y must not be equal:
same_hobby(X, Y) :-
likes(X, Z),
likes(Y, Z),
dif(X, Y).
This makes it so the interpreter recognizes that X and Y need to be two different entities in order for the same_hobby/2 predicate to be true.

Resources