The forward-chaining rules are run automatically when the rule base is activated to assert new statements of fact. Thus, forward-chaining rules are not directly used to determine whether any particular statement is true.
But backward-chaining rules are directly used to determine whether a particular statement is true. Thus, when a rule base name (or, more properly, a rule base category name, explained below) is used as the knowledge base name in a statement, it refers to the backward-chaining rules within that rule base.
Pyke runs all forward-chaining rules before running any backward-chaining rules.
Thus, using rule base names as the knowledge base name in statements within a forward-chaining rule is prohibited, as this would cause backward-chaining rules to run in order to process the forward-chaining rule.
Why Multiple Rule Bases?
There are two reasons to have more than one rule base (i.e., more than one .krb file):
To divide a large set of rules into human manageable units.
In this case, you want Pyke to use all of the rule bases combined.
For example, you may have rules governing the automatic generation of SQL statements, and other rules governing the generation of HTML documents. You want to keep these rules in different rule bases to make them more manageable.
To enable your Python program to choose between different rule bases that are tailored to different specific situations.
For example, some of the rules governing the automatic generation of SQL statements may vary depending upon the target database (e.g., mysql, postgresql, oracle).
In this case, you want to be able to tell Pyke which of several rule bases to use on each invocation, depending upon which target database you will be accessing. You would never use more than one of these rule bases at the same time, so these rule bases are mutually exclusive.
These two goals are met by three capabilities:
Rule Base Categories
All rule bases are grouped into categories. Each rule base category only gets to have one active rule base.
Thus, you place rule bases that you want to have active simultaneously into different rule base categories; and place rule bases that are mutually exclusive with each other (e.g., the mysql, postgresql and oracle rule bases) into the same rule base category.
Each rule base category has a unique name. In the example above you would want two rule base categories: database and html_generation.
The rule base category name is used as the knowledge base name for statements within rules of one rule base category that want to refer to rules within another rule base category. For example, rule bases in the html_generation category would need to use database.insert(...) to refer to the insert rules in the database category.
Rule Base Inheritance
The rule bases within the same category share rules amongst themselves through rule base inheritance.
This allows mutually exclusive rule bases to share common rules in a parent rule base without having to duplicate these rules amongst themselves.
Here is the definition, then, of a rule base category:
Each root rule base (through rule base inheritance) defines a unique rule base category. All rule bases derived (directly or indirectly) from that root rule base are in the same rule base category.
The name of the rule base category is simply the name of its root rule base.
So, our database and html_generation example would look like this:
We have one root rule base called database and it has derived rule bases called mysql, postgresql and oracle. And a second root rule base called html_generation with firefox and internet_explorer.
The two root rule bases define two rule base categories:
- database, which includes:
- html_generation, which includes:
The .krb files for these rule bases may be placed anywhere you want them within your Pyke source directory structure -- in other words, your directory structure is not required to match your rule base inheritance structure.
Only one rule base from each rule base category may be active at any point in time.
Within each of these rule bases, if the knowledge base name is omitted from a statement within a backward-chaining rule, it defaults to the rule base category of that rule base, not the rule base itself. Thus, insert(...) within postgresql would mean database.insert(...), and make_tag(...) within firefox would mean html_generation.make_tag(...).
Note that referring to a rule base category (either explicitly or implicitly) always refers to the active rule base within that category. This may not be the rule base with that name (the root rule base), or even the rule base making implicit use of the rule base category. For example, insert(...) within postgresql will end up referring to insert rules within the oracle rule base when oracle is the active rule base.
All rules referring to foreign rule base categories must explicitly use the rule base category name. For example, to refer to the insert rule for databases, within the html_generation category, you would have to say database.insert(...).
In this way, all of the rules will work no matter which rule base is active within each rule base category.
There is an important difference between how backward-chaining rule inheritance works within Pyke rule bases and how method inheritance works within Python classes:
When a derived class in Python defines a method by the same name as a method in its parent class, the derived method overrides the parent method. I.e., only the derived method is used when a call is made to it.
In contrast, when a derived rule base in Pyke defines backward-chaining rules for a goal that also has backward-chaining rules defined for it in the parent rule base, the derived rule extends the set of rules that may be used to try to prove this goal. All of the derived rules will be tried first. If all of these fail, then the parent rules are tried.
All forward-chaining rules in the parent rule base are always included in the derived rule base. The without clause only applies to backward-chaining rules.
Rule Base Activation
Loading rule bases only makes them available for use. It does not automatically activate any of them. This must be done explicitly by your Python program. Your program may decide to activate different rule bases in different situations.
Additionally, forward-chaining rules may be used to activate more specific rule bases, based upon their inferencing. But once a rule base has been activated for a rule base category, only children of the currently active rule base may be activated from that point on. Because these children inherit the rules of the currently active rule base; activating child rule bases only adds new rules, and doesn't take any away. Thus, any forward-chaining rule run during the activation of the first rule base are not invalidated by activating the second rule base.
In our database example, your program could activate the root database rule base and let the forward-chaining rules within the database rule base figure out which derived rule base to activate depending on the particular database in use at the time the program is run.