use ipfrs_tensorlogic::{
CacheManager, Constant, DistributedGoalResolver, DistributedReasoner, FactDiscoveryRequest,
IncrementalLoadRequest, KnowledgeBase, MockRemoteKnowledgeProvider, Predicate,
RemoteKnowledgeProvider, Rule, Substitution, TabledInferenceEngine, Term,
};
use std::collections::HashSet;
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Advanced Distributed Reasoning Example ===\n");
println!("1. Setting up knowledge bases...");
let (local_kb, remote_kb) = setup_knowledge_bases();
println!(
" ✓ Local KB: {} facts, {} rules",
local_kb.facts.len(),
local_kb.rules.len()
);
println!(
" ✓ Remote KB: {} facts, {} rules",
remote_kb.facts.len(),
remote_kb.rules.len()
);
println!("\n2. Creating distributed reasoning infrastructure...");
let cache_manager = Arc::new(CacheManager::new());
let remote_provider = Arc::new(MockRemoteKnowledgeProvider::new(Arc::new(remote_kb)));
let reasoner = DistributedReasoner::with_cache(cache_manager.clone())?;
let mut goal_resolver = DistributedGoalResolver::new(Arc::new(local_kb.clone()))
.with_provider(remote_provider.clone())
.with_timeout(5000);
println!(" ✓ Distributed reasoner created with cache");
println!(" ✓ Goal resolver configured");
println!("\n3. Local reasoning (cached)...");
let local_goal = Predicate::new(
"parent".to_string(),
vec![
Term::Const(Constant::String("alice".to_string())),
Term::Var("X".to_string()),
],
);
let local_solutions = reasoner.query(&local_goal, &local_kb).await?;
println!(" ✓ Found {} local solutions", local_solutions.len());
print_solutions("parent(alice, X)", &local_solutions);
println!("\n4. Remote fact discovery...");
let discovery_request = FactDiscoveryRequest {
predicate_name: "knows".to_string(),
arg_patterns: vec![],
max_hops: 3,
ttl: 30,
exclude_peers: HashSet::new(),
};
let discovery_response = remote_provider.discover_facts(discovery_request).await?;
println!(
" ✓ Discovered {} facts from {} peer(s)",
discovery_response.facts.len(),
discovery_response.peers_queried
);
for (i, fact) in discovery_response.facts.iter().take(3).enumerate() {
println!(" {}. {}", i + 1, fact);
}
println!("\n5. Incremental fact loading...");
let load_request = IncrementalLoadRequest {
predicate_name: "knows".to_string(),
batch_size: 2,
offset: 0,
filter: None,
};
let load_response = remote_provider.load_incremental(load_request).await?;
println!(
" ✓ Loaded batch: {} of {} total facts",
load_response.batch.len(),
load_response.total_count
);
println!(" ✓ More available: {}", !load_response.is_last);
println!("\n6. Prefetching remote facts...");
let prefetch_count = goal_resolver.prefetch_facts("knows").await?;
println!(" ✓ Prefetched {} facts", prefetch_count);
println!("\n7. Recursive query (ancestor relation)...");
let ancestor_goal = Predicate::new(
"ancestor".to_string(),
vec![
Term::Const(Constant::String("alice".to_string())),
Term::Var("Z".to_string()),
],
);
let tabled_engine = TabledInferenceEngine::new();
let ancestor_solutions = tabled_engine.query(&ancestor_goal, &local_kb)?;
println!(
" ✓ Found {} ancestors using tabling",
ancestor_solutions.len()
);
print_solutions("ancestor(alice, Z)", &ancestor_solutions);
let table_stats = tabled_engine.table_stats();
println!(
" ✓ Table statistics: {} entries, {} complete",
table_stats.entries, table_stats.complete_entries
);
println!("\n8. Distributed goal resolution...");
let distributed_goal = Predicate::new(
"knows".to_string(),
vec![
Term::Const(Constant::String("alice".to_string())),
Term::Var("Y".to_string()),
],
);
let distributed_solutions = goal_resolver
.resolve(&distributed_goal, &Substitution::new())
.await?;
println!(
" ✓ Resolved {} solutions using distributed reasoning",
distributed_solutions.len()
);
print_solutions("knows(alice, Y)", &distributed_solutions);
println!("\n9. Cache performance analysis...");
if let Some(stats) = reasoner.cache_stats() {
println!(" Query Cache:");
println!(" • Hits: {}", stats.query_stats.hits);
println!(" • Misses: {}", stats.query_stats.misses);
println!(" • Evictions: {}", stats.query_stats.evictions);
println!(
" • Hit Rate: {:.2}%",
stats.query_stats.hits as f64
/ (stats.query_stats.hits + stats.query_stats.misses).max(1) as f64
* 100.0
);
println!(" Fact Cache:");
println!(" • Hits: {}", stats.fact_stats.hits);
println!(" • Misses: {}", stats.fact_stats.misses);
println!(" • Evictions: {}", stats.fact_stats.evictions);
}
println!("\n10. Proof construction and verification...");
let proof = reasoner.prove(&local_goal, &local_kb).await?;
if let Some(proof) = proof {
println!(" ✓ Proof constructed:");
println!(" • Goal: {}", proof.goal);
println!(" • Is fact: {}", proof.is_fact());
println!(" • Depth: {}", proof.depth());
println!(" • Size: {} nodes", proof.size());
use ipfrs_tensorlogic::InferenceEngine;
let engine = InferenceEngine::new();
let valid = engine.verify(&proof, &local_kb)?;
println!(
" ✓ Proof verification: {}",
if valid { "VALID ✓" } else { "INVALID ✗" }
);
} else {
println!(" ✗ No proof found");
}
println!("\n=== Summary ===");
println!("✓ Demonstrated local reasoning with caching");
println!("✓ Performed remote fact discovery");
println!("✓ Used incremental loading for large datasets");
println!("✓ Applied recursive queries with tabling");
println!("✓ Executed distributed goal resolution");
println!("✓ Constructed and verified proofs");
println!("\nThe distributed reasoning system is fully operational!");
Ok(())
}
fn setup_knowledge_bases() -> (KnowledgeBase, KnowledgeBase) {
let mut local_kb = KnowledgeBase::new();
let mut remote_kb = KnowledgeBase::new();
local_kb.add_fact(Predicate::new(
"parent".to_string(),
vec![
Term::Const(Constant::String("alice".to_string())),
Term::Const(Constant::String("bob".to_string())),
],
));
local_kb.add_fact(Predicate::new(
"parent".to_string(),
vec![
Term::Const(Constant::String("bob".to_string())),
Term::Const(Constant::String("charlie".to_string())),
],
));
local_kb.add_fact(Predicate::new(
"parent".to_string(),
vec![
Term::Const(Constant::String("charlie".to_string())),
Term::Const(Constant::String("david".to_string())),
],
));
local_kb.add_rule(Rule::new(
Predicate::new(
"ancestor".to_string(),
vec![Term::Var("X".to_string()), Term::Var("Y".to_string())],
),
vec![Predicate::new(
"parent".to_string(),
vec![Term::Var("X".to_string()), Term::Var("Y".to_string())],
)],
));
local_kb.add_rule(Rule::new(
Predicate::new(
"ancestor".to_string(),
vec![Term::Var("X".to_string()), Term::Var("Z".to_string())],
),
vec![
Predicate::new(
"parent".to_string(),
vec![Term::Var("X".to_string()), Term::Var("Y".to_string())],
),
Predicate::new(
"ancestor".to_string(),
vec![Term::Var("Y".to_string()), Term::Var("Z".to_string())],
),
],
));
let people = ["alice", "bob", "charlie", "david", "eve", "frank"];
for i in 0..people.len() {
for j in (i + 1)..people.len() {
if (i + j) % 3 == 0 {
remote_kb.add_fact(Predicate::new(
"knows".to_string(),
vec![
Term::Const(Constant::String(people[i].to_string())),
Term::Const(Constant::String(people[j].to_string())),
],
));
}
}
}
(local_kb, remote_kb)
}
fn print_solutions(query: &str, solutions: &[Substitution]) {
if solutions.is_empty() {
println!(" No solutions found for {}", query);
return;
}
for (i, solution) in solutions.iter().take(5).enumerate() {
let bindings: Vec<String> = solution
.iter()
.map(|(var, term)| format!("{} = {}", var, term))
.collect();
println!(" {}. {{ {} }}", i + 1, bindings.join(", "));
}
if solutions.len() > 5 {
println!(" ... and {} more", solutions.len() - 5);
}
}