On 11/07/13 18:48, Joshua TAYLOR wrote:
I'm experiencing some confusion about how tabling and the side effects
(or required computation) of builtins interact. In particular, here's
a set of rules that implicitly describes a list structure (a -> b ->
c) where a value for each element can be computed only after the value
for its successor (if any) has been computed). I've represented this
with three backwards chaining rules. The computed value is simply a
string concatenation of 'value ' and the node's URI.
[rule_a: (a value ?value) <- (b value ?value0) (a compute ?value)]
[rule_b: (b value ?value) <- (c value ?value0) (b compute ?value)]
[rule_c: (c value ?value) <- (c compute ?value)]
[tableAndHide: -> tableAll() hide(compute)]
[compute: (?s compute ?o) <- bound(?s) print( ## computing value for
?s ) strConcat('value ', ?s, ?o)]
When I write the inference model built on a reasoner with these rules,
the print builtin is called more times than I would have expected.
The output is
## computing value for c
## computing value for b
## computing value for a
## computing value for a
<a> <value> "value a" .
## computing value for b
<b> <value> "value b" .
## computing value for c
<c> <value> "value c" .
In the very beginning, it's good that the print values are called in
the order c, b, a, but I'm confused as to why when each node in the
graph is printed, the corresponding print statement from the compute
rule is executed again. I had expected the tabling to memoize the
value. What am I missing here? A complete working example (whose
output is the above) is included here.
Tabling stores the results of goals for a particular shape. So whether
you re-evaluate rules depends on the order in which you ask goals. In
your case this depends on the N3 writer so is rather outside your control.
If I modify your code to do:
printStatements(infModel, null, null, null);
printStatements(infModel, null, null, null);
Then the output is:
## computing value for c
- (c value 'value c')
## computing value for b
- (b value 'value b')
## computing value for a
- (a value 'value a')
- (c value 'value c')
- (b value 'value b')
- (a value 'value a')
As you would expect.
If I asked a grounded goal first:
printStatements(infModel, infModel.createResource("a"), null, null);
printStatements(infModel, null, null, null);
Then I get:
## computing value for a
## computing value for c
## computing value for b
## computing value for a
- (a value 'value a')
- (a value 'value a')
- (b value 'value b')
- (c value 'value c')
The apparent duplicate computation for 'a' is because in the first case
rule_a is satisfying goal:
(a ? ?)
in the second case it satisfying:
(? ? ?)
It so happens that all solutions for rule_a will match the first pattern
so the second pattern won't turn up any new answers. But the current
rule engine is not clever enough to know that. It just sees that it has
results tabled for a special case and is now being asked about a more
general case so can't be sure the table is complete for the new goal.
Actually it's worse than that, if I remember rightly the tabling is
rather too goal specific and you not only get redundant computation but
redundant storage.
Dave
Thanks in advance!
Joshua Taylor
import com.hp.hpl.jena.rdf.model.InfModel;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.reasoner.rulesys.GenericRuleReasoner;
import com.hp.hpl.jena.reasoner.rulesys.Rule;
import com.hp.hpl.jena.vocabulary.ReasonerVocabulary;
public class RepeatedBuiltinExample {
private final static String rules = "\n" +
// Given a list structure, a -> b -> c, for each
element, the
element to its right
// must have a value before its own value can be
computed.
"[rule_a: (a value ?value) <- (b value ?value0) (a compute
?value)]\n" +
"[rule_b: (b value ?value) <- (c value ?value0) (b compute
?value)]\n" +
"[rule_c: (c value ?value) <- (c compute ?value)]\n" +
// Table everything, and don't show compute in the model
"[tableAndHide: -> tableAll() hide(compute)]\n" +
// The value of the compute property for a node is
'value [node]'.
"[compute: (?s compute ?o) <- bound(?s) print( ##
computing value
for ?s ) strConcat('value ', ?s, ?o)]";
public static void main( final String[] args ) {
final GenericRuleReasoner reasoner = new GenericRuleReasoner(
Rule.parseRules( rules ));
reasoner.setMode( GenericRuleReasoner.HYBRID );
reasoner.setParameter(ReasonerVocabulary.PROPtraceOn, false);
final InfModel infModel = ModelFactory.createInfModel( reasoner,
ModelFactory.createDefaultModel() );
infModel.write( System.out, "N3" );
}
}