PLN Details

From OpenCog


PLN or Probabilistic Logic Network is a systematic framework for carrying out reasoning under uncertainty. It was originally developed within the context of the Novamente AI Engine whose objective was to achieve general forms of cognition. The code base for PLN was written by Ari Heljakka in 2006. Recently Joel Pitt, with assistance of Cesar Marcondes (GSoc08) have been porting it from Novamente to OpenCog.

The main PLN mechanism ensembles a "logical programming systems", such as the one found in Prolog. However, instead of relying on formal logic, the approach is based on probabilistic roots. Thus, statements, logic inferences, queries and all sort of logical programming elements have specific probabilistic weights attached to the elements in either definite (simple) and indefinite probabilities.

PLN, as in Prolog, can be used to create a rich knowledge base where a number of relationship links connect elements nodes (Concepts, Temporal, etc). Thus, such set of axioms represent the knowledge base of the individual (aka. Universe) and it can be specified in an XML file (derived from natural language for example). Once these axioms are loaded in the system, the researcher/machine can use the network inference system to perform queries, generating new premises, update the weights and find solutions to binding certain values on predicates. In particular, PLN can use a backward chaining mechanism that allows the system to find the best option from many enumerated possibilities (for example, towards a specified goal or plan).

In what follows, we describe, in summary, some of the underpinnings of the PLN implementation. For more information, the best repository for knowledge about PLN is currently the book on the subject (see [the publications page])

PLN Architecture

PLN Big Picture

We start describing the PLN overall architecture using a diagram of the main components (PLN Big Picture) where the arrows represent pulling information around. In this diagram, we can observe that there are 4 core elements in the PLN architecture: Formulas, Rules, AtomSpace and Backward Inference, all the rest is composed or derived from these.

The AtomSpace provide the generic storage for Atoms (abstract knowledge concepts that can be realized in computer memory). Then, we can load Atoms from a XML file creating instantaneously the knowledge base to be used (set of premises). Each Atom or Element can be of many types representing from Concepts (informative atoms - This is a tree) to Relationships between Concepts. These last ones can be formalized in terms of Rules (the equivalent of formal logic operators in a knowledge compiled theory). Such Rules can be simple ones, such as AND of two elements, or more involved ones like Implication, bayesian inversion and modus ponens.

The Rules have embedded structural semantics, there is a certain arity (number of links connected to the vertex rule) depending on the Rule. For example, Bayes rules is applied whenever we have exactly three information elements: the prior, and the true probability of the elements, P(A|B), P(A), P(B) such that it is possible to calculate the posterior P(B|A). Using Rules is also possible to map the specific knowledge sub-trees in terms of one rule like Abduction, Negation or OR Rule. The Formulas piece composes the Rules with the mathematical way to calculate and update the underlying probabilities present in every element. For example, the AND rule has to combine fuzzy true assignments of two elements. Hence, if both elements have small probabilities, it is likely that the combination will be even smaller P(A AND B) = P(A) * P(B). Obviously, assuming a loose independence among the elements.

The Mathematical Formulas can be done algebraically in (1) the normal single probabilities way, where a single number probability represents the odds of the element / fact happen in the context, for example, 0.2 Rain means 20% chance of raining. Or (2) the indefinite probabilities that represent a subjective meaning of a probability (or reliability of the knowledge on the odds), for example, suppose I'm not from this city and someone says there is 20% chance of raining. Can I trust this person? Thus, I believe in a wide probability "range" of raining chance. However, if I'm a resident of that city and my neighbor says there is 20% chance of raining, I'm more certain of the odds of the estimate from my neighbor thus the probability "range" narrows around 20%.

The Rules are "templaterized" classes using Generic Programming techniques and aggregated together in a standard vector of Rules, just like a pool of Rules to be applied on the premises or combination of premises. During the process of inference, one can visualize every possible augmented trajectory of the backward inference system in order to study statistically how "understanding" is achieved by the machine.

The Core of the PLN system is the processing of the Rules pool in the premise nodes by the Backward Inference. It is given a Goal Node (represent by the small sub-tree of link-evaluations and concept nodes) and the system tries to starting from the Goal, backtrack and find what in the premises can possibly achieve that Goal. As new nodes are analyzed and bound it, we have the complete set of rules sequence (referred as Inference Nodes) that generate that Goal.


Instead of manipulating the AtomSpace directly, the idea behind AtomTableWrapper.h, AtomLookupProvider.h, iAtomTableWrapper.h is to separate the getHandle methods from addNode, addLink method and provide a unique AtomTable Singleton that holds the space.

The initial implementation contemplated several classes (from the way, the AtomSpace equivalent from Novamente called NM PseudoCore) to manipulate AtomSpace.

  • DirectATW is the direct route to AtomTable.
  • NormalizingATW normalizes the atoms before they are inserted to AT.
  • MindDBProxy is a NM construct, refer to NM core code docs. It should be replaced by the TLB.
  • Mindshadow is possibly obsolete.
  • LocalATW is IIRC for debugging, and obsolete.
AtomTableWrapper Methods

We illustrate this set of classes usage using an example of DirectATW (Direct AtomTableWrapper class). We re-use the CogServer implementation that stores a AtomSpace singleton (AS_PTR). Afterwards, there is an evaluation of the TruthValue to check if it is a simple truth or a variable type. Finally, the node (Type, name, TruthValue) is stored in the table as a node.

#define AS_PTR (CogServer::getAtomSpace())
Handle DirectATW::addNode(Type T, const string& name, 
const TruthValue& tvn, bool fresh,bool managed)
    printf("directATW addNode\n");
	AtomSpace *a = AS_PTR;
        const TruthValue& tv = SimpleTruthValue(tvn.getMean(), 0.0f); 
	const TruthValue& mod_tvn = 
		(!inheritsType(T, VARIABLE_NODE))? tvn : tv;
	return a->addNode( T, name, mod_tvn, fresh,managed);

In addition to the regular wrapped methods of addNode, addLink, getHandleSet. We can find method to parse XML files and load in premises in the AtomSpace, like loadAxioms.

// Give the filename, it will search in the usual directories
bool AtomTableWrapper::LoadAxioms(const string& path)
	string fname("../../../tests/reasoning/" + path);
	string fname2("../../tests/reasoning/" + path);
	if (!exists(fname.c_str()))
		fname = fname2;
	try {
                printf("Loading axioms from: %s \n", fname.c_str());
                // Heavy duty XML parser, adds new nodes to [[AtomSpace]]
		U = LoadXMLFile(this, fname);
	} catch(...) {
			LOG(0, "Unknown Exception"); 
			return false;  }
	return true;


The Rule as described previously, presents a major role in the evaluation of elements. It has structure semantics in the underlying graph evaluation of PLN backward chain inference. In the following figure RuleClass, we present a simple example of a generic rule: ORRule.


The ORRule class below inherits many characteristics from Rule the super-class and GenericRule, the template variation that passes a functor corresponding to the Formula type for the appropriate computation. In the Rule super-class the most important variables are the Arity of the formula (if free or not), if the Rule is computable (something related to the Hypothesis clause - "The sky is a place of angels - true on my hypothesis but not true for other conjectures"), and the priority of the Rule (a priority order in the Rule pool).

class Rule { 
    bool freeInputArity; bool computable; 
    float priority; 
    virtual o2iMetaExtra(...)
    float getPriority() and void setPriority()
    BoundVertex compute(...)

template<typename FormulaType> 
class GenericRule : public Rule { 
             mutable FormulaType f; 
             GenericRule(iAtomTableWrapper *_destTable,  
                                   bool _FreeInputArity, 
                                   std::string _name = "") : 
             Rule(_destTable, _FreeInputArity, true, _name) {	} 
... }

// It creates a new object to point to ... called ”ORRule(parent)”
ORRule::ORRule(iAtomTableWrapper *_destTable) : GenericRule<ORFormula>
             (_destTable, true, "OR Rule") { }

In the implementation description of the GenericRule above, we can observe that FormulaType template parameter is passed to the mutable "f" variable that later on ... calls f->compute( ); without the knowledge of the formula underneath. At this point, we can see the connection between the Rule and the Formula in the ORRule constructor specification <ORFormula>.

// Create the main pool of rules along with their priorities
DefaultVariableRuleProvider::DefaultVariableRuleProvider(void) {
	// obtain a pointer to the AtomTable
 	iAtomTableWrapper* parent = defaultAtomTableWrapper;  

	// some examples of adding rules – constructor “AtomTable, priority”)
	AddRule(new LookupRule(parent), 20.0f); 
        AddRule(new ORRule(parent), 10.0f);  	
        AddRule(new InversionRule<INHERITANCE_LINK>(parent), 7.0f); 

Finally, the DefaultVariableRuleProvider (called in the PLNShell) constructor above represent the pool of Rules been loaded to the Backward Inference Engine. In the example, the AtomTable is passed as parameter (subscribed) to the rules along with the priority number. For example ORRule has priority 10 while LookupRule has 20.

See the list of PLN rules for an overview of the different rule types.



The process of inferring under uncertainty. Differences between Formulas (simple and indefinite ones) Where are these used? How are these used? Some code description of the Formulas

Indefinite Truth

Why using this? How to calculate this formulas what are these? how are the rules related? symmetric versus non-symmetric Some code description of the Implementation

Backward Chaining

explaining the nuts and bolts of this implementation

PLNShell Usage

For a detailed description of command line options see ....

Loading Axioms

here it comes some basic description of this

Preparing Targets

here it comes some basic description of this

Studying the Inference

here it comes some basic description of this

Future ideas

Ideas to explore, both to improve performance and potentially understanding.