Author image Christophe IVORRA
and 1 contributors

NAME

Chorus::Engine - A very light inference engine combined with the frame model for knowledge representation.

VERSION

Version 1.04

INTRODUCTION

    Chorus-Engine makes possible to simply develop in Perl with an Articial Intelligence approach 
    by defining the knowledge with rules the inference engine will try to apply on your objects.
    
    Because inference engines use to waste a lot of time before finding interesting instanciations
    for rules, the property _SCOPE is used to optimise the space on which each rule must be tested.
    
    This not necessary but, uou can combinate Chorus::Engine with Chorus::Frame which gives a first level 
    for knowledge representation. The inference engine can then work on Frames using the function 'fmatch' 
    top optimise the _SCOPE for the rules which work on frames.  

SYNOPSIS

    use Chorus::Engine;

    my $agent = new Chorus::Engine();
    
    $agent->addrule(

      _SCOPE => {             # These arrays will be combinated as parameters (HASH) when calling _APPLY
             a => $subset,    # static array_ref
             b => sub { .. }  # returns an array ref
      },
      
      _APPLY => sub {
        my %opts = @_;        # provides $opt{a},$opt{b} (~ one combinaison of _SCOPE)

        if ( .. ) {
          ..                  
          return 1;           # rule could be applied (~ something has changed)
        }

        return undef;         # rule didn't apply
      }
    );
    
    $agent->loop();

SUBROUTINES/METHODS

addrule()

       Defines a new rule for the Chorus::Engine object
       
       arguments :
        
         _SCOPE : a hashtable defining the variables and their search scope for instanciation
                  Values must be SCALAR or ARRAY_REF
                                        
         _APPLY : function which will be called in a loop with all the possible 
                  combinaisons from scopes on a & b 
                  
       Ex. use Chorus::Engine;
           use Chorus::Frames;
           
           my $e=Chorus::Engine->new();
           
           $e->addrule(
                  
              _SCOPE => {

                  foo  => [ fmatch( .. ) ],         # selection of Frames bases on the filter 'fmatch' (static)
                  bar  => sub { [ fmatch( .. ) ] }, # same kind more dynamic 
                  baz  => [ .. ]                    # any other array (not only frames)

              },
                  
              _APPLY => sub {
                         my %opts = @_;          # provides $opt{foo},$opt{bar},$opt{baz}
                             
                         return undef if ( .. ); # rule didn't apply

                         if ( .. ) {
                           ..             # some actions
                           return 1;      # rule could be applied
                         }
       
                         return undef;    # rule didn't apply (last instruction)
              });

loop()

       Tells the Chorus::Engine object to enter its inference loop.
       The loop will end only after all rules fail (~ return false) in the same iteration
       
           Ex. my $agent = new Chorus::Engine();
           
               $agent->addrule( .. );
               ..
               $agent->addrule( .. );

               $agent->loop();

cut()

       Go directly to the next rule (same loop, same agent). This will break all nested instanciation loops
       on _SCOPE of the current rule. -> GO DIRECTLY TO NEXT RULE (SAME AGENT)
       
           Ex. $agent->addrule(
             _SCOPE => { .. },
             _APPLY => sub {
              if ( .. ) {
                 $agent->cut();    # ~ exit the rule
              }
           );

last()

       Breaks the current loop (on rules) for the current agent -> GO DIRECTLY TO NEXT AGENT
       This will force a cut() too.
       
           Ex. $agent->addrule(
             _SCOPE => { .. },
             _APPLY => sub {
              if ( .. ) {
                 $agent->last();
              }
           );

replay()

       Restart FROM THE BEGINNING (1st rule) for the CURRENT AGENT. This will force a cut() too.
       
           Ex. $agent->addrule(
             _SCOPE => { .. },
             _APPLY => sub {
              if ( .. ) {
                 $agent->replay();
              }
           );

replay_all()

       Restart FROM THE BEGINNING for the FIRST AGENT. This will force a cut() too.
       
           Ex. $agent->addrule(
             _SCOPE => { .. },
             _APPLY => sub {
              if ( .. ) {
                 $agent->replay_all();
              }
           );

solved()

       Tells the Chorus::Engine to terminate immediately. This will force a last() too
       
           Ex. $agent->addrule(
             _SCOPE => { .. },
             _APPLY => sub {
              if ( .. ) {
                 $agent->solved();
              }
           );

reorder()

       the rules of the agent will be reordered according to the function given as argument (works like with sort()).
       Note - The method last() will be automatically invoked.
       
       Exemple : the current rule in a syntax analyser has found the category 'CAT_C' for a word.
                 The next step whould invoque as soon as possible the rules declared as interested 
                 in this category.
       
           sub sortA {
               my ($r1, $r2) = @_;
               return 1  if $r1->_INTEREST->CAT_C;
               return -1 if $r2->_INTEREST->CAT_C; 
               return 0;
           }

           $agent->addrule(     # rule 1
             _INTEREST => {     # user slot
                 CAT_C => 'Y',
                 # ..
             },
             _SCOPE => { .. }
             _APPLY => sub { .. }
           );
       
           $agent->addrule(     # rule n
             _SCOPE => { .. }
             _APPLY => sub { 
               # ..
               if ( .. ) {
                 # ..
                 $agent->reorder(sortA);  # will put rules interested in CAT_A to the head of the queue
               }
             }
           );

pause()

       Disable a Chorus::Engine object until call to wakeup(). In this mode, the method loop() has no effect.
       This method can optimise the application by de-activating a Chorus::Engine object until it has 
       a good reason to work (ex. when a certain state is reached in the application ). 

wakeup()

       Enable a Chorus::Engine object -> will try again to apply its rules after next call to loop()

reorderRules()

  use from rules body to optimize the engine defining best candidates (rules) for next loop (break the current loop)

applyrules()

  main engine loop (iterates on $SELF->_RULES)

new contructor : initialize a new engine

AUTHOR

Christophe Ivorra, <ch.ivorra at free.fr>

BUGS

Please report any bugs or feature requests to bug-chorus-engine at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Chorus-Engine. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Chorus::Engine

You can also look for information at:

ACKNOWLEDGEMENTS

LICENSE AND COPYRIGHT

Copyright 2013 Christophe Ivorra.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.