14

How can I write the following rule in PROLOG: if P then not Q

I understand that you can easily write if P then Q the predicates like q(X) :- p(X), but how can you negate the q/1 predicate? I don't want to define new predicates with other semantics like non_q/1.

Erik Kaplun
  • 37,128
  • 15
  • 99
  • 111
Robert T.
  • 1,620
  • 2
  • 13
  • 20
  • i think that the way of the implementation depends on the way you are going to use it. What are you trying to do? After all, Prolog is a subset of First Class Logic (Horn Clauses in pure Prolog) – Thanos Tintinidis Jun 13 '11 at 16:37

4 Answers4

15

The clause "if P then not Q" is logically equivalent to the negative clause "not P OR not Q". As such it is a Horn clause without a positive literal, and as an application of the correspondence of SLD theorem proving and Horn clauses, can be represented in Prolog programming as a goal clause or "query":

?- P, Q.

Let's come back to this idea in a minute.

But the goal clause is perhaps not the sort of representation you have in mind. The facts and rules that constitute a Prolog "knowledgebase" are definite clauses, i.e. Horn clauses each with exactly one positive literal. "If P then not Q" has no positive literal, so in this sense it cannot be represented (as a definite clause).

The goal clause shown above "asks" if P and Q can both be proven. Prolog provides a notion of "negation as failure", so a more natural way to "ask" whether "not P OR not Q" holds would be:

?- not((P,Q)).

Then we would get success if either P or Q fails, and failure if both succeed.

However if your purpose is to assert the negation something in the knowledgebase, Prolog doesn't naturally support this. Depending on your application, there may be a reasonable way to work around the Prolog syntax and accomplish what is needed (there's always an unreasonable way to do it, as you've hinted as with a non_q predicate).

Ludovic Kuty
  • 4,868
  • 3
  • 28
  • 42
hardmath
  • 8,753
  • 2
  • 37
  • 65
  • 3
    This solves having "if P then not Q" having in a query, but it does not solve having it in the program. –  Jun 14 '11 at 13:37
  • Thank you for your answer. It helped me better understand the way Prolog is built. – Robert T. Jun 14 '11 at 18:27
  • You mentioned "However if your purpose is to assert the negation something in the knowledgebase, Prolog doesn't naturally support this.". Except, perhaps, if you state `something :- fail.` in your program. This provides a way of negating terms (such as the atom `something` here) and is in fact a very natural (and I'd argue not unreasonable) way of explicitly negating terms in Prolog. –  Feb 24 '12 at 05:38
  • 2
    @sharky: I agree that `q :- fail.` is a natural way of representing the negation of `q`. But it isn't, by itself, an effective way of "asserting" the falsehood of `q` in Prolog. For one thing, if this is the only rule about `q/0` we have, it amounts to having no rules at all (the same solutions are found for any query as if there were no rules in an ISO implementation). For another it doesn't prevent a subsequent assertion of a rule about `q/0` that can succeed in some fashion. We might mitigate the latter issue by adding a cut to your rule, at the loss of some "naturalness". – hardmath Feb 24 '12 at 16:13
  • Yep, extra clauses may succeed, but this would contradict the programmer's intention of explicitly negating the predicate. Using cut otherwise renders all such extra clauses irrelevant, so there'd be no point asserting them anyway. This kind of programming is uncommon however (because as you say, it amounts to the same behaviour as if the negation wasn't stated), so there's usually never a need to do this, but if it's required to make such an assertion explicit (e.g., switching off an atomic debug flag) then it's possible. By the way, I'd argue that using cut is natural, although impure :-) –  Feb 26 '12 at 22:01
8

Have you ever heard about cut in Prolog?

Anyway I don't know much about Prolog standard, but in SWI-Prolog the symbol \+ means negation. I know it don't have to work in every Prolog's interpreter.

You can make the predicate negation with Prolog's cut. The predicate is defined like:

not(Goal) :- call(Goal),!,fail.
not(Goal). 

It means that Goal can't be proven, not the Goal is false. Maybe this Prolog & Cut link will be useful.

iwtu
  • 81
  • 1
  • 4
4

"...if P then not Q" can be represented via the -> if-then control-flow predicate (e.g., GNU) , along with the \+ negation (or 'not-provable') operator (e.g., GNU), as follows:

(P -> \+ Q),

Note that, typically, \+ will implement what is known as negation-as-failure; i.e., the subgoal/expression \+ Q will succeed iff Q cannot. Note that the evaluation of Q under \+ will not affect the bindings of any variables present in the expression Q at execution.

For example, consider:

foo(a).
bar(b).

Given these facts, the following hold:

foo(a) -> \+ bar(a). % succeeds, as bar(a) is not provable.
foo(a) -> \+ bar(b). % fails, as bar(b) is provable.
foo(a) -> \+ bar(X). % fails, as bar(X) is provable; note that X remains unbound.
foo(X) -> \+ bar(X). % succeeds, as bar(X) where X unified to 'a' isn't provable.

Implementing something akin to \+ q(X) :- p(X) as you might want (in terms of a 'rule') isn't straightforward, as you describe, however a potential hack is:

q(X) :- p(X), !, fail.

This definition will only reflect the intention that q(X) is to fail for all X where p(X) succeeds iff it is asserted before any other clauses of q(X), but may not be ideal.

  • This negates p, but question was about negating q. –  Jun 14 '11 at 13:36
  • 2
    Hey @jan-burse, where have I described how to negate `p` in my answer? I don't see it. `q(X) :- p(X), !, fail.` negates `q(X)` for all `X` where `p(X)` holds, is interpreted as: given `p`, `q` is not provable. –  Jun 14 '11 at 23:46
  • Yes, on second thought, you are right. p is not negated, it is forced to fail. If there were a second clause q(X), then it would be negated. Interesting solution, should indeed work. Super cool. –  Jun 15 '11 at 09:15
  • But still I have a strange feeling. How do you express that in certain situations neither ~q nor q is derivable. You would need an additional clause q(X) :- throw(undefined) or q(X) :- loop_indefinitely. –  Jun 15 '11 at 09:39
1

You can use minimal logic to define a negative head. In minimal logic ~A can be viewed as A -> ff. Thus the following

P -> ~Q

Can be viewed as:

P -> (Q -> ff).

Now if we take the following identity (A -> (B -> C)) = (A & B -> C), we see that the above is equivalent to:

P & Q -> ff.

There is now one problem, how can we ask negative queries? There is one way to make use of minimal logic which is different from negation as failure. The idea is that a query of the form:

G |- A -> B

is answered by temporarily adding A to the prolog program G, and then trying to solve B, i.e. doing the following:

G, A |- B

Now lets turn to Prolog notation, we will show that p, and p -> ~q implies ~q by executing a (minimal logic) Prolog program. The prolog program is:

p.
ff :- p, q.

And the query is:

?- q -: ff.

We first need to define the new connective (-:)/2. A quick solution is as follows:

(A -: B) :- (assert(A); retract(A), fail), B, (retract(A); assert(A), fail).

Here you see a realisation of this minimal logic negation in SWI Prolog:

Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 5.10.4)
Copyright (c) 1990-2011 University of Amsterdam, VU Amsterdam

1 ?- [user].
:- op(1200,xfy,-:).
|: (A -: B) :- (assertz(A); retract(A), fail), B, (retract(A); assertz(A), fail).
|: p.
|: ff :- p, q.
|:
% user://1 compiled 0.02 sec, 1,832 bytes
true.

2 ?- q -: ff.
true .

Best Regards

Reference: Uniform Proofs as a Foundation for Logic Programming (1989) by Dale Miller, Gopalan Nadathur, Frank Pfenning, Andre Scedrov