1

I am starting to work with DLV (Disjunctive Datalog) and I have a rule that is reporting a "Rule is not safe" error, when running the code. The rule is the following:

foo(R, 1) :- not foo(R, _)

I have read the manual and seen that "cyclic dependencies are disallowed". I guess this is why I am being reported the error, but I am not sure how this statement is so problematic to DLV. The final goal is to have some kind of initialization in case that the predicate has not been defined.

More precisely, if there is no occurrence of 'foo' with the parameter R (and anything else), then define it with parameters R and 1. Once it is defined, the rule shouldn't be triggered again. So, this is not a real recursion in my opinion.

Any comments on how to solve this issue are welcomed!


I have realised that I probably need another predicate to match the parameter R in the body of the rule. Something like this:

foo(R, 1) :- not foo(R, _), bar(R)

Since, otherwise there would be no way to know whether there are no occurrences of foo(R, _). I don't know whether I made myself clear.

Anyway, this doesn't work either :(

false
  • 10,264
  • 13
  • 101
  • 209
rutex
  • 137
  • 3
  • 12
  • 1
    I'm a bit rusty in asp semantics, but a specialisation of your program is ```foo(dummy,1) :- not foo(dummy,1).``` i.e. foo(dummy,1) is in an extension if it is not in an extension? That sounds contradictory to me. – lambda.xy.x Jul 26 '16 at 15:20
  • I am new to asp but years ago I played with other languages alike. My final goal here is to find a way of defining foo(dummy, 1) if it hasn't been defined yet. My impression from what I know about DLV is that "not foo(.)" is considered as negation-as-failure, which means that it can be read as "if there is no evidence that foo(.) is true" or in other words "foo(.) does not appear" – rutex Jul 27 '16 at 07:15
  • 1
    As far as I remember the problem with cyclicity and negation is that you start with an empty model ```{}```, then ```not foo(_)``` holds and you extend the model to ```{foo(1)}```. But then the justification for using that rule is invalidated. What about a two stage approach? Something along the lines of```bar(1) :- not foo(_). bar(X) :- foo(X).```. – lambda.xy.x Jul 27 '16 at 10:07
  • Tried that but still returns a "Rule is not safe" error. I think the problem is with combining not and _. I just tried the rule I defined with something instead of _ and it works fine. Fortunately in this case, I only expect 3 different values here but what if _ could be say 256 values? – rutex Jul 28 '16 at 11:12

1 Answers1

1

To the particular "Rule is not safe" error: First of all this has nothing to do with cyclic or acyclic dependencies. The same error message shows up for the non-cyclic program:

foo2(R, 1) :- not foo(R,_), bar(R).

The problem is that the program is actually not safe (http://www.dlvsystem.com/html/DLV_User_Manual.html#SAFETY). As mentioned in the section on negative rules (anchor #AEN375, I am only allowed to use 2 links in my answer):

Variables, which occur in a negated literal, must also occur in a positive literal in the body.

Observe that the _ is an anonymous variable. I.e., the program

foo(R,1) :- not foo(R,_), bar(R).

can be equivalently written as (and is equivalent to)

foo(R,1) :- not foo(R,X), bar(R).

Anonymous variables (DLV manual, anchor #AEN264 - at the end of the section) just allow us to avoid inventing names for variables that will only occur once within the rule (i.e. for variables that only express "there is some value, I absolutely do not care about it), but they are variables nevertheless. And since negation with not is "negation" and not "true negation" (or "strong negation" as it is also often called), none of the three safety conditions is satisfied by the rule.

A very rough and high-level intuition for safety is that it guarantees that every variable in the program can be assigned to some finite domain - as it is now the case with R by adding bar(R). However, the same also must be the case for the anonymous variable _ .

To the actual problem of defining default values: As pointed out by lambda.xy.x, the problem here is the Answer Set (or stable model) semantics of DLV: Trying to do it in one rule does not give any solution: In order to get a safe program, we could replace the above problems e.g. by

foo(1,2). bar(1). bar(2).
tmp(R) :- foo(R,_).
foo(R,1) :- not tmp(R), bar(R).

This has no stable model: Assume the answer is, as intended, {foo(1,2), bar(1), bar(2), foo(2,1)} However, this is not a valid model, since tmp(R) :- foo(R,_) would require it to contain tmp(2). But then, "not tmp(2)" is no longer true, and therefore having foo(2,1) in the model violates the required minimality of the model. (This is not exactly what is going on, more a rough intuition. More technical details could be found in any article on answer set programming, a quick Google search gave me this paper as one of the first results: http://www.kr.tuwien.ac.at/staff/tkren/pub/2009/rw2009-asp.pdf)

In order to solve the problem, it is therefore somehow necessary to "break the cycle". One possibility would be:

foo(1,2). bar(1). bar(2). bar(3). 
tmp(R) :- foo(R,X), X!=1.
foo(R,1) :- bar(R), not tmp(R).

I.e., by explicitly stating that we want to add R into the intermediate atom only if the value is different from 1, having foo(2,1) in the model does not contradict tmp(2) not being part of the model as well. Of course, this no longer allows to distinguish whether foo(R,1) is there as default value or by input, but if this is not required ...

Another possibility would be to not use foo for the computation, but some foo1 instead. I.e. having

foo1(R,X) :- foo(R,X).
tmp(R) :- foo(R,_).
foo1(R,1) :- bar(R), not tmp(R).

and then just use foo1 instead of foo.

  • Thank you for your response. Now I came across a [similar problem](http://stackoverflow.com/questions/39655922/dlv-list-composition) and was wondering if you could help. I tried using the `tmp(R)' trick but didn't work. Using this, the result is empty... – rutex Sep 23 '16 at 08:47