use itertools::Itertools;
use crate::explanations::{drup_compute, UnsatCore};
use crate::formulas::{EncodedFormula, FormulaFactory, Literal};
use crate::propositions::Proposition;
use crate::solver::minisat::sat::MsVar;
use crate::solver::minisat::sat::Tristate::{True, Undef};
use crate::solver::minisat::MiniSat;
use std::collections::HashMap;
pub fn compute_unsat_core(solver: &mut MiniSat, f: &FormulaFactory) -> UnsatCore {
assert!(solver.config.proof_generation, "Cannot generate an unsat core if proof generation is not turned on");
assert_ne!(solver.result, True, "An unsat core can only be generated if the formula is solved and is UNSAT");
assert_ne!(solver.result, Undef, "Cannot generate an unsat core before the formula was solved.");
assert!(!solver.last_computation_with_assumptions, "Cannot compute an unsat core for a computation with assumptions.");
let mut clause2propositions = HashMap::new();
let mut clauses = Vec::with_capacity(solver.underlying_solver.pg_original_clauses.len());
for pi in solver.underlying_solver.pg_original_clauses.clone() {
let clause = get_formula_for_vector(solver, &pi.clause, f);
let proposition = pi.proposition.unwrap_or_else(|| Proposition::new(clause));
clauses.push(pi.clause);
clause2propositions.insert(clause, proposition);
}
if clauses.iter().any(Vec::is_empty) {
let empty_clause = clause2propositions.remove(&f.falsum()).unwrap();
return UnsatCore::new(vec![empty_clause], true);
}
let result = drup_compute(clauses, solver.underlying_solver.pg_proof.clone());
if result.trivial_unsat {
handle_trivial_case(solver, f)
} else {
UnsatCore::new(
result
.unsat_core
.iter()
.map(|c| clause2propositions.get(&get_formula_for_vector(solver, c, f)).unwrap().clone())
.dedup()
.collect(),
false,
)
}
}
fn handle_trivial_case(solver: &mut MiniSat, f: &FormulaFactory) -> UnsatCore {
let clauses = &solver.underlying_solver.pg_original_clauses;
for i in 0..clauses.len() {
let ci = &clauses[i];
for cj in clauses.iter().skip(i + 1) {
if ci.clause.len() == 1 && cj.clause.len() == 1 && ci.clause[0] + cj.clause[0] == 0 {
let ci_clone = ci.clone();
let cj_clone = cj.clone();
let pi = if let Some(prop) = ci_clone.proposition {
prop
} else {
Proposition::new(get_formula_for_vector(solver, &ci_clone.clause, f))
};
let pj = if let Some(prop) = cj_clone.proposition {
prop
} else {
Proposition::new(get_formula_for_vector(solver, &cj_clone.clause, f))
};
return UnsatCore::new(if pi == pj { vec![pi] } else { vec![pi, pj] }, false);
}
}
}
panic!("Should be a trivial unsat core, but did not found one.");
}
fn get_formula_for_vector(solver: &mut MiniSat, vector: &Vec<isize>, f: &FormulaFactory) -> EncodedFormula {
let mut literals = Vec::with_capacity(vector.len());
for &lit in vector {
let var = *solver.underlying_solver.idx2name.get(&MsVar(lit.unsigned_abs() - 1)).unwrap();
literals.push(Literal::new(var, lit > 0).into());
}
f.or(&literals)
}