Hey Mark.
On Mon, Dec 13, 2010 at 5:23 AM, Mark Birbeck <mark.birb
...@gmail.com> wrote:
> Hi Chime,
> First, thanks for a great library. I've come to it via the also
> excellent ORDF library, and the two together are proving to be a
> powerful combination.
Excellent. I'll be interested in learning how you are using both.
> My problem is that I'd like to use the forward-chaining features of
> ORDF+FuXi to not only generate simple values, but also to calculate
> values based on data coming in.
Ok.
> I've read other threads where you warn
> about performance issues, but I'm not so concerned about that at this
> stage, since I think the convenience of causing new values to be
> generated simply by creating rules is so great that it beats doing it
> some other -- possibly faster -- way.
Ok. Can you point out which thread you are talking about? I'm not
certain I exactly understand what you are trying to do. I can think
of 3 possible situations where you want to 'generate' values:
1. Unsafe rules (rules where not every variable which occurs in the
head of the rule also occurs in the body of the same rule). An
example is:
{ ?P a Person } => { ?P hasFather [] } .
{ ?P hasFather ?FATHER } => { ?FATHER a Person } .
The rule safety criteria ensures that they have a finite grounding, so
for example, these rule will result in an infinite chain of hasFather
statements. FuXi supports this via N3 rules with unamed BNodes in the
head:
The /test/testExistentialInHead.py file has an example of how to do this.
2. Builtins that create values. The math:product CWM builtin [1] is
an example of this:
{ ?Person hasWeight ?KG. ( ?KG 100 ) math:product ?G } => { ?Person
hasWeightInGrams ?G }
However, FuXi currently only supports binary builtins that evaluate to
true / false .
> ..snip...
> It took a bit of experimentation to get my
> functions to be called (and I'm still unable to add my own functions
> outside of the BuiltinPredicates.py module),
In order to register your functions, you can use the
additionalBuiltins keyword on either of these functions:
- FuXi.Rete.RuleStore.SetupRuleStore
- FuXi.Horn.NetworkFromN3
- FuXi.Horn.HornFromN3
It takes a dictionary which maps the builtin URIs to a function that
returns a function which is used to implement the builtin. So, for
example, <http://www.w3.org/2000/10/swap/string#startsWith> (from [1])
can be implemented with a function like this:
def StringStartsWith(subject,object_):
def startsWith(s,o):
return s.startswith(o)
return startsWith
And this can be registered and used in an N3 document in this way:
STRING_NS = Namespace("http://www.w3.org/2000/10/swap/string#")
rules = HornFromN3(open(n3FileName), additionalBuiltins={
STRING_NS.startsWith : StringStartsWith }))
> ..snip..
> The first thing I needed to establish was what the syntax should be in
> N3; does the following seem reasonable?:
> {?C v:organization-name ?name . ?name matching:funcEnc ?enc .}
> => {?C matching:encoded ?enc .}.
> I.e., for every organization name predicate, generate an encoded version of it?
Unfortunately, since only binary, boolean builtins are supported you
won't be able to support this via builtins.
>..snip..
> Since the loop in the propagate() method in BetaNode relies on these
> functions returning a boolean,
Yes, this is because only binary, boolean builtins are supported.
>..snip..
> I realise I'm layering one hack on top of another here, but at the
> moment I'm really just trying to find the right place in the sequence
> to focus on; once I have triples coming out then I'll tidy up.
> However, since I'm not familiar with the Rete algorithm I don't know
> whether I'm way too late in the process, whether I should be focusing
> on creating a token rather than modifying the bindings...or what.
Much of what you are describing is eerily similar to the struggle I
had in trying to implement builtins that generate values and can work
with the Rete algorithm some time ago. In the end, I chose to not
support them. However, I recently added support for externally
defined actions (meant as infrastructure for capabilities of the same
name in the new RIF-PRD) that are triggered when a rule is fired. I
have since added a wiki describing how it works, but it is not as easy
to setup as it should be and I will be adding an issue to that effect.
Essentially, you need to get a handle on the terminal node for the
rule you want to generate values, and register an execute action that
can do what you want to do (add triples with generated terms, for
instance). So, with the following rule:
{?person foaf:mbox ?email . } => {?person foaf:mbox_sha1sum [] }.
you can define an action like this:
def encodeAction(tNode, inferredTriple, token, binding):
from hashlib import sha1
person = binding[Variable('person')
email = binding[Variable('email')]
newTriple = (person,FOAF['mbox_sha1sum'],sha1(email).hexdigest())
tNode.network.addWME(ReteToken(newTriple))
And register it to override the handling of the rule firing
The wiki is here:
http://code.google.com/p/fuxi/wiki/ReteActions
Let me know if you have any questions, but this should support the
behavior you want.
[1] http://www.w3.org/2000/10/swap/doc/CwmBuiltins