use anyhow::Result;
use crate::{Rule, RuleAtom, RuleEngine, Term};
pub struct GettingStartedGuide;
impl GettingStartedGuide {
pub fn create_basic_engine() -> RuleEngine {
RuleEngine::new()
}
pub fn basic_example() -> Result<Vec<RuleAtom>> {
let mut engine = RuleEngine::new();
let mortality_rule = Rule {
name: "mortality_rule".to_string(),
body: vec![RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant("type".to_string()),
object: Term::Constant("Person".to_string()),
}],
head: vec![RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant("type".to_string()),
object: Term::Constant("Mortal".to_string()),
}],
};
engine.add_rule(mortality_rule);
let facts = vec![
RuleAtom::Triple {
subject: Term::Constant("socrates".to_string()),
predicate: Term::Constant("type".to_string()),
object: Term::Constant("Person".to_string()),
},
RuleAtom::Triple {
subject: Term::Constant("plato".to_string()),
predicate: Term::Constant("type".to_string()),
object: Term::Constant("Person".to_string()),
},
];
engine.forward_chain(&facts)
}
pub fn backward_chaining_example() -> Result<bool> {
let mut engine = RuleEngine::new();
let teaching_rule = Rule {
name: "teaching_rule".to_string(),
body: vec![
RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant("teaches".to_string()),
object: Term::Variable("Y".to_string()),
},
RuleAtom::Triple {
subject: Term::Variable("Y".to_string()),
predicate: Term::Constant("type".to_string()),
object: Term::Constant("Student".to_string()),
},
],
head: vec![RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant("type".to_string()),
object: Term::Constant("Teacher".to_string()),
}],
};
engine.add_rule(teaching_rule);
engine.add_fact(RuleAtom::Triple {
subject: Term::Constant("aristotle".to_string()),
predicate: Term::Constant("teaches".to_string()),
object: Term::Constant("alexander".to_string()),
});
engine.add_fact(RuleAtom::Triple {
subject: Term::Constant("alexander".to_string()),
predicate: Term::Constant("type".to_string()),
object: Term::Constant("Student".to_string()),
});
let goal = RuleAtom::Triple {
subject: Term::Constant("aristotle".to_string()),
predicate: Term::Constant("type".to_string()),
object: Term::Constant("Teacher".to_string()),
};
engine.backward_chain(&goal)
}
pub fn family_relationships_example() -> Result<Vec<RuleAtom>> {
let mut engine = RuleEngine::new();
let grandparent_rule = Rule {
name: "grandparent_rule".to_string(),
body: vec![
RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant("parent".to_string()),
object: Term::Variable("Y".to_string()),
},
RuleAtom::Triple {
subject: Term::Variable("Y".to_string()),
predicate: Term::Constant("parent".to_string()),
object: Term::Variable("Z".to_string()),
},
],
head: vec![RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant("grandparent".to_string()),
object: Term::Variable("Z".to_string()),
}],
};
let child_rule = Rule {
name: "child_rule".to_string(),
body: vec![RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant("parent".to_string()),
object: Term::Variable("Y".to_string()),
}],
head: vec![RuleAtom::Triple {
subject: Term::Variable("Y".to_string()),
predicate: Term::Constant("child".to_string()),
object: Term::Variable("X".to_string()),
}],
};
engine.add_rule(grandparent_rule);
engine.add_rule(child_rule);
let facts = vec![
RuleAtom::Triple {
subject: Term::Constant("alice".to_string()),
predicate: Term::Constant("parent".to_string()),
object: Term::Constant("bob".to_string()),
},
RuleAtom::Triple {
subject: Term::Constant("bob".to_string()),
predicate: Term::Constant("parent".to_string()),
object: Term::Constant("charlie".to_string()),
},
RuleAtom::Triple {
subject: Term::Constant("bob".to_string()),
predicate: Term::Constant("parent".to_string()),
object: Term::Constant("diana".to_string()),
},
];
engine.forward_chain(&facts)
}
pub fn ontology_reasoning_example() -> Result<Vec<RuleAtom>> {
let mut engine = RuleEngine::new();
let subclass_rule = Rule {
name: "subclass_inheritance".to_string(),
body: vec![
RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant("subClassOf".to_string()),
object: Term::Variable("Y".to_string()),
},
RuleAtom::Triple {
subject: Term::Variable("Z".to_string()),
predicate: Term::Constant("type".to_string()),
object: Term::Variable("X".to_string()),
},
],
head: vec![RuleAtom::Triple {
subject: Term::Variable("Z".to_string()),
predicate: Term::Constant("type".to_string()),
object: Term::Variable("Y".to_string()),
}],
};
let subproperty_rule = Rule {
name: "subproperty_inheritance".to_string(),
body: vec![
RuleAtom::Triple {
subject: Term::Variable("P".to_string()),
predicate: Term::Constant("subPropertyOf".to_string()),
object: Term::Variable("Q".to_string()),
},
RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Variable("P".to_string()),
object: Term::Variable("Y".to_string()),
},
],
head: vec![RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Variable("Q".to_string()),
object: Term::Variable("Y".to_string()),
}],
};
engine.add_rule(subclass_rule);
engine.add_rule(subproperty_rule);
let facts = vec![
RuleAtom::Triple {
subject: Term::Constant("Dog".to_string()),
predicate: Term::Constant("subClassOf".to_string()),
object: Term::Constant("Mammal".to_string()),
},
RuleAtom::Triple {
subject: Term::Constant("Mammal".to_string()),
predicate: Term::Constant("subClassOf".to_string()),
object: Term::Constant("Animal".to_string()),
},
RuleAtom::Triple {
subject: Term::Constant("owns".to_string()),
predicate: Term::Constant("subPropertyOf".to_string()),
object: Term::Constant("related".to_string()),
},
RuleAtom::Triple {
subject: Term::Constant("fido".to_string()),
predicate: Term::Constant("type".to_string()),
object: Term::Constant("Dog".to_string()),
},
RuleAtom::Triple {
subject: Term::Constant("john".to_string()),
predicate: Term::Constant("owns".to_string()),
object: Term::Constant("fido".to_string()),
},
];
engine.forward_chain(&facts)
}
}
pub struct RuleAuthoringBestPractices;
impl RuleAuthoringBestPractices {
pub fn variable_naming_guidelines() -> Vec<&'static str> {
vec![
"Use meaningful variable names (e.g., 'Person' instead of 'X')",
"Use consistent naming conventions across rules",
"Use uppercase for variables to distinguish from constants",
"Use descriptive names for complex patterns",
"Avoid single-letter variables except for simple cases",
"Use domain-specific prefixes (e.g., 'pers_' for person variables)",
]
}
pub fn rule_structure_guidelines() -> Vec<&'static str> {
vec![
"Order atoms from most specific to least specific",
"Place constant-heavy atoms first for efficient filtering",
"Group related atoms together for readability",
"Use built-in predicates judiciously for validation",
"Keep rule bodies concise and focused",
"Avoid overly complex rules - split into multiple simpler rules",
]
}
pub fn performance_tips() -> Vec<&'static str> {
vec![
"Place most selective atoms first in rule bodies",
"Use constants instead of variables when possible",
"Avoid rules that generate infinite loops",
"Use indexing hints for frequently used patterns",
"Consider rule ordering for optimization",
"Profile rule execution to identify bottlenecks",
"Use caching for expensive computations",
"Minimize variable scope and reuse",
]
}
pub fn common_pitfalls() -> Vec<(&'static str, &'static str)> {
vec![
("Infinite recursion", "Always ensure termination conditions"),
(
"Variable scope confusion",
"Use clear naming and scope management",
),
(
"Performance bottlenecks",
"Profile and optimize critical rules",
),
("Rule conflicts", "Test rule interactions thoroughly"),
(
"Over-generalization",
"Be specific about rule applicability",
),
("Under-specification", "Include necessary constraints"),
("Complex debugging", "Use rule tracing and debugging tools"),
("Memory issues", "Monitor memory usage with large rule sets"),
]
}
pub fn well_structured_rule_example() -> Rule {
Rule {
name: "employee_manager_hierarchy".to_string(),
body: vec![
RuleAtom::Triple {
subject: Term::Variable("Employee".to_string()),
predicate: Term::Constant("type".to_string()),
object: Term::Constant("Person".to_string()),
},
RuleAtom::Triple {
subject: Term::Variable("Employee".to_string()),
predicate: Term::Constant("worksFor".to_string()),
object: Term::Variable("Manager".to_string()),
},
RuleAtom::Triple {
subject: Term::Variable("Manager".to_string()),
predicate: Term::Constant("type".to_string()),
object: Term::Constant("Manager".to_string()),
},
],
head: vec![RuleAtom::Triple {
subject: Term::Variable("Employee".to_string()),
predicate: Term::Constant("hasManager".to_string()),
object: Term::Variable("Manager".to_string()),
}],
}
}
pub fn validate_rule_example() -> Result<bool> {
let rule = Self::well_structured_rule_example();
if rule.name.is_empty() {
return Ok(false);
}
if rule.body.is_empty() || rule.head.is_empty() {
return Ok(false);
}
let mut body_vars = std::collections::HashSet::new();
let mut head_vars = std::collections::HashSet::new();
for atom in &rule.body {
Self::collect_variables(atom, &mut body_vars);
}
for atom in &rule.head {
Self::collect_variables(atom, &mut head_vars);
}
for var in &head_vars {
if !body_vars.contains(var) {
println!("Warning: Variable {var} in head but not in body");
return Ok(false);
}
}
Ok(true)
}
fn collect_variables(atom: &RuleAtom, vars: &mut std::collections::HashSet<String>) {
if let RuleAtom::Triple {
subject,
predicate,
object,
} = atom
{
if let Term::Variable(var) = subject {
vars.insert(var.clone());
}
if let Term::Variable(var) = predicate {
vars.insert(var.clone());
}
if let Term::Variable(var) = object {
vars.insert(var.clone());
}
} }
}
pub struct DebuggingGuide;
impl DebuggingGuide {
pub fn enable_debugging_example() -> Result<()> {
use crate::debug::DebuggableRuleEngine;
let mut debug_engine = DebuggableRuleEngine::new();
debug_engine.enable_debugging(true);
debug_engine.add_breakpoint("specific_rule_name");
let facts = vec![RuleAtom::Triple {
subject: Term::Constant("test".to_string()),
predicate: Term::Constant("type".to_string()),
object: Term::Constant("entity".to_string()),
}];
let _result = debug_engine.debug_forward_chain(&facts)?;
let trace = debug_engine.get_trace();
let metrics = debug_engine.get_metrics();
let conflicts = debug_engine.get_conflicts();
println!("Execution trace: {} entries", trace.len());
println!("Performance metrics: {metrics:?}");
println!("Detected conflicts: {}", conflicts.len());
let report = debug_engine.generate_debug_report();
println!("{report}");
Ok(())
}
pub fn debugging_techniques() -> Vec<(&'static str, &'static str)> {
vec![
(
"Rule tracing",
"Enable execution tracing to see rule firing order",
),
(
"Breakpoints",
"Set breakpoints on specific rules for step debugging",
),
(
"Performance profiling",
"Measure rule execution times and memory usage",
),
(
"Conflict detection",
"Identify contradictory or redundant rules",
),
("Derivation paths", "Trace how specific facts were derived"),
("Cache analysis", "Monitor cache hit rates and performance"),
("Memory monitoring", "Track memory usage during execution"),
(
"Statistics collection",
"Gather execution statistics for optimization",
),
]
}
pub fn troubleshooting_checklist() -> Vec<&'static str> {
vec![
"Check rule syntax and structure",
"Verify variable consistency between head and body",
"Ensure termination conditions for recursive rules",
"Validate input facts format and types",
"Check for infinite loops or cycles",
"Monitor memory usage for large datasets",
"Verify rule execution order and dependencies",
"Test with simplified rule sets first",
"Use debugging tools to trace execution",
"Check for rule conflicts and contradictions",
]
}
}
pub struct IntegrationExamples;
impl IntegrationExamples {
pub fn rdf_integration_example() -> Result<Vec<RuleAtom>> {
let mut engine = RuleEngine::new();
let rdfs_rule = Rule {
name: "rdfs_subclass".to_string(),
body: vec![
RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant(
"http://www.w3.org/2000/01/rdf-schema#subClassOf".to_string(),
),
object: Term::Variable("Y".to_string()),
},
RuleAtom::Triple {
subject: Term::Variable("Z".to_string()),
predicate: Term::Constant(
"http://www.w3.org/1999/02/22-rdf-syntax-ns#type".to_string(),
),
object: Term::Variable("X".to_string()),
},
],
head: vec![RuleAtom::Triple {
subject: Term::Variable("Z".to_string()),
predicate: Term::Constant(
"http://www.w3.org/1999/02/22-rdf-syntax-ns#type".to_string(),
),
object: Term::Variable("Y".to_string()),
}],
};
engine.add_rule(rdfs_rule);
let facts = vec![
RuleAtom::Triple {
subject: Term::Constant("http://example.org/Dog".to_string()),
predicate: Term::Constant(
"http://www.w3.org/2000/01/rdf-schema#subClassOf".to_string(),
),
object: Term::Constant("http://example.org/Animal".to_string()),
},
RuleAtom::Triple {
subject: Term::Constant("http://example.org/fido".to_string()),
predicate: Term::Constant(
"http://www.w3.org/1999/02/22-rdf-syntax-ns#type".to_string(),
),
object: Term::Constant("http://example.org/Dog".to_string()),
},
];
engine.forward_chain(&facts)
}
pub fn caching_integration_example() -> Result<()> {
use crate::cache::RuleCache;
let cache = RuleCache::new();
let mut engine = RuleEngine::new();
engine.set_cache(Some(cache));
let rule = Rule {
name: "cached_rule".to_string(),
body: vec![RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant("likes".to_string()),
object: Term::Constant("coffee".to_string()),
}],
head: vec![RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant("drinks".to_string()),
object: Term::Constant("beverage".to_string()),
}],
};
engine.add_rule(rule);
let facts = vec![RuleAtom::Triple {
subject: Term::Constant("alice".to_string()),
predicate: Term::Constant("likes".to_string()),
object: Term::Constant("coffee".to_string()),
}];
let _result1 = engine.forward_chain(&facts)?;
let _result2 = engine.forward_chain(&facts)?;
if let Some(cache) = engine.get_cache() {
let stats = cache.get_statistics();
println!("Cache hit rate: {:.2}%", stats.rule_cache.hit_rate * 100.0);
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_example() -> Result<(), Box<dyn std::error::Error>> {
let result = GettingStartedGuide::basic_example();
assert!(result.is_ok());
let facts = result?;
assert!(!facts.is_empty());
let mortal_facts: Vec<_> = facts
.iter()
.filter(|fact| match fact {
RuleAtom::Triple {
predicate, object, ..
} => {
predicate == &Term::Constant("type".to_string())
&& object == &Term::Constant("Mortal".to_string())
}
_ => false,
})
.collect();
assert!(mortal_facts.len() >= 2);
Ok(())
}
#[test]
fn test_backward_chaining_example() -> Result<(), Box<dyn std::error::Error>> {
let result = GettingStartedGuide::backward_chaining_example();
assert!(result.is_ok());
assert!(result?); Ok(())
}
#[test]
fn test_family_relationships() -> Result<(), Box<dyn std::error::Error>> {
let result = GettingStartedGuide::family_relationships_example();
assert!(result.is_ok());
let facts = result?;
let grandparent_facts: Vec<_> = facts
.iter()
.filter(|fact| match fact {
RuleAtom::Triple { predicate, .. } => {
predicate == &Term::Constant("grandparent".to_string())
}
_ => false,
})
.collect();
assert!(!grandparent_facts.is_empty());
Ok(())
}
#[test]
fn test_rule_validation() -> Result<(), Box<dyn std::error::Error>> {
let result = RuleAuthoringBestPractices::validate_rule_example();
assert!(result.is_ok());
assert!(result?); Ok(())
}
#[test]
fn test_ontology_reasoning() -> Result<(), Box<dyn std::error::Error>> {
let result = GettingStartedGuide::ontology_reasoning_example();
assert!(result.is_ok());
let facts = result?;
assert!(!facts.is_empty());
Ok(())
}
#[test]
fn test_rdf_integration() -> Result<(), Box<dyn std::error::Error>> {
let result = IntegrationExamples::rdf_integration_example();
assert!(result.is_ok());
let facts = result?;
let animal_facts: Vec<_> = facts
.iter()
.filter(|fact| match fact {
RuleAtom::Triple {
subject, object, ..
} => {
subject == &Term::Constant("http://example.org/fido".to_string())
&& object == &Term::Constant("http://example.org/Animal".to_string())
}
_ => false,
})
.collect();
assert!(!animal_facts.is_empty());
Ok(())
}
}