Please don't feel obligated to answer the following before May, or even read it.
I didn't realize the space of Datalogs was so broad—I had thought that there was a single "stratified semantics" that was the standard. The stratified semantics that I knew about permits bottom-up evaluation with negation as failure to be decidable by putting negations of any predicate X/n into a stratum strictly higher than X/n (which is evaluated later), and non-negated consequences of X/n into a stratum equal to or higher than X/n's stratum.
Like, as I understand it, if we have
foo(X) :- bar(X), \+ baz(X, 3).
quux(X) :- foo(X).
then we put baz/2 in a lower stratum than foo/1, and quux/1 in a stratum not lower than foo/1. That way, by the time we are trying to infer foo/1 facts and quux/1 facts, we've already finished inferring all the baz/2 facts. Then, there's no way that we can infer more baz/2 facts in the future that could invalidate our foo/1 or quux/1 inferences.And this avoids the kind of non-monotonic loop you're talking about: if inferring fact A invalidates the inference of fact B, then B is in a strictly higher stratum than A, so we haven't inferred B yet at the time that we infer A.
I think that with unrestricted negation the inconsistency or nontermination problem you mention does exist, in which there exists no (consistent) model for a program (is that the right terminology?); the simplest example would be:
epimenides :- \+ epimenides.
The stratification restriction avoids this because it would require the stratum of epimenides/1 to be strictly greater than itself, which a standard CLP(FD) solver like SWI-Prolog's will easily tell you cannot be done: ?- use_module(library(clpfd)).
% library(error) compiled into error 0.00 sec, 17,872 bytes
% library(apply) compiled into apply 0.00 sec, 29,088 bytes
% library(assoc) compiled into assoc 0.00 sec, 36,240 bytes
% library(lists) compiled into lists 0.00 sec, 25,304 bytes
% library(pairs) compiled into pairs 0.00 sec, 9,040 bytes
% library(clpfd) compiled into clpfd 0.03 sec, 736,792 bytes
true.
?- X #> X.
false.
I think there's an additional problem as well, corresponding to Henkin sentences—programs for which models do exist, but for which there is no unique minimal model. For example, we could try to formalize George W. Bush's foreign policy: withUs(You) :- person(You), \+ withTheTerrorists(You).
withTheTerrorists(You) :- person(You), \+ withUs(You).
person(chirac).
Now we have two minimal models, one in which person(chirac), withUs(chirac) and one in which person(chirac), withTheTerrorists(chirac). (Thus we can explain Freedom Fries, one of the most ridiculous and terrifying aspects of the politics of the early 02000s.) Further inference rules might rule out one, the other, or both of these models.In the same way, the stratification rule rejects this program: withUs/1 needs to be above (evaluated later than) withTheTerrorists/1, but also vice versa. I'm not sure how to state this so SWIPL's CLP(FD) can tell that it's unsolvable, but that's probably because I'm a total noob at logic in general:
?- X #> Y, Y #> X.
X#=<Y+ -1,
Y#=<X+ -1.
?- X #> Y, Y #> X, label([X, Y]).
ERROR: Arguments are not sufficiently instantiated
Of course it is not a hard problem to assign strata—a straightforward topological sort will immediately reject the loop.The stratification rule is conservative, though; not only will it reject all the undecidable problems, it will also reject some programs where a unique minimal model does exist; as a trivial example:
withUs(chirac).
withUs(You) :- person(You), \+ withTheTerrorists(You).
withTheTerrorists(You) :- person(You), \+ withUs(You).
person(chirac).
So it makes sense that people would look for looser restrictions that still guarantee decidability.Anyway, that's my understanding of the situation! I might be mistaken about basic things.
Thanks for the reference to the book! It looks great and I'll try to read it. Or, I guess, work through it.