PLN Forward Chaining

From OpenCog
Jump to: navigation, search

Theory

Forward chaining is one of the two main methods of reasoning when using an inference engine and can be described logically as repeated application of modus ponens... see Wikipedia for more.
Modus Ponens is the rule of logic which states that if a conditional statement (‘if then ’) is accepted, and the antecedent () holds, then the consequent () may be inferred.

The inference process of Forward Chaining starts with 3 things:

  • an Initial source (in our case they are 'initial source' atoms),
  • a knowledge base (the atomspace in OpenCog lingua)
  • and a set of rules called the rule base.

The goal is to create new knowledge by selecting and applying appropriate rules matching the source to the knowledge base.

The OpenCog forward chainer is implemented as an iterative single step forward chaining process where a new source is selected each time from among potential sources and applied to a predefined set of atoms called the focus set. The termination criteria could be based on some fitness function or a predefined maximum iteration which the is the current approach.

Practise

In order to Invoke the forward chainer we need to define a rule base first as shown here.

Load the rules using scheme

(First you must be in the scheme prompt - type guile (the prompt will be something like 'scheme@(guile-user)>').

Load the deduction.scm file (use relative path with reference to that file - you might find it here ./opencog/atomspace/examples/c++-api/scm/deduction.scm):

(load "deduction.scm")

Associate the rules to the rule base (with weights, their semantics is currently undefined, we might settled with probabilities but it's not sure)

(MemberLink (stv 1 1)
   pln-rule-deduction-name
   (ConceptNode "FC_DEMO_RB")
)

Create the termination criteria parameters:

(ExecutionLink
   (SchemaNode "URE:maximum-iterations")
   (ConceptNode "FC_DEMO_RB")
   (NumberNode "100")
)

Set the attention allocation (set the TV strength to 0 to disable it, 1 to enable it):

(EvaluationLink (stv 0 1)
   (PredicateNode "FC_DEMO_RB:attention-allocation")
   (ConceptNode "FC_DEMO_RB")
)

Construct the Forward Chainer object

If you are still in the scheme/guile prompt, exit (ctrl-d) to start the process of creating your Forward Chainer object.


Forward Chainer object skeleton code

Just glance at this basic code then scroll down to the example - it is what the basic object code may look like. You can base your future FwdCh objects on something like this (see inline comments for descriptions):

  #include <opencog/atomspace/AtomSpace.h> 
  #include <opencog/util/Config.h>
  #include <opencog/rule-engine/forwardchainer/ForwardChainer.h>
  #include <opencog/guile/load-file.h>
  #include <opencog/guile/SchemeEval.h>

  void fc_demo(AtomSpace& as){
    //Make sure your rule base and knowledges are loaded to the atomspace.
    config().set("SCM_PRELOAD", "examples/c++-api/scm/deduction.scm, "
                 "examples/c++-api/scm/fc-simple-assertions.scm, "
                 "examples/c++-api/scm/fc-config.scm");
    load_scm_files_from_config (as);

    SchemeEval eval(&as);

    //Choose source atoms to apply forward chaining on.
    Handle source =
            eval.eval_h(
                    R"((ConceptNode "Socrates"))");

    //Get the handle to the rule base name exactly as defined in the rule base scm file.
    Handle rbs = as.get_node(CONCEPT_NODE, "FC_DEMO_RB");

    //The final argument to ForwardChainer constructor is used to pass
    //focus set atoms; when the focus set is not empty, the forward chainer
    //is constrained to apply rules only on the focus set atoms and applies
    //on the entire atomspace when focus set is empty.
    ForwardChainer fc(as, rbs,source, HandleSeq { });

    //Start chaining.
    //fc.do_step(); // For Single step forward chaining.
    fc.do_chain();  // Does Max_Iteration steps of forward chaining.
     
    //Get the results of your single step or full steps FCing
     HandleSeq fc_results = fc.get_chaining_results();
     
     //Some more processing here
    }

Specific Forward Chaining example

The code for the following example ('UREExample.cc') exists in this directory on your OpenCog install: ~/opencog/atomspace/examples/c++-api (you might want to go to this directory).

The code is also found here on the OpenCog git repository.

Note that UREExample.cc also contains an example backward chaining - which we can ignore for now - though an obvious follow up to you learning Forward Chaining would be the tutorial on Backward Chaining.


To compile the 'UREExample.cc' type : g++ UREExample.cc -latomspace -latomcore

The forward chaining sections are explained below:

Declare the function passing in AtomSpace by reference:

void forward_chain(AtomSpace&);

Note that in this simple example passing the AtomSpace to the forward_chain function by reference may not be required, but for purposes of optimization it is often a good idea not to pass by value (which creates another copy, instead of just providing a reference to it) especially if the AtomSpace is large.


In the main section the scheme statement to run the opencog modules is run, then the forward_chain

int main(int argc, char** args)
{
    AtomSpace as;

    // Load core types
    SchemeEval *eval = SchemeEval::get_evaluator(&as);
    eval->eval("(use-modules (opencog))");

...
...

    std::cout << "\nForward chaining demo:\n";
    forward_chain(as);

    return 0;
}

Note the AtomSpace datatype is included in here: #include <opencog/atomspace/AtomSpace.h>, the code to evaluate the scheme '(use-modules (opencog)) is found in this include: #include <opencog/guile/SchemeEval.h>, and the forward chaining logic is found in here: #include <opencog/rule-engine/forwardchainer/ForwardChainer.h>.




The forward_chain function - this example demonstrates how to invoke backward chaining and retrieve results back.

void forward_chain(AtomSpace& as)
{
    SchemeEval *eval = SchemeEval::get_evaluator(&as);
    eval->eval("(load-from-path \"scm/deduction.scm\")");
    eval->eval("(load-from-path \"scm/fc-simple-assertions.scm\")");
    eval->eval("(load-from-path \"scm/fc-config.scm\")");
...


Choose source atoms to apply forward chaining on. In this case the "Socrates" source atom is used:

...
    Handle source =
            eval->eval_h(
                    R"((ConceptNode "Socrates"))");

    Handle rbs = as.get_node(CONCEPT_NODE, "FC_DEMO_RB");


The final argument to ForwardChainer constructor is used to pass focus set atoms. When the focus set is not empty, the forward chainer is constrained to apply rules only on the focus set atoms and applies on the entire atomspace when focus set is empty.

...
    ForwardChainer fc(as, rbs, source, HandleSeq { });
...


Start chaining by calling the 'do_chain()' function of the ForwardChainer object.

...
    fc.do_chain();
...

Note, that there is a similar function called do_step() which iterates forward a single step instead of chaining ahead.


Output the source and the forward chaining results:

...
    std::cout << "Forward chaining on source:\n" << source->toShortString() << std::endl;
    std::cout << "FC results:\n";
    for(const auto& h : fc.get_chaining_result())
        std::cout << h->toShortString() << std::endl;
} // END void forward_chain(AtomSpace& as)



Also see the The Forward Chaining section of the C++ API Tutorial

Quizzes

1. What is forward chaining?

A technique of using linked lists where new elements are added to the front
starts with goals, and works backward to determine what facts must be asserted so that the goals can be achieved
It is one of the two main methods of reasoning when using an inference engine
It can be described logically as repeated application of modus ponens
A technique for using a bashing someone over the head with a morning star
It's a system that awaits new facts and tries applying conditions as soon as they arrive
starts with the known facts and asserts new facts
A technique of using linked lists where new elements are added to the back

2. When would a forward chaining program be appropriate?

When you have data available, and can use inference rules to extract more data to meet a final goal
When you have a clearly defined final goal, and want to use inference rules to work backwards from it
When you are feeling lazy

3. It is important to make sure each step in the task is written into the program.

True
False

4. Modes Ponens is..

the rule of logic which states that if a conditional statement (‘if then ’) is accepted, and the antecedent () holds, then the consequent () may be inferred.
the rule of logic which states that if a conditional statement (‘if then ’) is accepted, and the consequent () holds, then the () antecedent may be inferred.
the rule of logic which states that if a conditional statement (‘if then ’) is accepted, and the consequent () holds, then the antecedent () may be inferred.
the rule of logic which states that if a conditional statement (‘if then ’) is accepted, and the antecedent () holds, then the consequent () may be inferred.

Your score is 0 / 0

*If you dear reader think of some good quiz questions, add them to the discussion branch of this wiki page

Notes

Maintained by Adam & Misgana Priority: Medium

ToDo: Move smokes example from Python to C++? (Misgana sent code to Adam)