use std::ptr;
use crate::control::Control;
use crate::error::{ClingoError, check};
use crate::symbol::Symbol;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SolveResult {
pub satisfiable: bool,
pub unsatisfiable: bool,
pub exhausted: bool,
pub interrupted: bool,
}
impl SolveResult {
fn from_bitset(bits: u32) -> Self {
SolveResult {
satisfiable: bits & clingo_sys::clingo_solve_result_e_clingo_solve_result_satisfiable
!= 0,
unsatisfiable: bits
& clingo_sys::clingo_solve_result_e_clingo_solve_result_unsatisfiable
!= 0,
exhausted: bits & clingo_sys::clingo_solve_result_e_clingo_solve_result_exhausted != 0,
interrupted: bits & clingo_sys::clingo_solve_result_e_clingo_solve_result_interrupted
!= 0,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum ShowType {
Shown,
Atoms,
Terms,
Theory,
All,
}
impl ShowType {
fn to_bitset(self) -> u32 {
match self {
ShowType::Shown => clingo_sys::clingo_show_type_e_clingo_show_type_shown,
ShowType::Atoms => clingo_sys::clingo_show_type_e_clingo_show_type_atoms,
ShowType::Terms => clingo_sys::clingo_show_type_e_clingo_show_type_terms,
ShowType::Theory => clingo_sys::clingo_show_type_e_clingo_show_type_theory,
ShowType::All => clingo_sys::clingo_show_type_e_clingo_show_type_all,
}
}
}
pub struct Model {
ptr: *const clingo_sys::clingo_model_t,
}
impl Model {
pub(crate) fn from_ptr(ptr: *const clingo_sys::clingo_model_t) -> Self {
Model { ptr }
}
pub fn symbols(&self, show: ShowType) -> Result<Vec<Symbol>, ClingoError> {
let bits = show.to_bitset();
let mut size: usize = 0;
check(unsafe { clingo_sys::clingo_model_symbols_size(self.ptr, bits, &mut size) })?;
let mut raw = vec![0u64; size];
check(unsafe { clingo_sys::clingo_model_symbols(self.ptr, bits, raw.as_mut_ptr(), size) })?;
Ok(raw
.into_iter()
.map(|s| unsafe { Symbol::from_raw(s) })
.collect())
}
pub fn contains(&self, atom: Symbol) -> Result<bool, ClingoError> {
let mut contained = false;
check(unsafe { clingo_sys::clingo_model_contains(self.ptr, atom.raw(), &mut contained) })?;
Ok(contained)
}
pub fn number(&self) -> Result<u64, ClingoError> {
let mut n: u64 = 0;
check(unsafe { clingo_sys::clingo_model_number(self.ptr, &mut n) })?;
Ok(n)
}
pub fn optimality_proven(&self) -> Result<bool, ClingoError> {
let mut proven = false;
check(unsafe { clingo_sys::clingo_model_optimality_proven(self.ptr, &mut proven) })?;
Ok(proven)
}
pub fn cost(&self) -> Result<Vec<i64>, ClingoError> {
let mut size: usize = 0;
check(unsafe { clingo_sys::clingo_model_cost_size(self.ptr, &mut size) })?;
let mut costs = vec![0i64; size];
check(unsafe { clingo_sys::clingo_model_cost(self.ptr, costs.as_mut_ptr(), size) })?;
Ok(costs)
}
}
pub struct SolveHandle<'a> {
handle: *mut clingo_sys::clingo_solve_handle_t,
model: Option<Model>,
control: &'a mut Control,
}
impl Drop for SolveHandle<'_> {
fn drop(&mut self) {
unsafe {
clingo_sys::clingo_solve_handle_close(self.handle);
}
}
}
impl<'a> SolveHandle<'a> {
pub fn control(&self) -> &Control {
self.control
}
pub fn next_model(&mut self) -> Result<Option<&Model>, ClingoError> {
check(unsafe { clingo_sys::clingo_solve_handle_resume(self.handle) })?;
let mut model_ptr: *const clingo_sys::clingo_model_t = ptr::null();
check(unsafe { clingo_sys::clingo_solve_handle_model(self.handle, &mut model_ptr) })?;
if model_ptr.is_null() {
self.model = None;
Ok(None)
} else {
self.model = Some(Model::from_ptr(model_ptr));
Ok(self.model.as_ref())
}
}
pub fn current_model(&self) -> Option<&Model> {
self.model.as_ref()
}
pub fn close(self) -> Result<SolveResult, ClingoError> {
let mut result_bits: u32 = 0;
check(unsafe { clingo_sys::clingo_solve_handle_get(self.handle, &mut result_bits) })?;
Ok(SolveResult::from_bitset(result_bits))
}
}
pub(crate) fn solve_yielding(control: &mut Control) -> Result<SolveHandle<'_>, ClingoError> {
let mut handle: *mut clingo_sys::clingo_solve_handle_t = ptr::null_mut();
check(unsafe {
clingo_sys::clingo_control_solve(
control.ptr.as_ptr(),
clingo_sys::clingo_solve_mode_e_clingo_solve_mode_yield,
ptr::null(),
0,
None,
ptr::null_mut(),
&mut handle,
)
})?;
Ok(SolveHandle {
handle,
model: None,
control,
})
}