chore: align reasoning module documentation and notebooks with implementation

This commit is contained in:
KaifAhmad1
2025-12-08 13:29:45 +05:30
parent 75ffcb1031
commit 68f4eb6d2d
5 changed files with 1953 additions and 2041 deletions
+202 -277
View File
@@ -1,278 +1,203 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/advanced/08_Reasoning_and_Inference.ipynb)\n",
"\n",
"# Reasoning and Inference\n",
"\n",
"## Overview\n",
"\n",
"Build knowledge graphs, define rules, perform forward/backward chaining, and generate explanations for AI reasoning.\n",
"\n",
"\n",
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/reasoning/)\n",
"\n",
"## Installation\n",
"\n",
"Install Semantica from PyPI:\n",
"\n",
"```bash\n",
"pip install semantica\n",
"# Or with all optional dependencies:\n",
"pip install semantica[all]\n",
"```\n",
"\n",
"## Workflow: Build KG → Define Rules → Forward/Backward Chaining → Generate Explanations\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from semantica.kg import GraphBuilder\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 1: Build Knowledge Graph\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"builder = GraphBuilder()\n",
"\n",
"entities = [\n",
" {\"id\": \"alice\", \"type\": \"Person\", \"name\": \"Alice\"},\n",
" {\"id\": \"bob\", \"type\": \"Person\", \"name\": \"Bob\"},\n",
" {\"id\": \"charlie\", \"type\": \"Person\", \"name\": \"Charlie\"},\n",
" {\"id\": \"sf\", \"type\": \"Location\", \"name\": \"San Francisco\"},\n",
" {\"id\": \"california\", \"type\": \"Location\", \"name\": \"California\"},\n",
"]\n",
"\n",
"relationships = [\n",
" {\"source\": \"alice\", \"target\": \"bob\", \"type\": \"parent_of\"},\n",
" {\"source\": \"bob\", \"target\": \"charlie\", \"type\": \"parent_of\"},\n",
" {\"source\": \"sf\", \"target\": \"california\", \"type\": \"located_in\"},\n",
" {\"source\": \"alice\", \"target\": \"sf\", \"type\": \"lives_in\"},\n",
"]\n",
"\n",
"knowledge_graph = builder.build(entities, relationships)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 2: Define Rules\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class RuleManager:\n",
" def __init__(self):\n",
" self.rules = []\n",
" \n",
" def add_rules(self, rules):\n",
" self.rules.extend(rules)\n",
"\n",
"rule_manager = RuleManager()\n",
"\n",
"rules = [\n",
" \"IF A is parent_of B AND B is parent_of C THEN A is grandparent_of C\",\n",
" \"IF X is located_in Y AND Y is part_of Z THEN X is located_in Z\",\n",
" \"IF X lives_in Y AND Y is located_in Z THEN X lives_in Z\"\n",
"]\n",
"\n",
"rule_manager.add_rules(rules)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 3: Forward Chaining\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class InferenceEngine:\n",
" def forward_chain(self, kg, rule_manager):\n",
" new_facts = []\n",
" \n",
" for rule in rule_manager.rules:\n",
" if \"grandparent_of\" in rule:\n",
" parents = [r for r in relationships if r[\"type\"] == \"parent_of\"]\n",
" for p1 in parents:\n",
" for p2 in parents:\n",
" if p1[\"target\"] == p2[\"source\"]:\n",
" new_fact = {\n",
" \"source\": p1[\"source\"],\n",
" \"target\": p2[\"target\"],\n",
" \"type\": \"grandparent_of\",\n",
" \"inferred\": True\n",
" }\n",
" if new_fact not in new_facts:\n",
" new_facts.append(new_fact)\n",
" \n",
" elif \"lives_in\" in rule and \"located_in\" in rule:\n",
" lives_in = [r for r in relationships if r[\"type\"] == \"lives_in\"]\n",
" located_in = [r for r in relationships if r[\"type\"] == \"located_in\"]\n",
" \n",
" for live in lives_in:\n",
" for loc in located_in:\n",
" if live[\"target\"] == loc[\"source\"]:\n",
" new_fact = {\n",
" \"source\": live[\"source\"],\n",
" \"target\": loc[\"target\"],\n",
" \"type\": \"lives_in\",\n",
" \"inferred\": True\n",
" }\n",
" if new_fact not in new_facts:\n",
" new_facts.append(new_fact)\n",
" \n",
" return new_facts\n",
"\n",
"inference_engine = InferenceEngine()\n",
"new_facts = inference_engine.forward_chain(knowledge_graph, rule_manager)\n",
"\n",
"for fact in new_facts:\n",
" print(f\"{fact['source']} {fact['type']} {fact['target']} (inferred)\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 4: Backward Chaining\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def backward_chain(kg, rule_manager, goal):\n",
" proof_steps = []\n",
" \n",
" goal_source, goal_type, goal_target = goal\n",
" \n",
" for rel in relationships:\n",
" if rel[\"source\"] == goal_source and rel[\"type\"] == goal_type and rel[\"target\"] == goal_target:\n",
" proof_steps.append({\n",
" \"step\": \"Direct fact\",\n",
" \"fact\": f\"{goal_source} {goal_type} {goal_target}\",\n",
" \"source\": \"knowledge_graph\"\n",
" })\n",
" return proof_steps\n",
" \n",
" if goal_type == \"grandparent_of\":\n",
" for rel1 in relationships:\n",
" if rel1[\"source\"] == goal_source and rel1[\"type\"] == \"parent_of\":\n",
" intermediate = rel1[\"target\"]\n",
" for rel2 in relationships:\n",
" if rel2[\"source\"] == intermediate and rel2[\"type\"] == \"parent_of\" and rel2[\"target\"] == goal_target:\n",
" proof_steps.append({\n",
" \"step\": \"Rule application\",\n",
" \"fact\": f\"{goal_source} parent_of {intermediate}\",\n",
" \"source\": \"knowledge_graph\"\n",
" })\n",
" proof_steps.append({\n",
" \"step\": \"Rule application\",\n",
" \"fact\": f\"{intermediate} parent_of {goal_target}\",\n",
" \"source\": \"knowledge_graph\"\n",
" })\n",
" proof_steps.append({\n",
" \"step\": \"Inference\",\n",
" \"fact\": f\"{goal_source} grandparent_of {goal_target}\",\n",
" \"source\": \"inference_rule\"\n",
" })\n",
" return proof_steps\n",
" \n",
" return proof_steps\n",
"\n",
"goal = (\"alice\", \"grandparent_of\", \"charlie\")\n",
"proof = backward_chain(knowledge_graph, rule_manager, goal)\n",
"\n",
"for i, step in enumerate(proof, 1):\n",
" print(f\"Step {i}: {step['step']} - {step['fact']}\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 5: Generate Explanations\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class ExplanationGenerator:\n",
" def generate(self, proof, kg):\n",
" if not proof:\n",
" return \"No proof found for the given goal.\"\n",
" \n",
" explanation_parts = []\n",
" explanation_parts.append(\"Explanation:\")\n",
" \n",
" for i, step in enumerate(proof, 1):\n",
" if step['step'] == 'Direct fact':\n",
" explanation_parts.append(f\"{i}. We know that {step['fact']} from the knowledge graph.\")\n",
" elif step['step'] == 'Rule application':\n",
" explanation_parts.append(f\"{i}. From the knowledge graph: {step['fact']}.\")\n",
" elif step['step'] == 'Inference':\n",
" explanation_parts.append(f\"{i}. Therefore, by applying the inference rule: {step['fact']}.\")\n",
" \n",
" return \"\\n\".join(explanation_parts)\n",
"\n",
"explanation_gen = ExplanationGenerator()\n",
"explanation = explanation_gen.generate(proof, knowledge_graph)\n",
"print(explanation)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Summary\n",
"\n",
"Reasoning and inference workflow:\n",
"- Knowledge Graph Built\n",
"- Inference Rules Defined\n",
"- Forward Chaining Performed\n",
"- Backward Chaining Performed\n",
"- Explanations Generated\n"
]
}
],
"metadata": {
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/advanced/08_Reasoning_and_Inference.ipynb)\n",
"\n",
"# Reasoning and Inference\n",
"\n",
"## Overview\n",
"\n",
"Build knowledge graphs, define rules, perform forward/backward chaining, and generate explanations for AI reasoning using the **Semantica Reasoning Module**.\n",
"\n",
"\n",
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/reasoning/)\n",
"\n",
"## Installation\n",
"\n",
"Install Semantica from PyPI:\n",
"\n",
"```bash\n",
"pip install semantica\n",
"# Or with all optional dependencies:\n",
"pip install semantica[all]\n",
"```\n",
"\n",
"## Workflow: Build KG → Define Rules → Forward/Backward Chaining → Generate Explanations\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from semantica.kg import GraphBuilder\n",
"from semantica.reasoning import InferenceEngine, RuleManager, ExplanationGenerator\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 1: Build Knowledge Graph\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"builder = GraphBuilder()\n",
"\n",
"entities = [\n",
" {\"id\": \"alice\", \"type\": \"Person\", \"name\": \"Alice\"},\n",
" {\"id\": \"bob\", \"type\": \"Person\", \"name\": \"Bob\"},\n",
" {\"id\": \"charlie\", \"type\": \"Person\", \"name\": \"Charlie\"},\n",
" {\"id\": \"sf\", \"type\": \"Location\", \"name\": \"San Francisco\"},\n",
" {\"id\": \"california\", \"type\": \"Location\", \"name\": \"California\"},\n",
"]\n",
"\n",
"relationships = [\n",
" {\"source\": \"alice\", \"target\": \"bob\", \"type\": \"parent_of\"},\n",
" {\"source\": \"bob\", \"target\": \"charlie\", \"type\": \"parent_of\"},\n",
" {\"source\": \"sf\", \"target\": \"california\", \"type\": \"located_in\"},\n",
" {\"source\": \"alice\", \"target\": \"sf\", \"type\": \"lives_in\"},\n",
"]\n",
"\n",
"knowledge_graph = builder.build([{\"entities\": entities, \"relationships\": relationships}])\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 2: Define Rules\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Initialize Inference Engine\n",
"engine = InferenceEngine()\n",
"\n",
"# Define rules using logic syntax\n",
"rules = [\n",
" \"IF parent_of(?a, ?b) AND parent_of(?b, ?c) THEN grandparent_of(?a, ?c)\",\n",
" \"IF lives_in(?x, ?y) AND located_in(?y, ?z) THEN lives_in(?x, ?z)\"\n",
"]\n",
"\n",
"for rule in rules:\n",
" engine.add_rule(rule)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 3: Forward Chaining\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Load facts from relationships into the engine\n",
"for rel in relationships:\n",
" # Format: predicate(subject, object)\n",
" fact_str = f\"{rel['type']}({rel['source']}, {rel['target']})\"\n",
" engine.add_fact(fact_str)\n",
"\n",
"# Perform forward chaining to derive new facts\n",
"results = engine.forward_chain()\n",
"\n",
"print(f\"Inferred {len(results)} new facts:\")\n",
"for result in results:\n",
" print(f\" - {result.conclusion} (Rule: {result.rule_used.name})\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 4: Backward Chaining\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Define a goal to prove\n",
"goal = \"grandparent_of(alice, charlie)\"\n",
"\n",
"# Perform backward chaining\n",
"proof = engine.backward_chain(goal)\n",
"\n",
"if proof:\n",
" print(f\"Goal '{goal}' proven successfully!\")\n",
"else:\n",
" print(f\"Could not prove goal '{goal}'.\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 5: Generate Explanations\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"generator = ExplanationGenerator()\n",
"\n",
"# Explain the last forward chaining inference\n",
"if results:\n",
" explanation = generator.generate_explanation(results[0])\n",
" print(\"Explanation for first inferred fact:\")\n",
" print(explanation.natural_language)\n",
"\n",
"# If we have a proof from backward chaining, explain it\n",
"if proof:\n",
" proof_explanation = generator.generate_explanation(proof)\n",
" print(\"\\nExplanation for backward chaining proof:\")\n",
" print(proof_explanation.natural_language)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Summary\n",
"\n",
"Reasoning and inference workflow:\n",
"- Knowledge Graph Built\n",
"- Inference Rules Defined\n",
"- Facts Loaded into Engine\n",
"- Forward Chaining Performed\n",
"- Backward Chaining Performed\n",
"- Explanations Generated\n"
]
}
],
"metadata": {
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
@@ -279,7 +279,7 @@
"from semantica.reasoning import InferenceEngine, RuleManager\n",
"inference_engine = InferenceEngine()\n",
"rule_manager = RuleManager()\n",
"new_facts = inference_engine.forward_chain(kg, rule_manager)\n",
"new_facts = inference_engine.forward_chain()\n",
"```\n",
"\n",
"### 10. ONTOLOGY MODULE - Ontology Generation\n",
@@ -654,4 +654,4 @@
},
"nbformat": 4,
"nbformat_minor": 2
}
}
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -115,9 +115,9 @@ High-performance pattern matching engine.
| Method | Description |
|--------|-------------|
| `add_rule(rule)` | Compile rule into network |
| `build_network(rules)` | Compile rule into network |
| `add_fact(fact)` | Propagate fact through network |
| `get_activations()` | Get triggered rules |
| `match_patterns()` | Get triggered rules |
### SPARQLReasoner
@@ -128,7 +128,7 @@ SPARQL-based reasoner for RDF graphs.
| Method | Description |
|--------|-------------|
| `expand_query(query)` | Rewrite query with inference |
| `materialize(graph)` | Add inferred triples to graph |
| `infer_results(result)` | Add inferred triples to result |
### AbductiveReasoner
@@ -138,7 +138,7 @@ Generates explanations for observations.
| Method | Description |
|--------|-------------|
| `abduce(observation)` | Generate hypotheses |
| `generate_hypotheses(observations)` | Generate hypotheses |
| `rank_hypotheses(hyps)` | Score and sort |
**Example:**
@@ -147,7 +147,7 @@ Generates explanations for observations.
from semantica.reasoning import AbductiveReasoner
reasoner = AbductiveReasoner(rules)
hypotheses = reasoner.abduce("Pavement is wet")
hypotheses = reasoner.generate_hypotheses(["Pavement is wet"])
# Result: ["It rained", "Sprinkler was on"]
```
@@ -159,8 +159,8 @@ Explains *why* a fact was inferred.
| Method | Description |
|--------|-------------|
| `explain(fact)` | Generate reasoning trace |
| `visualize_trace(trace)` | Graph visualization |
| `generate_explanation(fact)` | Generate reasoning trace |
| `show_reasoning_path(trace)` | Graph visualization |
---
+20 -33
View File
@@ -49,7 +49,7 @@ reasoner = SPARQLReasoner(triple_store=kg)
# Execute query
query = "SELECT ?s ?p ?o WHERE { ?s ?p ?o }"
result = reasoner.query(query)
result = reasoner.execute_query(query)
print(f"Found {len(result.bindings)} results")
```
@@ -71,7 +71,7 @@ fact = Fact("f1", "Person", ["John"])
rete.add_fact(fact)
# Get matches
matches = rete.get_matches()
matches = rete.match_patterns()
print(f"Found {len(matches)} matches")
```
@@ -201,7 +201,7 @@ WHERE {
}
"""
result = reasoner.query(query)
result = reasoner.execute_query(query)
for binding in result.bindings:
print(f"Person: {binding.get('person')}, Company: {binding.get('company')}")
@@ -221,25 +221,12 @@ reasoner.add_inference_rule("IF ?x :type :Company THEN ?x :type :Organization")
query = "SELECT ?x WHERE { ?x :type :Organization }"
# Query is automatically expanded with inference rules
result = reasoner.query(query)
result = reasoner.execute_query(query)
# Results include both explicit :Organization types and inferred from :Company
```
### Query Optimization
```python
from semantica.reasoning import SPARQLReasoner
reasoner = SPARQLReasoner(triple_store=kg)
# Optimize query before execution
query = "SELECT ?s ?p ?o WHERE { ?s ?p ?o . ?s :type :Person }"
optimized = reasoner.optimize_query(query)
# Execute optimized query
result = reasoner.query(optimized)
```
### SPARQL with RDF Inference
@@ -261,7 +248,7 @@ WHERE {
"""
# Will also match :Person if :Employee rdfs:subClassOf :Person
result = reasoner.query(query)
result = reasoner.execute_query(query)
```
## Rete Algorithm
@@ -332,15 +319,16 @@ rete.build_network([rule1, rule2])
# Add facts incrementally
fact1 = Fact("f1", "Person", ["John"])
rete.add_fact(fact1)
matches1 = rete.get_matches() # Matches for rule1
# Get matches
matches = rete.match_patterns()
fact2 = Fact("f2", "WorksFor", ["John", "Acme"])
rete.add_fact(fact2)
matches2 = rete.get_matches() # Now includes matches for rule2
# Now includes matches for rule2
matches2 = rete.match_patterns()
# Remove fact
rete.remove_fact(fact1)
matches3 = rete.get_matches() # Updated matches
# Reset engine (clears facts and matches)
rete.reset()
```
### Rete Network Optimization
@@ -510,7 +498,7 @@ premises = [
# Generate proof for conclusion
conclusion_statement = "Socrates is mortal"
proof = reasoner.generate_proof(premises, conclusion_statement)
proof = reasoner.prove_theorem(conclusion_statement)
if proof:
print(f"Theorem: {proof.theorem}")
@@ -710,7 +698,7 @@ from semantica.reasoning import ExplanationGenerator
generator = ExplanationGenerator()
# Generate reasoning path
path = generator.generate_reasoning_path(inference_result)
path = generator.show_reasoning_path(inference_result)
print(f"Path ID: {path.path_id}")
print(f"Steps: {len(path.steps)}")
@@ -734,7 +722,7 @@ from semantica.reasoning import ExplanationGenerator
generator = ExplanationGenerator()
# Create justification
justification = generator.create_justification(conclusion, reasoning_path)
justification = generator.justify_conclusion(conclusion, reasoning_path)
print(f"Justification ID: {justification.justification_id}")
print(f"Conclusion: {justification.conclusion}")
@@ -1017,7 +1005,7 @@ conclusions = reasoner.apply_logic(premises)
```python
# Proof generation
proof = reasoner.generate_proof(premises, conclusion)
proof = reasoner.prove_theorem(conclusion)
# Constructs step-by-step proof
```
@@ -1104,8 +1092,7 @@ path = generator.generate_reasoning_path(inference_result)
- `build_network(rules)`: Build Rete network from rules
- `add_rule(rule)`: Add rule to network
- `add_fact(fact)`: Add fact and propagate through network
- `remove_fact(fact)`: Remove fact from network
- `get_matches()`: Get all rule matches
- `match_patterns()`: Get all rule matches
- `match_patterns(facts)`: Match patterns using Rete algorithm
#### AbductiveReasoner Methods
@@ -1118,7 +1105,7 @@ path = generator.generate_reasoning_path(inference_result)
#### DeductiveReasoner Methods
- `apply_logic(premises, **options)`: Apply logical inference rules
- `generate_proof(premises, conclusion)`: Generate proof for conclusion
- `prove_theorem(theorem)`: Prove theorem
- `prove_theorem(theorem, **options)`: Prove logical theorem
- `validate_argument(argument)`: Validate logical argument
@@ -1248,7 +1235,7 @@ for result in results:
# 6. Query with SPARQL reasoning
sparql_reasoner = SPARQLReasoner(triple_store=kg, enable_inference=True)
query_result = sparql_reasoner.query("SELECT ?x WHERE { ?x :type :Employee }")
query_result = sparql_reasoner.execute_query("SELECT ?x WHERE { ?x :type :Employee }")
```
### Abductive Explanation System
@@ -1305,7 +1292,7 @@ facts = [
for fact in facts:
rete.add_fact(fact)
matches = rete.get_matches()
matches = rete.match_patterns()
print(f"After adding {fact.fact_id}: {len(matches)} matches")
```
@@ -1360,7 +1347,7 @@ WHERE {
}
"""
result = reasoner.query(query)
result = reasoner.execute_query(query)
# Results include both explicit and inferred relationships
```