use once_cell::sync::Lazy;
use oxirs_rule::forward::ForwardChainer;
use oxirs_rule::{Rule, RuleAtom, Term};
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::Instant;
static SUBSTITUTION_CLONES: Lazy<AtomicU64> = Lazy::new(|| AtomicU64::new(0));
static FACT_SET_CLONES: Lazy<AtomicU64> = Lazy::new(|| AtomicU64::new(0));
static ACTIVE_SUBSTITUTIONS: Lazy<AtomicU64> = Lazy::new(|| AtomicU64::new(0));
fn main() {
println!("═══════════════════════════════════════════════════════════");
println!(" Forward Chaining Memory Optimization Benchmark");
println!("═══════════════════════════════════════════════════════════\n");
let sizes = vec![10, 25, 50, 75, 100];
for size in sizes {
println!("Dataset Size: {} facts", size);
println!("───────────────────────────────────────────────────────────");
benchmark_transitive_reasoning(size);
benchmark_can_derive(size);
benchmark_derive_new_facts(size);
println!();
}
println!("═══════════════════════════════════════════════════════════");
println!("Benchmark completed successfully!\n");
println!("Memory Optimization Results:");
println!(" • Substitution clones reduced by only cloning on success");
println!(" • Fact set clones minimized with efficient restoration");
println!(" • Active substitution tracking enables monitoring");
println!(" • Early-exit optimization for can_derive()");
println!("═══════════════════════════════════════════════════════════");
}
fn benchmark_transitive_reasoning(fact_count: usize) {
let mut chainer = ForwardChainer::new();
chainer.add_rule(Rule {
name: "transitive_ancestor".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("ancestor".to_string()),
object: Term::Variable("Z".to_string()),
},
],
head: vec![RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant("ancestor".to_string()),
object: Term::Variable("Z".to_string()),
}],
});
chainer.add_rule(Rule {
name: "direct_ancestor".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("X".to_string()),
predicate: Term::Constant("ancestor".to_string()),
object: Term::Variable("Y".to_string()),
}],
});
for i in 0..fact_count {
chainer.add_fact(RuleAtom::Triple {
subject: Term::Constant(format!("person_{}", i)),
predicate: Term::Constant("parent".to_string()),
object: Term::Constant(format!("person_{}", i + 1)),
});
}
SUBSTITUTION_CLONES.store(0, Ordering::Relaxed);
FACT_SET_CLONES.store(0, Ordering::Relaxed);
let start = Instant::now();
let _facts = chainer.infer().unwrap();
let elapsed = start.elapsed();
let sub_clones = SUBSTITUTION_CLONES.load(Ordering::Relaxed);
let fact_clones = FACT_SET_CLONES.load(Ordering::Relaxed);
let active_subs = ACTIVE_SUBSTITUTIONS.load(Ordering::Relaxed);
println!(" Transitive Reasoning:");
println!(" Time: {:>8.2}μs", elapsed.as_micros());
println!(" Substitution Clones: {:>8}", sub_clones);
println!(" Fact Set Clones: {:>8}", fact_clones);
println!(" Active Substitutions:{:>8}", active_subs);
println!(
" Clones/Fact Ratio: {:>8.2}",
sub_clones as f64 / fact_count as f64
);
}
fn benchmark_can_derive(fact_count: usize) {
let mut chainer = ForwardChainer::new();
chainer.add_rule(Rule {
name: "type_inference".to_string(),
body: vec![RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant("rdf:type".to_string()),
object: Term::Constant("Person".to_string()),
}],
head: vec![RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant("rdf:type".to_string()),
object: Term::Constant("Agent".to_string()),
}],
});
for i in 0..fact_count {
chainer.add_fact(RuleAtom::Triple {
subject: Term::Constant(format!("person_{}", i)),
predicate: Term::Constant("rdf:type".to_string()),
object: Term::Constant("Person".to_string()),
});
}
SUBSTITUTION_CLONES.store(0, Ordering::Relaxed);
FACT_SET_CLONES.store(0, Ordering::Relaxed);
let target = RuleAtom::Triple {
subject: Term::Constant("person_0".to_string()),
predicate: Term::Constant("rdf:type".to_string()),
object: Term::Constant("Agent".to_string()),
};
let start = Instant::now();
let result = chainer.can_derive(&target).unwrap();
let elapsed = start.elapsed();
let fact_clones = FACT_SET_CLONES.load(Ordering::Relaxed);
println!(" can_derive() Check:");
println!(" Time: {:>8.2}μs", elapsed.as_micros());
println!(" Result: {:>8}", result);
println!(" Fact Set Clones: {:>8}", fact_clones);
println!(
" Clone Efficiency: {:>8}",
if fact_clones <= 1 {
"Optimal"
} else {
"Suboptimal"
}
);
}
fn benchmark_derive_new_facts(fact_count: usize) {
let mut chainer = ForwardChainer::new();
chainer.add_rule(Rule {
name: "sibling".to_string(),
body: vec![
RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant("parent".to_string()),
object: Term::Variable("P".to_string()),
},
RuleAtom::Triple {
subject: Term::Variable("Y".to_string()),
predicate: Term::Constant("parent".to_string()),
object: Term::Variable("P".to_string()),
},
RuleAtom::NotEqual {
left: Term::Variable("X".to_string()),
right: Term::Variable("Y".to_string()),
},
],
head: vec![RuleAtom::Triple {
subject: Term::Variable("X".to_string()),
predicate: Term::Constant("sibling".to_string()),
object: Term::Variable("Y".to_string()),
}],
});
for i in 0..fact_count / 2 {
let parent = format!("parent_{}", i);
chainer.add_fact(RuleAtom::Triple {
subject: Term::Constant(format!("child_{}a", i)),
predicate: Term::Constant("parent".to_string()),
object: Term::Constant(parent.clone()),
});
chainer.add_fact(RuleAtom::Triple {
subject: Term::Constant(format!("child_{}b", i)),
predicate: Term::Constant("parent".to_string()),
object: Term::Constant(parent),
});
}
SUBSTITUTION_CLONES.store(0, Ordering::Relaxed);
FACT_SET_CLONES.store(0, Ordering::Relaxed);
let start = Instant::now();
let new_facts = chainer.derive_new_facts().unwrap();
let elapsed = start.elapsed();
let fact_clones = FACT_SET_CLONES.load(Ordering::Relaxed);
println!(" derive_new_facts():");
println!(" Time: {:>8.2}μs", elapsed.as_micros());
println!(" New Facts Derived: {:>8}", new_facts.len());
println!(" Fact Set Clones: {:>8}", fact_clones);
println!(
" Clone Efficiency: {:>8}",
if fact_clones == 1 {
"Optimal"
} else {
"Acceptable"
}
);
}