Quick Start
After installation is complete, run
python _examples/relationship.py --log_level RESULT
Below we will provide a detailed analysis of the relationship example.
The explanation proceeds in the following order:
- Problem and goal
- Concept / Operator modeling (Concept / Operator)
- Known facts (Assertion)
- Rule modeling (Rule)
- Constructing the query (QueryStructure)
- Calling the inference engine (InferenceEngine)
1. Problem and goal
The natural language question is as follows:
Given:
Aliceis a parent ofBob(parent(Alice, Bob) = Trueis true)Bobis a parent ofCarie(parent(Bob, Carie) = Trueis true)Rules:
- If
Xis a parent ofY, andYis a parent ofZ, thenXis a grandparent ofZ. (By transitive reasoning from twoparent(...) = Trueassertions)Question:
- Whose grandparent is Alice? (
grandparent(Alice, X) = True)
Logically, we want to infer the conclusion:
grandparent(Alice, Carie) = True
2. Import basic types and inference engine entry point
The example uses the following core types:
Concept: a concept (type), such asPerson.Operator: an operator, such asparentandgrandparent.Variable/Constant: variables and constants.CompoundTerm: a compound term composed of an operator + arguments (e.g.,parent(Alice, Bob)).Assertion: an assertion, in the formt1 = t2.Rule: a rule (head + body).InferenceEngine,QueryStructure: the inference engine and query structure.
from al_inference_engine.syntax import (
Constant,
Variable,
Concept,
Operator,
CompoundTerm,
Assertion,
Rule,
)
from al_inference_engine.main import InferenceEngine, QueryStructure
3. Concept and operator modeling
3.1 Concept modeling: Person
In this example’s domain, there are only two object types: people and boolean values. They are represented by two Concepts:
# === Concept: Person (human) ===
Person = Concept("Person")
from al_inference_engine.knowledge_bases.builtin_base.builtin_concepts import BOOL_CONCEPT # already built into the system
3.2 Operator modeling: parent and grandparent
We need two binary operators:
parent(X, Y): X is a parent of Y. This operator is only used to represent a relationship, so the output is set to a boolean value.grandparent(X, Y): X is a grandparent of Y. This operator is only used to represent a relationship, so the output is set to a boolean value.
Both take two Person inputs and output BOOL_CONCEPT.
# === Operators (Operator) ===
parent_op = Operator(
"parent",
input_concepts=[Person, Person],
output_concept=BOOL_CONCEPT
)
grandparent_op = Operator(
"grandparent",
input_concepts=[Person, Person],
output_concept=BOOL_CONCEPT
)
At this point, parent_op / grandparent_op are only operator names. You then construct terms via CompoundTerm(operator, [args...]), and further construct assertions from terms.
4. Constant and variable modeling
4.1 Variables: X, Y, Z
To generalize the rule to arbitrary people, we introduce three variables:
# === Variables ===
X = Variable("X")
Y = Variable("Y")
Z = Variable("Z")
These variables appear in operator argument positions within rules, representing “any value that satisfies the concept constraints.”
4.2 Individual constants: Alice, Bob, Carie, true_const
Specific people are represented by Constants with the concept Person:
# === Individual constants (names) ===
alice = Constant("Alice", Person)
bob = Constant("Bob", Person)
carie = Constant("Carie", Person)
from al_inference_engine.knowledge_bases.builtin_base.builtin_facts import true_const
5. Known facts (Assertion)
Natural language facts:
parent(Alice, Bob) = Trueis trueparent(Bob, Carie) = Trueis true
Logically, they are:
parent(Alice, Bob) = true_const
parent(Bob, Carie) = true_const
In code, each fact is an Assertion(t1, t2):
t1:CompoundTerm(parent_op, [alice, bob])t2:True(i.e.,true_const)
# === Initial facts (Facts) ===
facts = [
# parent(Alice, Bob) = true_const
Assertion(
CompoundTerm(parent_op, [alice, bob]),
true_const
),
# parent(Bob, Carie) = true_const
Assertion(
CompoundTerm(parent_op, [bob, carie]),
true_const
),
]
In this way, facts are uniformly encoded in an explicit equality form t1 = t2.
6. Rule modeling (Rule + Formula)
6.1 From natural language to logical form
Rule content:
If X is a parent of Y, and Y is a parent of Z, then X is a grandparent of Z.
Converted to a logical formula:
parent(X, Y) = true_const, parent(Y, Z) = true_const
→ grandparent(X, Z) = true_const
6.2 Use Assertion to express premises (body)
The premises consist of two Assertions:
body = [
Assertion(
CompoundTerm(parent_op, [X, Y]),
true_const
),
Assertion(
CompoundTerm(parent_op, [Y, Z]),
true_const
),
]
6.3 Use Assertion to express the conclusion (head)
The conclusion is one Assertion:
head = Assertion(
CompoundTerm(grandparent_op, [X, Z]),
true_const
)
6.4 Combine into a rule Rule
Wrap head and body into a rule object:
# === Rule (Rule) ===
# parent(X, Y) = true_const ∧ parent(Y, Z) = true_const
# → grandparent(X, Z) = true_const
R1 = Rule(
head=head,
body=body
)
rules = [R1]
At this point, one natural language rule has been fully encoded.
7. Constructing the query (QueryStructure)
The question in this example is:
Whose grandparent is Alice?
Logically, it can be written as:
grandparent(Alice, X) = true_const ?
That is, find which X makes the proposition grandparent(Alice, X) true.
Construct the corresponding Assertion:
query_assertion = Assertion(
CompoundTerm(grandparent_op, [alice, X]),
true_const
)
Then wrap the facts and the query into QueryStructure:
# === Query (Query) ===
query_question = QueryStructure(
premises=facts, # premises (facts) used in this query
question=[query_assertion] # proposition to ask: grandparent(Alice, X) = true_const ?
)
8. Calling the inference engine (InferenceEngine)
Finally, construct an inference engine instance and execute the query.
# === Inference engine ===
inference_engine = InferenceEngine(
facts=[], # this example does not use global facts; all facts are placed in QueryStructure.premises
rules=rules
)
result = inference_engine.infer_query(query_question)
print(result)
The inference process (conceptually) is:
Find two facts in the premises:
parent(Alice, Bob) = true_constparent(Bob, Carie) = true_const
Using rule R1, match
X = Alice, Y = Bob, Z = Carie, and derive:grandparent(Alice, Carie) = true_const
When answering the query
grandparent(Alice, X) = true_const ?, return the solution:X = Carie.
9. Full example code
from al_inference_engine.knowledge_bases.builtin_base.builtin_concepts import BOOL_CONCEPT
from al_inference_engine.syntax import (
Constant,
Variable,
Concept,
Operator,
CompoundTerm,
Assertion,
Rule,
Formula,
)
from al_inference_engine.main import InferenceEngine, QueryStructure
# === Concepts ===
Person = Concept("Person")
# === Boolean constant: true_const ===
true_const = Constant("true_const", BOOL_CONCEPT)
# === Operators (Operator) ===
parent_op = Operator(
"parent",
input_concepts=[Person, Person],
output_concept=BOOL_CONCEPT
)
grandparent_op = Operator(
"grandparent",
input_concepts=[Person, Person],
output_concept=BOOL_CONCEPT
)
# === Variables ===
X = Variable("X")
Y = Variable("Y")
Z = Variable("Z")
# === Individual constants (names) ===
alice = Constant("Alice", Person)
bob = Constant("Bob", Person)
carie = Constant("Carie", Person)
# === Initial facts (Facts) ===
facts = [
Assertion(
CompoundTerm(parent_op, [alice, bob]),
true_const
),
Assertion(
CompoundTerm(parent_op, [bob, carie]),
true_const
),
]
# === Rule (Rule) ===
# parent(X, Y) = true_const ∧ parent(Y, Z) = true_const
# → grandparent(X, Z) = true_const
R1 = Rule(
head=Assertion(
CompoundTerm(grandparent_op, [X, Z]),
true_const
),
body=Formula(
Assertion(
CompoundTerm(parent_op, [X, Y]),
true_const
),
"AND",
Assertion(
CompoundTerm(parent_op, [Y, Z]),
true_const
),
)
)
rules = [R1]
# === Query (Query) ===
query_question = QueryStructure(
premises=facts,
question=[
Assertion(
CompoundTerm(grandparent_op, [alice, X]),
true_const
)
]
)
# === Inference engine ===
inference_engine = InferenceEngine(
facts=[], # this example does not use global facts
rules=rules
)
result = inference_engine.infer_query(query_question)
print(result)