On 08/07/13 20:47, Joshua TAYLOR wrote:
On Mon, Jul 8, 2013 at 2:52 PM, Dave Reynolds <[email protected]> wrote:
On 08/07/13 16:14, Joshua TAYLOR wrote:
Hi all,
First off, my impression is that having a builtin do non-trivial query
of the graph (i.e., that depends on more inference), or modification
of the graph, is not supported. That said, I'd like to do something
akin to it, and I'm looking for suggestions.
Correct. Builtins are not supposed to modify the graph and there's no
provision for invoking the inference engine as part of executing a builtin.
I have a simple expression evaluator (essentially a simple
lambda-calculus interpreter) whose expressions can be encoded in RDF.
In the simplest case, I have a builtin called Eval which takes two
arguments, an expression, which should be concrete, and a result which
may be either a variable or concrete node. If the result is a
variable, then Eval binds the result of the evaluation to it, and
matches, and if the result is concrete, then Eval compares the
evaluation result with it, and succeeds if they are the same
(approximately with the primitive equal builtin).
Now, the expression language that Eval can handle has some primitives
for querying RDF graphs. The primitives are based on those presented
in a recent paper [1]. The idea here is to be able to write an
expression denoting a function of x, e.g., "the sum of the values of
the hasValue property for all the resources related to x by the
relatedTo property" and to store the result as a property of x. E.g.,
with the data
x relatedTo y, z .
y hasValue 3 .
z hasValue 4 .
we would compute the value 7. This is generalized by a rule that says
(?s ?p ?o) <-
(?s hasComputableProperty ?p)
(?s hasComputableExpression ?e)
Eval(?e,?o) .
Now the problem of recursion comes up when the values of y and z are
not stated explicitly, but should also be computed by this same rule.
Eval doesn't have access to the InfModel directly, but through the
context can access the InfGraph, but simply querying it from within
Eval causes problems with recursive query. (I assume that this is to
be expected. If it is not, please let me know, and I can reply with
the particular errors that I'm encountering.)
Has anyone done anything like this, or does anyone have any
suggestions for handling things like this? So far, I've considered
adding some preconditions to the rule that would require that
computable properties of related resources must be computed first
(which would require more explicit connections in the data), or having
Eval return some sort of continuation or promise/delay type object, or
a new rule that could finish the computation when more information
becomes available.
I think this is pushing the boundaries of the rule engine, but any and
all suggestions are welcome!
Pushing the boundaries indeed!
My inclination would be to use the precondition approach and forward rules.
So any computation whose values are available will fire the appropriate rule
which will assert new values. That in turn will unlock new rules. Thus you
get bottom up data flow rather than top down recursion.
Since your preconditions will amount to "all the values I need are
available" that will be easiest to implement via another builtin.
That combination will probably work (except where you have recursive
dependencies but that will be a problem anyway!). However, it's not obvious
to me what the rule engine is buying you in that case. You might want
consider implementing a custom inference engine in code which can recurse
directly.
Thanks for the reply! The reasons for using builtins and the rule
engine have more to do with integration with work we've already done,
as well as piggybacking on the Jena OWL reasoners so that we can use
restriction classes to define which expressions (also OWL individuals)
should be associated with which individuals. E.g.,
SportsCar SubClassOf (hasPerformanceExpression formula1)
FamilyCar SubClassOf (hasPerformanceExpression formula2)
You said, "Correct. Builtins are not supposed to modify the graph and
there's no provision for invoking the inference engine as part of
executing a builtin." To be clear though, it is OK if builtins access
the raw and deductions graph (without modifying them) to get data
/from/ the graph, right? (I think this is OK, but I'd rather get
explicit confirmation now than surprise experimental confirmation
later. :) ) I assume that this is OK because the suggested builtin
that would implement "are all functions of dependencies computed yet?"
would have to be examining the graph.
Yes, accessing the raw/deductions graph is legal though if any explicit
or implicit negation is involved then you should mark the builtin as
non-monotonic.
A question about this approach though; if a forward rule has such a
precondition, e.g.,
(?s hasComputableProperty ?p)
(?s hasComputableExpression ?e)
AllPreconditionsComputed( ?s )
Eval(?e,?o)
->
(?s ?p ?o )
I see where the order that the rules would have fire in would be
bottom up, but will the rule keep getting considered for firing?
No you are right. If the values that are going to be asserted aren't
even mentioned in the rule then it won't be reconsidered for firing.
I guess one option is to make the dependencies explicit in your rules:
(?s p ?o)
<-
(?s hasComputableProperty ?p)
(?s hasComputableExpression ?e)
(?x1 hasValue ?v1)
(?x2 hasValue ?v2)
...
Eval(?e, ?v1, ?v2, ...)
Where the ?xi are the values needed for ?e.
I assume you want to rule set to be generic, with the expression
breakdown driven from the graph data rather than the rules (otherwise
this whole thing would be a LOT easier!). In which case you could
probably have forward rules plus another magic builtin to generate the
data-specific backward rules. Details left for the reader :)
Dave