use partial_ref::{partial, split_borrow, PartialRef};
use varisat_formula::{Lit, Var};
use varisat_internal_proof::{clause_hash, lit_hash, DeleteClauseProof, ProofStep};
use crate::{
binary::simplify_binary,
clause::db::filter_clauses,
context::{parts::*, Context},
proof,
prop::{enqueue_assignment, Reason},
variables,
};
pub fn prove_units<'a>(
mut ctx: partial!(
Context<'a>,
mut ImplGraphP,
mut ProofP<'a>,
mut SolverStateP,
mut TrailP,
AssignmentP,
ClauseAllocP,
VariablesP,
),
) -> bool {
let mut new_unit = false;
if ctx.part(TrailP).current_level() == 0 {
let (impl_graph, mut ctx) = ctx.split_part_mut(ImplGraphP);
let mut unit_proofs = vec![];
let (trail, mut ctx) = ctx.split_part_mut(TrailP);
for &lit in trail.trail() {
new_unit = true;
let ctx_lits = ctx.borrow();
let reason = impl_graph.reason(lit.var());
if !reason.is_unit() {
let lits = impl_graph.reason(lit.var()).lits(&ctx_lits);
let hash = clause_hash(lits) ^ lit_hash(lit);
unit_proofs.push((lit, hash));
}
impl_graph.update_removed_unit(lit.var());
}
trail.clear();
if !unit_proofs.is_empty() {
proof::add_step(
ctx.borrow(),
true,
&ProofStep::UnitClauses {
units: &unit_proofs,
},
);
}
}
new_unit
}
pub fn resurrect_unit<'a>(
mut ctx: partial!(Context<'a>, mut AssignmentP, mut ImplGraphP, mut TrailP),
lit: Lit,
) {
if ctx.part(ImplGraphP).is_removed_unit(lit.var()) {
debug_assert!(ctx.part(AssignmentP).lit_is_true(lit));
ctx.part_mut(AssignmentP).unassign_var(lit.var());
enqueue_assignment(ctx.borrow(), lit, Reason::Unit);
}
}
pub fn unit_simplify<'a>(
mut ctx: partial!(
Context<'a>,
mut AssignmentP,
mut BinaryClausesP,
mut ClauseAllocP,
mut ClauseDbP,
mut ProofP<'a>,
mut SolverStateP,
mut VariablesP,
mut WatchlistsP,
mut VsidsP,
AssumptionsP,
),
) {
simplify_binary(ctx.borrow());
let (assignment, mut ctx) = ctx.split_part(AssignmentP);
let mut new_lits = vec![];
{
split_borrow!(proof_ctx = &(mut ProofP, mut SolverStateP, VariablesP) ctx);
let (ctx_2, mut ctx) = ctx.split_borrow();
filter_clauses(ctx_2, |alloc, cref| {
let clause = alloc.clause_mut(cref);
let redundant = clause.header().redundant();
new_lits.clear();
for &lit in clause.lits() {
match assignment.lit_value(lit) {
None => new_lits.push(lit),
Some(true) => {
proof::add_step(
proof_ctx.borrow(),
true,
&ProofStep::DeleteClause {
clause: clause.lits(),
proof: if redundant {
DeleteClauseProof::Redundant
} else {
DeleteClauseProof::Satisfied
},
},
);
return false;
}
Some(false) => (),
}
}
if new_lits.len() < clause.lits().len() {
if proof_ctx.part(ProofP).is_active() {
let hash = [clause_hash(clause.lits())];
proof::add_step(
proof_ctx.borrow(),
true,
&ProofStep::AtClause {
redundant: redundant && new_lits.len() > 2,
clause: &new_lits,
propagation_hashes: &hash[..],
},
);
proof::add_step(
proof_ctx.borrow(),
true,
&ProofStep::DeleteClause {
clause: clause.lits(),
proof: if redundant {
DeleteClauseProof::Redundant
} else {
DeleteClauseProof::Simplified
},
},
);
}
match new_lits[..] {
[] | [_] => unreachable!(),
[lit_0, lit_1] => {
ctx.part_mut(BinaryClausesP)
.add_binary_clause([lit_0, lit_1]);
false
}
ref lits => {
clause.lits_mut()[..lits.len()].copy_from_slice(lits);
clause.header_mut().set_len(lits.len());
true
}
}
} else {
true
}
});
}
for (var_index, &value) in assignment.assignment().iter().enumerate() {
let var = Var::from_index(var_index);
if !ctx.part(VariablesP).solver_var_present(var) {
continue;
}
let var_data = ctx.part_mut(VariablesP).var_data_solver_mut(var);
if let Some(value) = value {
var_data.unit = Some(value);
var_data.isolated = true;
}
if var_data.isolated && !var_data.assumed {
variables::remove_solver_var(ctx.borrow(), var);
}
}
}