use crate::{
context::ContextState,
db::clause::db_clause::dbClause,
ipasir::{
ipasir_one::{ipasir_failed, ipasir_init, ipasir_set_learn},
ContextBundle, IPASIR_SIGNATURE,
},
reports::Report,
structures::{
clause::{CClause, Clause, ClauseSource, IntClause},
literal::{CLiteral, Literal},
},
};
use super::ipasir_one::{
ipasir_release, ipasir_set_terminate, ipasir_signature, ipasir_solve, ipasir_val,
};
use std::ffi::{c_char, c_int, c_void};
#[allow(non_camel_case_types)]
#[repr(C)]
pub enum ipasir2_errorcode {
IPASIR2_E_OK = 0,
IPASIR2_E_UNKNOWN = 1,
IPASIR2_E_UNSUPPORTED,
IPASIR2_E_UNSUPPORTED_ARGUMENT,
IPASIR2_E_UNSUPPORTED_OPTION,
IPASIR2_E_INVALID_STATE,
IPASIR2_E_INVALID_ARGUMENT,
IPASIR2_E_INVALID_OPTION_VALUE,
}
#[allow(non_camel_case_types)]
#[repr(C)]
pub enum ipasir2_state {
IPASIR2_S_CONFIG = 0,
IPASIR2_S_INPUT = 1,
IPASIR2_S_SAT,
IPASIR2_S_UNSAT,
IPASIR2_S_SOLVING,
}
#[allow(non_camel_case_types)]
#[repr(C)]
pub struct ipasir2_option {
pub name: *const c_char,
pub min: i64,
pub max: i64,
pub max_state: ipasir2_state,
pub tunable: c_int,
pub indexed: c_int,
pub handle: *const c_void,
}
#[no_mangle]
pub unsafe extern "C" fn ipasir2_signature(signature: *mut *const c_char) -> ipasir2_errorcode {
std::ptr::write(signature, ipasir_signature());
ipasir2_errorcode::IPASIR2_E_OK
}
#[no_mangle]
pub unsafe extern "C" fn ipasir2_init(solver: *mut *mut c_void) -> ipasir2_errorcode {
std::ptr::write(solver, ipasir_init());
ipasir2_errorcode::IPASIR2_E_OK
}
#[no_mangle]
pub unsafe extern "C" fn ipasir2_release(solver: *mut c_void) -> ipasir2_errorcode {
ipasir_release(solver);
ipasir2_errorcode::IPASIR2_E_OK
}
#[no_mangle]
pub unsafe extern "C" fn ipasir2_options(
solver: *mut c_void,
options: *const *mut ipasir2_option,
count: *mut c_int,
) -> ipasir2_errorcode {
ipasir2_errorcode::IPASIR2_E_UNSUPPORTED
}
#[no_mangle]
pub unsafe extern "C" fn ipasir2_get_option_handle(
solver: *mut c_void,
name: *const c_char,
handle: *const ipasir2_option,
) -> ipasir2_errorcode {
ipasir2_errorcode::IPASIR2_E_UNSUPPORTED
}
#[no_mangle]
pub unsafe extern "C" fn ipasir2_set_option(
solver: *mut c_void,
handle: *const ipasir2_option,
value: i64,
index: i64,
) -> ipasir2_errorcode {
ipasir2_errorcode::IPASIR2_E_UNSUPPORTED
}
#[allow(unused_variables)]
#[no_mangle]
pub unsafe extern "C" fn ipasir2_add(
solver: *mut c_void,
clause: *const i32,
len: i32,
forgettable: i32,
proofmeta: *mut c_void,
) -> ipasir2_errorcode {
if !proofmeta.is_null() {
return ipasir2_errorcode::IPASIR2_E_UNSUPPORTED_ARGUMENT;
}
let clause = std::slice::from_raw_parts(clause, len as usize);
let bundle: &mut ContextBundle = &mut *(solver as *mut ContextBundle);
assert!(bundle.clause_buffer.is_empty());
for literal in clause {
let literal_atom = literal.unsigned_abs();
bundle.context.ensure_atom(literal_atom);
bundle
.clause_buffer
.push(CLiteral::new(literal_atom, literal.is_positive()));
}
bundle
.context
.add_clause_unchecked(std::mem::take(&mut bundle.clause_buffer));
ipasir2_errorcode::IPASIR2_E_OK
}
#[no_mangle]
pub unsafe extern "C" fn ipasir2_solve(
solver: *mut c_void,
result: *mut c_int,
literals: *const i32,
len: i32,
) -> ipasir2_errorcode {
let bundle: &mut ContextBundle = &mut *(solver as *mut ContextBundle);
if len != 0 {
let assumption_literals = std::slice::from_raw_parts(literals, len as usize);
for assumption in assumption_literals {
let literal_atom = assumption.unsigned_abs();
bundle.context.ensure_atom(literal_atom);
let assumption = CLiteral::new(literal_atom, assumption.is_positive());
bundle.context.add_assumption(assumption);
}
}
std::ptr::write(result, ipasir_solve(solver));
ipasir2_errorcode::IPASIR2_E_OK
}
#[no_mangle]
pub unsafe extern "C" fn ipasir2_value(
solver: *mut c_void,
lit: i32,
result: *mut i32,
) -> ipasir2_errorcode {
std::ptr::write(result, ipasir_val(solver, lit));
ipasir2_errorcode::IPASIR2_E_OK
}
#[no_mangle]
pub unsafe extern "C" fn ipasir2_failed(
solver: *mut c_void,
lit: i32,
result: *mut c_int,
) -> ipasir2_errorcode {
std::ptr::write(result, ipasir_failed(solver, lit));
ipasir2_errorcode::IPASIR2_E_OK
}
#[no_mangle]
pub unsafe extern "C" fn ipasir2_set_terminate(
solver: *mut c_void,
data: *mut c_void,
callback: Option<extern "C" fn(data: *mut c_void) -> c_int>,
) -> ipasir2_errorcode {
ipasir_set_terminate(solver, data, callback);
ipasir2_errorcode::IPASIR2_E_OK
}
#[no_mangle]
#[allow(clippy::useless_conversion)]
pub unsafe extern "C" fn ipasir2_set_export(
solver: *mut c_void,
data: *mut c_void,
max_length: c_int,
callback: Option<
extern "C" fn(data: *mut c_void, clause: *const i32, len: i32, proofmeta: *mut c_void),
>,
) -> ipasir2_errorcode {
if let Some(callback) = callback {
let bundle: &mut ContextBundle = &mut *(solver as *mut ContextBundle);
let callback = Box::new(move |clause: &dbClause, _: &ClauseSource| {
if clause.len() < (max_length as usize) {
let mut int_clause: Vec<c_int> = clause.literals().map(|l| l.into()).collect();
let callback_ptr: *mut i32 = int_clause.as_mut_ptr();
callback(
data,
callback_ptr,
clause.len() as i32,
std::ptr::null_mut(),
);
}
});
bundle.context.set_callback_addition(callback);
ipasir2_errorcode::IPASIR2_E_OK
} else {
ipasir2_errorcode::IPASIR2_E_INVALID_ARGUMENT
}
}
#[allow(clippy::useless_conversion)]
#[no_mangle]
pub unsafe extern "C" fn ipasir2_delete(
solver: *mut c_void,
data: *mut c_void,
callback: Option<
extern "C" fn(data: *mut c_void, clause: *const i32, len: i32, proofmeta: *mut c_void),
>,
) -> ipasir2_errorcode {
if let Some(callback) = callback {
let bundle: &mut ContextBundle = &mut *(solver as *mut ContextBundle);
let callback = Box::new(move |clause: &dbClause| {
let callback_ptr: *mut i32 = if cfg!(feature = "boolean") {
let mut int_clause: IntClause = clause.literals().map(|l| l.into()).collect();
int_clause.as_mut_ptr()
} else {
clause.as_ptr() as *mut i32
};
match clause.size().try_into() {
Ok(clause_size) => {
callback(data, callback_ptr, clause_size, std::ptr::null_mut());
}
Err(_) => {
log::error!("Clause too large for IPASIR delete callback");
}
}
});
bundle.context.set_callback_delete(callback);
ipasir2_errorcode::IPASIR2_E_OK
} else {
ipasir2_errorcode::IPASIR2_E_INVALID_ARGUMENT
}
}
#[no_mangle]
pub unsafe extern "C" fn ipasir2_set_import(
solver: *mut c_void,
data: *mut c_void,
callback: Option<extern "C" fn(data: *mut c_void)>,
) -> ipasir2_errorcode {
ipasir2_errorcode::IPASIR2_E_UNSUPPORTED
}
#[no_mangle]
pub unsafe extern "C" fn ipasir2_set_fixed(
solver: *mut c_void,
data: *mut c_void,
callback: Option<extern "C" fn(data: *mut c_void, fixed: i32)>,
) -> ipasir2_errorcode {
if let Some(callback) = callback {
let bundle: &mut ContextBundle = &mut *(solver as *mut ContextBundle);
let callback = Box::new(move |literal: CLiteral| {
callback(data, literal);
});
bundle.context.set_callback_fixed(callback);
ipasir2_errorcode::IPASIR2_E_OK
} else {
ipasir2_errorcode::IPASIR2_E_INVALID_ARGUMENT
}
}