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.
Related
The tag logical purity mentions (=)/2 as pure. Is it
"intrinsically" pure or "operational" pure? To the
best of my knowledge it can be defined by this Horn clause:
∀x(=(x, x))
Which is this Prolog fact, if were not already a built-in:
X = X.
This means (=)/2 would be "intrinsically" pure, as SWI-Prolog already remarks. So what is
then the difference to first order equality (FOL=), if there
are any differences?
The "intrinsinc" definition of (=)/2 I guess does assure that the unify predicate is reflexive, symmetric and transitive. Requirements that are also satisfied by FOL=. But FOL= also requires congruence, which is this axiom schema:
/* Predicate Congruence in FOL= */
∀x1..∀xn∀yj(=(xj, yj) & p(x1, .., xn) -> p(x1, .., xj-1, yj, xj+1, .., xn))
Which is not represented by the only Horn clause for the unify predicate. And since the unify predicate is a built-in, the missing Horn clauses can also not be added. So what can go wrong? Can we make an example that would go wrong?
The classical example is this fact:
p(morning_star).
Obviously this query succeeds in Prolog:
?- p(morning_star).
true
But this query fails in Prolog, whereas in FOL= it would succeed:
?- morning_star = evening_star, p(evening_star).
false
The situation is different in so called unification modulo theories, where the unification and also the unify predicate might change their meaning.
The question
I have a question related to logical purity.
Is this program pure?
when(ground(X), X > 2).
Some [ir]relevant details about the context
I'm trying to write pure predicates with good termination properties. For instance, I want to write a predicate list_length/2 that describes the relation between a list and its length. I want to achieve the same termination behaviour as the built-in predicate length/2.
My question seeks to find if the following predicate is pure:
list_length([], 0).
list_length([_|Tail], N):-
when(ground(N), (N > 0, N1 is N - 1)),
when(ground(N1), N is N1 + 1),
list_length(Tail, N1).
I can achieve my goal with clpfd ...
:- use_module(library(clpfd)).
:- set_prolog_flag(clpfd_monotonic, true).
list_length([], 0).
list_length([_|Tail], N):-
?(N) #> 0,
?(N1) #= ?(N) - 1,
list_length(Tail, N1).
... or I can use var/1, nonvar/1 and !/0, but then is hard to prove that the predicate is pure.
list_length([],0).
list_length([_|Tail], N):-
nonvar(N), !,
N > 0,
N1 is N - 1,
list_length(Tail, N1).
list_length([_|Tail], N):-
list_length(Tail, N1),
N is N1 + 1.
Logical purity of when/2 and ground/1
Note that there is the ISO built-in ground/1 which is just as impure as nonvar/1.
But it seems you are rather talking about the conditions for when/2. In fact, any accepted condition for when/2 is as pure as it can get. So this is not only true for ground/1.
Is this program pure?
when(ground(X), X > 2).
Yes, in the current sense of purity. That is, in the very same sense that considers library(clpfd) as pure. In the very early days of logic programming and Prolog, say in the 1970s, a pure program would have been only one that succeeds if it is true and fails if it is false. Nothing else.
However, today, we accept that ISO errors, like type errors are issued in place of silent failure. In fact, this makes much more sense from a practical point of view. Think of X = non_number, when(ground(X), X > 2 ). Note that this error system was introduced relatively late into Prolog.
While Prolog I reported errors of built-ins explicitly1 the subsequent DEC10-Prolog (as of, e.g. 1978, 1982) nor C-Prolog did not contain a reliable error reporting system. Instead, a message was printed and the predicate failed thus confusing errors with logical falsity. From this time, there is still the value warning of the Prolog flag unknown (7.11.2.4 in ISO/IEC 13211-1:1995) which causes the attempt to execute an undefined predicate to print a warning and fail.
So where's the catch? Consider
?- when(ground(X), X> 2), when(ground(X), X < 2).
when(ground(X), X>2), when(ground(X), X<2).
These when/2s, while perfectly correct, now contribute a lot to producing inconsistencies as answers. After all, above reads:
Yes, the query is true, provided the very same query is true.
Contrast this to SICStus' or SWI's library(clpfd):
?- X #> 2, X #< 2.
false.
So library(clpfd) is capable of detecting this inconsistency, whereas when/2 has to wait until its argument is ground.
Getting such conditional answers is often very confusing. In fact, many prefer in many situations a more mundane instantiation error to the somewhat cleaner when.
There is no obvious general answer to this. After all, many interesting theories for constraints are undecidable. Yes, the very harmless-looking library(clpfd) permits you to formulate undecidable problems already! So we will have to live with such conditional answers that do not contain solutions.
However, once you get a pure unconditional solution or once you get real failure you do know that this will hold.
list_length/2
Your definition using library(clpfd) is actually slightly better w.r.t. termination than what has been agreed upon for the Prolog prologue. Consider:
?- N in 1..3, list_length(L, N).
Also, the goal length(L,L) produces a type error in a very natural fashion. That is, without any explicit tests.
Your version using when/2 has some "natural" irregularities, like length(L,0+0) fails but length(L,1+0) succeeds. Otherwise it seems to be fine — by construction alone.
The earliest account is on p.9 of G. Battani, H. Meloni. Interpréteur du langage de programmation Prolog. Rapport de D.E.A. d'informatique appliquée, 1973. There, a built-in in error was replaced by a goal that was never resolved. In current terms plus/3 of II-3-6 a, p.13 would be in current systems with freeze/2:
plus(X, Y, Z) :-
( integer(X), integer(Y), ( var(Z) ; integer(Z) )
-> Z is X+Y
; freeze(_,erreur(plus(X,Y,Z)))
).
So plus/3 was not "multi-directional".
I have a little question about the negation as failure in Prolog language:
This is a question more theoretical than practical because I have clear how this example work.
so I have the following Prolog program:
/* Fatti che specificano quali esseri sono degli animali: */
animal(cat).
animal(dog).
animal(frog).
animal(horse).
animal(viper).
animal(boa).
animal(python).
/* Fatti che specificano quali esseri sono dei serpenti: */
snake(viper).
snake(boa).
snake(python).
/* X è un serpente, fallisce ed impedisce il backtracking quindi
il predicato likes(mary,X) risulta essere falso: */
likes(mary,X) :- snake(X),
!,
fail.
/* Se X è un animale allora a mary piace: */
likes(mary, X) :- animal(X).
In Prolog I can't simply say something like: "Mary loves every animals, BUT NOT THE SNAKES"
and I have to formulate it in this way: "If X is a snake, then Mary don't love it. Otherwise, if X it is an animal, mary love it"
The precedent program do exactly this thing, by the rule:
likes(mary,X) :- snake(X),
!,
fail.
Prolog check if it is true that X it is a snake, imposes the cut to avoid backtracking and force a failure of the predicate.
In this way if snake(X) is TRUE the program force the failure also of the head prediate likes(mary,X) and imposing backtracking avoid the possibility to execute the other rule in the program (that answer true because a snake is also an animal)
My question is: it seems me that this use of Prolog falls outside from the logical and declarative paradigm and in some way fall in some sort of procedural paradigm
Because:
I have to impose an order of the 2 predicate (so in some way I am saying: if the first fail, try the second).
But even more I am saying that: if the first rule match (X it is a snake) then execute a forced failure and imposes no backtracking.
This seems to me more near to a procedural meaning that a classical logical meaning...
Is it that? Is it that in these cases, Prolog uses a procedural behavior to overcome a limitation of the logic?
I disagree with 'limitations of the logic'.
The same would be
likes(mary,X) :- not(snake(X)) , animal(X).
Because Prolog uses a depth-first-search some things can be expressed in an shorter way that then depends on the depth-first-search backtracking algorithm.
x :- a, !, b.
x :- c.
x :- d.
is the same as
x :- a, b.
x :- not(a), c.
x :- not(a), d.
Programs that make use of cut (!) are most of the time
sensitive to the ordering of goals and clauses in their
meaning and not only in their termination, so they are
often not declarative.
The negation as failure (\+) ecapsulates in a certain way
the cut. It is defined and even implemented by most Prolog
systems as follows:
\+ X :- X, !, fail.
\+ _ .
Although it hints a logical meaning and thus declarativity,
the negation as failure is still sensitive to ordering of
goals. Here is an example. Assume we have the following
database:
p(a).
q(b,c).
Then the following query produces X=a as a solution:
?- p(X), \+ q(X,Y).
X = a.
But if the arguments of the conjunction (,)/2 switch side,
a different result is obtained:
?- \+ q(X,Y), p(X).
false.
Ergo, negation as failure is not declarative per se. For
ground term flow of arguments, negation as failure sneeks
in an existential quantifiers. So a query of the form:
?- A(X), \+ B(X,Y).
Has essentially the meaning that it quantifies the fresh
variables Y inside the negation:
?- A(X), ~ exists Y B(X,Y).
So in the above example where conjunction is switched, the
set of fresh variables in the negation as failure changes, thats
why different solutions are obtained.
Bye
In short, yes, it is procedural.
Negation as failure uses a cut, and cuts are procedural concepts. You cannot use negation as failure in a declarative way - it is not possible.
It is worth mentioning that not all uses of cuts throw declarativeness out of the window - some of them just increase efficiency. But unfortunately, this is not the case with negation as failure - declarativeness goes out the window.
(Prolog is just a procedural prover disguised as a declarative language lol)
I've got a very large number of equations which I am trying to use PROLOG to solve. However, I've come a minor cropper in that they are not specified in any sort of useful order- that is, some, if not many variables, are used before they are defined. These are all specified within the same predicate. Can PROLOG cope with the predicates being specified in a random order?
Absolutely... ni (in Italian, Yes and Not)
That is, ideally Prolog requires that you specify what must be computed, not how, writing down the equations controlling the solution in a fairly general logical form, Horn clauses.
But this ideal is far from reach, and this is the point where we, as programmers, play a role. You should try to topologically sort formulae, if you want Prolog just apply arithmetic/algorithms.
But at this point, Prolog is not more useful than any other procedural language. It just make easier to do such topological sort, in sense that formulas can be read (this builtin it's a full Prolog parser!), variables identified and quantified easily, terms transformed, evaluated, and the like (metalanguages features, a strong point of Prolog).
Situation changes if you can use CLP(FD). Just an example, a bidirectional factorial (cool, isn't it?), from the documentation of the shining implementation that Markus Triska developed for SWI-Prolog:
You can also use CLP(FD) constraints as a more declarative alternative for ordinary integer arithmetic with is/2, >/2 etc. For example:
:- use_module(library(clpfd)).
n_factorial(0, 1).
n_factorial(N, F) :- N #> 0, N1 #= N - 1, F #= N * F1, n_factorial(N1, F1).
This predicate can be used in all directions. For example:
?- n_factorial(47, F).
F = 258623241511168180642964355153611979969197632389120000000000 ;
false.
?- n_factorial(N, 1).
N = 0 ;
N = 1 ;
false.
?- n_factorial(N, 3).
false.
To make the predicate terminate if any argument is instantiated, add the (implied) constraint F #\= 0 before the recursive call. Otherwise, the query n_factorial(N, 0) is the only non-terminating case of this kind.
Thus if you write your equations in CLP(FD) you get much more chances to have your 'equation system' solved as is. SWI-Prolog has dedicated debugging for the low level details used to solve CLP(FD).
HTH
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