use super::eligibility::{Boundary, Eligibility};
use super::ir::HypergraphRule;
use super::var_order::VariableOrder;
use std::fmt::Write;
pub fn explain(hg: &HypergraphRule, eligibility: &Eligibility, vo: &dyn VariableOrder) -> String {
let mut out = String::new();
writeln!(out, "rule head={}", hg.head_predicate).unwrap();
if hg.vertices.is_empty() {
writeln!(out, " vertices: []").unwrap();
} else {
let names: Vec<&str> = hg.vertices.iter().map(|v| v.name.as_str()).collect();
writeln!(out, " vertices: [{}]", names.join(" ")).unwrap();
}
if hg.hyperedges.is_empty() {
writeln!(out, " hyperedges: <none>").unwrap();
} else {
writeln!(out, " hyperedges:").unwrap();
for edge in &hg.hyperedges {
let args: Vec<String> = edge
.vertex_positions
.iter()
.map(|p| match p {
Some(vid) => format!("?{}", hg.vertex(*vid).name),
None => "_".to_string(),
})
.collect();
writeln!(out, " {}({})", edge.predicate, args.join(", ")).unwrap();
}
}
writeln!(out, " filters: {}", hg.comparison_count).unwrap();
match eligibility {
Eligibility::Eligible => {
writeln!(out, " eligibility: Eligible").unwrap();
}
Eligibility::Ineligible(boundaries) => {
writeln!(out, " eligibility: Ineligible").unwrap();
for b in boundaries {
writeln!(out, " {}", format_boundary(b)).unwrap();
}
}
}
let order = vo.order(hg);
let order_names: Vec<&str> = order
.iter()
.map(|vid| hg.vertex(*vid).name.as_str())
.collect();
writeln!(
out,
" variable-order({}): [{}]",
vo.name(),
order_names.join(" ")
)
.unwrap();
out
}
fn format_boundary(b: &Boundary) -> String {
match b {
Boundary::GroundFact => "GroundFact".to_string(),
Boundary::HeadAggregation => "HeadAggregation".to_string(),
Boundary::BodyNegation => "BodyNegation".to_string(),
Boundary::BodyIsExpr => "BodyIsExpr".to_string(),
Boundary::InsufficientPositiveAtoms { positive_count } => {
format!("InsufficientPositiveAtoms(positive_count={positive_count})")
}
Boundary::JoinKeysExceedBinaryFallbackLimit {
context,
count,
limit,
} => {
format!(
"JoinKeysExceedBinaryFallbackLimit(context={context:?}, count={count}, limit={limit})"
)
}
Boundary::UnsupportedKeyType { var, ty } => {
format!("UnsupportedKeyType(var={var}, ty={ty:?})")
}
}
}