use logicaffeine_verify::ir::VerifyExpr;
pub fn decompose_conjunctive(expr: &VerifyExpr) -> Vec<VerifyExpr> {
let mut parts = Vec::new();
flatten_and(expr, &mut parts);
if parts.is_empty() {
return vec![expr.clone()];
}
let mut groups: Vec<(String, Vec<VerifyExpr>)> = Vec::new();
for part in parts {
let pattern = normalize_timesteps(&part);
if let Some(group) = groups.iter_mut().find(|(p, _)| *p == pattern) {
group.1.push(part);
} else {
groups.push((pattern, vec![part]));
}
}
groups.into_iter().map(|(_, members)| {
let mut result = members[0].clone();
for member in &members[1..] {
result = VerifyExpr::and(result, member.clone());
}
result
}).collect()
}
pub fn verify_decomposition_sound(
original: &VerifyExpr,
parts: &[VerifyExpr],
bound: u32,
) -> bool {
use logicaffeine_verify::equivalence::{check_equivalence, EquivalenceResult};
use std::collections::HashSet;
if parts.is_empty() {
return false;
}
let mut reconstructed = parts[0].clone();
for part in &parts[1..] {
reconstructed = VerifyExpr::and(reconstructed, part.clone());
}
let mut vars = HashSet::new();
logicaffeine_verify::equivalence::collect_vars_pub(original, &mut vars);
logicaffeine_verify::equivalence::collect_vars_pub(&reconstructed, &mut vars);
let signals: Vec<String> = vars
.iter()
.filter_map(|v| v.find('@').map(|pos| v[..pos].to_string()))
.collect::<HashSet<_>>()
.into_iter()
.collect();
matches!(
check_equivalence(original, &reconstructed, &signals, bound as usize),
EquivalenceResult::Equivalent
)
}
fn flatten_and(expr: &VerifyExpr, parts: &mut Vec<VerifyExpr>) {
match expr {
VerifyExpr::Binary { op: logicaffeine_verify::ir::VerifyOp::And, left, right } => {
flatten_and(left, parts);
flatten_and(right, parts);
}
_ => {
parts.push(expr.clone());
}
}
}
fn normalize_timesteps(expr: &VerifyExpr) -> String {
let debug = format!("{:?}", expr);
let mut result = String::with_capacity(debug.len());
let mut chars = debug.chars().peekable();
while let Some(c) = chars.next() {
result.push(c);
if c == '@' {
while chars.peek().map_or(false, |ch| ch.is_ascii_digit()) {
chars.next();
}
result.push('T');
}
}
result
}