How does prolog resolution use proof by contradiction? - prolog

I'm learning prolog, and I'm confused by the claim that prolog uses proof by contradiction:
The resolution proof process makes use of a technique that is known as reduction to the absurd: suppose that the formula to be proved is false, and show that this leads to a contradiction, thereby demonstrating that the formula to be proved is in fact true.
They show the following proof diagram (based on rules and facts established one section earlier):
But if I read these steps backwards it's a straightforward direct proof:
/* axiom: tottenham_court_road is connected to leicester_square by northern road */
connected(tottenham_court_road, leicester_square, northern)
/* therefore it's connected to something on some road */
connected(tottenham_court_road, W, L)
/* being connected to something also means it's nearby */
nearby(X,Y):-connected(X,Y,L)
/* Therefore tottenham_court_road is near something */
nearby(tottenham_court_road, W)
How is this a proof by contradiction? Why would that be a more useful framework than chaining reasoning from axioms?

Horn clauses
A Horn clause is a disjunction with at most one positive literal, where all variables are implicitly universally quantified over the whole formula. For example,
¬father(X,Y) ∨ ¬father(Y,Z) ∨ grandfather(X,Z)
is a Horn clause. Since ¬α ∨ ¬β is equivalent to ¬(α ∧ β), and ¬α ∨ β is equivalent to α → β, that Horn clause can be written as:
¬father(X,Y) ∨ ¬father(Y,Z) ∨ grandfather(X,Z)
≡ ¬(father(X,Y) ∧ father(Y,Z)) ∨ grandfather(X,Z)
≡ father(X,Y) ∧ father(Y,Z) → grandfather(X,Z)
Or, equivalently, as:
grandfather(X,Z) ← father(X,Y) ∧ father(Y,Z)
A Horn clause composed by a single positive literal is called a fact. For example, father(adam,cain) ∨ ⊥, which can be written as father(adam,cain) ← ⊤, is a fact.
A Horn clause without positive literal is called a goal (a.k.a. query). For example, ⊥ ∨ ¬father(adam,cain), which can be written as ⊥ ← father(adam,cain), is a goal.
A Horn clause of the form ⊥ ← ⊤ is called a contradiction. For example, the resolution of the goal ⊥ ← father(adam,cain) with the fact father(adam,cain) ← ⊤ produces the resolvent ⊥ ← ⊤. The literal at the LHS of ← is positive, and a literal at the RHS is negative. Therefore, two unifiable literals in opposite sides of ← can be cancelled by resolution.
A Horn clause that is not a goal clause is called a definite clause.
A set of definite clauses is called a logic program.
In logic programming, the constant literals ⊥ and ⊤ are often omitted. Usually, a fact is written as α ←, a goal is written as ← α, and a contradiction is written as ←.
Horn clauses express a subset of FOL with very useful properties (e.g., unique minimal models and relatively low computational complexity). In fact, Logic programming and Prolog are built on top of Horn clauses.
Proof by contradiction
Consider the following logic program (with numbered clauses):
(1) father(adam,abel) ←
(2) father(adam,cain) ←
(3) father(adam,seth) ←
(4) father(seth,enos) ←
(5) grandfather(X,Z) ← father(X,Y) ∧ father(Y,Z)
The question Who is Enos' grandfather? (that is, there is someone who is Enos' grandfather and we want to know who this person is) can be expressed by the formula ∃W.grandfather(W,enos). Clearly, that formula is not a Horn clause. However, in order to proof that formula by contradiction, we must consider its negation:
¬∃W.grandfather(W,enos)
≡ ∀W.¬grandfather(W,enos)
≡ ∀W.[⊥ ∨ ¬grandfather(W,enos)]
≡ ⊥ ← grandfather(W,enos)
≡ ← grandfather(W,enos)
which is, indeed, a Horn clause (or, more precisely, a goal clause).
So, if the logic program (1)-(5) is consistent and ∃W.grandfather(W,enos) is true w.r.t. that program, then the goal ← grandfather(W,enos) must lead to a contradiction (and the constant bound to the universal variable W must be the desired answer for the question):
← grandfather(W,enos) (5) grandfather(X,Z) ← father(X,Y) ∧ father(Y,Z)
| |
+-------------------------+ {X=W, Z=enos}
|
← father(W,Y) ∧ father(Y,enos) (3) father(adam,seth) ←
| |
+----------------------------------+ {W=adam, Y=seth}
|
← father(seth,enos) (4) father(seth,enos) ←
| |
+-----------------------+ {}
|
← [contradiction]
Horn clauses are useful in various applications due to their very nice
properties: the resolvent of two Horn clauses is a new Horn clause, and the
resolvent of a goal clause and a definite clause is a new goal clause.
Horn clauses and Prolog
In Prolog, the connective ∧ is replaced by , and the connective ← is replaced by :- (except in facts, where that connective is omitted, and in goals, where the top-level prompt ?- implicitly stands for ←).
"In logic, this is achieved by writing the statement as a rule with
an empty conclusion, i.e. a rule for which the truth of its premises would lead to falsity"
A clause with an empty conclusion is nothing more than a goal of the form ← α, which is equivalent to ⊥ ← α. So, if the premise α is true:
⊥ ← α
≡ ⊥ ← ⊤
≡ ⊥ ∨ ¬⊤
≡ ⊥ [falsity]
Thus, the symbols "?-" and ":-" are in fact equivalent. A
contradiction is found if resolution leads to the empty rule, of which
the premises are always true (since there are none), but the
conclusion is always false.
Since both symbols ?- and :- are used in place of ←, clearly, they are equivalent. Particularly, the symbol ?- is only implicitly used (when a query is typed in the top-level prompt). In some implementations of Prolog, a goal clause in the program source-code is automatically executed when that program is loaded. For example, when the following program is loaded in SWI-Prolog, the text Hi Alfred! is written to the current output:
user('Alfred'). % user('Alfred') ←
:- user(Name), format('Hi ~w!~n', [Name]). % ← user(Name), format('Hi ~w!~n', [Name]).
Empty rule is just another name for contradiction (i.e., ⊥ ← ⊤, often written simply as ←). Of course, the premise of an empty rule is always true (⊤) and its conclusion is always false (⊥).

You should probably ask the textbook authors what exactly they are talking about. They for example say "In logic, this is achieved by writing the statement as a rule with an empty conclusion, i.e. a rule for which the truth of its premises would lead to falsity" but do they mean that this is strictly in the world of logic but not in the world of Prolog programming? The example they show:
:- nearby(tottenham_court_road, W)
Doesn't exactly make sense in Prolog, ie, you can write it and it might even do something but it doesn't seem to be the thing that they are talking about "in logic". This sentence specifically gets more unclear the more times I read it:
Thus, the symbols "?-" and ":-" are in fact equivalent. A contradiction is found if resolution leads to the empty rule, of which the premises are always true (since there are none), but the conclusion is always false.
Maybe it made sense in their head when they wrote it but they failed miserably at the exercise of writing a textbook.

Related

Converting first-order logic to CNF without exponential blowup

When attempting to solve logic problems on a computer, it is usual to first convert them to CNF, because the best solving algorithms expect CNF as input.
For propositional logic, the textbook rules for this conversion are simple, but if you apply them as is, the result is one of the very rare cases where a program encounters double exponential resource consumption without being specifically constructed to do so:
a <=> (b <=> (c <=> ...))
with N variables, generates 2^2^N clauses, one exponential blowup in the conversion of equivalence to AND/OR, and another in the distribution of OR into AND.
The solution to this is to rename subterms. If we rewrite the above as something like
r <=> (c <=> ...)
a <=> (b <=> r)
where r is a fresh symbol that is being defined to be equal to a subterm - in general, we may need O(N) such symbols - the exponential blowups can be avoided.
Unfortunately, this runs into a problem when we try to extend it to first-order logic. Using TPTP notation where ? means 'there exists' and variables begin with capital letters, consider
a <=> ?[X]:p(X)
Admittedly this case is simple enough that there is no actual need to rename the subterm, but it's necessary to use a simple case for illustration, so suppose we are using an algorithm that just automatically renames arguments of the equivalence operator; the point generalizes to more complex cases.
If we try the above trick and rename the ? subterm, we get
r <=> ?[X]:p(X)
Existential variables are converted to Skolem symbols, so that ends up as
r <=> p(s)
The original formula then expands to
(~a | r) & (a | ~r)
Which is by construction equivalent to
(~a | p(s)) & (a | ~p(s))
But this is not correct! Suppose we had not done the renaming, but just expanded the original formula as it was, we would get
(~a | ?[X]:p(X)) & (a | ~?[X]:p(X))
(~a | ?[X]:p(X)) & (a | ![X]:~p(X))
(~a | p(s)) & (a | ~p(X))
which is critically different from the version we got with the renaming.
The problem is that equivalence needs both the positive and negative versions of each argument, but applying negation to terms that contain universal or existential quantifiers, structurally changes those terms; you cannot just encapsulate them in a definition, then apply the negation to the defined symbol.
The upshot of this is that when you have equivalence and the arguments may contain such quantifiers, you actually need to recur through each argument twice, once for the positive version, once for the negative. This suffices to bring back the existential blowup we hoped to avoid by doing the renaming. As far as I can see, this problem is not caused by the way a particular algorithm works, but by the nature of the task.
So my question:
Given an input formula that may contain arbitrary nesting of equivalence and quantifiers, is there any algorithm that will correctly turn this to CNF with a polynomial rather than exponential number of clauses?
As you observed, an existential such as ∃X.p(X) is not in fact equivalent to a Skolemized expression p(S). Its negation ¬∃X.p(X) is not equivalent to ¬p(S), but to ∀Y.¬p(Y).
Possible approaches that avoid the exponential blow-up:
Convert existentials such as ∃X.p(X) to universals such as ¬∀Y.p(Y), or vice versa, so you have a canonical form. Skolemize at a later step.
Remember when you convert that your p(S) is a Skolemized existential, and that its negation is ∀Y.¬p(Y).
Define terms equivalent to universals and existentials, such that a represents ∀Y.p(Y) and ¬a then represents ¬∀Y.p(Y), or equivalently, ∃X.¬p(X).
Use the symmetry of Boolean duals, so that the same transformations apply with AND and OR swapped, De Morgan’s Laws, and the equivalence between existentials and negated universals, to restore the symmetry between the expansions of r and ~r. The negations in the conversion between universals and existentials and in De Morgan's Laws cancel each other out, and the duality of switching AND and OR means you can re-use the result on the left to generate the one on the right mechanically again?
Given that you need to support ALL and NOT ALL statements anyway, this should not create any new problems. Just canonicalize and use the same approach you would for a universal.
If you’re solving by converting to SAT, your terms can represent universals, too. So, in your example, you’re trying to replace a with r, but you can still use ~a, equivalent to the negative universal.
In your expressions. you’d still use (~a | r) & (a | ~r), but expand ~r to its correct rather than the incorrect value. That example is trivial, since that’s just ~a, but you’d normally define r as equivalent to a more complex transformation, and in that case you need to remember what both r and ~r represent. It is not really a simple mechanical transformation of the Skolemized expression.
In this example, I’m not sure why it’s a problem that (~a | r) & (a | ~r) is equivalent to (~a | r) & (a | ~a), which simplifies to (~a | r). That’s not going to give you exponential blow-up? When you translate back to first-order predicate logic, make the correct translation.
Update
Thanks for clarifying what the problem was in chat. As I currently think I understand it, what you have is an equivalence with a left and a right side, which contains other nested equivalences, and you want to expand both the equivalence and its negation. The problem is that, because the negation does not have symmetrical form, you need to recurse twice for each nested equivalence in the tree, once when expanding the equivalence and once when expanding its negation?
You should define a transformation that generates the negative expansion from the positive expansion in linear time, and divide-and-conquer the expressions containing nested equivalences using that. This seems to be what you were after with the ~p(S) transformation.
To do this, you recall that ¬∃X.p(X) is equivalent to ∀X.¬p(X), and vice versa. Then if you’ve expanded p(x) into normal form as conjunctions and disjunctions, De Morgan’s Laws lets you turn an expression like ¬(a ∨ ¬b) into ¬a ∧ b. The inner ¬ on the quantifier transformation and the outer ¬ on the De Morgan transformation cancel each other out. Finally, the dual of any Boolean equivalence remains valid when you replace each ∨ and ∧ with the other and any atom a or ¬a with its inverse.
So, while I might be making an error, especially at 1 AM, it looks to me like what you want is the dual transformation that substitutes:
An outer ∃ for ∀ and vice versa
∧ for ∨ and vice versa
Each term t with ¬t and vice versa
Apply this to the expansion of the positive equivalence to generate the negative dual in time proportional to its length, without further recursion.

what's the semantics of Prolog's implementation of negation with non-ground literals

I am familiar with Prolog's implementation of negation as NaF and that even its implementation of NaF is incomplete, esp. floundering with non ground negated literals. My question here is regarding the specific semantics. Suppose you have a clause p(X) :- q(Y). This is the clausal form of \A x,y(q(y) -> p(x)) which is \E y q(y) -> \A x p(x), and this is indeed the semantics that prolog implements. But now consider if I have p(X) :- \+ q(Y). In FOL this would be expressed as \E y ~q(y) -> \A x p(x) ie "if q fails for some y then p holds for every x" but this does not appear to be the semantics that Prolog implements. Rather Prolog will require q to finitely fail for every y before \+ q(y) succeeds and p is true for any x. So its semantics appears to be very different, not just incomplete. Am I missing something?
thanks
In Prolog, p(X) :- \+ q(Y). on its own doesn't sufficiently express the notion that p holds true for every X if q fails for some Y because Prolog doesn't know the possible universe of Y values that are eligible to test q. So, it doesn't know of any values of Y for which q(Y) is not provable.
Let's suppose you had, though, the following:
q(a).
q(b).
q(c).
valid_y(Y) :- member(Y, [a,b,c,d,e]).
Then you could write:
p(_) :- valid_y(Y), \+ q(Y).
Then p(_) succeeds twice as Prolog seeks all solutions. You could use a cut or once/1 to avoid that.

Logical Negation in Prolog

I've read quite a bit about Prolog's Negation by Failure where Prolog in order to prove that \+Goal holds tries to prove that Goal fails.
This is highly connected with CWA (close world assumption) where for example if we query \+P(a) (where P is a predicate of arity 1) and we have no clues that lead to prove P(a) Prolog assumes (due to CWA) that not P(a) holds so \+P(a) succeeds.
From what I've searched this is a way to solve classical logic weakness where if we had no clue about P(a) then we could not answer whether \+P(a) holds.
What described above was the way of introducing non-monotonic reasoning in Prolog. Moreover the interesting part is that Clark proved that Negation by Failure is compatible/similar with classical negation only for ground clauses. I understand that for example:
X=1, \+X==1.: should return false in Prolog (and in classical Logic).
\+X==1, X=1.: should return false in classical logic but it succeeds in Prolog since the time that NF is examined X is not bound, this differs from classic-Pure Logic.
\+X==1.: should not give any answer in classical logic until X is bound, but in Prolog it returns false (possibly to break weakness of classical logic) and this is not same/compatible with pure Logic.
My attempt was to simulate classic negation, thanks to #false's suggestions in comments, current implementation is:
\\+(Goal) :- when(ground(Goal), \+Goal).
Some testing:
?- \\+(X==1).
when(ground(X), \+X==1).
?- X=1, \\+(X==1).
false.
?- \\+(X==1), X=1.
false.
My question:
Is the above a correct interpretation of classical negation?
(Are there any obvious corner cases that it misses?? also I'm concerned about Logic Purity when using when/2, is it safe to assume that the above is pure??).
Prolog cannot do classical negation. Since it does not
use classical inference. Even in the presence of Clark
completion, it cannot detect the following
two classical laws:
Law of noncontradiction: ~(p /\ ~p)
Law of excluded middle: p \/ ~p
Here is an example, take this logic program
and these queries:
p :- p
?- \+(p, \+p)
?- p; \+p
The Clark completion of the logic program is
as follows and the negation as failure query
execution yields the following:
p <-> p
loops
loops
Clark completion adresses the issue of predicate definitions
and negative information. See also section 5.2 Rules and
their Completion. On the other hand, when no predicate
definitions are around, CLP(X) can sometimes do both laws,
when a negation operator is defined deMorgan style. Here is
a negation operator for CLP(B):
?- listing(neg/1).
neg((A;B)) :-
neg(A),
neg(B).
neg((A, _)) :-
neg(A).
neg((_, A)) :-
neg(A).
neg(neg(A)) :-
call(A).
neg(sat(A)) :-
sat(~A).
And here is some execution:
?- sat(P); neg(sat(P)).
P = 0
P = 1.
?- neg((sat(P), neg(sat(P)))).
P = 0
P = 1.
CLP(X) will also have problems when the negation affects domains,
that are usually finite and that would then get infinite. So for
example a constraint such as (#=)/2, ... shouldn't be a problem,
since it can be replaced by a constraint (#\=)/2, ... .
But negation for CLP(FD) will usually not work when applied to constraints
(in)/2. The situation can slightly be mitigated if the CLP(X) system offers
reification. In this case the disjunction can be rendered a little bit more intelligent than just using Prolog backtracking disjunction.
In SWI-Prolog, it is possible to implement the rules of inference for classical logic in Constraint Handling Rules, including de Morgan's laws and the law of noncontradiction:
:- use_module(library(chr)).
:- chr_constraint is_true/1.
:- chr_constraint animal/2.
:- initialization(main).
:- set_prolog_flag('double_quotes','chars').
is_true(A),is_true(A) <=> is_true(A).
is_true(A=B) ==> A=B.
is_true(A\=B) ==> not(A=B).
is_true(not(A)),is_true(A) ==> false.
is_true(not((A;B))) ==> is_true((not(A),not(B))).
is_true(not((A,B))) ==> is_true((not(A);not(B))).
is_true((A,B)) ==> is_true(A),is_true(B).
is_true((A;B)) ==> is_true(A),(is_true(B);is_true(not(B)));is_true(B),(is_true(A);is_true(not(A))).
is_true(not(not(A))) ==> is_true(A).
Then, you can use the solver like this:
is_true(animal(X,A)),is_true(animal((Y,A))) ==> X \= Y,false;X==Y.
is_true((A->B)) ==> is_true(((A;not(A)),B));is_true(((not(A);A),not(B))).
main :- is_true(((X=cat;X=dog;X=moose),(not((animal(dog,tom);animal(moose,tom))),animal(X,tom)))),writeln(animal(X,tom)).
This program prints animal(cat,tom).
But this formula could be solved more efficiently using a different algorithm, such as DPLL.

How to do cases with an inductive type in Coq

I wan to use the destruct tactic to prove a statement by cases. I have read a couple of examples online and I'm confused. Could someone explain it better?
Here is a small example (there are other ways to solve it but try using destruct):
Inductive three := zero
| one
| two.
Lemma has2b2: forall a:three, a<>zero /\ a<>one -> a=two.
Now some examples online suggest doing the following:
intros. destruct a.
In which case I get:
3 subgoals H : zero <> zero /\ zero <> one
______________________________________(1/3)
zero = two
______________________________________(2/3)
one = two
______________________________________(3/3)
two = two
So, I want to prove that the first two cases are impossible. But the machine lists them as subgoals and wants me to PROVE them... which is impossible.
Summary:
How to exactly discard the impossible cases?
I have seen some examples using inversion but I don't understand the procedure.
Finally, what happens if my lemma depends on several inductive types and I still want to cover ALL cases?
How to discard impossible cases? Well, it's true that the first two obligations are impossible to prove, but note they have contradicting assumptions (zero <> zero and one <> one, respectively). So you will be able to prove those goals with tauto (there are also more primitive tactics that will do the trick, if you are interested).
inversion is a more advanced version of destruct. Additional to 'destructing' the inductive, it will sometimes generate some equalities (that you may need). It itself is a simple version of induction, which will additionally generate an induction hypothesis for you.
If you have several inductive types in your goal, you can destruct/invert them one by one.
More detailed walk-through:
Inductive three := zero | one | two .
Lemma test : forall a, a <> zero /\ a <> one -> a = two.
Proof.
intros a H.
destruct H. (* to get two parts of conjunction *)
destruct a. (* case analysis on 'a' *)
(* low-level proof *)
compute in H. (* to see through the '<>' notation *)
elimtype False. (* meaning: assumptions are contradictory, I can prove False from them *)
apply H.
reflexivity.
(* can as well be handled with more high-level tactics *)
firstorder.
(* the "proper" case *)
reflexivity.
Qed.
If you see an impossible goal, there are two possibilities: either you made a mistake in your proof strategy (perhaps your lemma is wrong), or the hypotheses are contradictory.
If you think the hypotheses are contradictory, you can set the goal to False, to get a little complexity out of the way. elimtype False achieves this. Often, you prove False by proving a proposition P and its negation ~P; the tactic absurd P deduces any goal from P and ~P. If there's a particular hypothesis which is contradictory, contradict H will set the goal to ~H, or if the hypothesis is a negation ~A then the goal will be A (stronger than ~ ~A but usually more convenient). If one particular hypothesis is obviously contradictory, contradiction H or just contradiction will prove any goal.
There are many tactics involving hypotheses of inductive types. Figuring out which one to use is mostly a matter of experience. Here are the main ones (but you will run into cases not covered here soon):
destruct simply breaks down the hypothesis into several parts. It loses information about dependencies and recursion. A typical example is destruct H where H is a conjunction H : A /\ B, which splits H into two independent hypotheses of types A and B; or dually destruct H where H is a disjunction H : A \/ B, which splits the proof into two different subproofs, one with the hypothesis A and one with the hypothesis B.
case_eq is similar to destruct, but retains the connections that the hypothesis has with other hypotheses. For example, destruct n where n : nat breaks the proof into two subproofs, one for n = 0 and one for n = S m. If n is used in other hypotheses (i.e. you have a H : P n), you may need to remember that the n you've destructed is the same n used in these hypotheses: case_eq n does this.
inversion performs a case analysis on the type of a hypothesis. It is particularly useful when there are dependencies in the type of the hypothesis that destruct would forget. You would typically use case_eq on hypotheses in Set (where equality is relevant) and inversion on hypotheses in Prop (which have very dependent types). The inversion tactic leaves a lot of equalities behind, and it's often followed by subst to simplify the hypotheses. The inversion_clear tactic is a simple alternative to inversion; subst but loses a little information.
induction means that you are going to prove the goal by induction (= recursion) on the given hypothesis. For example, induction n where n : nat means that you'll perform integer induction and prove the base case (n replaced by 0) and the inductive case (n replaced by m+1).
Your example is simple enough that you can prove it as “obvious by case analysis on a”.
Lemma has2b2: forall a:three, a<>zero/\a<>one ->a=two.
Proof. destruct a; tauto. Qed.
But let's look at the cases generated by the destruct tactic, i.e. after just intros; destruct a.. (The case where a is one is symmetric; the last case, where a is two, is obvious by reflexivity.)
H : zero <> zero /\ zero <> one
============================
zero = two
The goal looks impossible. We can tell this to Coq, and here it can spot the contradiction automatically (zero=zero is obvious, and the rest is a first-order tautology handled by the tauto tactic).
elimtype False. tauto.
In fact tauto works even if you don't start by telling Coq not to worry about the goal and wrote tauto without the elimtype False first (IIRC it didn't in older versions of Coq). You can see what Coq is doing with the tauto tactic by writing info tauto. Coq will tell you what proof script the tauto tactic generated. It's not very easy to follow, so let's look at a manual proof of this case. First, let's split the hypothesis (which is a conjunction) into two.
destruct H as [H0 H1].
We now have two hypotheses, one of which is zero <> zero. This is clearly false, because it's the negation of zero = zero which is clearly true.
contradiction H0. reflexivity.
We can look in even more detail at what the contradiction tactic does. (info contradiction would reveal what happens under the scene, but again it's not novice-friendly). We claim that the goal is true because the hypotheses are contradictory so we can prove anything. So let's set the intermediate goal to False.
assert (F : False).
Run red in H0. to see that zero <> zero is really notation for ~(zero=zero) which in turn is defined as meaning zero=zero -> False. So False is the conclusion of H0:
apply H0.
And now we need to prove that zero=zero, which is
reflexivity.
Now we've proved our assertion of False. What remains is to prove that False implies our goal. Well, False implies any goal, that's its definition (False is defined as an inductive type with 0 case).
destruct F.

Prolog implying a negative predicate

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

Resources