Introduction
Why choose KELE?
Supports user-defined executable operators (operators are a concept in assertion logic; for ease of understanding, they can be analogized to functions in first-order logic. Executable operators can be analogized to meta-predicates in Prolog);
Naturally supports term-level fact storage and reasoning;
Supports equality axioms;
Allows building nested composite terms among operators.
Installation
Install via pip
WIP
Install and configure from source
If you want to run the project locally from source, first clone the repository and install dependencies via Poetry or uv:
git clone [https://github.com/USTC-KnowledgeComputingLab/KELE](https://github.com/USTC-KnowledgeComputingLab/KELE)
poetry install # uv sync
eval $(poetry env activate) # or Invoke-Expression (poetry env activate) or poetry shell ...
For more complete instructions on activating the Poetry environment, see Poetry-Activating the environment。
Usage
Install via pip
import al_inference_engine
Install and configure from source
To use al_inference_engine in your program, you need to add the project root directory to the Python path.
You can do this by adding the following code in your program:
import sys
sys.path.append('/path/to/AL_inference_engine')
import al_inference_engine
Examples
See the py files under the _examples folder and the explanation in the Quick Start section.
Overview of the inference process
In KELE’s forward-chaining inference, the system starts from existing facts and automatically derives new facts. This process is split into two relatively independent but closely coordinated stages:
- Grounder: find candidate instantiations for variables in rules based on the current facts;
- Executor: under concretely instantiated rules, check whether all premises hold, and produce new facts accordingly.
Below is a brief explanation of these two stages.
1. Grounder: finding instantiation candidates for variables
In rules, we usually use variables to denote “any object that satisfies the domain constraints”. For example:
parent(X, Y) = True AND parent(Y, Z) = True -> grandparent(X, Z) = True
Here X, Y, Z are variables, meaning “some object” / “some person”, rather than specific constants. In contrast, the fact base stores already determined facts, e.g.:
parent(Alice, Bob) = True
parent(Bob, Carie) = True
parent(Alice, Dave) = True
The Grounder is responsible for:
- Based on the given set of facts, computing all possible variable substitution sets for each rule,
- Applying these substitutions to the rule to generate instantiated rules (grounded rules) that contain only constants.
For example, given the facts above, the Grounder may produce substitutions such as:
- One substitution:
X = Alice, Y = Bob, Z = Carie - Another substitution:
X = Alice, Y = Bob, Z = Dave - As well as other non-matching combinations.
For each substitution, the Grounder replaces variables with the corresponding constants and obtains a concrete instantiated rule, e.g.:
parent(Alice, Bob) = True AND parent(Bob, Carie) = True
-> grandparent(Alice, Carie) = True
After instantiating all rules under their respective substitution sets, we obtain the full set of grounded rules.
You can think of the Grounder as an enumeration stage: it does not decide whether these instantiated rules are “actually true”; instead, it first enumerates “all concrete cases that could potentially hold” to prepare for the next execution step.
2. Executor: checking rule premises and producing new facts
After obtaining the grounded rule set, the Executor performs the actual “inference checking”.
The Executor is responsible for:
- For each grounded rule, checking whether each assertion in the rule is entailed by the current fact base;
- If all premises (the rule body) are true, then adding the conclusion as a new fact to the fact base.
Using the instantiated rule above as an example:
parent(Alice, Bob) = True AND parent(Bob, Carie) = True
-> grandparent(Alice, Carie) = True
The Executor will check in order:
- Whether the fact base entails
parent(Alice, Bob) = True - Whether the fact base entails
parent(Bob, Carie) = True
If both exist, then the premises parent(Alice, Bob) = True AND parent(Bob, Carie) = True are entailed, and the Executor will write the conclusion:
grandparent(Alice, Carie) = True
as a new fact into the fact base.
Conversely, for a grounded rule that cannot be entailed, the rule is considered not satisfied in the current state, and its conclusion will not be added to the fact base.
3. How the two stages work together in forward chaining
In practice, forward chaining does not run for only one round (hereafter called an iteration), but loops multiple times:
- The Grounder instantiates the rule set using the current fact base;
- The Executor checks these grounded rules and adds new facts to the fact base;
- If new facts are produced, Grounding and Executing can be run again based on the updated fact base.
This loop continues until no new facts are produced or the solving process ends.
```