AI::Perlog continued

Ovid on 2002-07-29T18:47:15

I actually got a lot done on AI::Perlog this weekend. It's brainwrenching, but it now works and, as a curious side-effect, is about twice as fast as it was for binary queries. The bug that I alluded to in a previous entry was the following:

my $pg = AI::Perlog->new;
$pg->add_fact( bizzle => qw/ foo bar baz / );
$pg->add_fact( bizzle => qw/ tic tac toe / );
$pg->bizzle( qw/ foo _ toe / ); # returns true

Clearly, that should not return true, but my original, naive implementation didn't check whether subsequent arguments were dependent on their predecessors. Now, it's just a simple query inside the module:

if ($self->{_arg_pos}{$predicate}[$pos1]{$arg1}[$pos2]{$arg2}) {

Ugh. That's nasty. On the other hand, it's lightning fast so long as you don't have so many facts that you eat up all of your memory. I'm becoming convinced that I am developing something that no one else is going to be able to work on, though the interface is fairly easy to use.


Post it to CPAN !!!

arhuman on 2002-07-30T14:46:52

You just can't go on like this, making us waiting for that beast....

;-)

Please post it on CPAN fo we can all play with it...

Moreover :
  • You'll got testers for free
  • You'll improve your karma
  • I'll vote for you if you ever decide to be a president.
  • Maybe I could help (Let me dream ;-)

Not much to post, really...

Ovid on 2002-07-30T15:54:15

Currently, I only have a modest module with no real functionality beyond what I have described. I would like to post it to the CPAN, but only after there's enough there for it to be useful. If you absolutely have to play with it (and stroke my little ego), you can download it from my site. The documentation is minimal and I wouldn't even consider this alpha quality code.

If you want to see what it does, you'll have to read the tests. If you want to see how it does it, you're crazy :) -- though it's not really difficult to figure out.

The following is provided on the off chance that you want to add stuff and submit patches and tests.

The only thing that would give you pause is the HoHoAoHoAoH. That, believe it or not, is not as difficult as it appears.

Let's say I add one fact to the database -- database being a Prolog term, not what we usually think of:

# Ovid desperately grovels for <pre> tags, but that's a complete non-sequiter -- ignore it
$pg->add_fact( owns => ('Ovid', 'Cheap Whiskey'));

In this example, the predicate 'owns' gets an ID of 1, 'Ovid' gets an ID of 2 and 'Cheap Whiskey' gets an ID of 3. I should also add that the order of a predicate's arguments does not truly have meaning so long as it is consistent. Therefore, the above fact is just ask likely to mean that "Ovid owns cheap whiskey" as "cheap whiskey owns Ovid", but I prefer not to think about the latter.

The first item in that nasty data structure is a single key _arg_levels (which I forgot to rename). In the above example, the predicate ID for 'owns', 1, becomes a key in the _arg_levels hash. In fact, every predicate 'owns' will have the same ID, just different arguments -- but the same number of arguments -- so what we have left is the AoHoAoH. The above fact generates the following array values for the predicate 'owns':

[0]{2}[1]{3} = {}
[1]{3} = {}

What that means is that for the first argument we have 'Ovid' (id of 2) who has in the second argument position a value of 'Cheap Whiskey' (that's the first line). The second line says that for the second argument, we have the value of 'Cheap Whiskey' and no dependants. It can be confusing, but once you read through the code and get a feel for it, you'll see what this does and why. To verify a fact of X arguments, this data structure requires at most X+1 iterations. Space for time, space for time ...

My next step on this is going to be taking a first pass at the unification problem. If that goes well, simple things can be written, though a natural way of creating new rules is a barrier (you'll still have to hardcode rules that deal with more than one predicate).

I also have to tackle allowing lists and embedded facts. The list syntax will be easy:.

$pg->add_fact( location => 'kitchen drawer', [qw/ knife fork kitten /]);

I still haven't figured out the best way to handle the embedded facts.

/* Prolog */
gives( ovid, book( learningPerl ), merlyn ).

How do I handle that? I'd rather avoid creating some weird parsing rules at this point. I could do it like this:

my $fact_id = $pg->add_fact( book => 'learningPerl' );
$pg->add_fact( gives => ('Ovid', $fact_id, 'merlyn');

That would work because everything in the database will have a unique ID (I haven't assigned those to individual facts yet) and I can embed the ID for a particular fact in another fact. Still, I think it's ugly as sin. Prolog makes it simple. Perl should make it simple.