Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

AI::Perlog -- Simple implementation

by Ovid (Cardinal)
on Jul 30, 2002 at 20:15 UTC ( [id://186348]=perlmeditation: print w/replies, xml ) Need Help??

There has been a bit of interest expressed in my AI::Perlog implementation, including requests for what code I have written so far. While I do not intend to upload anything to the CPAN as I consider this code to be pre-alpha quality, I figured I may as well honor the request and let you download the code. The documentation is spotty, but the tests pass and the should give an indication of what's working and what's not. Currently, the only thing I have implemented is boolean queries on facts.

use AI::Perlog; my $pg = AI::Perlog->new; $pg->add_fact( gives => qw/ Ovid money kudra / ); $pg->add_fact( gives => qw/ grep grief Ovid / ); # an underscore is synonymous with the empty string or undef print "y\n" if $pg->gives( qw/ _ _ kudra / ); # does anyone give + anything to kudra? print "y\n" if $pg->gives( '', '', 'kudra' ); # same thing print "y\n" if $pg->gives( undef, undef, 'kudra' ); # same thing print "y\n" if $pg->gives( qw/ grep _ Ovid / ); # does grep give a +nything to Ovid? print "n\n" if ! $pg->gives( qw/ Ovid _ grep / ); # Returns false. O +vid gives nothing to grep

Needless to say, it's just a toy right now, but I hope to have the first stab at unification done later this week, at which point this might actually have some limited utility. Currently, the code generates a spurious warning under Cygwin, but runs clean on Windows 2000 and RH 7.2 (both running 5.6.1).

Cheers,
Ovid

Update: You can read about some of the future plans at use.perl.

Update 2: Also be aware that this beast eats memory for breakfast. If anyone can come up with a less memory intestive solution that doesn't sacrifice performance, that would be great. Also, I intend to eventually port much of this to Inline::C, so the simpler the data structures, the better.

Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Replies are listed 'Best First'.
Re: AI::Perlog -- Simple implementation
by mitd (Curate) on Jul 31, 2002 at 07:12 UTC
    Finally, after watching this latest Ovid work of the devil unfold for the last few weeks, I went searching the mitd library for my copy of Sterling and Shapio's 'The Art of Prolog' (MIT Press, 1986) which BTW I was reminded has one the most esthetically pleasing covers of any technical book in my collection.

    Anyway, I was thinking that as AI:Perlog matures it might be fun to implement a few of the examples from 'The Art'.

    Go! Go! Ovid Perl meets Logic programming, evil ... pure evil.

    mitd-Made in the Dark
    'Interactive! Paper tape is interactive!
    If you don't believe me I can show you my paper cut scars!'

Re: AI::Perlog -- Simple implementation
by mattr (Curate) on Aug 02, 2002 at 13:12 UTC
    Silly me, trying to build and test this on cygwin. Machine is fine, but insane - can't find perl, Test::More, etc.

    Anyway tried it, seems to answer "does somebody own gold" and "does x own gold". How to find out everyone who owns gold, or who does not.. or is that what _check_path does?

    FWIW I'd like to specify "*" as an alias to "_". Or would that mess up inside a qw()? Also I feel scared by the underscore since it seems like the mysterious used $_ without the $ and always wonder if something will get evaled when I wasn't watching. Though maybe intentional? Does look like a "fill in the blank" which is kinda neat.

    I see use of "exists" and a note about autovivification in the code. Is this too fragile for me to touch the knowledgebase hash?

    What else needed to solve the thief problem? How about intersections?

    What has been your experience using a graph?

      Test::More is only required for the tests. If you trust the code, you could go ahead and install it and hope it works.

      How to find out everyone who owns gold, or who does not.. or is that what _check_path does?

      That feature isn't implemented yet. It's what is called "unification", where data gets associated with a variable in a query. To find out who owns gold, a query like the following would probably be made:

      $pg->owns( qw/ $Who gold / );

      Because Perlog would know that arguments beginning with a dollar sign are variables, it would know to grab the appropriate data and return it. I've been very busy this week or I would have put that in -- which is really the first thing that needs to go in to actually make this useful.

      As a side note: I hate the proposed syntax above, so I am open for suggestions.

      _check_path() is called from the following:

      my $a = shift @important; while( my $z = shift @important ) { return if !$self->_check_path($predicate_id,$a,$z,@args[$a,$z] +); $a = $z; } return 1;

      That loops over the arguments supplied in a query and says foreach argument, return false if I don't find a path to the next argument. The actual method call had a bunch of comments that I hadn't bothered to clean out since I wasn't planning on releasing this yet. You can ignore them. There was also a leftover line of debugging code that I forgot to clean out :) Here's the cleaned up method:

      sub _check_path { my ( $self, $predicate, $lvl1, $lvl2, $arg1, $arg2 ) = @_; return 1 if exists $self->{_arg_levels}{$predicate}[$lvl1]{$arg1}[$lvl +2]{$arg2}; return; # nope, didn't find it }

      If you want to try and figure out that hideous data structure, you can read this brief explanation.

      If you really, really are foolish enough to work on this, thank you :) Other than that, here's what you need to know about the object keys.

      _next_vertex
      Every unique argument and predicate is given this value, and then the value is incremented. This ensures that everything has a unique id.
      _object_vertex
      This is a mapping of object names (keys) to their vertex ids (values).
      _predicates
      Poorly named. I should have named it _predicate_vertex. I'll probably change it. It's a mapping of predicate names to their unique ids.
      _arg_levels
      Too complicated to explain here. See the link above.

      If it's not clear, a predicate can be thought of as the name of a rule.

      $pg->add_fact( owns => qw/ Ovid socks / ); $pg->add_fact( gives => qw/ grep grief Ovid / );

      In the above expample, "owns" and "gives" are the predicates.

      FWIW I'd like to specify "*" as an alias to "_". Or would that mess up inside a qw()? Also I feel scared by the underscore since it seems like the mysterious used $_ without the $ and always wonder if something will get evaled when I wasn't watching. Though maybe intentional?

      As for your comments about the underscore: that's borrowed from Prolog. If someone wants to make the query gives( qw/ grep grief _ / ); (which translates to "does grep give grief to anyone?"), then you cannot use the qw// syntax if only the empty string and undef are skipped. As for the asterisk suggestion, I like it, but for practical reasons, I can only use one character for that and I may as well use the standard one.

      What else needed to solve the thief problem?

      Unification.

      What has been your experience using a graph?

      I was using a graph at first, but I realized that it was lacking some of the things that I needed so I rolled my own data structure. Right now, even though Graph.pm is listed as a prerequisite, I actually pulled it out of the module completely. I was mostly using it for tests. Pulling it out also had the nice side effect of doubling the speed of my code.

      Cheers,
      Ovid

      Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

        Just one thing I'd like to say now, What about Who? :) Or, how to differentiate between declarations and queries.. Maybe you want to say that the user specified in the string $Who does in fact own gold.

        So to answer your question about $Who syntax I started thinking about dbi-like placeholders, (e.g. :who) but Who can be multivalued, right? So a Set object or even a simple list might be good.

        Somehow I got this funny idea of letting the underscore ("anyone"/"anything") symbol contribute dimensions to the answer of who gives what to Kudra, so $pg->gives(qw( _ _ kudra )) could give you a two-dimensional array, which works out to a hash %_ that says $_{who} = what. Is this useful? One problem I see besides speed is that of autovivification. If your structure didn't present autoviv. problems to the casual user you could even return an array of references to points in the knowledge base so they could easily modify it. I think I need to know a lot more about how Prolog is used to be intelligent about this.

        I went back to the Haskell page when thinking about your question re embedded facts. I was interested to see that they mention SQL in the context of functional languages. And from their languages page I found an example of syntax in the Curry language which might be applicable.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://186348]
Approved by VSarkiss
Front-paged by FoxtrotUniform
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (3)
As of 2024-03-28 18:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found