Reasoning¶
Simplified reasoning module supporting rule-based inference, SPARQL, and high-performance pattern matching.
🎯 Overview¶
The Reasoning Module provides logical inference capabilities for deriving new knowledge from existing facts. It supports rule-based inference, SPARQL-based reasoning, and high-performance pattern matching.
What is Reasoning?¶
Reasoning is the process of deriving new facts from existing knowledge using logical rules. For example: - Given: `Parent(Alice, Bob)` and `Parent(Bob, Charlie)` - Rule: `IF Parent(?x, ?y) AND Parent(?y, ?z) THEN Grandparent(?x, ?z)` - Inferred: `Grandparent(Alice, Charlie)`
Why Use the Reasoning Module?¶
- Knowledge Discovery: Find implicit relationships not explicitly stored
- Query Expansion: Answer queries that require inference
- Validation: Check logical consistency of knowledge graphs
- Explanation: Understand how facts were derived
- Rule-Based Logic: Define domain-specific inference rules
How It Works¶
- Rule Definition: Define inference rules (IF-THEN patterns)
- Fact Matching: Match facts against rule conditions
- Variable Binding: Bind variables in rules to actual entities
- Inference: Derive new facts from matched rules
- Explanation: Generate explanations for inferred facts
-
Rule-based Inference
Forward-chaining inference engine with variable substitution
-
SPARQL Reasoning
Query expansion and property chain inference for RDF graphs
-
Rete Algorithm
High-performance pattern matching for large rule sets
-
Explanation
Generate natural language explanations for inferred facts
When to Use
- Inference: Deriving new facts from existing data (e.g.,
`Parent(A,B) & Parent(B,C) -> Grandparent(A,C)`) - Query Expansion: Finding results that aren't explicitly stored but implied
- Explanation: Understanding the reasoning path for any derived fact
- Validation: Checking logical consistency of the knowledge graph
⚙️ Algorithms Used¶
Forward Chaining¶
Purpose: Derive new facts from existing knowledge using logical rules.
How it works:
- Variable Substitution: Supports patterns like
`Person(?x)`to match facts and bind variables - Recursive Inference: Continues deriving facts until no new information can be found
- Priority-based Execution: Rules can be prioritized to control the inference flow
Complexity: `O(n * m)` where n is the number of facts and m is the number of rules
Example:
# Forward chaining implementation
reasoner = Reasoner()
rules = ["IF Person(?x) THEN Human(?x)"]
facts = ["Person(John)"]
new_facts = reasoner.infer_facts(facts, rules)
Rete Algorithm¶
Purpose: High-performance pattern matching for large rule sets with frequent fact updates.
How it works:
- Alpha Nodes: Filter facts by single attributes (e.g.,
`type=Person`) - Beta Nodes: Join results from Alpha nodes (e.g.,
`Person.id == Parent.child_id`) - Memory: Stores partial matches to avoid re-computation
- Efficiency: Optimal for scenarios with many rules and frequent fact updates
Complexity: `O(n + m)` where n is the number of facts and m is the number of rules (amortized)
Main Classes¶
Reasoner (Facade)¶
The high-level interface for the reasoning module.
Methods:
| Method | Description |
|---|---|
`infer_facts(facts, rules)` | Derive new facts from initial state |
`backward_chain(goal)` | Prove a goal using backward chaining |
`add_rule(rule)` | Add a new inference rule |
`add_fact(fact)` | Add a fact to working memory |
`clear()` | Reset the reasoner state |
ReteEngine¶
High-performance pattern matching engine.
Methods:
| Method | Description |
|---|---|
`build_network(rules)` | Compile rules into a Rete network |
`add_fact(fact)` | Propagate fact through the network |
`match_patterns()` | Get triggered rules |
ExplanationGenerator¶
Explains why a fact was inferred.
Methods:
| Method | Description |
|---|---|
`generate_explanation(result)` | Generate reasoning trace for an InferenceResult |
Usage Examples¶
Simple Rule-based Inference¶
from semantica.reasoning import Reasoner
reasoner = Reasoner()
# Define rules
rules = [
"IF Person(?x) THEN Human(?x)",
"IF Human(?x) AND Parent(?x, ?y) THEN Human(?y)"
]
# Initial facts
facts = ["Person(John)", "Parent(John, Jane)"]
# Run inference
new_facts = reasoner.infer_facts(facts, rules)
# Result: ["Human(John)", "Human(Jane)"]
Goal-driven Reasoning (Backward Chaining)¶
from semantica.reasoning import Reasoner
reasoner = Reasoner()
reasoner.add_rule("IF Parent(?a, ?b) AND Parent(?b, ?c) THEN Grandparent(?a, ?c)")
reasoner.add_fact("Parent(Alice, Bob)")
reasoner.add_fact("Parent(Bob, Charlie)")
# Prove a goal
proof = reasoner.backward_chain("Grandparent(Alice, Charlie)")
if proof:
print(f"Proven: {proof.conclusion}")
print(f"Steps: {proof.premises}")
Knowledge Graph Enrichment¶
from semantica.reasoning import Reasoner, Rule
from semantica.kg import KnowledgeGraph
# 1. Define Rules
rules = [
"IF Sibling(?x, ?y) THEN Sibling(?y, ?x)",
"IF Ancestor(?x, ?y) AND Ancestor(?y, ?z) THEN Ancestor(?x, ?z)"
]
# 2. Load Graph and Run Inference
kg = KnowledgeGraph()
reasoner = Reasoner()
inferred = reasoner.infer_facts(kg.get_all_triplets(), rules)
# 3. Update Graph
for fact_str in inferred:
kg.add_fact_from_string(fact_str)
Best Practices¶
- Limit Recursion: Be careful with recursive rules (e.g.,
`A(x,y) -> A(y,x)`) which can cause infinite loops in naive implementations - Use Rete for Scale: For >100 rules or >10k facts, always use the Rete engine
- Materialize vs. Query: Materialize (pre-compute) for read-heavy workloads; Query-rewrite for write-heavy workloads
- Validate Rules: Ensure rules are logically consistent to avoid exploding the fact space
Cookbook¶
Interactive tutorials to learn reasoning and inference:
- Reasoning and Inference: Use logical reasoning to infer new knowledge from existing facts
- Topics: Logic rules, inference engines, forward chaining, SPARQL reasoning, Rete algorithm
- Difficulty: Advanced
- Use Cases: Deriving new facts, query expansion, logical validation
See Also¶
- Ontology Module - Source of schema-based rules
- Triplet Store Module - Backend for SPARQL reasoning
- Modules Guide - Consistency checking overview