natural_number(1) -> false. Problems with s/1 predicate - prolog

I'm using swi-prolog. I'm simply trying to follow the examples in the book "the art of prolog", but I'm not getting the correct results. I'm afraid this might be due to the s/1 predicate. I can't even find s/1 in the documentation for swipl, the only predicate that is similar is succ/2: http://www.swi-prolog.org/pldoc/man?predicate=succ/2 This can't be used the same way as s/1. I'd much prefer to have the s predicate.
This is the program for determining whether a number is a natural number:
natural_number(0).
natural_number(s(X)) :- natural_number(X).
However, natural_number(1) for example yields false. What's the problem here?

Related

Why is Prolog's failure by negation not considered logical negation?

In many Prolog guides the following code is used to illustrate "negation by failure" in Prolog.
not(Goal) :- call(Goal), !, fail.
not(Goal).
However, those same tutorials and texts warn that this is not "logical negation".
Question: What is the difference?
I have tried to read those texts further, but they don't elaborate on the difference.
I like #TesselatingHeckler's answer because it puts the finger on the heart of the matter. You might still be wondering, what that means for Prolog in more concrete terms. Consider a simple predicate definition:
p(something).
On ground terms, we get the expected answers to our queries:
?- p(something).
true.
?- \+ p(something).
false.
?- p(nothing).
false.
?- \+ p(nothing).
true.
The problems start, when variables and substitution come into play:
?- \+ p(X).
false.
p(X) is not always false because p(something) is true. So far so good. Let's use equality to express substitution and check if we can derive \+ p(nothing) that way:
?- X = nothing, \+ p(X).
X = nothing.
In logic, the order of goals does not matter. But when we want to derive a reordered version, it fails:
?- \+ p(X), X = nothing.
false.
The difference to X = nothing, \+ p(X) is that when we reach the negation there, we have already unified X such that Prolog tries to derive \+p(nothing) which we know is true. But in the other order the first goal is the more general \+ p(X) which we saw was false, letting the whole query fail.
This should certainly not happen - in the worst case we would expect non-termination but never failure instead of success.
As a consequence, we cannot rely on our logical interpretation of a clause anymore but have to take Prolog's execution strategy into account as soon as negation is involved.
Logical claim: "There is a black swan".
Prolog claim: "I found a black swan".
That's a strong claim.
Logical negation: "There isn't a black swan".
Prolog negation: "I haven't found a black swan".
Not such a strong a claim; the logical version has no room for black swans, the Prolog version does have room: bugs in the code, poor quality code not searching everywhere, finite resource limits to searching the entire universe down to swan size areas.
The logical negation doesn't need anyone to look anywhere, the claim stands alone separate from any proof or disproof. The Prolog logic is tangled up in what Prolog can and cannot prove using the code you write.
There are a couple of reasons why,
Insufficient instantiation
A goal not(Goal_0) will fail, iff Goal0 succeeds at the point in time when this not/1 is executed. Thus, its meaning depends on the very instantiations that happen to be present when this goal is executed. Changing the order of goals may thus change the outcome of not/1. So conjunction is not commutative.
Sometimes this problem can be solved by reformulating the actual query.
Another way to prevent incorrect answers is to check if the goal is sufficiently instantiated, by checking that say ground(Goal_0) is true producing an instantiation error otherwise. The downside of this approach is that quite too often instantiation errors are produced and people do not like them.
And even another way is to delay the execution of Goal_0 appropriately. The techniques to improve the granularity of this approach are called constructive negation. You find quite some publications about it but they have not found their way into general Prolog libraries. One reason is that such programs are particularly hard to debug when many delayed goals are present.
Things get even worse when combining Prolog's negation with constraints. Think of X#>Y,Y#>X which does not have a solution but not/1 just sees its success (even if that success is conditional).
Semantic ambiguity
With general negation, Prolog's view that there exists exactly one minimal model no longer holds. This is not a problem as long as only stratified programs are considered. But there are many programs that are not stratified yet still correct, like a meta-interpreter that implements negation. In the general case there are several minimal models. Solving this goes far beyond Prolog.
When learning Prolog stick to the pure, monotonic part first. This part is much richer than many expect. And you need to master that part in any case.

What am I missing about equality and unification in Prolog?

I'm working through Clocksin and Mellish to try and finally go beyond just dabbling in Prolog. FWIW, I'm running SWI-Prolog:
SWI-Prolog version 7.2.3 for x86_64-linux
Anyway, I implemented a diff/2 predicate as part of exercise 1.4. The predicate is very simple:
diff(X,Y) :- X \== Y.
And it works when used in the sister_of predicate, like this:
sister_of(X,Y) :-
female(X),
diff(X,Y),
parents(X, Mum, Dad ),
parents(Y, Mum, Dad ).
in that, assuming the necessary additional facts, doing this:
?- sister_of(alice,alice).
returns false as expected. But here's the rub. If I do this instead:
?- sister_of(alice, Who).
(again, given the additional facts necessary)
I get
Who = edward ;
Who = alice;
false
Even though, as already shown, the sister_of predicate does not treat alice as her own sister.
On the other hand, if I use the SWI provided dif/2 predicate, then everything works the way I would naively expect.
Can anyone explain why this is happening this way, and why my diff implementation doesn't work the way I'm expecting, in the case where I ask for additional unifications from that query?
The entire source file I'm working with can be found here
Any help is much appreciated.
As you note, the problem stems from the interplay between equality (or rather, inequality) and unification. Observe that in your definition of sister_of, you first find a candidate value for X, then try to constrain Y to be different, but Y is still an uninstantiated logic variable and the check is always going to succeed, like diff(alice, Y) will. The following constraints, including the last one that gives a concrete value to Y, come too late.
In general, what you need to do is ensure that by the time you get to the inequality check all variables are instantiated. Negation is a non-logical feature of Prolog and therefore potentially dangerous, but checking whether two ground terms are not equal is safe.

Prolog parsing malfunctioning

My code takes an expression like or(lit(true),lit(X)),X) and outputs it as a list of lists.
tocnf(Tree, Expr) :-
trans(Tree ,Expr, []).
trans(lit(X)) -->bbool(X).
trans(or(lit(X1),lit(X2))) --> bconj(X1), bdisj(X2).
trans(and(lit(X1),lit(X2))) --> bbool(X1), bconj(X2).
bdisj(Conj) --> bconj(Conj).
bconj(Bool) --> bbool(Bool).
bbool(X) --> [[X]].
this code should take something like
tocnf(lit(X),X)
output it as
[[X]]
or
tocnf(or(lit(true),lit(X)),X)
and output it as
[[true],[X]].
Question is why when I do
tocnf(or(lit(true), and(lit(X),lit(true))),X)
it outputs
false.
Preliminaries
First, a note on style: You should always use the phrase/2 interface to access DCGs, so write tocnf/2 as:
tocnf(Tree, Expr) :-
phrase(trans(Tree), Expr).
Further, tocnf/2 is a rather imperative name, since it implies a direction of use ("to" CNF). However, the relation also makes sense in other directions, for example to generate answers. Therefore, try to find a better name, that does justice to this general nature of Prolog. I leave this as an exercise.
Declarative debugging
Now, on to your actual question. Apply declarative debugging to find the reason for the failure.
We start with the query you posted:
?- tocnf(or(lit(true), and(lit(X),lit(true))), X).
false.
This means that the program is unexpectedly too specific: It fails in a case we expect to succeed.
Now, we generalize the query, to find simpler cases that still fail. This is completely admissible because your program is written using the monotonic subset of Prolog, as is highly recommended to make declarative debugging applicable.
To generalize the query, I use variables instead of some subterms. For example:
?- tocnf(or(lit(_), and(lit(X),lit(true))), X).
false.
Aha! This still fails, and therefore every more specific query will also fail.
So, we proceed like this, using variables instead of some subterms:
?- tocnf(or(lit(_), and(lit(X),lit(_))), X).
false.
?- tocnf(or(_, and(lit(X),lit(_))), X).
false.
?- tocnf(or(_, and(_,lit(_))), X).
false.
?- tocnf(or(_, and(_,_)), X).
false.
All of these queries also fail.
Now, we take it just one step further:
?- tocnf(or(_, _), X).
X = [[_G793], [_G795]].
Aha! So we have found a case that succeeds, and one slightly more specific though still very simple case that fails:
?- tocnf(or(_, and(_,_)), X).
false.
This is the case I would start with: Think about why your relation does not work for terms of the form or(_, and(_,_)).
Automated solution
A major attraction of pure monotonic Prolog is that the reasoning above can be automated:
The machine should find the reason for the failure, so that we can focus on more important tasks.
One way to do this was generously made available by Ulrich Neumerkel.
To try it out, you need to install:
library(diadem) and
library(lambda).
Now, to recapitulate: We have found a query that unexpectedly fails. It was:
?- tocnf(or(lit(true), and(lit(X),lit(true))), X).
false.
To find a reason for this, we first load library(diadem):
?- use_module(library(diadem)).
true.
Then, we repost the query with a slight twist:
?- tocnf(or(lit(true), and(lit(X),lit(true))), X).?Generalization.
That is, I have simply appended ?Generalization. to the previous query.
In response, we get:
Generalization = tocnf(or(_, and(_, _)), _) .
Thus, Generalization is a more general goal that still fails. Since the Prolog program we are considering is completely pure and monotonic, we know that every more specific query will also fail. Therefore, I suggest you focus on this simpler and more general case, which was found automatically in this case, and is the same goal we also found manually after several steps.
Unexpected failure is a common issue when learning Prolog, and automated declarative debugging lets you quickly find the reasons.

Prolog not returning expected values

I'm trying to get comfortable with Prolog (SWI Prolog specifically).
I have this very simple listing:
animal(bear).
animal(mouse).
animal(bird).
Now whenever I ask for all atoms that fulfill (what is the correct expression?) the predicate
animal I always get only the first one.
?- animal(X).
X = bear .
Though all three atoms evaluate to 'true' for animal.
?- animal(mouse).
true.
?- animal(bird).
true.
What am I doing wrong? Is this behavior controllable via some setting?
There is nothing wrong in your code. Prolog is a reasoning machine. So it tries to find the first solution that will satisfy all the variables.
Once the solution is found it prints it out.
Now if you need additional solution there should be some combination that you should enter so that prolog will continue searching.
If I remember correctly it might be a semicolon...
Hope this helps

Applying constraints in swipl

I am required to write my own version of all_different in SWI-Prolog. I've written a predicate that returns the same true/false on the inputs I'm giving as all_different does, but I'm having trouble finding online a way to actually apply this predicate as a constraint.. Here is my version of all_different.
distinct([]).
distinct([X|Xs]) :-
different(X,Xs),
distinct(Xs).
different(_,[]).
different(X,[Y|Ys]) :-
(nonvar(X), nonvar(Y) -> X \= Y
;
true
),
different(X,Ys).
I need it to apply to a list of integers and _. Yes, this is the sudoku program project. Sorry if this is a dumb question, but I am still very new to Prolog, and I find it difficult to find sufficient documentation online.
Please help!
You have written a predicate and not a constraint. In a nutshell, predicates either succeed or fail, while constraints only express restrictions on the possible values. Constraints are being recorded by the constraints' solver that does some black magic to simplify them and to indicate ranges of possible values for the variables involved. Hence, you cannot apply your predicate as a constraint.
You can either reconsider the original problem and check whether you need a constraint, or modify your implementation above as follows (I'm using SWI-Prolog):
different(X,[Y|Ys]) :-
X#\= Y,
different(X,Ys).
#\= indicates that the disequality expression is a constraint.
You might like to check http://www.swi-prolog.org/man/clpfd.html and specifically differences between all_different/1 and all_distinct/1.

Resources