summaryrefslogtreecommitdiffstats
path: root/vendor/varisat/src/load.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/varisat/src/load.rs')
-rw-r--r--vendor/varisat/src/load.rs259
1 files changed, 259 insertions, 0 deletions
diff --git a/vendor/varisat/src/load.rs b/vendor/varisat/src/load.rs
new file mode 100644
index 000000000..43415dbfb
--- /dev/null
+++ b/vendor/varisat/src/load.rs
@@ -0,0 +1,259 @@
+//! Loading a formula into the solver.
+use vec_mut_scan::VecMutScan;
+
+use partial_ref::{partial, PartialRef};
+
+use varisat_formula::Lit;
+use varisat_internal_proof::{DeleteClauseProof, ProofStep};
+
+use crate::{
+ clause::{db, ClauseHeader, Tier},
+ context::{parts::*, Context},
+ proof,
+ prop::{assignment, full_restart, Reason},
+ state::SatState,
+ unit_simplify::resurrect_unit,
+ variables,
+};
+
+/// Adds a clause to the current formula.
+///
+/// The input uses user variable names.
+///
+/// Removes duplicated literals, ignores tautological clauses (eg. x v -x v y), handles empty
+/// clauses and dispatches among unit, binary and long clauses.
+pub fn load_clause<'a>(
+ mut ctx: partial!(
+ Context<'a>,
+ mut AnalyzeConflictP,
+ mut AssignmentP,
+ mut AssumptionsP,
+ mut BinaryClausesP,
+ mut ClauseAllocP,
+ mut ClauseDbP,
+ mut ImplGraphP,
+ mut ProofP<'a>,
+ mut SolverStateP,
+ mut TmpDataP,
+ mut TmpFlagsP,
+ mut TrailP,
+ mut VariablesP,
+ mut VsidsP,
+ mut WatchlistsP,
+ ),
+ user_lits: &[Lit],
+) {
+ match ctx.part(SolverStateP).sat_state {
+ SatState::Unsat => return,
+ SatState::Sat => {
+ ctx.part_mut(SolverStateP).sat_state = SatState::Unknown;
+ }
+ _ => {}
+ }
+
+ ctx.part_mut(SolverStateP).formula_is_empty = false;
+
+ // Restart the search when the user adds new clauses.
+ full_restart(ctx.borrow());
+
+ // Convert the clause from user to solver literals.
+ let (tmp_data, mut ctx_variables) = ctx.split_part_mut(TmpDataP);
+ variables::solver_from_user_lits(ctx_variables.borrow(), &mut tmp_data.lits, user_lits, true);
+
+ let (tmp_data, mut ctx) = ctx.split_part_mut(TmpDataP);
+
+ let lits = &mut tmp_data.lits;
+ let false_lits = &mut tmp_data.lits_2;
+
+ lits.sort_unstable();
+ lits.dedup();
+
+ proof::add_clause(ctx.borrow(), &lits);
+
+ // Detect tautological clauses
+ let mut last = None;
+
+ for &lit in lits.iter() {
+ if last == Some(!lit) {
+ return;
+ }
+ last = Some(lit);
+ }
+
+ // If we're not a unit clause the contained variables are not isolated anymore.
+ if lits.len() > 1 {
+ for &lit in lits.iter() {
+ ctx.part_mut(VariablesP)
+ .var_data_solver_mut(lit.var())
+ .isolated = false;
+ }
+ }
+
+ // Remove satisfied clauses and handle false literals.
+ //
+ // Proof generation expects us to start with the actual input clauses. If we would remove false
+ // literals we would have to generate proof steps for that. This would result in derived clauses
+ // being added during loading. If we're running proof processors on the fly, they'd see those
+ // derived clauses interspersed with the input clauses.
+ //
+ // We don't want to require each proof processor to handle dervied clause additions during
+ // loading of the initial formula. Thus we need to handle clauses with false literals here.
+ false_lits.clear();
+
+ let mut lits_scan = VecMutScan::new(lits);
+
+ let mut clause_is_true = false;
+
+ // We move unassigned literals to the beginning to make sure we're going to watch unassigned
+ // literals.
+ while let Some(lit) = lits_scan.next() {
+ match ctx.part(AssignmentP).lit_value(*lit) {
+ Some(true) => {
+ clause_is_true = true;
+ break;
+ }
+ Some(false) => {
+ false_lits.push(lit.remove());
+ }
+ None => (),
+ }
+ }
+
+ drop(lits_scan);
+
+ let will_conflict = lits.is_empty();
+
+ // We resurrect any removed false literals to ensure propagation by this new clause. This is
+ // also required to eventually simplify this clause.
+ for &lit in false_lits.iter() {
+ resurrect_unit(ctx.borrow(), !lit);
+ }
+
+ lits.extend_from_slice(&false_lits);
+
+ if clause_is_true {
+ if lits.len() > 1 {
+ proof::add_step(
+ ctx.borrow(),
+ true,
+ &ProofStep::DeleteClause {
+ clause: lits,
+ proof: DeleteClauseProof::Satisfied,
+ },
+ );
+ }
+ return;
+ }
+
+ match lits[..] {
+ [] => ctx.part_mut(SolverStateP).sat_state = SatState::Unsat,
+ [lit] => {
+ if will_conflict {
+ ctx.part_mut(SolverStateP).sat_state = SatState::Unsat
+ } else {
+ assignment::enqueue_assignment(ctx.borrow(), lit, Reason::Unit)
+ }
+ }
+ [lit_0, lit_1] => {
+ ctx.part_mut(BinaryClausesP)
+ .add_binary_clause([lit_0, lit_1]);
+ }
+ _ => {
+ let mut header = ClauseHeader::new();
+ header.set_tier(Tier::Irred);
+
+ db::add_clause(ctx.borrow(), header, lits);
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use partial_ref::IntoPartialRefMut;
+
+ use varisat_formula::lits;
+
+ use crate::clause::Tier;
+
+ #[test]
+ fn unsat_on_empty_clause() {
+ let mut ctx = Context::default();
+ let mut ctx = ctx.into_partial_ref_mut();
+
+ load_clause(ctx.borrow(), &[]);
+
+ assert_eq!(ctx.part(SolverStateP).sat_state, SatState::Unsat);
+ }
+
+ #[test]
+ fn unit_clauses() {
+ let mut ctx = Context::default();
+ let mut ctx = ctx.into_partial_ref_mut();
+
+ load_clause(ctx.borrow(), &lits![1]);
+
+ assert_eq!(ctx.part(TrailP).trail().len(), 1);
+
+ load_clause(ctx.borrow(), &lits![3, -3]);
+
+ assert_eq!(ctx.part(TrailP).trail().len(), 1);
+
+ load_clause(ctx.borrow(), &lits![-2]);
+
+ assert_eq!(ctx.part(TrailP).trail().len(), 2);
+
+ load_clause(ctx.borrow(), &lits![1, 1]);
+
+ assert_eq!(ctx.part(TrailP).trail().len(), 2);
+
+ assert_eq!(ctx.part(SolverStateP).sat_state, SatState::Unknown);
+
+ load_clause(ctx.borrow(), &lits![2]);
+
+ assert_eq!(ctx.part(TrailP).trail().len(), 2);
+
+ assert_eq!(ctx.part(SolverStateP).sat_state, SatState::Unsat);
+ }
+
+ #[test]
+ fn binary_clauses() {
+ let mut ctx = Context::default();
+ let mut ctx = ctx.into_partial_ref_mut();
+
+ load_clause(ctx.borrow(), &lits![1, 2]);
+
+ assert_eq!(ctx.part(BinaryClausesP).count(), 1);
+
+ load_clause(ctx.borrow(), &lits![-1, 3, 3]);
+
+ assert_eq!(ctx.part(BinaryClausesP).count(), 2);
+
+ load_clause(ctx.borrow(), &lits![4, -4]);
+
+ assert_eq!(ctx.part(BinaryClausesP).count(), 2);
+
+ assert_eq!(ctx.part(SolverStateP).sat_state, SatState::Unknown);
+ }
+
+ #[test]
+ fn long_clauses() {
+ let mut ctx = Context::default();
+ let mut ctx = ctx.into_partial_ref_mut();
+
+ load_clause(ctx.borrow(), &lits![1, 2, 3]);
+
+ assert_eq!(ctx.part(ClauseDbP).count_by_tier(Tier::Irred), 1);
+
+ load_clause(ctx.borrow(), &lits![-2, 3, 3, 4]);
+
+ assert_eq!(ctx.part(ClauseDbP).count_by_tier(Tier::Irred), 2);
+
+ load_clause(ctx.borrow(), &lits![4, -5, 5, 2]);
+
+ assert_eq!(ctx.part(ClauseDbP).count_by_tier(Tier::Irred), 2);
+
+ assert_eq!(ctx.part(SolverStateP).sat_state, SatState::Unknown);
+ }
+}