use bridge::ffi;
use cxx::UniquePtr;
pub mod bridge;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Status {
SATISFIABLE = 10,
UNSATISFIABLE = 20,
UNKNOWN = 0,
}
impl From<i32> for Status {
fn from(val: i32) -> Self {
match val {
10 => Status::SATISFIABLE,
20 => Status::UNSATISFIABLE,
0 => Status::UNKNOWN,
_ => unreachable!(),
}
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum State {
INITIALIZING = 1,
CONFIGURING = 2,
STEADY = 4,
ADDING = 8,
SOLVING = 16,
SATISFIED = 32,
UNSATISFIED = 64,
DELETING = 128,
READY = 102,
VALID = 110,
INVALID = 129,
}
impl From<i32> for State {
fn from(val: i32) -> Self {
match val {
1 => State::INITIALIZING,
2 => State::CONFIGURING,
4 => State::STEADY,
8 => State::ADDING,
16 => State::SOLVING,
32 => State::SATISFIED,
64 => State::UNSATISFIED,
128 => State::DELETING,
102 => State::READY,
110 => State::VALID,
129 => State::INVALID,
_ => unreachable!(),
}
}
}
pub struct CaDiCal {
solver: UniquePtr<ffi::Solver>,
last_terminator: Option<UniquePtr<ffi::Terminator>>,
last_learner: Option<UniquePtr<ffi::Learner>>,
}
impl Clone for CaDiCal {
fn clone(&self) -> Self {
let mut r = Self::new();
Self::copy(self, &mut r);
r
}
}
impl Default for CaDiCal {
fn default() -> Self {
Self::new()
}
}
impl CaDiCal {
#[must_use]
#[inline]
pub fn new() -> Self {
Self {
solver: ffi::constructor(),
last_terminator: None,
last_learner: None,
}
}
#[inline]
pub fn add(&mut self, lit: i32) {
ffi::add(&mut self.solver, lit);
}
#[inline]
pub fn clause1(&mut self, l1: i32) {
ffi::clause1(&mut self.solver, l1);
}
#[inline]
pub fn clause2(&mut self, l1: i32, l2: i32) {
ffi::clause2(&mut self.solver, l1, l2);
}
#[inline]
pub fn clause3(&mut self, l1: i32, l2: i32, l3: i32) {
ffi::clause3(&mut self.solver, l1, l2, l3);
}
#[inline]
pub fn clause4(&mut self, l1: i32, l2: i32, l3: i32, l4: i32) {
ffi::clause4(&mut self.solver, l1, l2, l3, l4);
}
#[inline]
pub fn clause5(&mut self, l1: i32, l2: i32, l3: i32, l4: i32, l5: i32) {
ffi::clause5(&mut self.solver, l1, l2, l3, l4, l5);
}
#[inline]
pub fn clause6(&mut self, v: &[i32]) {
ffi::clause6(&mut self.solver, v);
}
#[inline]
pub fn inconsistent(&mut self) -> bool {
ffi::inconsistent(&mut self.solver)
}
#[inline]
pub fn assume(&mut self, lit: i32) {
ffi::assume(&mut self.solver, lit);
}
#[inline]
pub fn solve(&mut self) -> Status {
ffi::solve(&mut self.solver).into()
}
#[inline]
pub fn val(&mut self, lit: i32) -> i32 {
ffi::val(&mut self.solver, lit)
}
#[inline]
pub fn flip(&mut self, lit: i32) -> bool {
ffi::flip(&mut self.solver, lit)
}
#[inline]
pub fn flippable(&mut self, lit: i32) -> bool {
ffi::flippable(&mut self.solver, lit)
}
#[inline]
pub fn failed(&mut self, lit: i32) -> bool {
ffi::failed(&mut self.solver, lit)
}
#[inline]
#[allow(clippy::missing_panics_doc)]
pub fn connect_terminator<'a, 'b: 'a, T: Terminator>(&'a mut self, terminator: &'b mut T) {
fn f<T: Terminator>(state: *mut u8) -> bool {
let ptr: *mut T = state.cast::<T>();
let i = unsafe { &mut *ptr };
i.terminated()
}
let terminator =
unsafe { ffi::new_terminator(std::ptr::from_mut(terminator).cast::<u8>(), f::<T>) };
self.last_terminator = Some(terminator);
ffi::connect_terminator(&mut self.solver, self.last_terminator.as_mut().unwrap());
}
#[inline]
pub fn disconnect_terminator(&mut self) {
ffi::disconnect_terminator(&mut self.solver);
self.last_terminator = None;
}
#[inline]
#[allow(clippy::missing_panics_doc)]
pub fn connect_learner<'a, 'b: 'a, T: Learner>(&'a mut self, learner: &'b mut T) {
fn learning<T: Learner>(state: *mut u8, size: i32) -> bool {
let ptr: *mut T = state.cast::<T>();
let i = unsafe { &mut *ptr };
i.learning(size)
}
fn learn<T: Learner>(state: *mut u8, lit: i32) {
let ptr: *mut T = state.cast::<T>();
let i = unsafe { &mut *ptr };
i.learn(lit);
}
let learner = unsafe {
ffi::new_learner(
std::ptr::from_mut(learner).cast::<u8>(),
learning::<T>,
learn::<T>,
)
};
self.last_learner = Some(learner);
ffi::connect_learner(&mut self.solver, self.last_learner.as_mut().unwrap());
}
#[inline]
pub fn disconnect_learner(&mut self) {
ffi::disconnect_learner(&mut self.solver);
self.last_learner = None;
}
#[inline]
pub fn disconnect_fixed_listener(&mut self) {
ffi::disconnect_fixed_listener(&mut self.solver);
}
#[inline]
pub fn add_observed_var(&mut self, var: i32) {
ffi::add_observed_var(&mut self.solver, var);
}
#[inline]
pub fn remove_observed_var(&mut self, var: i32) {
ffi::remove_observed_var(&mut self.solver, var);
}
#[inline]
pub fn reset_observed_vars(&mut self) {
ffi::reset_observed_vars(&mut self.solver);
}
#[inline]
pub fn is_decision(&mut self, lit: i32) -> bool {
ffi::is_decision(&mut self.solver, lit)
}
#[inline]
pub fn force_backtrack(&mut self, new_level: usize) {
ffi::force_backtrack(&mut self.solver, new_level);
}
#[inline]
pub fn constrain(&mut self, lit: i32) {
ffi::constrain(&mut self.solver, lit);
}
#[inline]
pub fn constraint_failed(&mut self) -> bool {
ffi::constraint_failed(&mut self.solver)
}
#[inline]
pub fn lookahead(&mut self) -> i32 {
ffi::lookahead(&mut self.solver)
}
#[inline]
pub fn generate_cubes(&mut self, x: i32, min_depth: i32, result_cubes: &mut Vec<i32>) -> i32 {
ffi::generate_cubes(&mut self.solver, x, min_depth, result_cubes)
}
#[inline]
pub fn reset_assumptions(&mut self) {
ffi::reset_assumptions(&mut self.solver);
}
#[inline]
pub fn reset_constraint(&mut self) {
ffi::reset_constraint(&mut self.solver);
}
#[must_use]
#[inline]
pub fn state(&self) -> State {
ffi::state(&self.solver).into()
}
#[must_use]
#[inline]
pub fn status(&self) -> Status {
ffi::status(&self.solver).into()
}
#[must_use]
#[inline]
pub fn version() -> String {
ffi::version()
}
#[inline]
pub fn copy(source: &CaDiCal, destination: &mut CaDiCal) {
ffi::copy(&source.solver, &mut destination.solver);
}
#[inline]
pub fn vars(&mut self) -> i32 {
ffi::vars(&mut self.solver)
}
#[inline]
pub fn reserve(&mut self, min_max_var: i32) {
ffi::reserve(&mut self.solver, min_max_var);
}
#[must_use]
#[inline]
pub fn is_valid_option(name: String) -> bool {
ffi::is_valid_option(name)
}
#[must_use]
#[inline]
pub fn is_preprocessing_option(name: String) -> bool {
ffi::is_preprocessing_option(name)
}
#[must_use]
#[inline]
pub fn is_valid_long_option(arg: String) -> bool {
ffi::is_valid_long_option(arg)
}
#[inline]
pub fn get(&mut self, name: String) -> i32 {
ffi::get(&mut self.solver, name)
}
#[inline]
pub fn prefix(&mut self, verbose_message_prefix: String) {
ffi::prefix(&mut self.solver, verbose_message_prefix);
}
#[inline]
pub fn set(&mut self, name: String, val: i32) -> bool {
ffi::set(&mut self.solver, name, val)
}
#[inline]
pub fn set_long_option(&mut self, arg: String) -> bool {
ffi::set_long_option(&mut self.solver, arg)
}
#[must_use]
#[inline]
pub fn is_valid_configuration(name: String) -> bool {
ffi::is_valid_configuration(name)
}
#[inline]
pub fn configure(&mut self, name: String) -> bool {
ffi::configure(&mut self.solver, name)
}
#[inline]
pub fn optimize(&mut self, val: i32) {
ffi::optimize(&mut self.solver, val);
}
#[inline]
pub fn limit(&mut self, arg: String, val: i32) -> bool {
ffi::limit(&mut self.solver, arg, val)
}
#[inline]
pub fn is_valid_limit(&mut self, arg: String) -> bool {
ffi::is_valid_limit(&mut self.solver, arg)
}
#[must_use]
#[inline]
pub fn active(&self) -> i32 {
ffi::active(&self.solver)
}
#[must_use]
#[inline]
pub fn redundant(&self) -> i64 {
ffi::redundant(&self.solver)
}
#[must_use]
#[inline]
pub fn irredundant(&self) -> i64 {
ffi::irredundant(&self.solver)
}
#[inline]
pub fn simplify(&mut self, rounds: i32) -> Status {
ffi::simplify(&mut self.solver, rounds).into()
}
#[inline]
pub fn terminate(&mut self) {
ffi::terminate(&mut self.solver);
}
#[must_use]
#[inline]
pub fn frozen(&self, lit: i32) -> bool {
ffi::frozen(&self.solver, lit)
}
#[inline]
pub fn freeze(&mut self, lit: i32) {
ffi::freeze(&mut self.solver, lit);
}
#[inline]
pub fn melt(&mut self, lit: i32) {
ffi::melt(&mut self.solver, lit);
}
#[must_use]
#[inline]
pub fn fixed(&self, lit: i32) -> i32 {
ffi::fixed(&self.solver, lit)
}
#[inline]
pub fn phase(&mut self, lit: i32) {
ffi::phase(&mut self.solver, lit);
}
#[inline]
pub fn unphase(&mut self, lit: i32) {
ffi::unphase(&mut self.solver, lit);
}
#[inline]
pub fn trace_proof1(&mut self, file: String, name: String) -> bool {
ffi::trace_proof1(&mut self.solver, file, name)
}
#[inline]
pub fn trace_proof2(&mut self, path: String) -> bool {
ffi::trace_proof2(&mut self.solver, path)
}
#[inline]
pub fn flush_proof_trace(&mut self, print: bool) {
ffi::flush_proof_trace(&mut self.solver, print);
}
#[inline]
pub fn close_proof_trace(&mut self, print: bool) {
ffi::close_proof_trace(&mut self.solver, print);
}
#[inline]
pub fn conclude(&mut self) {
ffi::conclude(&mut self.solver);
}
#[inline]
pub fn usage() {
ffi::usage();
}
#[inline]
pub fn configurations() {
ffi::configurations();
}
#[inline]
pub fn statistics(&mut self) {
ffi::statistics(&mut self.solver);
}
#[inline]
pub fn resources(&mut self) {
ffi::resources(&mut self.solver);
}
#[inline]
pub fn options(&mut self) {
ffi::options(&mut self.solver);
}
#[inline]
pub fn traverse_clauses<I: ClauseIterator>(&self, i: &mut I) -> bool {
fn f<I: ClauseIterator>(state: *mut u8, clause: &[i32]) -> bool {
let ptr: *mut I = state.cast::<I>();
let i = unsafe { &mut *ptr };
i.clause(clause)
}
let mut iter =
unsafe { ffi::new_clause_iterator(std::ptr::from_mut(i).cast::<u8>(), f::<I>) };
ffi::traverse_clauses(&self.solver, &mut iter)
}
#[inline]
pub fn traverse_witnesses_backward<I: WitnessIterator>(&self, i: &mut I) -> bool {
fn f<I: WitnessIterator>(state: *mut u8, clause: &[i32], witness: &[i32], id: u64) -> bool {
let ptr: *mut I = state.cast::<I>();
let i = unsafe { &mut *ptr };
i.witness(clause, witness, id)
}
let mut iter =
unsafe { ffi::new_witness_iterator(std::ptr::from_mut(i).cast::<u8>(), f::<I>) };
ffi::traverse_witnesses_backward(&self.solver, &mut iter)
}
#[inline]
pub fn traverse_witnesses_forward<I: WitnessIterator>(&self, i: &mut I) -> bool {
fn f<I: WitnessIterator>(state: *mut u8, clause: &[i32], witness: &[i32], id: u64) -> bool {
let ptr: *mut I = state.cast::<I>();
let i = unsafe { &mut *ptr };
i.witness(clause, witness, id)
}
let mut iter =
unsafe { ffi::new_witness_iterator(std::ptr::from_mut(i).cast::<u8>(), f::<I>) };
ffi::traverse_witnesses_forward(&self.solver, &mut iter)
}
#[inline]
pub fn read_dimacs1(
&mut self,
file: String,
name: String,
vars: &mut i32,
strict: i32,
) -> String {
ffi::read_dimacs1(&mut self.solver, file, name, vars, strict)
}
#[inline]
pub fn read_dimacs2(&mut self, path: String, vars: &mut i32, strict: i32) -> String {
ffi::read_dimacs2(&mut self.solver, path, vars, strict)
}
#[inline]
pub fn read_dimacs3(
&mut self,
file: String,
name: String,
vars: &mut i32,
strict: i32,
incremental: &mut bool,
cubes: &mut Vec<i32>,
) -> String {
ffi::read_dimacs3(
&mut self.solver,
file,
name,
vars,
strict,
incremental,
cubes,
)
}
#[inline]
pub fn read_dimacs4(
&mut self,
path: String,
vars: &mut i32,
strict: i32,
incremental: &mut bool,
cubes: &mut Vec<i32>,
) -> String {
ffi::read_dimacs4(&mut self.solver, path, vars, strict, incremental, cubes)
}
#[inline]
pub fn write_dimacs(&mut self, path: String, min_max_var: i32) -> String {
ffi::write_dimacs(&mut self.solver, path, min_max_var)
}
#[inline]
pub fn write_extension(&mut self, path: String) -> String {
ffi::write_extension(&mut self.solver, path)
}
#[inline]
pub fn build(file: String, prefix: String) {
ffi::build(file, prefix);
}
}
pub trait Terminator {
fn terminated(&mut self) -> bool;
}
pub trait Learner {
fn learning(&mut self, size: i32) -> bool;
fn learn(&mut self, lit: i32);
}
pub trait FixedAssignmentListener {
fn notify_fixed_assignment(&mut self, lit: i32);
}
use std::vec::Vec;
pub trait ExternalPropagator {
fn is_lazy(&self) -> bool {
false
}
fn are_reasons_forgettable(&self) -> bool {
false
}
fn notify_assignment(&mut self, lits: &[i32]);
fn notify_new_decision_level(&mut self);
fn notify_backtrack(&mut self, new_level: usize);
fn cb_check_found_model(&self, model: &[i32]) -> bool;
fn cb_decide(&self) -> i32 {
0
}
fn cb_propagate(&self) -> i32 {
0
}
fn cb_add_reason_clause_lit(&self, _propagated_lit: i32) -> i32 {
0
}
fn cb_has_external_clause(&self, is_forgettable: &mut bool) -> bool;
fn cb_add_external_clause_lit(&self) -> i32;
}
pub trait ClauseIterator {
fn clause(&mut self, clause: &[i32]) -> bool;
}
pub trait WitnessIterator {
fn witness(&mut self, clause: &[i32], witness: &[i32], id: u64) -> bool;
}