#![doc(html_root_url = "https://docs.rs/clingo/0.7.2")]
#![doc = include_str!("../README.md")]
#![allow(non_upper_case_globals)]
#![allow(clippy::try_err)]
use bitflags::bitflags;
use clingo_sys::*;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::convert::Infallible;
use std::convert::TryInto;
use std::ffi::CStr;
use std::ffi::CString;
use std::ffi::NulError;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::os::raw::c_char;
use std::os::raw::c_void;
use std::ptr::NonNull;
use std::str::Utf8Error;
use std::time::Duration;
use thiserror::Error;
/// Functions and data structures to work with program ASTs.
pub mod ast;
mod ast_internals;
pub mod theory;
/// ClingoError in the rust wrapper, like null pointers or failed matches of C enums.
///
/// Includes internal error from the clingo library.
///
/// **Note:** Errors can only be recovered from if explicitly mentioned; most
/// functions do not provide strong exception guarantees. This means that in
/// case of errors associated objects cannot be used further.
#[derive(Error, Debug)]
pub enum ClingoError {
#[error("NulError: ")]
NulError(#[from] NulError),
#[error("Utf8Error: ")]
Utf8Error(#[from] Utf8Error),
#[error("FFIError: {msg}")]
FFIError { msg: &'static str },
#[error("InternalError: {msg}, code: {code:?}, last: {last}")]
InternalError {
msg: &'static str,
code: ErrorCode,
last: &'static str,
},
#[error("ExternalError: ")]
ExternalError(#[from] ExternalError),
}
impl ClingoError {
fn new_internal(msg: &'static str) -> ClingoError {
ClingoError::InternalError {
msg,
code: error_code(),
last: error_message(),
}
}
fn new_external(msg: &'static str) -> ClingoError {
ExternalError { msg }.into()
}
}
#[derive(Error, Debug)]
#[error("ExternalError: {msg}")]
pub struct ExternalError {
pub msg: &'static str,
}
/// Enumeration of clingo error types
/// See: set_error()
#[derive(Debug, Copy, Clone)]
pub enum ErrorType {
/// Successful API calls
Success = clingo_error_e_clingo_error_success as isize,
/// Errors only detectable at runtime like invalid input
Runtime = clingo_error_e_clingo_error_runtime as isize,
/// Wrong usage of the clingo API
Logic = clingo_error_e_clingo_error_logic as isize,
/// Memory could not be allocated
BadAlloc = clingo_error_e_clingo_error_bad_alloc as isize,
/// Errors unrelated to clingo
Unknown = clingo_error_e_clingo_error_unknown as isize,
}
/// Enumeration of clingo error codes for [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError).
#[derive(Debug, Copy, Clone)]
pub enum ErrorCode {
/// Successful API calls
Success,
/// Errors only detectable at runtime like invalid input
Runtime,
/// Wrong usage of the clingo API
Logic,
/// Memory could not be allocated
BadAlloc,
/// Errors unrelated to clingo
Unknown,
/// FFI failed to match clingo_error
FFIError,
}
impl From<i32> for ErrorCode {
fn from(error: i32) -> Self {
match error as u32 {
clingo_error_e_clingo_error_success => ErrorCode::Success,
clingo_error_e_clingo_error_runtime => ErrorCode::Runtime,
clingo_error_e_clingo_error_logic => ErrorCode::Logic,
clingo_error_e_clingo_error_bad_alloc => ErrorCode::BadAlloc,
clingo_error_e_clingo_error_unknown => ErrorCode::Unknown,
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_error {}",
file!(),
line!(),
column!(),
x
);
ErrorCode::FFIError
}
}
}
}
/// Get the last error code set by a clingo API call.
///
/// **Note:** Each thread has its own local error code.
fn error_code() -> ErrorCode {
ErrorCode::from(unsafe { clingo_error_code() })
}
/// Get the last error message set if an API call fails.
///
/// **Note:** Each thread has its own local error message.
fn error_message() -> &'static str {
let char_ptr: *const c_char = unsafe { clingo_error_message() };
if char_ptr.is_null() {
"Ooops, original error message is null."
} else {
let c_str = unsafe { CStr::from_ptr(char_ptr) };
c_str
.to_str()
.unwrap_or("Ooops, original error message was no valid utf8 string.")
}
}
/// Set an error code and message in the active thread.
///
/// # Errors
///
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `message` contains a nul byte
pub fn set_error(code: ErrorType, message: &str) -> Result<(), NulError> {
let message = CString::new(message)?;
unsafe { clingo_set_error(code as clingo_error_t, message.as_ptr()) }
Ok(())
}
fn set_internal_error(code: ErrorType, message: &'static str) {
// unwrap won't panic, because the function is only used internally on valid strings
let message = CString::new(message).unwrap();
unsafe { clingo_set_error(code as clingo_error_t, message.as_ptr()) }
}
/// Object to add command-line options.
pub struct Options(clingo_options_t);
/// Represents three-valued truth values.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum TruthValue {
/// No truth value
Free = clingo_truth_value_e_clingo_truth_value_free as isize,
/// True
True = clingo_truth_value_e_clingo_truth_value_true as isize,
/// False
False = clingo_truth_value_e_clingo_truth_value_false as isize,
}
impl TruthValue {
fn try_from(code: u32) -> Result<TruthValue, ClingoError> {
match code {
clingo_truth_value_e_clingo_truth_value_false => Ok(TruthValue::False),
clingo_truth_value_e_clingo_truth_value_true => Ok(TruthValue::True),
clingo_truth_value_e_clingo_truth_value_free => Ok(TruthValue::Free),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_truth_value {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_truth_value.",
})
}
}
}
}
/// Enumeration of clause types determining the lifetime of a clause.
///
/// Clauses in the solver are either cleaned up based on a configurable deletion policy or at the end of a solving step.
/// The values of this enumeration determine if a clause is subject to one of the above deletion strategies.
#[derive(Debug, Copy, Clone)]
pub enum ClauseType {
/// The clause is subject to the solvers deletion policy
Learnt = clingo_clause_type_e_clingo_clause_type_learnt as isize,
/// The clause is not subject to the solvers deletion policy
Static = clingo_clause_type_e_clingo_clause_type_static as isize,
/// Like `Learnt` but the clause is deleted after a solving step
Volatile = clingo_clause_type_e_clingo_clause_type_volatile as isize,
/// Like `Static` but the clause is deleted after a solving step
VolatileStatic = clingo_clause_type_e_clingo_clause_type_volatile_static as isize,
}
/// Enumeration of solve events.
#[derive(Debug)]
enum SolveEventType {
/// Issued if a model is found.
Model = clingo_solve_event_type_e_clingo_solve_event_type_model as isize,
/// Issued if an optimization problem is found unsatisfiable.
Unsat = clingo_solve_event_type_e_clingo_solve_event_type_unsat as isize,
/// Issued when the statistics can be updated.
Statistics = clingo_solve_event_type_e_clingo_solve_event_type_statistics as isize,
/// Issued if the search has completed.
Finish = clingo_solve_event_type_e_clingo_solve_event_type_finish as isize,
}
impl SolveEventType {
fn try_from(code: u32) -> Result<SolveEventType, ClingoError> {
match code {
clingo_solve_event_type_e_clingo_solve_event_type_model => Ok(SolveEventType::Model),
clingo_solve_event_type_e_clingo_solve_event_type_unsat => Ok(SolveEventType::Unsat),
clingo_solve_event_type_e_clingo_solve_event_type_statistics => {
Ok(SolveEventType::Statistics)
}
clingo_solve_event_type_e_clingo_solve_event_type_finish => Ok(SolveEventType::Finish),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_solve_event_type {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_solve_event_type.",
})
}
}
}
}
/// Enumeration of solve events.
#[derive(Debug)]
pub enum SolveEvent<'a> {
/// Issued if a model is found.
Model(&'a mut Model),
/// Issued if an optimization problem is found unsatisfiable.
Unsat,
/// Issued when the statistics can be updated.
Statistics {
step: &'a mut Statistics,
akku: &'a mut Statistics,
},
/// Issued if the search has completed.
Finish(&'a mut SolveResult),
}
/// Enumeration for entries of the statistics.
#[derive(Debug, Copy, Clone)]
pub enum StatisticsType {
/// The entry is invalid (has neither of the types below)
Empty = clingo_statistics_type_e_clingo_statistics_type_empty as isize,
/// The entry is a (double) value
Value = clingo_statistics_type_e_clingo_statistics_type_value as isize,
/// The entry is an array
Array = clingo_statistics_type_e_clingo_statistics_type_array as isize,
/// The entry is a map
Map = clingo_statistics_type_e_clingo_statistics_type_map as isize,
}
impl StatisticsType {
fn try_from(code: u32) -> Result<StatisticsType, ClingoError> {
match code {
clingo_statistics_type_e_clingo_statistics_type_empty => Ok(StatisticsType::Empty),
clingo_statistics_type_e_clingo_statistics_type_value => Ok(StatisticsType::Value),
clingo_statistics_type_e_clingo_statistics_type_array => Ok(StatisticsType::Array),
clingo_statistics_type_e_clingo_statistics_type_map => Ok(StatisticsType::Map),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_statistics_type {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_statistics_type.",
})
}
}
}
}
/// Enumeration of available symbol types.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum SymbolType {
/// The `#inf` symbol
Infimum = clingo_symbol_type_e_clingo_symbol_type_infimum as isize,
/// A numeric symbol, e.g., `1`
Number = clingo_symbol_type_e_clingo_symbol_type_number as isize,
/// A string symbol, e.g., `"a"`
String = clingo_symbol_type_e_clingo_symbol_type_string as isize,
/// A numeric symbol, e.g., `c`, `(1, "a")`, or `f(1,"a")`
Function = clingo_symbol_type_e_clingo_symbol_type_function as isize,
/// The `#sup` symbol
Supremum = clingo_symbol_type_e_clingo_symbol_type_supremum as isize,
}
impl SymbolType {
fn try_from(code: u32) -> Result<SymbolType, ClingoError> {
match code {
clingo_symbol_type_e_clingo_symbol_type_infimum => Ok(SymbolType::Infimum),
clingo_symbol_type_e_clingo_symbol_type_number => Ok(SymbolType::Number),
clingo_symbol_type_e_clingo_symbol_type_string => Ok(SymbolType::String),
clingo_symbol_type_e_clingo_symbol_type_function => Ok(SymbolType::Function),
clingo_symbol_type_e_clingo_symbol_type_supremum => Ok(SymbolType::Supremum),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_symbol_type {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_symbol_type.",
})
}
}
}
}
/// Enumeration of warning codes.
#[derive(Debug, Copy, Clone)]
pub enum Warning {
/// Undefined arithmetic operation or weight of aggregate
OperationUndefined = clingo_warning_e_clingo_warning_operation_undefined as isize,
/// To report multiple errors; a corresponding runtime error is raised later
RuntimeError = clingo_warning_e_clingo_warning_runtime_error as isize,
/// An undefined atom in program
AtomUndefined = clingo_warning_e_clingo_warning_atom_undefined as isize,
/// The Same file included multiple times
FileIncluded = clingo_warning_e_clingo_warning_file_included as isize,
/// CSP variable with unbounded domain
VariableUnbound = clingo_warning_e_clingo_warning_variable_unbounded as isize,
/// A global variable in tuple of aggregate element
GlobalVariable = clingo_warning_e_clingo_warning_global_variable as isize,
/// Other kinds of warnings
Other = clingo_warning_e_clingo_warning_other as isize,
}
impl Warning {
fn try_from(code: u32) -> Result<Warning, ClingoError> {
match code {
clingo_warning_e_clingo_warning_atom_undefined => Ok(Warning::AtomUndefined),
clingo_warning_e_clingo_warning_file_included => Ok(Warning::FileIncluded),
clingo_warning_e_clingo_warning_global_variable => Ok(Warning::GlobalVariable),
clingo_warning_e_clingo_warning_operation_undefined => Ok(Warning::OperationUndefined),
clingo_warning_e_clingo_warning_other => Ok(Warning::Other),
clingo_warning_e_clingo_warning_runtime_error => Ok(Warning::RuntimeError),
clingo_warning_e_clingo_warning_variable_unbounded => Ok(Warning::VariableUnbound),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_warning {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_warning.",
})
}
}
}
}
/// Enumeration of different external statements.
#[derive(Debug, Copy, Clone)]
pub enum ExternalType {
/// Allow an external to be assigned freely
Free = clingo_external_type_e_clingo_external_type_free as isize,
/// Assign an external to true
True = clingo_external_type_e_clingo_external_type_true as isize,
/// Assign an external to false
False = clingo_external_type_e_clingo_external_type_false as isize,
/// No longer treat an atom as external
Release = clingo_external_type_e_clingo_external_type_release as isize,
}
impl ExternalType {
fn try_from(code: u32) -> Result<ExternalType, ClingoError> {
match code {
clingo_external_type_e_clingo_external_type_false => Ok(ExternalType::False),
clingo_external_type_e_clingo_external_type_free => Ok(ExternalType::Free),
clingo_external_type_e_clingo_external_type_release => Ok(ExternalType::Release),
clingo_external_type_e_clingo_external_type_true => Ok(ExternalType::True),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_external_type {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_external_type.",
})
}
}
}
}
/// Enumeration of different heuristic modifiers.
#[derive(Debug, Copy, Clone)]
pub enum HeuristicType {
/// Set the level of an atom
Level = clingo_heuristic_type_e_clingo_heuristic_type_level as isize,
/// Configure which sign to chose for an atom
Sign = clingo_heuristic_type_e_clingo_heuristic_type_sign as isize,
/// Modify VSIDS factor of an atom
Factor = clingo_heuristic_type_e_clingo_heuristic_type_factor as isize,
/// Modify the initial VSIDS score of an atom
Init = clingo_heuristic_type_e_clingo_heuristic_type_init as isize,
/// Set the level of an atom and choose a positive sign
True = clingo_heuristic_type_e_clingo_heuristic_type_true as isize,
/// Set the level of an atom and choose a negative sign
False = clingo_heuristic_type_e_clingo_heuristic_type_false as isize,
}
impl HeuristicType {
fn try_from(code: u32) -> Result<HeuristicType, ClingoError> {
match code {
clingo_heuristic_type_e_clingo_heuristic_type_factor => Ok(HeuristicType::Factor),
clingo_heuristic_type_e_clingo_heuristic_type_false => Ok(HeuristicType::False),
clingo_heuristic_type_e_clingo_heuristic_type_init => Ok(HeuristicType::Init),
clingo_heuristic_type_e_clingo_heuristic_type_level => Ok(HeuristicType::Level),
clingo_heuristic_type_e_clingo_heuristic_type_sign => Ok(HeuristicType::Sign),
clingo_heuristic_type_e_clingo_heuristic_type_true => Ok(HeuristicType::True),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_heuristic_type {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_heuristic_type.",
})
}
}
}
}
/// Enumeration of theory term types.
#[derive(Debug, Copy, Clone)]
pub enum TheoryTermType {
/// A tuple term, e.g., `(1,2,3)`
Tuple = clingo_theory_term_type_e_clingo_theory_term_type_tuple as isize,
/// A list term, e.g., `[1,2,3]`
List = clingo_theory_term_type_e_clingo_theory_term_type_list as isize,
/// A set term, e.g., `{1,2,3}`
Set = clingo_theory_term_type_e_clingo_theory_term_type_set as isize,
/// A function term, e.g., `f(1,2,3)`
Function = clingo_theory_term_type_e_clingo_theory_term_type_function as isize,
/// A number term, e.g., `42`
Number = clingo_theory_term_type_e_clingo_theory_term_type_number as isize,
/// A symbol term, e.g., `c`
Symbol = clingo_theory_term_type_e_clingo_theory_term_type_symbol as isize,
}
impl TheoryTermType {
fn try_from(code: u32) -> Result<TheoryTermType, ClingoError> {
match code {
clingo_theory_term_type_e_clingo_theory_term_type_tuple => Ok(TheoryTermType::Tuple),
clingo_theory_term_type_e_clingo_theory_term_type_list => Ok(TheoryTermType::List),
clingo_theory_term_type_e_clingo_theory_term_type_set => Ok(TheoryTermType::Set),
clingo_theory_term_type_e_clingo_theory_term_type_function => {
Ok(TheoryTermType::Function)
}
clingo_theory_term_type_e_clingo_theory_term_type_number => Ok(TheoryTermType::Number),
clingo_theory_term_type_e_clingo_theory_term_type_symbol => Ok(TheoryTermType::Symbol),
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_theory_term_type {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_theory_term_type.",
})
}
}
}
}
/// Enumeration for the different model types.
#[derive(Debug, Copy, Clone)]
pub enum ModelType {
/// The model represents a stable model.
StableModel = clingo_model_type_e_clingo_model_type_stable_model as isize,
/// The model represents a set of brave consequences.
BraveConsequences = clingo_model_type_e_clingo_model_type_brave_consequences as isize,
/// The model represents a set of cautious consequences.
CautiousConsequences = clingo_model_type_e_clingo_model_type_cautious_consequences as isize,
}
impl ModelType {
fn try_from(code: u32) -> Result<ModelType, ClingoError> {
match code {
clingo_model_type_e_clingo_model_type_stable_model => Ok(ModelType::StableModel),
clingo_model_type_e_clingo_model_type_brave_consequences => {
Ok(ModelType::BraveConsequences)
}
clingo_model_type_e_clingo_model_type_cautious_consequences => {
Ok(ModelType::CautiousConsequences)
}
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_model_type {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_model_type.",
})
}
}
}
}
/// Supported check modes for propagators.
/// Note that total checks are subject to the lock when a model is found.
/// This means that information from previously found models can be used to discard assignments in check calls.
#[derive(Debug, Copy, Clone)]
pub enum PropagatorCheckMode {
/// Do not call [`Propagator::check()`](trait.Propagator.html#method.check) at all
None = clingo_propagator_check_mode_e_clingo_propagator_check_mode_none as isize,
/// Call [`Propagator::check()`](trait.Propagator.html#method.check) on total assignments
Total = clingo_propagator_check_mode_e_clingo_propagator_check_mode_total as isize,
/// Call [`Propagator::check()`](trait.Propagator.html#method.check) on propagation fixpoints
Fixpoint = clingo_propagator_check_mode_e_clingo_propagator_check_mode_fixpoint as isize,
/// Call [`Propagator::check()`](trait.Propagator.html#method.check) on propagation fixpoints and total assignments
Both = clingo_propagator_check_mode_e_clingo_propagator_check_mode_both as isize,
}
impl PropagatorCheckMode {
fn try_from(code: u32) -> Result<PropagatorCheckMode, ClingoError> {
match code {
clingo_propagator_check_mode_e_clingo_propagator_check_mode_fixpoint => {
Ok(PropagatorCheckMode::Fixpoint)
}
clingo_propagator_check_mode_e_clingo_propagator_check_mode_total => {
Ok(PropagatorCheckMode::Total)
}
clingo_propagator_check_mode_e_clingo_propagator_check_mode_none => {
Ok(PropagatorCheckMode::None)
}
x => {
eprintln!(
"FFIError in {} {}, {} : Failed to match clingo_propagator_check_mode {}",
file!(),
line!(),
column!(),
x
);
Err(ClingoError::FFIError {
msg: "Failed to match clingo_propagator_check_mode.",
})
}
}
}
}
/// Enumeration of weight_constraint_types.
#[derive(Debug, Copy, Clone)]
pub enum WeigthConstraintType {
/// The weight constraint implies the literal
ImplicationLeft =
clingo_weight_constraint_type_e_clingo_weight_constraint_type_implication_left as isize,
/// The literal implies the weight constraint
ImplicationRight =
clingo_weight_constraint_type_e_clingo_weight_constraint_type_implication_right as isize,
/// The weight constraint is equivalent to the literal
Equivalence =
clingo_weight_constraint_type_e_clingo_weight_constraint_type_equivalence as isize,
}
bitflags! {
/// Bit flags describing the entries of a configuration.
pub struct ConfigurationType: u32 {
/// The entry is a (string) value.
const VALUE =
clingo_configuration_type_e_clingo_configuration_type_value;
/// The entry is an array.
const ARRAY =
clingo_configuration_type_e_clingo_configuration_type_array;
/// The entry is a map.
const MAP =
clingo_configuration_type_e_clingo_configuration_type_map;
}
}
bitflags! {
/// Bit flags describing solve modes.
pub struct SolveMode: u32 {
/// Enable non-blocking search.
const ASYNC = clingo_solve_mode_e_clingo_solve_mode_async;
/// Yield models in calls to clingo_solve_handle_model.
const YIELD = clingo_solve_mode_e_clingo_solve_mode_yield;
}
}
bitflags! {
/// Bit flags to select symbols in models.
pub struct ShowType: u32 {
/// Select symbols added by theory.
const THEORY = clingo_show_type_e_clingo_show_type_theory;
/// Select CSP assignments.
const CSP = clingo_show_type_e_clingo_show_type_csp;
/// Select shown atoms and terms.
const SHOWN = clingo_show_type_e_clingo_show_type_shown;
/// Select all atoms.
const ATOMS = clingo_show_type_e_clingo_show_type_atoms;
/// Select all terms.
const TERMS = clingo_show_type_e_clingo_show_type_terms;
/// Select everything.
const ALL = clingo_show_type_e_clingo_show_type_all;
/// Select false instead of true atoms (Atoms) or terms (Terms)."
const COMPLEMENT = clingo_show_type_e_clingo_show_type_complement;
}
}
bitflags! {
/// Bit flags that describes the result of a solve call.
pub struct SolveResult: u32 {
/// The problem is satisfiable.
const SATISFIABLE = clingo_solve_result_e_clingo_solve_result_satisfiable;
/// The problem is unsatisfiable.
const UNSATISFIABLE =
clingo_solve_result_e_clingo_solve_result_unsatisfiable;
/// The search space was exhausted.
const EXHAUSTED = clingo_solve_result_e_clingo_solve_result_exhausted;
/// The search was interupted.
const INTERRUPTED = clingo_solve_result_e_clingo_solve_result_interrupted;
}
}
type SolveEventCallback = unsafe extern "C" fn(
type_: clingo_solve_event_type_t,
event: *mut c_void,
event_handler: *mut c_void,
goon: *mut bool,
) -> bool;
pub trait SolveEventHandler {
/// Callback function called during search to notify when the search is finished or a model is ready
///
/// **Attention:** If the search is finished, the model is NULL.
///
/// # Arguments
///
/// * `event` - the solve event
/// * `goon` - can be set to false to stop solving
///
/// **Returns** whether the call was successful
///
/// **See:** [`Control::solve()`](struct.Control.html#method.solve)
fn on_solve_event(&mut self, _event: SolveEvent, _goon: &mut bool) -> bool {
true
}
}
unsafe extern "C" fn unsafe_solve_callback<T: SolveEventHandler>(
event_type: clingo_solve_event_type_t,
event_data: *mut c_void,
event_handler: *mut c_void,
goon: *mut bool,
) -> bool {
// check for null pointers
if event_handler.is_null() | goon.is_null() {
set_internal_error(
ErrorType::Runtime,
"unsafe_solve_callback() got a null pointer.",
);
return false;
}
let event_handler = &mut *(event_handler as *mut T);
let goon = &mut *goon;
match SolveEventType::try_from(event_type) {
Ok(SolveEventType::Model) => {
let model = &mut *(event_data as *mut Model);
let event = SolveEvent::Model(model);
event_handler.on_solve_event(event, goon)
}
Ok(SolveEventType::Unsat) => {
let event = SolveEvent::Unsat;
event_handler.on_solve_event(event, goon)
}
Ok(SolveEventType::Statistics) => {
// check for null pointers
if event_data.is_null() {
set_internal_error(
ErrorType::Runtime,
"unsafe_solve_callback() got a null pointer event_data.",
);
return false;
}
let stats: &mut [&mut Statistics] =
std::slice::from_raw_parts_mut(event_data as *mut &mut Statistics, 2);
let stats: &mut [&mut Statistics; 2] =
stats.try_into().expect("slice has more than two items");
let stats = stats.split_at_mut(1);
let event = SolveEvent::Statistics {
step: stats.0[0],
akku: stats.1[0],
};
event_handler.on_solve_event(event, goon)
}
Ok(SolveEventType::Finish) => {
// check for null pointers
if event_data.is_null() {
set_internal_error(
ErrorType::Runtime,
"unsafe_solve_callback() got a null pointer event_data.",
);
return false;
}
let solve_result = &mut *(event_data as *mut SolveResult);
let event = SolveEvent::Finish(solve_result);
event_handler.on_solve_event(event, goon)
}
Err(e) => {
eprintln!("{}", e);
// from the libclingo docs:
// If a (non-recoverable) clingo API function fails in this callback, it must return false.
// In case of errors not related to clingo, set error code ErrorType::Unknown and return false to stop solving with an error.
set_internal_error(
ErrorType::Runtime,
"Error in unsafe_solve_callback(): unknown event_type.",
);
false
}
}
}
type LoggingCallback =
unsafe extern "C" fn(code: clingo_warning_t, message: *const c_char, logger: *mut c_void);
/// An instance of this trait has to be registered with a solver to implement a custom logging.
pub trait Logger {
/// Callback to intercept warning messages.
///
/// # Arguments
///
/// * `code` - associated warning code
/// * `message` - warning message
///
/// **See:**
///
/// * [`Control::new_with_logger()`](struct.Control.html#method.new_with_logger)
/// * [`parse_term_with_logger()`](fn.parse_term_with_logger.html)
/// * [`parse_program_with_logger()`](fn.parse_program_with_logger.html)
fn log(&mut self, code: Warning, message: &str) {
eprintln!("warn {:?}: {}", code, message);
}
}
unsafe extern "C" fn unsafe_logging_callback<L: Logger>(
code: clingo_warning_t,
message: *const c_char,
logger: *mut c_void,
) {
// check for null pointers
if message.is_null() | logger.is_null() {
set_internal_error(
ErrorType::Runtime,
"unsafe_logging_callback() got a null pointer.",
);
return;
}
let message = CStr::from_ptr(message);
let logger = &mut *(logger as *mut L);
if let Err(e) = try_logging_callback(logger, code, message) {
eprintln!("Error in unsafe_logging_callback(): {}.", e);
set_internal_error(ErrorType::Runtime, "Error in unsafe_logging_callback().");
}
}
fn try_logging_callback<L: Logger>(
logger: &mut L,
code: clingo_warning_t,
message: &CStr,
) -> Result<(), ClingoError> {
let code = Warning::try_from(code as u32)?;
let message = message.to_str()?;
logger.log(code, message);
Ok(())
}
type GroundCallback = unsafe extern "C" fn(
location: *const clingo_location_t,
name: *const c_char,
arguments: *const clingo_symbol_t,
arguments_size: usize,
event_handler: *mut c_void,
symbol_callback: clingo_symbol_callback_t,
symbol_callback_data: *mut c_void,
) -> bool;
pub trait FunctionHandler {
/// Callback function to implement external functions.
///
/// If an external function of form `@name(parameters)` occurs in a logic program,
/// then this function is called with its location, name, parameters, and a callback to inject symbols as arguments.
/// The callback can be called multiple times; all symbols passed are injected.
///
/// # Arguments
///
/// * `location` - location from which the external function was called
/// * `name` - name of the called external function
/// * `arguments` - arguments of the called external function
///
/// **Returns** a vector of symbols
///
/// **See:** [`Control::ground_with_event_handler()`](struct.Control.html#method.ground_with_event_handler)
///
/// The following example implements the external function `@f()` returning 42.
/// ```ignore
/// fn on_external_function(
/// &mut self,
/// _location: &ast::Location,
/// name: &str,
/// arguments: &[Symbol],
/// ) -> Result<Vec<Symbol>,Error> {
/// if name == "f" && arguments.len() == 0 {
/// let symbol = Symbol::create_number(42);
/// Ok(vec![symbol])
/// } else {
/// Err(MyError{ msg: "function not found"})?
/// }
/// }
/// ```
fn on_external_function(
&mut self,
location: &ast::Location,
name: &str,
arguments: &[Symbol],
) -> Result<Vec<Symbol>, ExternalError>;
}
unsafe extern "C" fn unsafe_ground_callback<T: FunctionHandler>(
location: *const clingo_location_t,
name: *const c_char,
arguments: *const clingo_symbol_t,
arguments_size: usize,
event_handler: *mut c_void,
symbol_callback: clingo_symbol_callback_t,
symbol_callback_data: *mut c_void,
) -> bool {
// check for null pointers
if location.is_null()
| name.is_null()
| (arguments_size > 0 && arguments.is_null())
| event_handler.is_null()
{
set_internal_error(
ErrorType::Runtime,
"unsafe_ground_callback() got a null pointer.",
);
return false;
}
let location = &*(location as *const ast::Location);
let name = CStr::from_ptr(name);
let arguments = std::slice::from_raw_parts(arguments as *const Symbol, arguments_size);
let event_handler = &mut *(event_handler as *mut T);
match try_symbol_callback(
event_handler,
location,
name,
arguments,
symbol_callback,
symbol_callback_data,
) {
Ok(x) => x,
Err(e) => {
// from the libclingo docs:
// If a (non-recoverable) clingo API function fails in this callback, it must return false.
// In case of errors not related to clingo, set error code ErrorType::Unknown and return false to stop solving with an error.
eprintln!("Error in unsafe_ground_callback(): {}.", e);
set_internal_error(ErrorType::Runtime, "Error in unsafe_ground_callback().");
false
}
}
}
unsafe fn try_symbol_callback<T: FunctionHandler>(
efh: &mut T,
location: &ast::Location,
name: &CStr,
arguments: &[Symbol],
symbol_callback: clingo_symbol_callback_t,
symbol_callback_data: *mut c_void,
) -> Result<bool, ClingoError> {
let name = name.to_str()?;
let symbols = efh.on_external_function(location, name, arguments)?;
if let Some(symbol_callback) = symbol_callback {
let v: Vec<clingo_symbol_t> = symbols.iter().map(|symbol| (*symbol).0).collect();
Ok(symbol_callback(
v.as_slice().as_ptr(),
v.len(),
symbol_callback_data,
))
} else {
// no symbol callback
Ok(true)
}
}
// /// Signed integer type used for aspif.
// #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
// pub struct Literal(clingo_literal_t);
// impl Literal {
// pub fn negate(self) -> Literal {
// Literal(-(self.0))
// }
// pub fn from(Atom(atom): Atom) -> Literal {
// Literal(atom as clingo_literal_t)
// }
// pub fn get_integer(self) -> i32 {
// self.0
// }
// }
/// Signed integer type used for solver literals.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct SolverLiteral(clingo_literal_t);
impl SolverLiteral {
pub fn negate(self) -> SolverLiteral {
SolverLiteral(-(self.0))
}
// TODO: remove get_integer ?
pub fn get_integer(self) -> i32 {
self.0
}
}
impl From<Atom> for SolverLiteral {
fn from(atom: Atom) -> Self {
SolverLiteral(atom.0 as i32)
}
}
/// Unsigned integer type used for aspif atoms.
#[derive(Debug, Copy, Clone)]
pub struct Atom(clingo_atom_t);
impl From<SolverLiteral> for Atom {
fn from(literal: SolverLiteral) -> Self {
Atom(literal.0 as u32)
}
}
/// Unsigned integer type used in various places.
#[derive(Debug, Copy, Clone)]
pub struct Id(clingo_id_t);
impl Id {
pub fn get_integer(self) -> u32 {
self.0
}
}
impl fmt::Display for Id {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
/// A Literal with an associated weight.
#[derive(Debug, Copy, Clone)]
pub struct WeightedLiteral(clingo_weighted_literal);
impl WeightedLiteral {
pub fn literal(self) -> SolverLiteral {
SolverLiteral(self.0.literal)
}
pub fn weight(self) -> i32 {
self.0.weight
}
}
/// Represents a predicate signature.
///
/// Signatures have a name and an arity, and can be positive or negative (to
/// represent classical negation).
#[derive(Debug, Copy, Clone)]
pub struct Signature(clingo_signature_t);
impl PartialEq for Signature {
/// Check if two signatures are equal.
fn eq(&self, other: &Signature) -> bool {
unsafe { clingo_signature_is_equal_to(self.0, other.0) }
}
}
impl Eq for Signature {}
impl PartialOrd for Signature {
/// Compare two signatures.
///
/// Signatures are compared first by sign (unsigned < signed), then by arity,
/// then by name.
fn partial_cmp(&self, other: &Signature) -> Option<Ordering> {
if unsafe { clingo_signature_is_less_than(self.0, other.0) } {
return Some(Ordering::Less);
}
if unsafe { clingo_signature_is_less_than(other.0, self.0) } {
return Some(Ordering::Greater);
}
Some(Ordering::Equal)
}
}
impl Hash for Signature {
/// Calculate a hash code of a signature.
fn hash<H: Hasher>(&self, state: &mut H) {
unsafe { clingo_signature_hash(self.0) }.hash(state);
}
}
impl Signature {
/// Create a new signature.
///
/// # Arguments
///
/// * `name` - name of the signature
/// * `arity` - arity of the signature
/// * `positive` - false if the signature has a classical negation sign
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `name` contains a nul byte
pub fn new(name: &str, arity: u32, positive: bool) -> Result<Signature, ClingoError> {
let name = CString::new(name)?;
let mut signature = 0;
if !unsafe { clingo_signature_create(name.as_ptr(), arity, positive, &mut signature) } {
return Err(ClingoError::new_internal(
"Call to clingo_signature_create() failed",
));
}
Ok(Signature(signature))
}
// TODO: should i return empty string vs Error
/// Get the name of a signature.
/// **Note:**
/// The string is internalized and valid for the duration of the process.
pub fn name(&self) -> Result<&'static str, Utf8Error> {
let char_ptr: *const c_char = unsafe { clingo_signature_name(self.0) };
if char_ptr.is_null() {
Ok("")
} else {
let c_str = unsafe { CStr::from_ptr(char_ptr) };
c_str.to_str()
}
}
/// Get the arity of a signature.
pub fn arity(self) -> u32 {
unsafe { clingo_signature_arity(self.0) }
}
/// Whether the signature is positive (is not classically negated).
pub fn is_positive(self) -> bool {
unsafe { clingo_signature_is_positive(self.0) }
}
/// Whether the signature is negative (is classically negated).
pub fn is_negative(self) -> bool {
unsafe { clingo_signature_is_negative(self.0) }
}
}
/// Represents a symbol.
///
/// This includes numbers, strings, functions (including constants when
/// arguments are empty and tuples when the name is empty), \#inf and \#sup.
#[derive(Debug, Copy, Clone)]
pub struct Symbol(clingo_symbol_t);
impl PartialEq for Symbol {
fn eq(&self, other: &Symbol) -> bool {
unsafe { clingo_symbol_is_equal_to(self.0, other.0) }
}
}
impl Eq for Symbol {}
impl PartialOrd for Symbol {
/// Compare two symbols.
///
/// Symbols are first compared by type. If the types are equal, the values are
/// compared (where strings are compared using strcmp). Functions are first
/// compared by signature and then lexicographically by arguments.
fn partial_cmp(&self, other: &Symbol) -> Option<Ordering> {
if unsafe { clingo_symbol_is_less_than(self.0, other.0) } {
return Some(Ordering::Less);
}
if unsafe { clingo_symbol_is_less_than(other.0, self.0) } {
return Some(Ordering::Greater);
}
Some(Ordering::Equal)
}
}
impl Hash for Symbol {
/// Calculate a hash code of a symbol.
fn hash<H: Hasher>(&self, state: &mut H) {
unsafe { clingo_symbol_hash(self.0) }.hash(state);
}
}
impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut size: usize = 0;
if !unsafe { clingo_symbol_to_string_size(self.0, &mut size) } {
eprintln!("Call to clingo_symbol_to_string_size() failed");
return Err(fmt::Error);
}
let mut string = Vec::with_capacity(size);
let string_ptr = string.as_mut_ptr();
if !unsafe { clingo_symbol_to_string(self.0, string_ptr, size) } {
eprintln!("Call to clingo_symbol_to_string() failed");
return Err(fmt::Error);
}
let c_str: &CStr = unsafe { CStr::from_ptr(string_ptr) };
let str_slice: &str = match c_str.to_str() {
Ok(slice) => slice,
Err(e) => {
eprintln!("{}", e);
return Err(fmt::Error);
}
};
std::fmt::Display::fmt(str_slice, f)
}
}
impl Symbol {
/// Construct a symbol representing a number.
pub fn create_number(number: i32) -> Symbol {
let mut symbol = 0;
unsafe { clingo_symbol_create_number(number, &mut symbol) };
Symbol(symbol)
}
/// Construct a symbol representing \#sup.
pub fn create_supremum() -> Symbol {
let mut symbol = 0;
unsafe { clingo_symbol_create_supremum(&mut symbol) };
Symbol(symbol)
}
/// Construct a symbol representing \#inf
pub fn create_infimum() -> Symbol {
let mut symbol = 0;
unsafe { clingo_symbol_create_infimum(&mut symbol) };
Symbol(symbol)
}
/// Construct a symbol representing a string.
///
/// # Arguments
///
/// * `string` - the string
///
/// # Errors:
///
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `string` contains a nul byte
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn create_string(string: &str) -> Result<Symbol, ClingoError> {
let mut symbol = 0;
let c_str = CString::new(string)?;
if !unsafe { clingo_symbol_create_string(c_str.as_ptr(), &mut symbol) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbol_create_string() failed",
));
}
Ok(Symbol(symbol))
}
/// Construct a symbol representing an id.
///
/// **Note:** This is just a shortcut for [`create_function()`](struct.Symbol.html#method.create_function) with
/// empty arguments.
///
/// # Arguments
///
/// * `name` - the name of the symbol
/// * `positive` - whether the symbol has a classical negation sign
///
/// # Errors
///
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `name` contains a nul byte
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn create_id(name: &str, positive: bool) -> Result<Symbol, ClingoError> {
let mut symbol = 0;
let name = CString::new(name)?;
if !unsafe { clingo_symbol_create_id(name.as_ptr(), positive, &mut symbol) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbol_create_id() failed",
));
}
Ok(Symbol(symbol))
}
/// Construct a symbol representing a function or tuple.
///
///
/// **Note:** To create tuples, the empty string has to be used as name.
///
/// # Arguments
///
/// * `name` - the name of the function
/// * `arguments` - the arguments of the function
/// * `positive` - whether the symbol has a classical negation sign
///
/// # Errors
///
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `name` contains a nul byte
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn create_function(
name: &str,
arguments: &[Symbol],
positive: bool,
) -> Result<Symbol, ClingoError> {
let mut symbol = 0;
let name = CString::new(name)?;
if !unsafe {
clingo_symbol_create_function(
name.as_ptr(),
arguments.as_ptr() as *const clingo_symbol_t,
arguments.len(),
positive,
&mut symbol,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_symbol_create_function() failed",
));
}
Ok(Symbol(symbol))
}
/// Get the number of a symbol.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if symbol is not of type [`SymbolType::Number`](enum.SymbolType.html#variant.Number)
pub fn number(self) -> Result<i32, ClingoError> {
let mut number = 0;
if !unsafe { clingo_symbol_number(self.0, &mut number) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbol_number() failed",
));
}
Ok(number)
}
/// Get the name of a symbol.
///
/// **Note:**
/// The string is internalized and valid for the duration of the process.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if symbol is not of type [`SymbolType::Function`](enum.SymbolType.html#variant.Function)
/// - [`ClingoError::Utf8Error`](enum.ClingoError.html#variant.Utf8Error)
pub fn name(&self) -> Result<&'static str, ClingoError> {
let mut char_ptr = std::ptr::null();
if !unsafe { clingo_symbol_name(self.0, &mut char_ptr) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbol_name() failed",
));
}
if char_ptr.is_null() {
return Err(ClingoError::new_internal(
"clingo_symbol_name() returned a null pointer.",
));
}
let c_str = unsafe { CStr::from_ptr(char_ptr) };
Ok(c_str.to_str()?)
}
/// Get the string of a symbol.
///
/// **Note:**
/// The string is internalized and valid for the duration of the process.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if symbol is not of type [`SymbolType::String`](enum.SymbolType.html#variant.String)
/// - [`ClingoError::Utf8Error`](enum.ClingoError.html#variant.Utf8Error)
pub fn string(&self) -> Result<&'static str, ClingoError> {
let mut char_ptr = std::ptr::null();
if !unsafe { clingo_symbol_string(self.0, &mut char_ptr) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbol_string() failed",
));
}
if char_ptr.is_null() {
return Err(ClingoError::FFIError {
msg: "clingo_symbol_string() returned a null pointer.",
});
}
let c_str = unsafe { CStr::from_ptr(char_ptr) };
Ok(c_str.to_str()?)
}
/// Check if a function is positive (does not have a sign).
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if symbol is not of type [`SymbolType::Function`](enum.SymbolType.html#variant.Function)
pub fn is_positive(self) -> Result<bool, ClingoError> {
let mut positive = false;
if !unsafe { clingo_symbol_is_positive(self.0, &mut positive) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbol_is_positive() failed",
));
}
Ok(positive)
}
/// Check if a function is negative (has a sign).
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if symbol is not of type [`SymbolType::Function`](enum.SymbolType.html#variant.Function)
pub fn is_negative(self) -> Result<bool, ClingoError> {
let mut negative = false;
if !unsafe { clingo_symbol_is_negative(self.0, &mut negative) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbol_is_negative() failed",
));
}
Ok(negative)
}
/// Get the arguments of a symbol.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if symbol is not of type [`SymbolType::Function`](enum.SymbolType.html#variant.Function)
pub fn arguments(self) -> Result<Vec<Symbol>, ClingoError> {
let mut symbol_ptr = std::ptr::null();
let mut size: usize = 0;
if !unsafe { clingo_symbol_arguments(self.0, &mut symbol_ptr, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbol_arguments() failed",
));
}
let mut symbols = Vec::<Symbol>::with_capacity(size);
// let symbols_ptr = symbols.as_mut_ptr();
// let symbols = unsafe {std::slice::from_raw_parts(symbols_ptr, size)};
for _ in 0..size {
if symbol_ptr.is_null() {
return Err(ClingoError::FFIError {
msg: "clingo_symbol_arguments() returned a null pointer.",
});
}
let nsymbol = unsafe { *symbol_ptr };
symbols.push(Symbol(nsymbol));
symbol_ptr = unsafe { symbol_ptr.offset(1) };
}
Ok(symbols)
}
/// Get the type of a symbol.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) - may failed to match clingo symbol type
pub fn symbol_type(self) -> Result<SymbolType, ClingoError> {
SymbolType::try_from(unsafe { clingo_symbol_type(self.0) } as u32)
}
}
/// Obtain the clingo version.
///
/// `(major version, minor version, revision number)`
pub fn version() -> (i32, i32, i32) {
let mut major = 0;
let mut minor = 0;
let mut revision = 0;
unsafe { clingo_version(&mut major, &mut minor, &mut revision) };
(major, minor, revision)
}
/// Struct used to specify the program parts that have to be grounded.
///
/// Programs may be structured into parts, which can be grounded independently with [`Control::ground()`](struct.Control.html#method.ground).
/// Program parts are mainly interesting for incremental grounding and multi-shot solving.
/// For single-shot solving, program parts are not needed.
///
/// **Note:** Parts of a logic program without an explicit `#program`
/// specification are by default put into a program called `base` - without
/// arguments.
///
/// **See:** [`Control::ground()`](struct.Control.html#method.ground)
#[derive(Debug, Clone)]
pub struct Part {
part: clingo_part,
_params: Vec<Symbol>,
}
impl Part {
/// Create a new program part object.
///
/// # Arguments
///
/// * `name` - the identifier of the program
/// * `params` - the parameter of the program
///
/// # Errors
///
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `name` contains a nul byte
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if argument parsing fails
pub fn new(name: &str, params: Vec<Symbol>) -> Result<Part, ClingoError> {
let name = internalize_string(name)?;
Ok(Part {
part: clingo_part {
name: name as *const c_char,
params: params.as_ptr() as *const clingo_symbol_t,
size: params.len(),
},
_params: params,
})
}
}
/// An instance of this trait has to be registered with a solver to implement a custom propagator.
///
/// Not all functions have to be implemented, there exist default implementations.
pub trait Propagator {
/// This function is called once before each solving step.
/// It is used to map relevant program literals to solver literals, add watches for solver
/// literals, and initialize the data structures used during propagation.
///
/// **Note:** This is the last point to access symbolic and theory atoms.
/// Once the search has started, they are no longer accessible.
///
/// # Arguments
///
/// * `init` - initizialization object
///
/// **Returns** whether the call was successful
fn init(&mut self, _init: &mut PropagateInit) -> bool {
true
}
/// Can be used to propagate solver literals given a
/// [partial assignment](struct.Assignment.html).
///
/// Called during propagation with a non-empty array of
/// [watched solver literals](struct.PropagateInit.html#method.add_watch)
/// that have been assigned to true since the last call to either propagate, undo, (or the start
/// of the search) - the change set.
/// Only watched solver literals are contained in the change set.
/// Each literal in the change set is true w.r.t. the current
/// [assignment](struct.Assignment.html).
/// [`PropagateControl::add_clause()`](struct.PropagateControl.html#method.add_clause) can be
/// used to add clauses.
/// If a clause is unit resulting, it can be propagated using
/// [`PropagateControl::propagate()`](struct.PropagateControl.html#method.propagate).
/// If the result of either of the two methods is false, the propagate function must return
/// immediately.
///
/// The following snippet shows how to use the methods to add clauses and propagate consequences
/// within the callback.
/// The important point is to return true (true to indicate there was no error) if the result of
/// either of the methods is false.
/// ```ignore
/// let clause= &[ ... ];
/// // add a clause
/// if let Ok(x) = control.add_clause(clause, ClauseType::Learnt) {
/// if !x {
/// true
/// }
/// } else {
/// false
/// }
/// // propagate its consequences
/// if let Ok(x) = control.propagate() {
/// if !x {
/// true
/// }
/// } else {
/// false
/// }
/// // add further clauses and propagate them
/// ...
/// true
/// ```
///
/// **Note:**
/// This function can be called from different solving threads.
/// Each thread has its own assignment and id, which can be obtained using
/// [`PropagateControl::thread_id()`](struct.PropagateControl.html#method.thread_id).
///
/// # Arguments
///
/// * `control` - control object for the target solver
/// * `changes` - the change set
///
/// **Returns** whether the call was successful
fn propagate(&mut self, _control: &mut PropagateControl, _changes: &[SolverLiteral]) -> bool {
true
}
/// Called whenever a solver undoes assignments to watched solver literals.
///
/// This callback is meant to update assignment dependent state in the propagator.
///
/// **Note:** No clauses must be propagated in this callback and no errors should be set.
///
/// # Arguments
///
/// * `control` - control object for the target solver
/// * `changes` - the change set
///
/// **Returns** whether the call was successful
fn undo(&mut self, _control: &mut PropagateControl, _changes: &[SolverLiteral]) {}
/// This function is similar to
/// [`PropagateControl::propagate()`](struct.PropagateControl.html#method.propagate) but is only
/// called on total assignments without a change set.
///
/// When exactly this function is called, can be configured using the
/// [`PropagateInit::set_check_mode()`](struct.PropagateInit.html#method.set_check_mode)
/// function.
///
/// **Note:** This function is called even if no watches have been added.
///
/// # Arguments
///
/// * `control` - control object for the target solver
///
/// **Returns** whether the call was successful
fn check(&mut self, _control: &mut PropagateControl) -> bool {
true
}
/// This function allows a propagator to implement domain-specific heuristics.
///
/// It is called whenever propagation reaches a fixed point and
/// should return a free solver literal that is to be assigned true.
/// In case multiple propagators are registered,
/// this function can return 0 to let a propagator registered later make a decision.
/// If all propagators return 0, then the fallback literal is
///
/// # Arguments
///
/// * `thread_id` - the solver's thread id
/// * `assignment` - the assignment of the solver
/// * `fallback` - the literal choosen by the solver's heuristic
/// * `decision` - the literal to make true
///
/// **Returns** whether the call was successful
fn decide(
&mut self,
_thread_id: Id,
_assignment: &Assignment,
_fallback: SolverLiteral,
_decision: &mut SolverLiteral,
) -> bool {
true
}
}
unsafe extern "C" fn unsafe_init<T: Propagator>(
init: *mut clingo_propagate_init_t,
propagator: *mut c_void,
) -> bool {
// check for null pointers
if init.is_null() | propagator.is_null() {
set_internal_error(ErrorType::Runtime, "unsafe_init() got a null pointer.");
return false;
}
let init = &mut *(init as *mut PropagateInit);
let propagator = &mut *(propagator as *mut T);
propagator.init(init)
}
unsafe extern "C" fn unsafe_propagate<T: Propagator>(
control: *mut clingo_propagate_control_t,
changes: *const clingo_literal_t,
size: usize,
propagator: *mut c_void,
) -> bool {
// check for null pointers
if control.is_null() | (size > 0 && changes.is_null()) | propagator.is_null() {
set_internal_error(ErrorType::Runtime, "unsafe_propagate() got a null pointer.");
return false;
}
let control = &mut *(control as *mut PropagateControl);
let changes = std::slice::from_raw_parts(changes as *const SolverLiteral, size);
let propagator = &mut *(propagator as *mut T);
propagator.propagate(control, changes)
}
unsafe extern "C" fn unsafe_undo<T: Propagator>(
control: *const clingo_propagate_control_t,
changes: *const clingo_literal_t,
size: usize,
propagator: *mut c_void,
) {
// check for null pointers
if control.is_null() | (size > 0 && changes.is_null()) | propagator.is_null() {
set_internal_error(ErrorType::Runtime, "unsafe_undo() got a null pointer.");
return;
}
let control = &mut *(control as *mut PropagateControl);
let changes = std::slice::from_raw_parts(changes as *const SolverLiteral, size);
let propagator = &mut *(propagator as *mut T);
propagator.undo(control, changes)
}
unsafe extern "C" fn unsafe_check<T: Propagator>(
control: *mut clingo_propagate_control_t,
propagator: *mut c_void,
) -> bool {
// check for null pointers
if control.is_null() | propagator.is_null() {
set_internal_error(ErrorType::Runtime, "unsafe_check() got a null pointer.");
return false;
}
let control = &mut *(control as *mut PropagateControl);
let propagator = &mut *(propagator as *mut T);
propagator.check(control)
}
unsafe extern "C" fn unsafe_decide<T: Propagator>(
thread_id: clingo_id_t,
assignment: *const clingo_assignment_t,
fallback: clingo_literal_t,
propagator: *mut ::std::os::raw::c_void,
decision: *mut clingo_literal_t,
) -> bool {
// check for null pointers
if assignment.is_null() | propagator.is_null() | decision.is_null() {
set_internal_error(ErrorType::Runtime, "unsafe_decide() got a null pointer.");
return false;
}
let assignment = &*(assignment as *const Assignment);
let fallback = SolverLiteral(fallback);
let propagator = &mut *(propagator as *mut T);
let decision = &mut *(decision as *mut SolverLiteral);
propagator.decide(Id(thread_id), assignment, fallback, decision)
}
pub mod defaults {
use crate::ast::Location;
use crate::{
ExternalError, FunctionHandler, GroundProgramObserver, Logger, Propagator,
SolveEventHandler, Symbol,
};
/// Default implementation for Logger, Propagator, GroundProgramObserver, FunctionHandler and SolveEventHandler
pub struct Non;
impl Logger for Non {}
impl Propagator for Non {}
impl GroundProgramObserver for Non {}
impl FunctionHandler for Non {
fn on_external_function(
&mut self,
_location: &Location,
_name: &str,
_arguments: &[Symbol],
) -> Result<Vec<Symbol>, ExternalError> {
Ok(vec![])
}
}
impl SolveEventHandler for Non {}
}
/// Control object holding grounding and solving state.
#[derive(Debug)]
pub struct GenericControl<L: Logger, P: Propagator, O: GroundProgramObserver, F: FunctionHandler> {
ctl: NonNull<clingo_control_t>,
copied: bool,
logger: Option<Box<L>>,
propagator: Option<Box<P>>,
observer: Option<Box<O>>,
function_handler: Option<Box<F>>,
}
impl<L: Logger, P: Propagator, O: GroundProgramObserver, F: FunctionHandler> Drop
for GenericControl<L, P, O, F>
{
fn drop(&mut self) {
if !self.copied {
unsafe { clingo_control_free(self.ctl.as_ptr()) }
}
}
}
pub type ControlWithLogger<L> = GenericControl<L, defaults::Non, defaults::Non, defaults::Non>;
pub type ControlWithPropagator<P> = GenericControl<defaults::Non, P, defaults::Non, defaults::Non>;
pub type Control = GenericControl<defaults::Non, defaults::Non, defaults::Non, defaults::Non>;
impl<L: Logger, P: Propagator, O: GroundProgramObserver, F: FunctionHandler>
GenericControl<L, P, O, F>
{
/// Ground the selected [parts](struct.Part.html) of the current (non-ground) logic
/// program.
///
/// After grounding, logic programs can be solved with [`solve()`](struct.Control.html#method.solve).
///
/// **Note:** Parts of a logic program without an explicit `#program`
/// specification are by default put into a program called `base` - without
/// arguments.
///
/// # Arguments
///
/// * `parts` - array of [parts](struct.Part.html) to ground
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn ground(&mut self, parts: &[Part]) -> Result<(), ClingoError> {
let parts_size = parts.len();
let parts = parts
.iter()
.map(|arg| arg.part)
.collect::<Vec<clingo_part>>();
match &mut self.function_handler {
Some(function_handler) => {
if !unsafe {
clingo_control_ground(
self.ctl.as_ptr(),
parts.as_ptr(),
parts_size,
Some(unsafe_ground_callback::<F> as GroundCallback),
function_handler.as_mut() as *mut F as *mut c_void,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_control_ground() failed",
));
}
Ok(())
}
None => unreachable!(),
}
}
/// Register a handler for external functions
///
/// # Arguments
///
/// * `function_handler` - implementing the trait [`FunctionHandler`](trait.FunctionHandler.html)
pub fn register_function_handler<T: FunctionHandler>(
mut self,
function_handler: T,
) -> GenericControl<L, P, O, T> {
let function_handler = Some(Box::new(function_handler));
let logger = self.logger.take();
let propagator = self.propagator.take();
let observer = self.observer.take();
self.copied = true;
GenericControl {
ctl: self.ctl,
copied: false,
logger,
propagator,
observer,
function_handler,
}
}
/// Solve the currently [grounded](struct.Control.html#method.ground) logic program
/// enumerating its models.
///
/// # Arguments
///
/// * `mode` - configures the search mode
/// * `assumptions` - array of assumptions to solve under
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if solving could not be started
pub fn solve(
self,
mode: SolveMode,
assumptions: &[SolverLiteral],
) -> Result<GenericSolveHandle<L, P, O, F, defaults::Non>, ClingoError> {
let mut handle = std::ptr::null_mut();
let event_handler = std::ptr::null_mut();
if !unsafe {
clingo_control_solve(
self.ctl.as_ptr(),
mode.bits(),
assumptions.as_ptr() as *const clingo_literal_t,
assumptions.len(),
None,
event_handler,
&mut handle,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_control_solve() failed",
));
}
match NonNull::new(handle) {
Some(handle) => Ok(GenericSolveHandle {
handle,
ctl: self,
_event_handler: Box::new(defaults::Non),
}),
None => Err(ClingoError::FFIError {
msg: "Tried creating NonNull from a null pointer.",
})?,
}
}
/// Solve the currently [grounded](struct.Control.html#method.ground) logic program
/// enumerating its models.
///
/// # Arguments
///
/// * `mode` - configures the search mode
/// * `assumptions` - array of assumptions to solve under
/// * `handler` - implementing the trait [`SolveEventHandler`](trait.SolveEventHandler.html)
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if solving could not be started
pub fn solve_with_event_handler<T: SolveEventHandler>(
self,
mode: SolveMode,
assumptions: &[SolverLiteral],
event_handler: T,
) -> Result<GenericSolveHandle<L, P, O, F, T>, ClingoError> {
let mut handle = std::ptr::null_mut();
let mut event_handler = Box::new(event_handler);
if !unsafe {
clingo_control_solve(
self.ctl.as_ptr(),
mode.bits(),
assumptions.as_ptr() as *const clingo_literal_t,
assumptions.len(),
Some(unsafe_solve_callback::<T> as SolveEventCallback),
event_handler.as_mut() as *mut T as *mut c_void,
&mut handle,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_control_solve() failed",
));
}
match NonNull::new(handle) {
Some(handle) => Ok(GenericSolveHandle {
handle,
ctl: self,
_event_handler: event_handler,
}),
None => Err(ClingoError::FFIError {
msg: "Tried creating NonNull from a null pointer.",
})?,
}
}
// NODO: pub fn clingo_control_load(control: *mut Control, file: *const c_char) -> bool;
/// Extend the logic program with the given non-ground logic program in string form.
///
/// This function puts the given program into a block of form: `#program name(parameters).`
///
/// After extending the logic program, the corresponding program parts are typically grounded
/// with `ground()`.
///
/// # Arguments
///
/// * `name` - name of the program block
/// * `parameters` - string array of parameters of the program block
/// * `program` - string representation of the program
///
/// # Errors
///
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if a any argument contains a nul byte
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if parsing fails
pub fn add(
&mut self,
name: &str,
parameters: &[&str],
program: &str,
) -> Result<(), ClingoError> {
let name = CString::new(name)?;
let program = CString::new(program)?;
let program_ptr = program.as_ptr();
let parameters_size = parameters.len();
// create a vector of zero terminated strings
let mut l_parameters = vec![];
for arg in parameters {
l_parameters.push(CString::new(*arg)?);
}
// convert the strings to raw pointers
let c_parameters = l_parameters
.iter()
.map(|arg| arg.as_ptr())
.collect::<Vec<*const c_char>>();
if !unsafe {
clingo_control_add(
self.ctl.as_ptr(),
name.as_ptr(),
c_parameters.as_ptr(),
parameters_size,
program_ptr,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_control_add() failed",
));
}
Ok(())
}
/// **See:** [`Control::get_enable_cleanup()`](struct.Control.html#method.get_enable_cleanup) and [`Control::set_enable_cleanup()`](struct.Control.html#method.set_enable_cleanup)
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn cleanup(&mut self) -> Result<(), ClingoError> {
if !unsafe { clingo_control_cleanup(self.ctl.as_ptr()) } {
return Err(ClingoError::new_internal(
"Call to clingo_control_cleanup() failed",
));
}
Ok(())
}
/// Assign a truth value to an external atom.
///
/// If a negative literal is passed, the corresponding atom is assigned the
/// inverted truth value.
///
/// If the atom does not exist or is not external, this is a noop.
///
/// # Arguments
///
/// * `literal` - literal to assign
/// * `value` - the truth value
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn assign_external(
&mut self,
literal: SolverLiteral,
value: TruthValue,
) -> Result<(), ClingoError> {
if !unsafe {
clingo_control_assign_external(
self.ctl.as_ptr(),
literal.0,
value as clingo_truth_value_t,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_control_assign_external() failed",
));
}
Ok(())
}
/// Release an external atom.
///
/// If a negative literal is passed, the corresponding atom is released.
///
/// After this call, an external atom is no longer external and subject to
/// program simplifications. If the atom does not exist or is not external,
/// this is a noop.
///
/// # Arguments
///
/// * `literal` - literal to release
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn release_external(
&mut self,
SolverLiteral(literal): SolverLiteral,
) -> Result<(), ClingoError> {
if !unsafe { clingo_control_release_external(self.ctl.as_ptr(), literal) } {
return Err(ClingoError::new_internal(
"Call to clingo_control_release_external() failed",
));
}
Ok(())
}
/// Register a custom propagator with the control object.
///
/// If the sequential flag is set to true, the propagator is called
/// sequentially when solving with multiple threads.
///
/// # Arguments
///
/// * `propagator` - implementing the trait [`Propagator`](trait.Propagator.html)
/// * `sequential` - whether the propagator should be called sequentially
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn register_propagator<T: Propagator>(
mut self,
propagator: T,
sequential: bool,
) -> Result<GenericControl<L, T, O, F>, ClingoError> {
let mut propagator = Box::new(propagator);
let logger = self.logger.take();
let observer = self.observer.take();
let function_handler = self.function_handler.take();
let clingo_propagator = clingo_propagator_t {
init: Some(unsafe_init::<T>),
propagate: Some(unsafe_propagate::<T>),
undo: Some(unsafe_undo::<T>),
check: Some(unsafe_check::<T>),
decide: Some(unsafe_decide::<T>),
};
if !unsafe {
clingo_control_register_propagator(
self.ctl.as_ptr(),
&clingo_propagator,
propagator.as_mut() as *mut T as *mut c_void,
sequential,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_control_register_propagator() failed",
));
}
self.copied = true;
Ok(GenericControl {
ctl: self.ctl,
copied: false,
logger,
propagator: Some(propagator),
observer,
function_handler,
})
}
/// Check if the solver has determined that the internal program representation is conflicting.
///
/// If this function returns true, solve calls will return immediately with an unsatisfiable solve result.
/// Note that conflicts first have to be detected, e.g. -
/// initial unit propagation results in an empty clause,
/// or later if an empty clause is resolved during solving.
/// Hence, the function might return false even if the problem is unsatisfiable.
pub fn is_conflicting(&self) -> bool {
unsafe { clingo_control_is_conflicting(self.ctl.as_ptr()) }
}
/// Get a statistics object to inspect solver statistics.
///
/// Statistics are updated after a solve call.
///
/// **Attention:**
/// The level of detail of the statistics depends on the stats option
/// (which can be set using [`Configuration`](struct.Configuration.html) or passed as an
/// option when [creating the control object](struct.Control.html#method.new)).
/// The default level zero only provides basic statistics,
/// level one provides extended and accumulated statistics,
/// and level two provides per-thread statistics.
/// Furthermore, the statistics object is best accessed right after solving.
/// Otherwise, not all of its entries have valid values.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn statistics(&self) -> Result<&Statistics, ClingoError> {
let mut stat = std::ptr::null();
if !unsafe { clingo_control_statistics(self.ctl.as_ptr(), &mut stat) } {
return Err(ClingoError::new_internal(
"Call to clingo_control_statistics() failed",
));
}
match unsafe { (stat as *mut Statistics).as_ref() } {
Some(x) => Ok(x),
None => Err(ClingoError::FFIError {
msg: "Tried casting a null pointer to &Statistics.",
}),
}
}
/// Interrupt the active solve call (or the following solve call right at the beginning).
pub fn interrupt(&mut self) {
unsafe {
clingo_control_interrupt(self.ctl.as_ptr());
}
}
/// Get a configuration object to change the solver configuration.
pub fn configuration_mut(&mut self) -> Result<&mut Configuration, ClingoError> {
let mut conf = std::ptr::null_mut();
if !unsafe { clingo_control_configuration(self.ctl.as_ptr(), &mut conf) } {
return Err(ClingoError::new_internal(
"Call to clingo_control_configuration() failed",
));
}
match unsafe { (conf as *mut Configuration).as_mut() } {
Some(x) => Ok(x),
None => Err(ClingoError::FFIError {
msg: "Tried casting a null pointer to &mut Configuration.",
}),
}
}
/// Get a configuration object to change the solver configuration.
pub fn configuration(&self) -> Result<&Configuration, ClingoError> {
let mut conf = std::ptr::null_mut();
if !unsafe { clingo_control_configuration(self.ctl.as_ptr(), &mut conf) } {
return Err(ClingoError::new_internal(
"Call to clingo_control_configuration() failed",
));
}
match unsafe { (conf as *const Configuration).as_ref() } {
Some(x) => Ok(x),
None => Err(ClingoError::FFIError {
msg: "Tried casting a null pointer to &Configuration.",
}),
}
}
/// Configure how learnt constraints are handled during enumeration.
///
/// If the enumeration assumption is enabled, then all information learnt from
/// the solver's various enumeration modes is removed after a solve call. This
/// includes enumeration of cautious or brave consequences, enumeration of
/// answer sets with or without projection, or finding optimal models, as well
/// as clauses added with [`SolveControl::add_clause()`](struct.SolveControl.html#method.add_clause).
///
/// **Attention:** For practical purposes, this option is only interesting for single-shot
/// solving or before the last solve call to squeeze out a tiny bit of performance.
/// Initially, the enumeration assumption is enabled.
///
/// # Arguments
///
/// * `enable` - whether to enable the assumption
pub fn set_enable_enumeration_assumption(&mut self, enable: bool) -> Result<(), ClingoError> {
if !unsafe { clingo_control_set_enable_enumeration_assumption(self.ctl.as_ptr(), enable) } {
return Err(ClingoError::new_internal(
"Call to clingo_control_use_enumeration_assumption() failed",
));
}
Ok(())
}
/// Check whether the enumeration assumption is enabled.
///
/// **See** [`Control::set_enable_assumption()`](struct.Control.html#method.set_enable_assumption)
///
/// **Returns** using the enumeration assumption is enabled
pub fn get_enable_enumeration_assumption(&self) -> bool {
unsafe { clingo_control_get_enable_enumeration_assumption(self.ctl.as_ptr()) }
}
/// Enable automatic cleanup after solving.
///
/// **Note:** Cleanup is enabled by default.
///
/// # Arguments
///
/// * `enable` - whether to enable cleanups
///
/// **Returns** whether the call was successful
///
/// **See** [`Control::cleanup()`](struct.Control.html#method.cleanup) and [`Control::get_enable_cleanup()`](struct.Control.html#method.get_enable_cleanup)
pub fn set_enable_cleanup(&mut self, enable: bool) -> bool {
unsafe { clingo_control_set_enable_cleanup(self.ctl.as_ptr(), enable) }
}
/// Check whether automatic cleanup is enabled.
///
/// **See** [`Control::cleanup()`](struct.Control.html#method.cleanup) and [`Control::set_enable_cleanup()`](struct.Control.html#method.set_enable_cleanup)
pub fn get_enable_cleanup(&self) -> bool {
unsafe { clingo_control_get_enable_cleanup(self.ctl.as_ptr()) }
}
/// Return the symbol for a constant definition of form: `#const name = symbol`.
///
/// # Arguments
///
/// * `name` - the name of the constant if it exists
///
/// # Errors
///
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `name` contains a nul byte
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError)
pub fn get_const(&self, name: &str) -> Result<Symbol, ClingoError> {
let name = CString::new(name)?;
let mut symbol = 0;
if !unsafe { clingo_control_get_const(self.ctl.as_ptr(), name.as_ptr(), &mut symbol) } {
return Err(ClingoError::new_internal(
"Call to clingo_control_get_const() failed",
));
}
Ok(Symbol(symbol))
}
/// Check if there is a constant definition for the given constant.
///
/// # Arguments
///
/// * `name` - the name of the constant
///
/// # Errors
///
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `name` contains a nul byte
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError)
///
/// **See:** [`Part::get_const()`](struct.Part.html#method.get_const)
pub fn has_const(&self, name: &str) -> Result<bool, ClingoError> {
let name = CString::new(name)?;
let mut exist = false;
if !unsafe { clingo_control_has_const(self.ctl.as_ptr(), name.as_ptr(), &mut exist) } {
return Err(ClingoError::new_internal(
"Call to clingo_control_has_const() failed",
));
}
Ok(exist)
}
/// Get an object to inspect symbolic atoms (the relevant Herbrand base) used
pub fn symbolic_atoms<'a>(&self) -> Result<&'a SymbolicAtoms, ClingoError> {
let mut atoms = std::ptr::null();
if !unsafe { clingo_control_symbolic_atoms(self.ctl.as_ptr(), &mut atoms) } {
return Err(ClingoError::new_internal(
"Call to clingo_control_symbolic_atoms() failed",
));
}
match unsafe { (atoms as *const SymbolicAtoms).as_ref() } {
Some(x) => Ok(x),
None => Err(ClingoError::FFIError {
msg: "Tried casting a null pointer to &SymbolicAtoms.",
}),
}
}
/// Get an object to inspect theory atoms that occur in the grounding.
pub fn theory_atoms(&self) -> Result<&TheoryAtoms, ClingoError> {
let mut atoms = std::ptr::null();
if !unsafe { clingo_control_theory_atoms(self.ctl.as_ptr(), &mut atoms) } {
return Err(ClingoError::new_internal(
"Call to clingo_control_theory_atoms() failed",
));
}
match unsafe { (atoms as *const TheoryAtoms).as_ref() } {
Some(x) => Ok(x),
None => Err(ClingoError::FFIError {
msg: "Tried casting a null pointer to &TheoryAtoms.",
}),
}
}
/// Register a program observer with the control object.
///
/// # Arguments
///
/// * `observer` - the observer to register
/// * `replace` - just pass the grounding to the observer but not the solver
///
/// **Returns** whether the call was successful
pub fn register_observer<T: GroundProgramObserver>(
mut self,
observer: T,
replace: bool,
) -> Result<GenericControl<L, P, T, F>, ClingoError> {
let mut observer = Box::new(observer);
let logger = self.logger.take();
let propagator = self.propagator.take();
let function_handler = self.function_handler.take();
let gpo = clingo_ground_program_observer_t {
init_program: Some(unsafe_init_program::<T>),
begin_step: Some(unsafe_begin_step::<T>),
end_step: Some(unsafe_end_step::<T>),
rule: Some(unsafe_rule::<T>),
weight_rule: Some(unsafe_weight_rule::<T>),
minimize: Some(unsafe_minimize::<T>),
project: Some(unsafe_project::<T>),
output_atom: Some(unsafe_output_atom::<T>),
output_term: Some(unsafe_output_term::<T>),
output_csp: Some(unsafe_output_csp::<T>),
external: Some(unsafe_external::<T>),
assume: Some(unsafe_assume::<T>),
heuristic: Some(unsafe_heuristic::<T>),
acyc_edge: Some(unsafe_acyc_edge::<T>),
theory_term_number: Some(unsafe_theory_term_number::<T>),
theory_term_string: Some(unsafe_theory_term_string::<T>),
theory_term_compound: Some(unsafe_theory_term_compound::<T>),
theory_element: Some(unsafe_theory_element::<T>),
theory_atom: Some(unsafe_theory_atom::<T>),
theory_atom_with_guard: Some(unsafe_theory_atom_with_guard::<T>),
};
if unsafe {
clingo_control_register_observer(
self.ctl.as_ptr(),
&gpo,
replace,
observer.as_mut() as *mut T as *mut c_void,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_control_register_observer() failed",
));
}
self.copied = true;
Ok(GenericControl {
ctl: self.ctl,
copied: false,
logger,
propagator,
observer: Some(observer),
function_handler,
})
}
/// Get an object to add ground directives to the program.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn backend(&mut self) -> Result<Backend, ClingoError> {
let mut backend = std::ptr::null_mut();
if !unsafe { clingo_control_backend(self.ctl.as_ptr(), &mut backend) } {
return Err(ClingoError::new_internal(
"Call to clingo_control_backend() failed",
));
}
if !unsafe { clingo_backend_begin(backend) } {
return Err(ClingoError::new_internal(
"Call to clingo_backend_begin() failed",
));
}
match unsafe { backend.as_mut() } {
Some(backend_ref) => Ok(Backend {
theref: backend_ref,
}),
None => Err(ClingoError::FFIError {
msg: "Tried casting a null pointer to &mut clingo_backend.",
}),
}
}
pub fn add_facts(&mut self, facts: &FactBase) -> Result<(), ClingoError> {
for sym in facts.iter() {
let loc = ast::Location::default();
// initilize atom to add
let symbolic_term = ast::symbolic_term(&loc, sym)?;
let atom = ast::symbolic_atom(symbolic_term)?;
// create literal
let lit = ast::basic_literal_from_symbolic_atom(&loc, ast::Sign::NoSign, atom).unwrap();
let head: ast::Literal = ast::Literal::from(lit);
// create (fact) rule
let fact = ast::rule(&loc, head, &[]).unwrap();
// get the program builder
let mut builder = ast::ProgramBuilder::from(self).unwrap();
// add the rewritten statement to the program
builder
.add(&fact.into())
.expect("Failed to add statement to ProgramBuilder.");
builder.end().expect("Failed to finish building a program.");
}
Ok(())
}
/// Covenience function that returns an iterator over the models.
/// Uses [`solve()`](struct.Control.html#method.solve) with [SolveMode::Yield](enum.SolveMode.html#variant.YIELD) and empty assumptions.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if solving could not be started
pub fn all_models(self) -> Result<AllModels<L, P, O, F, defaults::Non>, ClingoError> {
let mut handle = std::ptr::null_mut();
let event_handler = std::ptr::null_mut();
if !unsafe {
clingo_control_solve(
self.ctl.as_ptr(),
SolveMode::YIELD.bits(),
std::ptr::null() as *const clingo_literal_t,
0,
None,
event_handler,
&mut handle,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_control_solve() failed",
));
}
match NonNull::new(handle) {
Some(handle) => Ok(AllModels(GenericSolveHandle {
handle,
ctl: self,
_event_handler: Box::new(defaults::Non),
})),
None => Err(ClingoError::FFIError {
msg: "Tried creating NonNull from a null pointer.",
})?,
}
}
/// Covenience function that returns an iterator over the optimal models.
/// Uses [`solve()`](struct.Control.html#method.solve) with [SolveMode::Yield](enum.SolveMode.html#variant.YIELD) and empty assumptions.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if solving could not be started
pub fn optimal_models(self) -> Result<OptimalModels<L, P, O, F, defaults::Non>, ClingoError> {
let mut handle = std::ptr::null_mut();
let event_handler = std::ptr::null_mut();
if !unsafe {
clingo_control_solve(
self.ctl.as_ptr(),
SolveMode::YIELD.bits(),
std::ptr::null() as *const clingo_literal_t,
0,
None,
event_handler,
&mut handle,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_control_solve() failed",
));
}
match NonNull::new(handle) {
Some(handle) => Ok(OptimalModels(GenericSolveHandle {
handle,
ctl: self,
_event_handler: Box::new(defaults::Non),
})),
None => Err(ClingoError::FFIError {
msg: "Tried creating NonNull from a null pointer.",
})?,
}
}
}
/// Create a new control object.
///
/// **Note:** Only gringo options (without `--output`) and clasp's options are supported as
/// arguments, except basic options such as `--help`.
/// Furthermore, a control object is blocked while a search call is active;
/// you must not call any member function during search.
///
/// Messages are printed to stderr.
///
/// # Arguments
///
/// * `arguments` - string array of command line arguments
///
/// # Errors
///
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if an argument contains a nul byte
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if argument parsing fails
pub fn control(arguments: std::vec::Vec<String>) -> Result<Control, ClingoError> {
let logger = None;
let logger_data = std::ptr::null_mut();
// create a vector of zero terminated strings
let mut args = vec![];
for arg in arguments {
args.push(CString::new(arg)?);
}
// convert the strings to raw pointers
let c_args = args
.iter()
.map(|arg| arg.as_ptr())
.collect::<Vec<*const c_char>>();
let mut ctl_ptr = std::ptr::null_mut();
if !unsafe {
clingo_control_new(
c_args.as_ptr(),
c_args.len(),
logger,
logger_data,
0,
&mut ctl_ptr,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_control_new() failed",
));
}
match NonNull::new(ctl_ptr) {
Some(ctl) => Ok(GenericControl {
ctl,
copied: false,
logger: Some(Box::new(defaults::Non)),
propagator: Some(Box::new(defaults::Non)),
observer: Some(Box::new(defaults::Non)),
function_handler: Some(Box::new(defaults::Non)),
}),
None => Err(ClingoError::FFIError {
msg: "Tried creating NonNull from a null pointer.",
})?,
}
}
/// Create a new control object.
///
/// **Note:** Only gringo options (without `--output`) and clasp's options are supported as
/// arguments,
/// except basic options such as `--help`.
/// Furthermore, a control object is blocked while a search call is active;
/// you must not call any member function during search.
///
/// # Arguments
///
/// * `arguments` - string array of command line arguments
/// * `logger` - callback functions for warnings and info messages
/// * `message_limit` - maximum number of times the logger callback is called
///
/// # Errors
///
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if an argument contains a nul byte
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if argument parsing fails
pub fn control_with_logger<L: Logger>(
arguments: Vec<String>,
logger: L,
message_limit: u32,
) -> Result<ControlWithLogger<L>, ClingoError> {
let mut args = vec![];
for arg in arguments {
args.push(CString::new(arg)?);
}
// convert the strings to raw pointers
let c_args = args
.iter()
.map(|arg| arg.as_ptr())
.collect::<Vec<*const c_char>>();
let mut ctl_ptr = std::ptr::null_mut();
let mut logger = Box::new(logger);
if !unsafe {
clingo_control_new(
c_args.as_ptr(),
c_args.len(),
Some(unsafe_logging_callback::<L> as LoggingCallback),
logger.as_mut() as *mut L as *mut c_void,
message_limit,
&mut ctl_ptr,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_control_new() failed",
));
}
match NonNull::new(ctl_ptr) {
Some(ctl) => Ok(GenericControl {
ctl,
copied: false,
logger: Some(logger),
propagator: Some(Box::new(defaults::Non)),
observer: Some(Box::new(defaults::Non)),
function_handler: Some(Box::new(defaults::Non)),
}),
None => Err(ClingoError::FFIError {
msg: "Tried creating NonNull from a null pointer.",
})?,
}
}
/// Handle for the solver configuration.
#[derive(Debug)]
pub struct Configuration(clingo_configuration_t);
impl Configuration {
/// Get the root key of the configuration.
pub fn root(&self) -> Result<Id, ClingoError> {
let mut root_key = 0;
if !unsafe { clingo_configuration_root(&self.0, &mut root_key) } {
return Err(ClingoError::new_internal(
"Call to clingo_configuration_root() failed",
));
}
Ok(Id(root_key))
}
/// Get the type of a key.
/// The type is a bitset, an entry can have multiple (but at least one) type.
pub fn configuration_type(&self, Id(key): Id) -> Result<ConfigurationType, ClingoError> {
let mut ctype = 0;
if !unsafe { clingo_configuration_type(&self.0, key, &mut ctype) } {
return Err(ClingoError::new_internal(
"Call to clingo_configuration_type() failed",
));
}
match ConfigurationType::from_bits(ctype) {
Some(x) => Ok(x),
None => {
eprintln!(
"Failed to match to clingo_configuration_type_bitset_t {}.",
ctype
);
Err(ClingoError::FFIError {
msg: "Failed to match to clingo_configuration_type_bitset_t.",
})
}
}
}
/// Get the description of an entry.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError)
/// - [`ClingoError::Utf8Error`](enum.ClingoError.html#variant.Utf8Error)
pub fn description(&self, Id(key): Id) -> Result<&str, ClingoError> {
let mut description_ptr = std::ptr::null();
if !unsafe { clingo_configuration_description(&self.0, key, &mut description_ptr) } {
return Err(ClingoError::new_internal(
"Call to clingo_configuration_description() failed",
));
}
if description_ptr.is_null() {
return Err(ClingoError::FFIError {
msg: "clingo_configuration_description() returned a null pointer.",
});
}
let cstr = unsafe { CStr::from_ptr(description_ptr) };
Ok(cstr.to_str()?)
}
/// Get the size of an array entry.
///
/// # Pre-condition
///
/// The [type](struct.Configuration.html#method.type) of the entry must be [`ConfigurationType::ARRAY`](struct.ConfigurationType.html#associatedconstant.ARRAY).
pub fn array_size(&self, Id(key): Id) -> Result<usize, ClingoError> {
let mut size = 0;
if !unsafe { clingo_configuration_array_size(&self.0, key, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_configuration_array_size() failed",
));
}
Ok(size)
}
/// Get the subkey at the given offset of an array entry.
///
/// **Note:** Some array entries, like fore example the solver configuration, can be accessed
/// past there actual size to add subentries.
///
/// # Pre-condition
///
/// The [type](struct.Configuration.html#method.type) of the entry must be [`ConfigurationType::ARRAY`](struct.ConfigurationType.html#associatedconstant.ARRAY).
///
/// # Arguments
///
/// * `key` - the key
/// * `offset` - the offset in the array
pub fn array_at(&self, Id(key): Id, offset: usize) -> Result<Id, ClingoError> {
let mut nkey = 0;
if !unsafe { clingo_configuration_array_at(&self.0, key, offset, &mut nkey) } {
return Err(ClingoError::new_internal(
"Call to clingo_configuration_array_at() failed",
));
}
Ok(Id(nkey))
}
/// Get the number of subkeys of a map entry.
///
/// # Pre-condition
///
/// The [type](struct.Configuration.html#method.type) of the entry must be [`ConfigurationType::MAP`](struct.ConfigurationType.html#associatedconstant.MAP).
pub fn map_size(&self, Id(key): Id) -> Result<usize, ClingoError> {
let mut size = 0;
if !unsafe { clingo_configuration_map_size(&self.0, key, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_configuration_map_size() failed",
));
}
Ok(size)
}
/// Query whether the map has a key.
///
/// # Pre-condition
///
/// The [type](struct.Configuration.html#method.type) of the entry must be [`ConfigurationType::Map`](enum.ConfigurationType.html#variant.Map).
///
/// **Note:** Multiple levels can be looked up by concatenating keys with a period.
///
/// # Arguments
///
/// * `key` - the key
/// * `name` - the name to lookup the subkey
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError)
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `name` contains a nul byte
///
/// **Returns** whether the key is in the map
pub fn map_has_subkey(&self, Id(key): Id, name: &str) -> Result<bool, ClingoError> {
let mut result = false;
let name = CString::new(name)?;
if !unsafe { clingo_configuration_map_has_subkey(&self.0, key, name.as_ptr(), &mut result) }
{
return Err(ClingoError::new_internal(
"Call to clingo_configuration_map_has_subkey() failed",
));
}
Ok(result)
}
/// Get the name associated with the offset-th subkey.
///
/// # Pre-condition
///
/// The [type](struct.Configuration.html#method.type) of the entry must be [`ConfigurationType::MAP`](struct.ConfigurationType.html#associatedconstant.MAP).
///
/// # Arguments
///
/// * `key` - the key
/// * `offset` - the offset of the name
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError)
/// - [`ClingoError::Utf8Error`](enum.ClingoError.html#variant.Utf8Error)
pub fn map_subkey_name(&self, Id(key): Id, offset: usize) -> Result<&str, ClingoError> {
let mut name_ptr = std::ptr::null();
if !unsafe { clingo_configuration_map_subkey_name(&self.0, key, offset, &mut name_ptr) } {
return Err(ClingoError::new_internal(
"Call to clingo_configuration_map_subkey_name() failed",
));
}
if name_ptr.is_null() {
return Err(ClingoError::FFIError {
msg: "clingo_configuration_map_subkey_name() returned a null pointer.",
});
}
let cstr = unsafe { CStr::from_ptr(name_ptr) };
Ok(cstr.to_str()?)
}
/// Lookup a subkey under the given name.
///
/// # Pre-condition
///
/// The [type](struct.Configuration.html#method.type) of the entry must be [`ConfigurationType::MAP`](struct.ConfigurationType.html#associatedconstant.MAP).
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError)
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `name` contains a nul byte
///
/// **Note:** Multiple levels can be looked up by concatenating keys with a period.
pub fn map_at(&self, Id(key): Id, name: &str) -> Result<Id, ClingoError> {
let mut nkey = 0;
let name = CString::new(name)?;
if !unsafe { clingo_configuration_map_at(&self.0, key, name.as_ptr(), &mut nkey) } {
return Err(ClingoError::new_internal(
"Call to clingo_configuration_value_is_assigned() failed",
));
}
Ok(Id(nkey))
}
/// Check whether a entry has a value.
///
/// # Pre-condition
///
/// The [type](struct.Configuration.html#method.type) of the entry must be [`ConfigurationType::VALUE`](struct.ConfigurationType.html#associatedconstant.VALUE).
///
/// # Arguments
///
/// * `key` - the key
pub fn value_is_assigned(&self, Id(key): Id) -> Result<bool, ClingoError> {
let mut assigned = false;
if !unsafe { clingo_configuration_value_is_assigned(&self.0, key, &mut assigned) } {
return Err(ClingoError::new_internal(
"Call to clingo_configuration_value_is_assigned() failed",
));
}
Ok(assigned)
}
// NODO: fn clingo_configuration_value_get_size(&mut self.0, key, &mut size)
/// Get the string value of the given entry.
///
/// # Pre-condition
///
/// The [type](struct.Configuration.html#method.type) of the entry must be [`ConfigurationType::VALUE`](struct.ConfigurationType.html#associatedconstant.VALUE).
///
/// # Arguments
///
/// * `key` - the key
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError)
/// - [`ClingoError::Utf8Error`](enum.ClingoError.html#variant.Utf8Error)
pub fn value_get(&self, Id(key): Id) -> Result<String, ClingoError> {
let mut size = 0;
if !unsafe { clingo_configuration_value_get_size(&self.0, key, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_configuration_value_get_size() failed",
));
}
let mut string = Vec::with_capacity(size);
let string_ptr = string.as_mut_ptr();
if !unsafe { clingo_configuration_value_get(&self.0, key, string_ptr, size) } {
return Err(ClingoError::new_internal(
"Call to clingo_configuration_value_get() failed",
));
}
let c_str: &CStr = unsafe { CStr::from_ptr(string_ptr) };
let str_slice: &str = c_str.to_str()?;
Ok(str_slice.to_owned())
}
/// Set the value of an entry.
///
/// # Pre-condition
///
/// The [type](struct.Configuration.html#method.type) of the entry must be [`ConfigurationType::VALUE`](struct.ConfigurationType.html#associatedconstant.VALUE).
///
/// # Arguments
///
/// * `key` - the key
/// * `value` - the value to set
///
/// # Errors
///
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `value` contains a nul byte
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError)
pub fn value_set(&mut self, Id(key): Id, value: &str) -> Result<(), ClingoError> {
let value = CString::new(value)?;
if !unsafe { clingo_configuration_value_set(&mut self.0, key, value.as_ptr()) } {
return Err(ClingoError::new_internal(
"Call to clingo_configuration_value_set() failed",
));
}
Ok(())
}
}
/// Handle to the backend to add directives in aspif format.
#[derive(Debug)]
pub struct Backend<'a> {
theref: &'a mut clingo_backend_t,
}
impl<'a> Drop for Backend<'a> {
/// Finalize the backend after using it.
fn drop(&mut self) {
// println!("drop Backend");
if !unsafe { clingo_backend_end(self.theref) } {
panic!("Call to clingo_backend_end() failed");
}
}
}
impl<'a> Backend<'a> {
/// Add a rule to the program.
///
/// # Arguments
///
/// * `choice` determines if the head is a choice or a disjunction
/// * `head` - the head atoms
/// * `body` - the body literals
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn rule(
&mut self,
choice: bool,
head: &[Atom],
body: &[SolverLiteral],
) -> Result<(), ClingoError> {
if !unsafe {
clingo_backend_rule(
self.theref,
choice,
head.as_ptr() as *const clingo_atom_t,
head.len(),
body.as_ptr() as *const clingo_literal_t,
body.len(),
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_backend_rule() failed",
));
}
Ok(())
}
/// Add a weight rule to the program.
///
/// **Attention:** All weights and the lower bound must be positive.
///
/// # Arguments
/// * `choice` - determines if the head is a choice or a disjunction
/// * `head` - the head atoms
/// * `lower_bound` - the lower bound of the weight rule
/// * `body` - the weighted body literals
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn weight_rule(
&mut self,
choice: bool,
head: &[Atom],
lower_bound: i32,
body: &[WeightedLiteral],
) -> Result<(), ClingoError> {
if !unsafe {
clingo_backend_weight_rule(
self.theref,
choice,
head.as_ptr() as *const clingo_atom_t,
head.len(),
lower_bound,
body.as_ptr() as *const clingo_weighted_literal_t,
body.len(),
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_backend_weight_rule() failed",
));
}
Ok(())
}
/// Add a minimize constraint (or weak constraint) to the program.
///
/// # Arguments
///
/// * `priority` - the priority of the constraint
/// * `literals` - the weighted literals whose sum to minimize
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn minimize(
&mut self,
priority: i32,
literals: &[WeightedLiteral],
) -> Result<(), ClingoError> {
if !unsafe {
clingo_backend_minimize(
self.theref,
priority,
literals.as_ptr() as *const clingo_weighted_literal_t,
literals.len(),
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_backend_minimize() failed",
));
}
Ok(())
}
/// Add a projection directive.
///
/// # Arguments
///
/// * `atoms` - the atoms to project on
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn project(&mut self, atoms: &[Atom]) -> Result<(), ClingoError> {
if !unsafe {
clingo_backend_project(
self.theref,
atoms.as_ptr() as *const clingo_atom_t,
atoms.len(),
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_backend_project() failed",
));
}
Ok(())
}
/// Add an external statement.
///
/// # Arguments
///
/// * `atom` - the external atom
/// * `type` - the type of the external statement
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn external(&mut self, atom: Atom, type_: ExternalType) -> Result<(), ClingoError> {
if !unsafe { clingo_backend_external(self.theref, atom.0, type_ as clingo_external_type_t) }
{
return Err(ClingoError::new_internal(
"Call to clingo_backend_external() failed",
));
}
Ok(())
}
/// Add an assumption directive.
///
/// # Arguments
///
/// * `literals` - the literals to assume (positive literals are true and negative literals
/// false for the next solve call)
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn assume(&mut self, literals: &[SolverLiteral]) -> Result<(), ClingoError> {
let size = literals.len();
if !unsafe {
clingo_backend_assume(
self.theref,
literals.as_ptr() as *const clingo_literal_t,
size,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_backend_assume() failed",
));
}
Ok(())
}
/// Add an heuristic directive.
///
/// # Arguments
///
/// * `atom` - the target atom
/// * `htype` - the type of the heuristic modification
/// * `bias` - the heuristic bias
/// * `priority` - the heuristic priority
/// * `condition` - the condition under which to apply the heuristic modification
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn heuristic(
&mut self,
atom: Atom,
htype: HeuristicType,
bias: i32,
priority: u32,
condition: &[SolverLiteral],
) -> Result<(), ClingoError> {
let size = condition.len();
if !unsafe {
clingo_backend_heuristic(
self.theref,
atom.0,
htype as clingo_heuristic_type_t,
bias,
priority,
condition.as_ptr() as *const clingo_literal_t,
size,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_backend_heuristic() failed",
));
}
Ok(())
}
/// Add an edge directive.
///
/// # Arguments
///
/// * `node_u` - the start vertex of the edge
/// * `node_v` - the end vertex of the edge
/// * `condition` - the condition under which the edge is part of the graph
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn acyc_edge(
&mut self,
node_u: i32,
node_v: i32,
condition: &[SolverLiteral],
) -> Result<(), ClingoError> {
let size = condition.len();
if !unsafe {
clingo_backend_acyc_edge(
self.theref,
node_u,
node_v,
condition.as_ptr() as *const clingo_literal_t,
size,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_backend_acyc_edge() failed",
));
}
Ok(())
}
/// Get a fresh atom to be used in aspif directives.
/// # Arguments
///
/// * `symbol` - optional symbol to associate the atom with
pub fn add_atom(&mut self, symbol: Option<Symbol>) -> Result<Atom, ClingoError> {
match symbol {
Some(Symbol(mut symbol)) => {
let mut atom = 0;
if unsafe { clingo_backend_add_atom(self.theref, &mut symbol, &mut atom) } {
Ok(Atom(atom))
} else {
Err(ClingoError::new_internal(
"Call to clingo_backend_add_atom() failed",
))
}
}
None => {
let mut atom = 0;
let null = std::ptr::null_mut();
if unsafe { clingo_backend_add_atom(self.theref, null, &mut atom) } {
Ok(Atom(atom))
} else {
Err(ClingoError::new_internal(
"Call to clingo_backend_add_atom() failed",
))
}
}
}
}
}
/// Handle for to the solver statistics.
#[derive(Debug)]
pub struct Statistics(clingo_statistics_t);
impl Statistics {
/// Get the root key of the statistics.
pub fn root(&self) -> Result<u64, ClingoError> {
let mut root_key = 0;
if !unsafe { clingo_statistics_root(&self.0, &mut root_key) } {
return Err(ClingoError::new_internal(
"Call to clingo_statistics_root() failed",
));
}
Ok(root_key)
}
/// Get the type of a key.
///
/// # Arguments
///
/// * `key` - the key
pub fn statistics_type(&self, key: u64) -> Result<StatisticsType, ClingoError> {
let mut stype = 0;
if !unsafe { clingo_statistics_type(&self.0, key, &mut stype) } {
return Err(ClingoError::new_internal(
"Call to clingo_statistics_type() failed",
));
}
StatisticsType::try_from(stype as u32)
}
/// Get the size of an array entry.
///
/// # Pre-condition
///
/// The [statistics type](struct.Statistics.html#method.statistics_type) of the entry must be
/// [`StatisticsType::Array`](enum.StatisticsType.html#variant.Array).
///
/// # Arguments
///
/// * `key` - the key
pub fn array_size(&self, key: u64) -> Result<usize, ClingoError> {
let mut size = 0;
if !unsafe { clingo_statistics_array_size(&self.0, key, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_statistics_array_size() failed",
));
}
Ok(size)
}
/// Get the subkey at the given offset of an array entry.
///
/// # Pre-condition
///
/// The [statistics type](struct.Statistics.html#method.statistics_type) of the entry must be
/// [`StatisticsType::Array`](enum.StatisticsType.html#variant.Array).
///
/// # Arguments
///
/// * `key` - the key
/// * `offset` - the offset in the array
pub fn array_at(&self, key: u64, offset: usize) -> Result<u64, ClingoError> {
let mut subkey = 0;
if !unsafe { clingo_statistics_array_at(&self.0, key, offset, &mut subkey) } {
return Err(ClingoError::new_internal(
"Call to clingo_statistics_array_at() failed",
));
}
Ok(subkey)
}
/// Create the subkey at the end of an array entry.
///
/// #Pre-condition
///
/// The [statistics type](struct.Statistics.html#method.statistics_type) of the entry must
/// be [`StatisticsType::Array`](enum.StatisticsType.html#variant.Array)
///
/// # Arguments
///
/// * `key` - the key
/// * `stype` - the type of the new subkey
pub fn array_push(&mut self, key: u64, stype: StatisticsType) -> Result<u64, ClingoError> {
let mut subkey = 0;
if !unsafe {
clingo_statistics_array_push(
&mut self.0,
key,
stype as clingo_statistics_type_t,
&mut subkey,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_statistics_array_push() failed",
));
}
Ok(subkey)
}
/// Get the number of subkeys of a map entry.
///
/// # Pre-condition
///
/// The [statistics type](struct.Statistics.html#method.statistics_type) of the entry must
/// be [`StatisticsType::Map`](enum.StatisticsType.html#variant.Map).
///
/// # Arguments
///
/// * `key` - the key
pub fn map_size(&self, key: u64) -> Result<usize, ClingoError> {
let mut size = 0;
if !unsafe { clingo_statistics_map_size(&self.0, key, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_statistics_map_size() failed",
));
}
Ok(size)
}
/// Test if the given map contains a specific subkey.
///
/// # Pre-condition
///
/// The [statistics type](struct.Statistics.html#method.statistics_type) of the entry must
/// be [`StatisticsType::Map`](enum.StatisticsType.html#variant.Map).
///
/// # Arguments
///
/// * `key` - the key
/// * `name` - name of the subkey
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError)
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `name` contains a nul byte
pub fn map_has_subkey(&self, key: u64, name: &str) -> Result<bool, ClingoError> {
let mut result = false;
let name = CString::new(name)?;
if !unsafe { clingo_statistics_map_has_subkey(&self.0, key, name.as_ptr(), &mut result) } {
return Err(ClingoError::new_internal(
"Call to clingo_statistics_map_has_subkey() failed",
));
}
Ok(result)
}
/// Get the name associated with the offset-th subkey.
///
/// # Pre-condition
///
/// The [statistics type](struct.Statistics.html#method.statistics_type) of the entry must be
/// [`StatisticsType::Map`](enum.StatisticsType.html#variant.Map).
///
/// # Arguments
///
/// * `key` - the key
/// * `offset` - the offset of the name
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError)
/// - [`ClingoError::Utf8Error`](enum.ClingoError.html#variant.Utf8Error)
pub fn map_subkey_name(&self, key: u64, offset: usize) -> Result<&str, ClingoError> {
let mut name = std::ptr::null();
if !unsafe { clingo_statistics_map_subkey_name(&self.0, key, offset, &mut name) } {
return Err(ClingoError::new_internal(
"Call to clingo_statistics_map_subkey_name() failed",
));
}
if name.is_null() {
return Err(ClingoError::FFIError {
msg: "clingo_statistics_map_subkey_name() returned a null pointer.",
});
}
Ok(unsafe { CStr::from_ptr(name) }.to_str()?)
}
/// Lookup a subkey under the given name.
///
/// # Pre-condition
///
/// The [statistics type](struct.Statistics.html#method.statistics_type) of the entry must be
/// [`StatisticsType::Map`](enum.StatisticsType.html#variant.Map).
///
/// **Note:** Multiple levels can be looked up by concatenating keys with a period.
///
/// # Arguments
///
/// * `key` - the key
/// * `name` - the name to lookup the subkey
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError)
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `name` contains a nul byte
pub fn map_at(&self, key: u64, name: &str) -> Result<u64, ClingoError> {
let mut subkey = 0;
let name = CString::new(name)?;
if !unsafe { clingo_statistics_map_at(&self.0, key, name.as_ptr(), &mut subkey) } {
return Err(ClingoError::new_internal(
"Call to clingo_statistics_map_at() failed",
));
}
Ok(subkey)
}
/// Add a subkey with the given name.
///
/// # Pre-condition
///
/// The [statistics type](struct.Statistics.html#method.statistics_type) of the entry must be
/// [`StatisticsType::Map`](enum.StatisticsType.html#variant.Map).
///
/// # Arguments
///
/// * `key` - the key
/// * `name` - the name to lookup the subkey
/// * `stype` - the type of the new subkey
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError)
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `name` contains a nul byte
///
/// **Returns** the index of the resulting subkey
pub fn map_add_subkey(
&mut self,
key: u64,
name: &str,
stype: StatisticsType,
) -> Result<u64, ClingoError> {
let mut subkey = 0;
let name = CString::new(name)?;
if !unsafe {
clingo_statistics_map_add_subkey(
&mut self.0,
key,
name.as_ptr(),
stype as clingo_statistics_type_t,
&mut subkey,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_statistics_map_add_subkey() failed",
));
}
Ok(subkey)
}
/// Get the value of the given entry.
///
/// # Pre-condition
///
/// The [statistics type](struct.Statistics.html#method.statistics_type) of the entry must be
/// [`StatisticsType::Value`](enum.StatisticsType.html#variant.Value).
///
/// # Arguments
///
/// * `key` - the key
pub fn value_get(&self, key: u64) -> Result<f64, ClingoError> {
let mut value = 0.0;
if !unsafe { clingo_statistics_value_get(&self.0, key, &mut value) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbolic_atoms_size() failed",
));
}
Ok(value)
}
/// Set the value of the given entry.
///
/// # Pre-condition
///
/// The [statistics type](struct.Statistics.html#method.statistics_type) of the entry must be
/// [`StatisticsType::Value`](enum.StatisticsType.html#variant.Value).
///
/// # Arguments
///
/// * `key` - the key
/// * `value` - the new value
///
/// **Returns** whether the call was successful
pub fn value_set(&mut self, key: u64, value: f64) -> bool {
unsafe { clingo_statistics_value_set(&mut self.0, key, value) }
}
}
/// Container that stores symbolic atoms in a program -- the relevant Herbrand base
/// gringo uses to instantiate programs.
///
/// **See:** [`Control::symbolic_atoms()`](struct.Control.html#method.symbolic_atoms)
#[derive(Debug)]
pub struct SymbolicAtoms(clingo_symbolic_atoms_t);
impl SymbolicAtoms {
/// Get the number of different atoms occurring in a logic program.
pub fn size(&self) -> Result<usize, ClingoError> {
let mut size = 0;
if !unsafe { clingo_symbolic_atoms_size(&self.0, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbolic_atoms_size() failed",
));
}
Ok(size)
}
/// Get a forward iterator of the sequence of all symbolic atoms.
pub fn iter(&self) -> Result<SymbolicAtomsIterator, ClingoError> {
let mut begin = 0;
if !unsafe { clingo_symbolic_atoms_begin(&self.0, std::ptr::null(), &mut begin) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbolic_atoms_begin() failed",
));
}
let mut end = 0;
if !unsafe { clingo_symbolic_atoms_end(&self.0, &mut end) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbolic_atoms_end() failed",
));
}
Ok(SymbolicAtomsIterator {
cur: begin,
end,
atoms: &self.0,
})
}
/// Get a forward iterator of the sequence of all symbolic atoms restricted to a given signature.
///
/// # Arguments
///
/// * `signature` - the signature
pub fn iter_with_signature(
&self,
sig: Signature,
) -> Result<SymbolicAtomsIterator, ClingoError> {
let mut begin = 0;
if !unsafe { clingo_symbolic_atoms_begin(&self.0, &sig.0, &mut begin) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbolic_atoms_begin() failed",
));
}
let mut end = 0;
if !unsafe { clingo_symbolic_atoms_end(&self.0, &mut end) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbolic_atoms_end() failed",
));
}
Ok(SymbolicAtomsIterator {
cur: begin,
end,
atoms: &self.0,
})
}
// NODO: fn clingo_symbolic_atoms_signatures_size()
/// Get the predicate signatures occurring in a logic program.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if the size is too small
pub fn signatures(&self) -> Result<Vec<Signature>, ClingoError> {
let mut size = 0;
if !unsafe { clingo_symbolic_atoms_signatures_size(&self.0, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbolic_atoms_signatures_size() failed",
));
}
let mut signatures = vec![Signature(0); size];
if !unsafe {
clingo_symbolic_atoms_signatures(
&self.0,
signatures.as_mut_ptr() as *mut clingo_signature_t,
size,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_symbolic_atoms_signatures() failed",
));
}
Ok(signatures)
}
// NODO: fn clingo_symbolic_atoms_is_valid()
}
/// An iterator over symbolic atoms.
pub struct SymbolicAtomsIterator<'a> {
cur: clingo_symbolic_atom_iterator_t,
end: clingo_symbolic_atom_iterator_t,
atoms: &'a clingo_symbolic_atoms_t,
}
impl<'a> Iterator for SymbolicAtomsIterator<'a> {
type Item = SymbolicAtom<'a>;
fn next(&mut self) -> Option<SymbolicAtom<'a>> {
let mut equal = false;
if !unsafe {
clingo_symbolic_atoms_iterator_is_equal_to(self.atoms, self.cur, self.end, &mut equal)
} {
return None;
}
if equal {
return None;
}
let ret = SymbolicAtom {
cur: self.cur,
atoms: self.atoms,
};
if !unsafe { clingo_symbolic_atoms_next(self.atoms, self.cur, &mut self.cur) } {
panic!(
"Call clingo_symbolic_atoms_next() failed {}{}{}.",
file!(),
line!(),
column!()
);
}
Some(ret)
}
}
/// A symbolic atom in a program.
pub struct SymbolicAtom<'a> {
cur: clingo_symbolic_atom_iterator_t,
atoms: &'a clingo_symbolic_atoms_t,
}
impl<'a> SymbolicAtom<'a> {
/// Check whether an atom is a fact.
///
/// **Note:** This does not determine if an atom is a cautious consequence. The
/// grounding or solving component's simplifications can only detect this in
/// some cases.
pub fn is_fact(&self) -> Result<bool, ClingoError> {
let mut fact = false;
if !unsafe { clingo_symbolic_atoms_is_fact(self.atoms, self.cur, &mut fact) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbolic_atoms_is_fact() failed",
));
}
Ok(fact)
}
/// Check whether an atom is external.
///
/// An atom is external if it has been defined using an external directive and
/// has not been released or defined by a rule.
pub fn is_external(&self) -> Result<bool, ClingoError> {
let mut external = false;
if !unsafe { clingo_symbolic_atoms_is_external(self.atoms, self.cur, &mut external) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbolic_atoms_is_external() failed",
));
}
Ok(external)
}
/// Get the symbolic representation of an atom.
pub fn symbol(&self) -> Result<Symbol, ClingoError> {
let mut symbol = 0;
if !unsafe { clingo_symbolic_atoms_symbol(self.atoms, self.cur, &mut symbol) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbolic_atoms_symbol() failed",
));
}
Ok(Symbol(symbol))
}
/// Returns the (numeric) aspif literal corresponding to the given symbolic atom.
///
/// Such a literal can be mapped to a solver literal (see [`Propagator`](struct.Propagator)).
/// or be used in rules in aspif format (see [`ProgramBuilder`](struct.ProgramBuilder.html)).
pub fn literal(&self) -> Result<SolverLiteral, ClingoError> {
let mut literal = 0;
if !unsafe { clingo_symbolic_atoms_literal(self.atoms, self.cur, &mut literal) } {
return Err(ClingoError::new_internal(
"Call to clingo_symbolic_atoms_literal() failed",
));
}
Ok(SolverLiteral(literal))
}
}
/// Container that stores theory atoms, elements, and terms of a program.
///
/// **See:** [`Control::theory_atoms()`](struct.Control.html#method.theory_atoms)
#[derive(Debug)]
pub struct TheoryAtoms(clingo_theory_atoms_t);
impl TheoryAtoms {
/// Get the total number of theory atoms.
pub fn size(&self) -> Result<usize, ClingoError> {
let mut size = 0;
if !unsafe { clingo_theory_atoms_size(&self.0, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_size() failed",
));
}
Ok(size)
}
/// Returns an iterator over the theory atoms.
pub fn iter(&self) -> TheoryAtomsIterator {
TheoryAtomsIterator {
count: 0,
atoms: &self,
}
}
/// Get the type of the given theory term.
///
/// # Arguments
///
/// * `term` - id of the term
pub fn term_type(&self, Id(term): Id) -> Result<TheoryTermType, ClingoError> {
let mut ttype = 0;
if !unsafe { clingo_theory_atoms_term_type(&self.0, term, &mut ttype) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_term_type() failed",
));
}
TheoryTermType::try_from(ttype as u32)
}
/// Get the number of the given numeric theory term.
///
/// # Pre-condition
///
/// The term must be of type [`TermType::Number`](enum.TermType.html#variant.Number).
///
/// # Arguments
///
/// * `term` - id of the term
pub fn term_number(&self, Id(term): Id) -> Result<i32, ClingoError> {
let mut number = 0;
if !unsafe { clingo_theory_atoms_term_number(&self.0, term, &mut number) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_term_number() failed",
));
}
Ok(number)
}
/// Get the name of the given constant or function theory term.
///
/// # Pre-condition
///
/// The term must be of type [`TermType::Function`](enum.TermType.html#variant.Function) or
/// [`TermType::Symbol`](enum.TermType.html#variant.Symbol).
///
/// **Note:**
/// The lifetime of the string is tied to the current solve step.
///
/// # Arguments
///
/// * `term` id of the term
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError)
/// - [`ClingoError::Utf8Error`](enum.ClingoError.html#variant.Utf8Error)
pub fn term_name<'a>(&self, Id(term): Id) -> Result<&'a str, ClingoError> {
let mut char_ptr = std::ptr::null();
if !unsafe { clingo_theory_atoms_term_name(&self.0, term, &mut char_ptr) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_term_name() failed",
));
}
if char_ptr.is_null() {
return Err(ClingoError::FFIError {
msg: "clingo_theory_atoms_term_name() returned a null pointer.",
});
}
let c_str = unsafe { CStr::from_ptr(char_ptr) };
Ok(c_str.to_str()?)
}
/// Get the arguments of the given function theory term.
///
/// # Pre-condition
///
/// The term must be of type [`TermType::Function`](enum.TermType.html#variant.Function).
///
/// # Arguments
///
/// * `term` - id of the term
pub fn term_arguments(&self, Id(term): Id) -> Result<&[Id], ClingoError> {
let mut size = 0;
let mut c_ptr = std::ptr::null();
if !unsafe { clingo_theory_atoms_term_arguments(&self.0, term, &mut c_ptr, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_term_arguments() failed",
));
}
let arguments_ref = unsafe { std::slice::from_raw_parts(c_ptr as *const Id, size) };
Ok(arguments_ref)
}
// NODO: fn clingo_theory_atoms_term_to_string_size()
/// Get the string representation of the given theory term.
///
/// # Arguments
///
/// * `term` - id of the term
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if the size is too small
/// or [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// - [`ClingoError::Utf8Error`](enum.ClingoError.html#variant.Utf8Error)
pub fn term_to_string(&self, Id(term): Id) -> Result<String, ClingoError> {
let mut size = 0;
if !unsafe { clingo_theory_atoms_term_to_string_size(&self.0, term, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_term_to_string_size() failed",
));
}
let mut string = Vec::with_capacity(size);
let string_ptr = string.as_mut_ptr();
if !unsafe { clingo_theory_atoms_term_to_string(&self.0, term, string_ptr, size) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_term_to_string() failed",
));
}
let c_str: &CStr = unsafe { CStr::from_ptr(string_ptr) };
let str_slice: &str = c_str.to_str()?;
Ok(str_slice.to_owned())
}
/// Get the tuple (array of theory terms) of the given theory element.
///
/// # Arguments
///
/// * `element` - id of the element
pub fn element_tuple(&self, Id(element): Id) -> Result<&[Id], ClingoError> {
let mut size = 0;
let mut tuple_ptr = std::ptr::null();
if !unsafe {
clingo_theory_atoms_element_tuple(&self.0, element, &mut tuple_ptr, &mut size)
} {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_element_tuple() failed",
));
}
let tuple_ref = unsafe { std::slice::from_raw_parts(tuple_ptr as *const Id, size) };
Ok(tuple_ref)
}
/// Get the condition (array of aspif literals) of the given theory element.
///
/// # Arguments
///
/// * `element` - id of the element
pub fn element_condition(&self, Id(element): Id) -> Result<&[SolverLiteral], ClingoError> {
let mut size = 0;
let mut condition_ptr = std::ptr::null();
if !unsafe {
clingo_theory_atoms_element_condition(&self.0, element, &mut condition_ptr, &mut size)
} {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_element_condition() failed",
));
}
let condition_ref =
unsafe { std::slice::from_raw_parts(condition_ptr as *const SolverLiteral, size) };
Ok(condition_ref)
}
/// Get the id of the condition of the given theory element.
///
/// **Note:**
/// This id can be mapped to a solver literal using [`PropagateInit::solver_literal()`](struct.PropagateInit.html#method.solver_literal).
/// This id is not (necessarily) an aspif literal;
/// to get aspif literals use [`TheoryAtoms::element_condition()`](struct.TheoryAtoms.html#method.element_condition).
///
/// # Arguments
///
/// * `element` - id of the element
pub fn element_condition_id(&self, Id(element): Id) -> Result<SolverLiteral, ClingoError> {
let condition_ptr = std::ptr::null_mut();
if !unsafe { clingo_theory_atoms_element_condition_id(&self.0, element, condition_ptr) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_element_condition_id() failed",
));
}
if condition_ptr.is_null() {
return Err(ClingoError::FFIError {
msg: "clingo_theory_atoms_element_condition_id() returned a null pointer.",
});
}
Ok(SolverLiteral(unsafe { *condition_ptr }))
}
// NODO: fn clingo_theory_atoms_element_to_string_size()
/// Get the string representation of the given theory element.
///
/// # Arguments
///
/// * `element` - id of the element
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if the size is too small
/// or [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// - [`ClingoError::Utf8Error`](enum.ClingoError.html#variant.Utf8Error)
pub fn element_to_string(&self, Id(element): Id) -> Result<String, ClingoError> {
let mut size = 0;
if !unsafe { clingo_theory_atoms_element_to_string_size(&self.0, element, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_element_to_string_size() failed",
));
}
let mut string = Vec::with_capacity(size);
let string_ptr = string.as_mut_ptr();
if !unsafe { clingo_theory_atoms_element_to_string(&self.0, element, string_ptr, size) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_element_to_string() failed",
));
}
let c_str: &CStr = unsafe { CStr::from_ptr(string_ptr) };
let str_slice: &str = c_str.to_str()?;
Ok(str_slice.to_owned())
}
/// Get the theory term associated with the theory atom.
///
/// # Arguments
///
/// * `atom` - id of the atom
pub fn atom_term(&self, Id(atom): Id) -> Result<Id, ClingoError> {
let mut term = 0;
if !unsafe { clingo_theory_atoms_atom_term(&self.0, atom, &mut term) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_atom_term() failed",
));
}
Ok(Id(term))
}
/// Get the theory elements associated with the theory atom.
///
/// # Arguments
///
/// * `atom` - id of the atom
pub fn atom_elements(&self, Id(atom): Id) -> Result<&[Id], ClingoError> {
let mut size = 0;
let mut elements_ptr = std::ptr::null() as *const clingo_id_t;
if !unsafe {
clingo_theory_atoms_atom_elements(&self.0, atom, &mut elements_ptr, &mut size)
} {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_atom_elements() failed",
));
}
let elements = unsafe { std::slice::from_raw_parts(elements_ptr as *const Id, size) };
Ok(elements)
}
/// Whether the theory atom has a guard.
///
/// # Arguments
///
/// * `atom` - id of the atom
pub fn atom_has_guard(&self, Id(atom): Id) -> Result<bool, ClingoError> {
let mut has_guard = false;
if !unsafe { clingo_theory_atoms_atom_has_guard(&self.0, atom, &mut has_guard) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_atom_has_guard() failed",
));
}
Ok(has_guard)
}
/// Get the guard consisting of a theory operator and a theory term of the given theory atom.
///
/// **Note:**
/// The lifetime of the string is tied to the current solve step.
///
/// # Arguments
///
/// * `atom` - id of the atom
///
/// # Errors
///
/// - [`ClingoError::Utf8Error`](enum.ClingoError.html#variant.Utf8Error)
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError)
pub fn atom_guard(&self, Id(atom): Id) -> Result<(&str, Id), ClingoError> {
let mut c_ptr = std::ptr::null() as *const c_char;
let mut term = 0;
if !unsafe { clingo_theory_atoms_atom_guard(&self.0, atom, &mut c_ptr, &mut term) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_atom_guard() failed",
));
}
if c_ptr.is_null() {
return Err(ClingoError::FFIError {
msg: "clingo_theory_atoms_atom_guard() returned a null pointer.",
});
}
let cstr = unsafe { CStr::from_ptr(c_ptr) };
Ok((cstr.to_str()?, Id(term)))
}
/// Get the aspif literal associated with the given theory atom.
///
/// # Arguments
///
/// * `atom` id of the atom
pub fn atom_literal(&self, Id(atom): Id) -> Result<SolverLiteral, ClingoError> {
let mut literal = 0;
if !unsafe { clingo_theory_atoms_atom_literal(&self.0, atom, &mut literal) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_atom_literal() failed",
));
}
Ok(SolverLiteral(literal))
}
// NODO: fn clingo_theory_atoms_atom_to_string_size()
/// Get the string representation of the given theory atom.
///
/// # Arguments
///
/// * `atom` - id of the element
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if the size is too small
/// or [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// - [`ClingoError::Utf8Error`](enum.ClingoError.html#variant.Utf8Error)
pub fn atom_to_string(&self, Id(atom): Id) -> Result<String, ClingoError> {
let mut size = 0;
if !unsafe { clingo_theory_atoms_atom_to_string_size(&self.0, atom, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_atom_to_string_size() failed",
));
}
let mut string = Vec::with_capacity(size);
let string_ptr = string.as_mut_ptr();
if !unsafe { clingo_theory_atoms_atom_to_string(&self.0, atom, string_ptr, size) } {
return Err(ClingoError::new_internal(
"Call to clingo_theory_atoms_atom_to_string() failed",
));
}
let c_str: &CStr = unsafe { CStr::from_ptr(string_ptr) };
let str_slice: &str = c_str.to_str()?;
Ok(str_slice.to_owned())
}
}
/// Iterator over theory atoms.
pub struct TheoryAtomsIterator<'a> {
count: usize,
atoms: &'a TheoryAtoms,
}
impl<'a> Iterator for TheoryAtomsIterator<'a> {
type Item = Id;
fn next(&mut self) -> Option<Id> {
// check to see if we've finished counting or not.
if self.count < self.atoms.size().unwrap() {
let ret = Id(self.count as clingo_id_t);
// increment our count.
self.count += 1;
Some(ret)
} else {
None
}
}
}
/// Represents a model.
#[derive(Debug)]
pub struct Model(clingo_model_t);
impl Model {
/// Get the type of the model.
pub fn model_type(&self) -> Result<ModelType, ClingoError> {
let mut mtype = 0;
if !unsafe { clingo_model_type(&self.0, &mut mtype) } {
return Err(ClingoError::new_internal(
"Call to clingo_model_type() failed",
));
}
ModelType::try_from(mtype as u32)
}
/// Get the running number of the model.
pub fn number(&self) -> Result<u64, ClingoError> {
let mut number = 0;
if !unsafe { clingo_model_number(&self.0, &mut number) } {
return Err(ClingoError::new_internal(
"Call to clingo_model_number() failed",
));
}
Ok(number)
}
// NODO: fn clingo_model_symbols_size()
/// Get the symbols of the selected types in the model.
///
/// **Note:** CSP assignments are represented using functions with name "$"
/// where the first argument is the name of the CSP variable and the second one its
/// value.
///
/// # Arguments
///
/// * `show` - which symbols to select
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if the size is too small
pub fn symbols(&self, show: ShowType) -> Result<Vec<Symbol>, ClingoError> {
let mut size: usize = 0;
if !unsafe { clingo_model_symbols_size(&self.0, show.bits(), &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_model_symbols_size() failed",
));
}
let symbols = vec![Symbol(0); size];
if !unsafe {
clingo_model_symbols(
&self.0,
show.bits(),
symbols.as_ptr() as *mut clingo_symbol_t,
size,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_model_symbols() failed",
));
}
Ok(symbols)
}
/// Constant time lookup to test whether an atom is in a model.
///
/// # Arguments
///
/// * `atom` - the atom to lookup
pub fn contains(&self, Symbol(atom): Symbol) -> Result<bool, ClingoError> {
let mut contained = false;
if !unsafe { clingo_model_contains(&self.0, atom, &mut contained) } {
return Err(ClingoError::new_internal(
"Call to clingo_model_contains() failed",
));
}
Ok(contained)
}
/// Check whether a program literal is true in a model.
///
/// # Arguments
///
/// * `literal` - the literal to lookup
pub fn is_true(&self, literal: SolverLiteral) -> Result<bool, ClingoError> {
let mut is_true = false;
if !unsafe { clingo_model_is_true(&self.0, literal.0, &mut is_true) } {
return Err(ClingoError::new_internal(
"Call to clingo_model_is_true() failed",
));
}
Ok(is_true)
}
// NODO: fn clingo_model_cost_size(model: *mut Model, size: *mut size_t) -> u8;
/// Get the cost vector of a model.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if the size is too small
///
/// **See:** [`Model::optimality_proven()`](struct.Model.html#method.optimality_proven)
pub fn cost(&self) -> Result<Vec<i64>, ClingoError> {
let mut size: usize = 0;
if !unsafe { clingo_model_cost_size(&self.0, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_model_cost_size() failed",
));
}
let mut cost = vec![0; size];
if !unsafe { clingo_model_cost(&self.0, cost.as_mut_ptr(), size) } {
return Err(ClingoError::new_internal(
"Call to clingo_model_cost() failed",
));
}
Ok(cost)
}
/// Whether the optimality of a model has been proven.
///
/// **See:** [`Model::cost()`](struct.Model.html#method.cost)
pub fn optimality_proven(&self) -> Result<bool, ClingoError> {
let mut proven = false;
if !unsafe { clingo_model_optimality_proven(&self.0, &mut proven) } {
return Err(ClingoError::new_internal(
"Call to clingo_model_optimality_proven() failed",
));
}
Ok(proven)
}
/// Get the id of the solver thread that found the model.
pub fn thread_id(&self) -> Result<Id, ClingoError> {
let mut id = 0;
if !unsafe { clingo_model_thread_id(&self.0, &mut id) } {
return Err(ClingoError::new_internal(
"Call to clingo_model_thread_id() failed",
));
}
Ok(Id(id))
}
/// Add symbols to the model.
///
/// These symbols will appear in clingo\'s output, which means that this
/// function is only meaningful if there is an underlying clingo application.
/// Only models passed to the ::clingo_solve_event_callback_t are extendable.
///
/// # Arguments
///
/// * `symbols` - the symbols to add
///
/// **Returns** whether the call was successful
pub fn extend(&mut self, symbols: &[Symbol]) -> bool {
unsafe {
clingo_model_extend(
&mut self.0,
symbols.as_ptr() as *const clingo_symbol_t,
symbols.len(),
)
}
}
/// Get the associated solve control object of a model.
///
/// This object allows for adding clauses during model enumeration.
pub fn context(&self) -> Result<&mut SolveControl, ClingoError> {
let control_ptr = std::ptr::null_mut();
if !unsafe { clingo_model_context(&self.0, control_ptr) } {
return Err(ClingoError::new_internal(
"Call to clingo_model_context() failed",
));
}
if control_ptr.is_null() {
return Err(ClingoError::FFIError {
msg: "clingo_model_context() returned a null pointer.",
});
}
unsafe { Ok(&mut *(control_ptr as *mut SolveControl)) }
}
}
/// Object to add clauses during search.
#[derive(Debug)]
pub struct SolveControl(clingo_solve_control_t);
impl SolveControl {
/// Add a clause that applies to the current solving step during model
/// enumeration.
///
/// **Note:** The [`Propagator`](trait.Propagator.html) trait provides a more sophisticated
/// interface to add clauses - even on partial assignments.
///
/// # Arguments
///
/// * `clause` - array of literals representing the clause
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if adding the clause fails
pub fn add_clause(&mut self, clause: &[SolverLiteral]) -> Result<(), ClingoError> {
if !unsafe {
clingo_solve_control_add_clause(
&mut self.0,
clause.as_ptr() as *const clingo_literal_t,
clause.len(),
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_solve_control_add_clause() failed",
));
}
Ok(())
}
/// Get an object to inspect the symbolic atoms.
pub fn symbolic_atoms(&self) -> Result<&SymbolicAtoms, ClingoError> {
let mut atoms = std::ptr::null() as *const clingo_symbolic_atoms_t;
if !unsafe { clingo_solve_control_symbolic_atoms(&self.0, &mut atoms) } {
return Err(ClingoError::new_internal(
"Call to clingo_assignment_level() failed",
));
}
match unsafe { (atoms as *const SymbolicAtoms).as_ref() } {
Some(stm) => Ok(stm),
None => Err(ClingoError::FFIError {
msg: "Tried casting a null pointer to &SymbolicAtoms.",
}),
}
}
}
/// Represents a (partial) assignment of a particular solver.
///
/// An assignment assigns truth values to a set of literals.
/// A literal is assigned to either [true or false, or is unassigned](struct.Assignment.html#method.truth_value).
/// Furthermore, each assigned literal is associated with a [decision level](struct.Assignment.html#method.level).
/// There is exactly one [decision literal](struct.Assignment.html#method.decision) for each decision level greater than zero.
/// Assignments to all other literals on the same level are consequences implied by the current and possibly previous decisions.
/// Assignments on level zero are immediate consequences of the current program.
/// Decision levels are consecutive numbers starting with zero up to and including the [current decision level](struct.Assignment.html#method.decision_level).
#[derive(Debug)]
pub struct Assignment(clingo_assignment_t);
impl Assignment {
/// Get the current decision level.
pub fn decision_level(&self) -> u32 {
unsafe { clingo_assignment_decision_level(&self.0) }
}
/// Get the current root level.
///
/// Decisions levels smaller or equal to the root level are not backtracked during solving.
pub fn root_level(&self) -> u32 {
unsafe { clingo_assignment_root_level(&self.0) }
}
/// Check whether the given assignment is conflicting.
pub fn has_conflict(&self) -> bool {
unsafe { clingo_assignment_has_conflict(&self.0) }
}
/// Check whether the given literal is part of a (partial) assignment.
///
/// # Arguments
///
/// * `literal` - the literal
pub fn has_literal(&self, literal: SolverLiteral) -> bool {
unsafe { clingo_assignment_has_literal(&self.0, literal.0) }
}
/// Determine the decision level of a given literal.
///
/// # Arguments
///
/// * `literal` - the literal
///
/// **Returns** the decision level of the given literal
pub fn level(&self, literal: SolverLiteral) -> Result<u32, ClingoError> {
let mut level = 0;
if !unsafe { clingo_assignment_level(&self.0, literal.0, &mut level) } {
return Err(ClingoError::new_internal(
"Call to clingo_assignment_level() failed",
));
}
Ok(level)
}
/// Determine the decision literal given a decision level.
///
/// # Arguments
///
/// * `level` - the level
///
/// **Returns** the decision literal for the given decision level
pub fn decision(&self, level: u32) -> Result<SolverLiteral, ClingoError> {
let mut lit = 0;
if !unsafe { clingo_assignment_decision(&self.0, level, &mut lit) } {
return Err(ClingoError::new_internal(
"Call to clingo_assignment_decision() failed",
));
}
Ok(SolverLiteral(lit))
}
/// Check if a literal has a fixed truth value.
///
/// # Arguments
///
/// * `literal` - the literal
///
/// **Returns** whether the literal is fixed
pub fn is_fixed(&self, literal: SolverLiteral) -> Result<bool, ClingoError> {
let mut is_fixed = false;
if !unsafe { clingo_assignment_is_fixed(&self.0, literal.0, &mut is_fixed) } {
return Err(ClingoError::new_internal(
"Call to clingo_assignment_is_fixed() failed",
));
}
Ok(is_fixed)
}
/// Check if a literal is true.
///
/// # Arguments
///
/// * `literal` - the literal
/// **Returns** whether the literal is true (see [`Assignment::truth_value()`](struct.Assignment.html#method.truth_value))
pub fn is_true(&self, literal: SolverLiteral) -> Result<bool, ClingoError> {
let mut is_true = false;
if !unsafe { clingo_assignment_is_true(&self.0, literal.0, &mut is_true) } {
return Err(ClingoError::new_internal(
"Call to clingo_assignment_is_true() failed",
));
}
Ok(is_true)
}
/// Check if a literal has a fixed truth value.
///
/// # Arguments
/// * `literal` - the literal
///
/// **Returns** whether the literal is false (see [`Assignment::truth_value()`](struct.Assignment.html#method.truth_value))
pub fn is_false(&self, literal: SolverLiteral) -> Result<bool, ClingoError> {
let mut is_false = false;
if !unsafe { clingo_assignment_is_false(&self.0, literal.0, &mut is_false) } {
return Err(ClingoError::new_internal(
"Call to clingo_assignment_is_false() failed",
));
}
Ok(is_false)
}
/// Determine the truth value of a given literal.
///
/// # Arguments
///
/// * `literal` - the literal
/// * `value` - the resulting truth value
///
/// **Returns** whether the call was successful
pub fn truth_value(&self, literal: SolverLiteral) -> Result<TruthValue, ClingoError> {
let mut value = 0;
if !unsafe { clingo_assignment_truth_value(&self.0, literal.0, &mut value) } {
return Err(ClingoError::new_internal(
"Call to clingo_assignment_truth_value() failed",
));
}
TruthValue::try_from(value as u32)
}
/// The number of (positive) literals in the assignment.
pub fn size(&self) -> usize {
unsafe { clingo_assignment_size(&self.0) }
}
/// The (positive) literal at the given offset in the assignment.
///
/// # Arguments
///
/// * `offset` - the offset of the literal
///
/// **Returns** the literal
pub fn at(&self, offset: usize) -> Result<SolverLiteral, ClingoError> {
let mut lit = 0;
if !unsafe { clingo_assignment_at(&self.0, offset, &mut lit) } {
return Err(ClingoError::new_internal(
"Call to clingo_assignment_at() failed",
));
}
Ok(SolverLiteral(lit))
}
/// Check if the assignmen is total, i.e. there are no free literal.
pub fn is_total(&self) -> bool {
unsafe { clingo_assignment_is_total(&self.0) }
}
/// Returns the number of literals in the trail, i.e., the number of assigned literals.
pub fn trail_size(&self) -> Result<u32, ClingoError> {
let mut size = 0;
if !unsafe { clingo_assignment_trail_size(&self.0, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_assignment_trail_size() failed",
));
}
Ok(size)
}
/// Returns the offset of the decision literal with the given decision level in
/// the trail.
///
/// **Note:**SolverLiterals in the trail are ordered by decision levels, where the first
/// literal with a larger level than the previous literals is a decision; the
/// following literals with same level are implied by this decision literal.
/// Each decision level up to and including the current decision level has a
/// valid offset in the trail.
///
/// # Arguments
///
/// * `level` - the decision level
///
/// **Returns** the offset of the decision literal
pub fn trail_begin(&self, level: u32) -> Result<u32, ClingoError> {
let mut offset = 0;
if !unsafe { clingo_assignment_trail_begin(&self.0, level, &mut offset) } {
return Err(ClingoError::new_internal(
"Call to clingo_assignment_trail_begin() failed",
));
}
Ok(offset)
}
/// Returns the offset following the last literal with the given decision level.
///
/// **Note:** This function is the counter part to clingo_assignment_trail_begin().
///
/// # Arguments
///
/// * `level` - the decision level
///
/// **Returns** the offset
pub fn trail_end(&self, level: u32) -> Result<u32, ClingoError> {
let mut offset = 0;
if !unsafe { clingo_assignment_trail_end(&self.0, level, &mut offset) } {
return Err(ClingoError::new_internal(
"Call to clingo_assignment_trail_end() failed",
));
}
Ok(offset)
}
/// Returns the literal at the given position in the trail.
///
/// # Arguments
///
/// * `offset` - the offset of the literal
///
/// **Returns** the literal
pub fn trail_at(&self, offset: u32) -> Result<SolverLiteral, ClingoError> {
let mut lit = 0;
if !unsafe { clingo_assignment_trail_at(&self.0, offset, &mut lit) } {
return Err(ClingoError::new_internal(
"Call to clingo_assignment_trail_at() failed",
));
}
Ok(SolverLiteral(lit))
}
}
/// This object can be used to add clauses and propagate literals while solving.
#[derive(Debug)]
pub struct PropagateControl(clingo_propagate_control_t);
impl PropagateControl {
/// Get the id of the underlying solver thread.
///
/// Thread ids are consecutive numbers starting with zero.
pub fn thread_id(&self) -> u32 {
unsafe { clingo_propagate_control_thread_id(&self.0) }
}
/// Get the assignment associated with the underlying solver.
pub fn assignment(&self) -> Result<&Assignment, ClingoError> {
match unsafe {
(clingo_propagate_control_assignment(&self.0) as *const Assignment).as_ref()
} {
Some(stm) => Ok(stm),
None => Err(ClingoError::FFIError {
msg: "Tried casting a null pointer to &Assignment.",
}),
}
}
/// Get the assignment associated with the underlying solver.
pub fn assignment_mut(&self) -> Result<&mut Assignment, ClingoError> {
match unsafe { (clingo_propagate_control_assignment(&self.0) as *mut Assignment).as_mut() }
{
Some(stm) => Ok(stm),
None => Err(ClingoError::FFIError {
msg: "Tried casting a null pointer to &mut Assignment.",
}),
}
}
/// Adds a new volatile literal to the underlying solver thread.
///
/// **Attention:** The literal is only valid within the current solving step and solver thread.
/// All volatile literals and clauses involving a volatile literal are deleted after the current search.
///
/// # Arguments
///
/// * `result` - the (positive) solver literal
///
/// **Errors:**
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Logic`](enum.ErrorCode.html#variant.Logic) if the assignment is conflicting
pub fn add_literal(&mut self, result: &mut SolverLiteral) -> Result<(), ClingoError> {
if !unsafe { clingo_propagate_control_add_literal(&mut self.0, &mut result.0) } {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_control_add_literal() failed",
));
}
Ok(())
}
/// Add a watch for the solver literal in the given phase.
///
/// **Note:** Unlike [`PropagateInit::add_watch()`](struct.PropagateInit.html#method.add_watch) this does not add a watch to all solver threads but just the current one.
///
/// # Arguments
///
/// * `literal` - the literal to watch
///
/// **Errors:**
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Logic`](enum.ErrorCode.html#variant.Logic) if the literal is invalid
///
/// **See:** [`PropagateControl::remove_watch()`](struct.PropagateControl.html#method.remove_watch)
pub fn add_watch(&mut self, literal: SolverLiteral) -> Result<(), ClingoError> {
if !unsafe { clingo_propagate_control_add_watch(&mut self.0, literal.0) } {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_control_add_watch() failed",
));
}
Ok(())
}
/// Check whether a literal is watched in the current solver thread.
///
/// # Arguments
///
/// * `literal` - the literal to check
pub fn has_watch(&self, literal: SolverLiteral) -> bool {
unsafe { clingo_propagate_control_has_watch(&self.0, literal.0) }
}
/// Removes the watch (if any) for the given solver literal.
///
/// **Note:** Similar to [`PropagateInit::add_watch()`](struct.PropagateInit.html#method.add_watch) this just removes the watch in the current solver thread.
///
/// # Arguments
///
/// * `literal` - the literal to remove
pub fn remove_watch(&mut self, literal: SolverLiteral) {
unsafe { clingo_propagate_control_remove_watch(&mut self.0, literal.0) }
}
/// Add the given clause to the solver.
///
/// This method sets its result to false if the current propagation must be stopped for the solver to backtrack.
///
/// **Attention:** No further calls on the control object or functions on the assignment should be called when the result of this method is false.
///
/// # Arguments
///
/// * `clause` - the clause to add
/// * `ctype` - the clause type determining its lifetime
///
/// **Returns** result indicating whether propagation has to be stopped
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn add_clause(
&mut self,
clause: &[SolverLiteral],
ctype: ClauseType,
) -> Result<bool, ClingoError> {
let mut result = false;
if !unsafe {
clingo_propagate_control_add_clause(
&mut self.0,
clause.as_ptr() as *const clingo_literal_t,
clause.len(),
ctype as clingo_clause_type_t,
&mut result,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_control_add_clause() failed",
));
}
Ok(result)
}
/// Propagate implied literals (resulting from added clauses).
///
/// This method sets its result to false if the current propagation must be stopped for the
/// solver to backtrack.
///
/// **Attention:** No further calls on the control object or functions on the assignment should
/// be called when the result of this method is false.
///
/// **Returns** result indicating whether propagation has to be stopped
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn propagate(&mut self) -> Result<bool, ClingoError> {
let mut result = false;
if !unsafe { clingo_propagate_control_propagate(&mut self.0, &mut result) } {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_control_propagate() failed",
));
}
Ok(result)
}
}
/// Object to initialize a user-defined propagator before each solving step.
///
/// Each [symbolic](struct.SymbolicAtoms.html) or [theory atom](struct.TheoryAtoms.html) is uniquely associated with an aspif atom in form of a positive integer ([`Literal`](struct.Literal.html)).
/// Aspif literals additionally are signed to represent default negation.
/// Furthermore, there are non-zero integer solver literals (also represented using [`Literal`](struct.Literal.html).
/// There is a surjective mapping from program atoms to solver literals.
///
/// All methods called during propagation use solver literals whereas [`SymbolicAtoms::literal()`](struct.SymbolicAtoms.html#method.literal) and [`TheoryAtoms::atom_literal()`](struct.TheoryAtoms.html#method.atom_literal) return program literals.
/// The function [`PropagateInit::solver_literal()`](struct.PropagateInit.html#method.solver_literal) can be used to map program literals or [condition ids](struct.TheoryAtoms.html#method.element_condition_id) to solver literals.
#[derive(Debug)]
pub struct PropagateInit(clingo_propagate_init_t);
impl PropagateInit {
/// Map the given program literal or condition id to its solver literal.
///
/// # Arguments
///
/// * `aspif_literal` - the aspif literal to map
///
/// **Returns** the corresponding solver literal
pub fn solver_literal(
&self,
SolverLiteral(aspif_literal): SolverLiteral,
) -> Result<SolverLiteral, ClingoError> {
let mut solver_literal = 0;
if !unsafe {
clingo_propagate_init_solver_literal(&self.0, aspif_literal, &mut solver_literal)
} {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_init_solver_literal() failed",
));
}
Ok(SolverLiteral(solver_literal))
}
/// Add a watch for the solver literal in the given phase.
///
/// # Arguments
///
/// * `solver_literal` - the solver literal
pub fn add_watch(
&mut self,
SolverLiteral(solver_literal): SolverLiteral,
) -> Result<(), ClingoError> {
if !unsafe { clingo_propagate_init_add_watch(&mut self.0, solver_literal) } {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_init_add_watch() failed",
));
}
Ok(())
}
/// Add a watch for the solver literal in the given phase to the given solver thread.
///
/// # Arguments
///
/// * `solver_literal` - the solver literal
/// * `thread_id` - the id of the solver thread
pub fn add_watch_to_thread(
&mut self,
SolverLiteral(solver_literal): SolverLiteral,
thread_id: u32,
) -> Result<(), ClingoError> {
if !unsafe {
clingo_propagate_init_add_watch_to_thread(&mut self.0, solver_literal, thread_id)
} {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_init_add_watch_to_thread() failed",
));
}
Ok(())
}
/// Get an object to inspect the symbolic atoms.
pub fn symbolic_atoms(&self) -> Result<&SymbolicAtoms, ClingoError> {
let mut atoms_ptr = std::ptr::null() as *const clingo_symbolic_atoms_t;
if !unsafe { clingo_propagate_init_symbolic_atoms(&self.0, &mut atoms_ptr) } {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_init_symbolic_atoms() failed",
));
}
match unsafe { (atoms_ptr as *const SymbolicAtoms).as_ref() } {
Some(x) => Ok(x),
None => Err(ClingoError::FFIError {
msg: "Tried casting a null pointer to &SymbolicAtoms.",
}),
}
}
/// Get an object to inspect the theory atoms.
pub fn theory_atoms(&self) -> Result<&TheoryAtoms, ClingoError> {
let mut atoms_ptr = std::ptr::null() as *const clingo_theory_atoms_t;
if !unsafe { clingo_propagate_init_theory_atoms(&self.0, &mut atoms_ptr) } {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_init_symbolic_atoms() failed",
));
}
match unsafe { (atoms_ptr as *const TheoryAtoms).as_ref() } {
Some(x) => Ok(x),
None => Err(ClingoError::FFIError {
msg: "Tried casting a null pointer to &TheoryAtoms.",
}),
}
}
/// Get the number of threads used in subsequent solving.
///
/// **See:** [`PropagateControl::thread_id()`](struct.PropagateControl.html#method.thread_id)
pub fn number_of_threads(&self) -> usize {
(unsafe { clingo_propagate_init_number_of_threads(&self.0) }) as usize
}
/// Configure when to call the check method of the propagator.
///
/// # Arguments
///
/// * `mode` - bitmask when to call the propagator
///
/// **See:** [`Propagator::check()`](trait.Propagator.html#method.check)
pub fn set_check_mode(&mut self, mode: PropagatorCheckMode) {
unsafe {
clingo_propagate_init_set_check_mode(
&mut self.0,
mode as clingo_propagator_check_mode_t,
)
}
}
/// Get the current check mode of the propagator.
///
/// **Returns** bitmask when to call the propagator
///
/// **See:** [`PropagateInit::set_check_mode()`](struct.PropagateInit.html#method.set_check_mode)
pub fn get_check_mode(&self) -> Result<PropagatorCheckMode, ClingoError> {
PropagatorCheckMode::try_from(
unsafe { clingo_propagate_init_get_check_mode(&self.0) } as u32
)
}
/// Get the top level assignment solver.
///
/// **Returns** the assignment
pub fn assignment(&self) -> Result<&Assignment, ClingoError> {
match unsafe { (clingo_propagate_init_assignment(&self.0) as *const Assignment).as_ref() } {
Some(stm) => Ok(stm),
None => Err(ClingoError::FFIError {
msg: "Tried casting a null pointer to &mut Assignment.",
}),
}
}
/// Add a literal to the solver.
///
/// To be able to use the variable in clauses during propagation or add watches to it, it has to be frozen.
/// Otherwise, it might be removed during preprocessing.
///
/// **Attention** If varibales were added, subsequent calls to functions adding constraints or ::clingo_propagate_init_propagate() are expensive.
/// It is best to add varables in batches.
///
/// # Arguments
///
/// * `freeze` - whether to freeze the literal
/// **Returns** the added literal
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn add_literal(&mut self, freeze: bool) -> Result<&mut SolverLiteral, ClingoError> {
let literal_ptr = std::ptr::null_mut() as *mut clingo_literal_t;
if !unsafe { clingo_propagate_init_add_literal(&mut self.0, freeze, literal_ptr) } {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_init_add_literal() failed",
));
}
match unsafe { (literal_ptr as *mut SolverLiteral).as_mut() } {
Some(x) => Ok(x),
None => Err(ClingoError::FFIError {
msg: "Tried casting a null pointer to &mutSolverLiteral.",
}),
}
}
/// Add the given clause to the solver.
///
/// **Attention** No further calls on the init object or functions on the assignment should be called when the result of this method is false.
///
/// # Arguments
///
/// * `clause` - the clause to add
///
/// **Returns** whether the problem became unsatisfiable
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn add_clause(&mut self, clause: &[SolverLiteral]) -> Result<bool, ClingoError> {
let mut result = false;
if !unsafe {
clingo_propagate_init_add_clause(
&mut self.0,
clause.as_ptr() as *const clingo_literal_t,
clause.len(),
&mut result,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_init_add_clause() failed",
));
}
Ok(result)
}
/// Add the given weight constraint to the solver.
///
/// This function adds a constraint of form `literal <=> { lit=weight | (lit, weight) in literals } >= bound` to the solver.
/// Depending on the type the `<=>` connective can be either a left implication, right implication, or equivalence.
///
/// **Attention** No further calls on the init object or functions on the assignment should be called when the result of this method is false.
///
/// * `literal` - the literal of the constraint
/// * `literals` - the weighted literals
/// * `bound` - the bound of the constraint
/// * `wctype` - the type of the weight constraint
/// * `compare_equal` - if true compare equal instead of less than equal
///
/// **Returns** result indicating whether the problem became unsatisfiable
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn add_weight_constraint(
&mut self,
literal: SolverLiteral,
literals: &[WeightedLiteral],
bound: i32,
wctype: WeigthConstraintType,
compare_equal: bool,
) -> Result<bool, ClingoError> {
let mut result = false;
if !unsafe {
clingo_propagate_init_add_weight_constraint(
&mut self.0,
literal.0,
literals.as_ptr() as *const clingo_weighted_literal_t,
literals.len(),
bound,
wctype as i32,
compare_equal,
&mut result,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_init_add_weight_constraint() failed",
));
}
Ok(result)
}
/// Add the given literal to minimize to the solver.
///
/// This corresponds to a weak constraint of form `:~ literal. [weight@priority]`.
///
/// * `literal` - the literal to minimize
/// * `weight` - the weight of the literal
/// * `priority` - the priority of the literal
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn add_minimize(
&mut self,
literal: SolverLiteral,
weight: i32,
priority: i32,
) -> Result<(), ClingoError> {
if !unsafe { clingo_propagate_init_add_minimize(&mut self.0, literal.0, weight, priority) }
{
return Err(ClingoError::new_internal(
"Call to clingo_propagate_init_add_minimize() failed",
));
}
Ok(())
}
/// Propagates consequences of the underlying problem excluding registered propagators.
///
/// **Note** The function has no effect if SAT-preprocessing is enabled.
///
/// **Attention** No further calls on the init object or functions on the assignment should be called when the result of this method is false.
///
/// **Returns** result indicating whether the problem became unsatisfiable
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn propagate(&mut self) -> Result<bool, ClingoError> {
let mut result = false;
if !unsafe { clingo_propagate_init_propagate(&mut self.0, &mut result) } {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_init_propagate() failed",
));
}
Ok(result)
}
/// Remove the watch for the solver literal in the given phase.
///
/// # Arguments
///
/// * `literal` - the solver literal
pub fn remove_watch(&mut self, literal: &SolverLiteral) -> Result<(), ClingoError> {
if !unsafe { clingo_propagate_init_remove_watch(&mut self.0, literal.0) } {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_init_remove_watch() failed",
));
}
Ok(())
}
/// Remove the watch for the solver literal in the given phase from the given solver thread.
///
/// * `literal` - the solver literal
/// * `thread_id`- the id of the solver thread
pub fn remove_watch_from_thread(
&mut self,
literal: &SolverLiteral,
thread_id: u32,
) -> Result<(), ClingoError> {
if !unsafe {
clingo_propagate_init_remove_watch_from_thread(&mut self.0, literal.0, thread_id)
} {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_init_remove_watch_from_thread() failed",
));
}
Ok(())
}
/// Freeze the given solver literal.
///
/// Any solver literal that is not frozen is subject to simplification and might be removed in a preprocessing step after propagator initialization.
/// A propagator should freeze all literals over which it might add clauses during propagation.
/// Note that any watched literal is automatically frozen and that it does not matter which phase of the literal is frozen.
///
/// * `literal` - the solver literal
pub fn freeze_literal(&mut self, literal: &SolverLiteral) -> Result<(), ClingoError> {
if !unsafe { clingo_propagate_init_freeze_literal(&mut self.0, literal.0) } {
return Err(ClingoError::new_internal(
"Call to clingo_propagate_init_freeze_literal() failed",
));
}
Ok(())
}
}
/// Search handle to a solve call.
#[derive(Debug)]
pub struct GenericSolveHandle<
L: Logger,
P: Propagator,
O: GroundProgramObserver,
F: FunctionHandler,
E: SolveEventHandler,
> {
handle: NonNull<clingo_solve_handle_t>,
ctl: GenericControl<L, P, O, F>,
_event_handler: Box<E>,
}
pub type SolveHandleWithLogger<L> =
GenericSolveHandle<L, defaults::Non, defaults::Non, defaults::Non, defaults::Non>;
pub type SolveHandleWithPropagator<P> =
GenericSolveHandle<defaults::Non, P, defaults::Non, defaults::Non, defaults::Non>;
pub type SolveHandleWithEventHandler<E> =
GenericSolveHandle<defaults::Non, defaults::Non, defaults::Non, defaults::Non, E>;
pub type SolveHandle =
GenericSolveHandle<defaults::Non, defaults::Non, defaults::Non, defaults::Non, defaults::Non>;
impl<
L: Logger,
P: Propagator,
O: GroundProgramObserver,
F: FunctionHandler,
E: SolveEventHandler,
> GenericSolveHandle<L, P, O, F, E>
{
/// Get the next solve result.
///
/// Blocks until the result is ready.
/// When yielding partial solve results can be obtained, i.e.,
/// when a model is ready, the result will be satisfiable but neither the search exhausted nor the optimality proven.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if solving fails
pub fn get(&mut self) -> Result<SolveResult, ClingoError> {
let mut result = 0;
if !unsafe { clingo_solve_handle_get(self.handle.as_ptr(), &mut result) } {
return Err(ClingoError::new_internal(
"Call to clingo_solve_handle_get() failed",
));
}
if let Some(res) = SolveResult::from_bits(result) {
Ok(res)
} else {
eprintln!("Unknown bitflag in clingo_solve_result: {}.", result);
Err(ClingoError::FFIError {
msg: "Unknown bitflag in clingo_solve_result.",
})
}
}
/// Wait for the specified amount of time to check if the next result is ready.
///
/// If the time is set to zero, this function can be used to poll if the search is still active.
/// If the time is negative, the function blocks until the search is finished.
///
/// # Arguments
///
/// * `timeout` - the maximum time to wait
pub fn wait(&mut self, timeout: Duration) -> bool {
let mut result = false;
let timeout_secs = timeout.as_secs_f64();
unsafe { clingo_solve_handle_wait(self.handle.as_ptr(), timeout_secs, &mut result) }
result
}
/// Get the next model or None if there are no more models.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if solving fails
pub fn model(&mut self) -> Result<Option<&Model>, ClingoError> {
let mut model = std::ptr::null_mut() as *const clingo_model_t;
if !unsafe { clingo_solve_handle_model(self.handle.as_ptr(), &mut model) } {
return Err(ClingoError::new_internal(
"Call to clingo_solve_handle_model() failed",
));
}
Ok(unsafe { (model as *const Model).as_ref() })
}
/// Get the next model or None if there are no more models.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if solving fails
pub fn model_mut(&mut self) -> Result<Option<&mut Model>, ClingoError> {
let mut model = std::ptr::null_mut() as *const clingo_model_t;
if !unsafe { clingo_solve_handle_model(self.handle.as_ptr(), &mut model) } {
return Err(ClingoError::new_internal(
"Call to clingo_solve_handle_model() failed",
));
}
Ok(unsafe { (model as *mut Model).as_mut() })
}
/// When a problem is unsatisfiable, get a subset of the assumptions that made the problem unsatisfiable.
///
/// If the program is not unsatisfiable, an empty vector is returned.
///
/// **Returns** the unsatisfiable core
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
pub fn core(&mut self) -> Result<Vec<SolverLiteral>, ClingoError> {
let mut literal_ptr = std::ptr::null();
let mut size: usize = 0;
if !unsafe { clingo_solve_handle_core(self.handle.as_ptr(), &mut literal_ptr, &mut size) } {
return Err(ClingoError::new_internal(
"Call to clingo_solve_handle_core() failed",
));
}
// let literals = unsafe {std::slice::from_raw_parts(literal_ptr, size)};
let mut literals = Vec::<SolverLiteral>::with_capacity(size);
for _ in 0..size {
if literal_ptr.is_null() {
return Err(ClingoError::FFIError {
msg: "clingo_solve_handle_core() returned a null pointer.",
});
}
let nliteral = unsafe { *literal_ptr };
literals.push(SolverLiteral(nliteral));
literal_ptr = unsafe { literal_ptr.offset(1) };
}
Ok(literals)
}
/// Discards the last model and starts the search for the next one.
///
/// If the search has been started asynchronously, this function continues the search in the
/// background.
///
/// **Note:** This function does not block.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if solving fails
pub fn resume(&mut self) -> Result<(), ClingoError> {
if !unsafe { clingo_solve_handle_resume(self.handle.as_ptr()) } {
return Err(ClingoError::new_internal(
"Call to clingo_solve_handle_resume() failed",
));
}
Ok(())
}
/// Stop the running search and block until done.
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if solving fails
pub fn cancel(&mut self) -> Result<(), ClingoError> {
if !unsafe { clingo_solve_handle_cancel(self.handle.as_ptr()) } {
return Err(ClingoError::new_internal(
"Call to clingo_solve_handle_cancel() failed",
));
}
Ok(())
}
/// Stops the running search and releases the handle.
///
/// Blocks until the search is stopped (as if an implicit cancel was called before the handle is
/// released).
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if solving fails
pub fn close(self) -> Result<GenericControl<L, P, O, F>, ClingoError> {
if !unsafe { clingo_solve_handle_close(self.handle.as_ptr()) } {
return Err(ClingoError::new_internal(
"Call to clingo_solve_handle_close() failed",
));
}
Ok(self.ctl)
}
}
pub struct OptimalModels<
L: Logger,
P: Propagator,
O: GroundProgramObserver,
F: FunctionHandler,
E: SolveEventHandler,
>(GenericSolveHandle<L, P, O, F, E>);
impl<
L: Logger,
P: Propagator,
O: GroundProgramObserver,
F: FunctionHandler,
E: SolveEventHandler,
> Iterator for OptimalModels<L, P, O, F, E>
{
type Item = MModel;
fn next(&mut self) -> Option<Self::Item> {
loop {
self.0.resume().expect("Failed resume on solve handle.");
match self.0.model() {
Ok(Some(model)) => {
if model.optimality_proven().unwrap() {
let symbols = model.symbols(ShowType::SHOWN).unwrap();
let cost = model.cost().unwrap();
return Some(MModel {
symbols,
cost,
model_type: model.model_type().unwrap(),
number: model.number().unwrap(),
});
}
}
Ok(None) => {
return None;
}
Err(e) => panic!("{}", e),
}
}
}
}
pub struct AllModels<
L: Logger,
P: Propagator,
O: GroundProgramObserver,
F: FunctionHandler,
E: SolveEventHandler,
>(GenericSolveHandle<L, P, O, F, E>);
impl<
L: Logger,
P: Propagator,
O: GroundProgramObserver,
F: FunctionHandler,
E: SolveEventHandler,
> Iterator for AllModels<L, P, O, F, E>
{
type Item = MModel;
fn next(&mut self) -> Option<Self::Item> {
loop {
self.0.resume().expect("Failed resume on solve handle.");
match self.0.model() {
Ok(Some(model)) => {
let symbols = model.symbols(ShowType::SHOWN).unwrap();
let cost = model.cost().unwrap();
return Some(MModel {
symbols,
cost,
model_type: model.model_type().unwrap(),
number: model.number().unwrap(),
});
}
Ok(None) => {
return None;
}
Err(e) => panic!("{}", e),
}
}
}
}
pub struct MModel {
pub symbols: Vec<Symbol>,
pub cost: Vec<i64>,
pub model_type: ModelType,
pub number: u64,
}
// #[doc = "! Callback to customize clingo main function."]
// #[doc = "!"]
// #[doc = "! @param[in] control corresponding control object"]
// #[doc = "! @param[in] files files passed via command line arguments"]
// #[doc = "! @param[in] size number of files"]
// #[doc = "! @param[in] data user data for the callback"]
// #[doc = "!"]
// #[doc = "! @return whether the call was successful"]
// pub type clingo_main_function_t = ::std::option::Option<
// unsafe extern "C" fn(
// control: *mut clingo_control_t,
// files: *const *const ::std::os::raw::c_char,
// size: usize,
// data: *mut ::std::os::raw::c_void,
// ) -> bool,
// >;
// #[doc = "! Callback to print a model in default format."]
// #[doc = "!"]
// #[doc = "! @param[in] data user data for the callback"]
// #[doc = "!"]
// #[doc = "! @return whether the call was successful"]
// pub type clingo_default_model_printer_t =
// ::std::option::Option<unsafe extern "C" fn(data: *mut ::std::os::raw::c_void) -> bool>;
// #[doc = "! Callback to customize model printing."]
// #[doc = "!"]
// #[doc = "! @param[in] model the model"]
// #[doc = "! @param[in] printer the default model printer"]
// #[doc = "! @param[in] printer_data user data for the printer"]
// #[doc = "! @param[in] data user data for the callback"]
// #[doc = "!"]
// #[doc = "! @return whether the call was successful"]
// pub type clingo_model_printer_t = ::std::option::Option<
// unsafe extern "C" fn(
// model: *const clingo_model_t,
// printer: clingo_default_model_printer_t,
// printer_data: *mut ::std::os::raw::c_void,
// data: *mut ::std::os::raw::c_void,
// ) -> bool,
// >;
// #[doc = "! This struct contains a set of functions to customize the clingo application."]
// #[repr(C)]
// #[derive(Debug, Copy, Clone)]
// pub struct clingo_application {
// #[doc = "!< callback to obtain program name"]
// pub program_name: ::std::option::Option<
// unsafe extern "C" fn(data: *mut ::std::os::raw::c_void) -> *const ::std::os::raw::c_char,
// >,
// #[doc = "!< callback to obtain version information"]
// pub version: ::std::option::Option<
// unsafe extern "C" fn(data: *mut ::std::os::raw::c_void) -> *const ::std::os::raw::c_char,
// >,
// #[doc = "!< callback to obtain message limit"]
// pub message_limit: ::std::option::Option<
// unsafe extern "C" fn(data: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_uint,
// >,
// #[doc = "!< callback to override clingo's main function"]
// pub main: clingo_main_function_t,
// #[doc = "!< callback to override default logger"]
// pub logger: clingo_logger_t,
// #[doc = "!< callback to override default model printing"]
// pub printer: clingo_model_printer_t,
// #[doc = "!< callback to register options"]
// pub register_options: ::std::option::Option<
// unsafe extern "C" fn(
// options: *mut clingo_options_t,
// data: *mut ::std::os::raw::c_void,
// ) -> bool,
// >,
// #[doc = "!< callback validate options"]
// pub validate_options:
// ::std::option::Option<unsafe extern "C" fn(data: *mut ::std::os::raw::c_void) -> bool>,
// }
// #[doc = "! This struct contains a set of functions to customize the clingo application."]
// pub type clingo_application_t = clingo_application;
// pub trait Application {
// fn program_name(&self) -> String;
// }
// unsafe extern "C" fn unsafe_program_name<T: Application>(data: *mut ::std::os::raw::c_void) -> *const ::std::os::raw::c_char {
// // check for null pointers
// if data.is_null()
// {
// set_internal_error(
// ErrorType::Runtime,
// "unsafe_program_name() got a null pointer.",
// );
// return std::ptr::null();
// }
// let data = &mut *(data as *mut T);
// let name = data.program_name();
// let c_name: CStr = name.into();
// c_name.as_ptr()
// }
// extern "C" {
// #[doc = "! Add an option that is processed with a custom parser."]
// #[doc = "!"]
// #[doc = "! Note that the parser also has to take care of storing the semantic value of"]
// #[doc = "! the option somewhere."]
// #[doc = "!"]
// #[doc = "! Parameter option specifies the name(s) of the option."]
// #[doc = "! For example, \"ping,p\" adds the short option \"-p\" and its long form \"--ping\"."]
// #[doc = "! It is also possible to associate an option with a help level by adding \",@l\" to the option specification."]
// #[doc = "! Options with a level greater than zero are only shown if the argument to help is greater or equal to l."]
// #[doc = "!"]
// #[doc = "! @param[in] options object to register the option with"]
// #[doc = "! @param[in] group options are grouped into sections as given by this string"]
// #[doc = "! @param[in] option specifies the command line option"]
// #[doc = "! @param[in] description the description of the option"]
// #[doc = "! @param[in] parse callback to parse the value of the option"]
// #[doc = "! @param[in] data user data for the callback"]
// #[doc = "! @param[in] multi whether the option can appear multiple times on the command-line"]
// #[doc = "! @param[in] argument optional string to change the value name in the generated help output"]
// #[doc = "! @return whether the call was successful"]
// pub fn clingo_options_add(
// options: *mut clingo_options_t,
// group: *const ::std::os::raw::c_char,
// option: *const ::std::os::raw::c_char,
// description: *const ::std::os::raw::c_char,
// parse: ::std::option::Option<
// unsafe extern "C" fn(
// value: *const ::std::os::raw::c_char,
// data: *mut ::std::os::raw::c_void,
// ) -> bool,
// >,
// data: *mut ::std::os::raw::c_void,
// multi: bool,
// argument: *const ::std::os::raw::c_char,
// ) -> bool;
// }
// extern "C" {
// #[doc = "! Add an option that is a simple flag."]
// #[doc = "!"]
// #[doc = "! This function is similar to @ref clingo_options_add() but simpler because it only supports flags, which do not have values."]
// #[doc = "! If a flag is passed via the command-line the parameter target is set to true."]
// #[doc = "!"]
// #[doc = "! @param[in] options object to register the option with"]
// #[doc = "! @param[in] group options are grouped into sections as given by this string"]
// #[doc = "! @param[in] option specifies the command line option"]
// #[doc = "! @param[in] description the description of the option"]
// #[doc = "! @param[in] target boolean set to true if the flag is given on the command-line"]
// #[doc = "! @return whether the call was successful"]
// pub fn clingo_options_add_flag(
// options: *mut clingo_options_t,
// group: *const ::std::os::raw::c_char,
// option: *const ::std::os::raw::c_char,
// description: *const ::std::os::raw::c_char,
// target: *mut bool,
// ) -> bool;
// }
// extern "C" {
// #[doc = "! Run clingo with a customized main function (similar to python and lua embedding)."]
// #[doc = "!"]
// #[doc = "! @param[in] application struct with callbacks to override default clingo functionality"]
// #[doc = "! @param[in] arguments command line arguments"]
// #[doc = "! @param[in] size number of arguments"]
// #[doc = "! @param[in] data user data to pass to callbacks in application"]
// #[doc = "! @return exit code to return from main function"]
// pub fn clingo_mai<T: Application>(app:&mut T, arguments: Vec<String>) -> Result<i32,ClingoError> {
// let c_app = clingo_application{
// program_name: Some(<T>::unsafe_program_name::<T>),
// version: Some(<T>::unsafe_version::<T>),
// message_limit: Some(<T>::unsafe_message_limit::<T>),
// main: Some(<T>::unsafe_main::<T>),
// logger: Some(<T>::unsafe_logger::<T>),
// printer: Some(<T>::unsafe_printer::<T>),
// register_options: Some(<T>::unsafe_register_options::<T>),
// validate_options: Some(<T>::unsafe_validate_options::<T>)
// };
// let mut args = vec![];
// for arg in arguments {
// args.push(CString::new(arg)?);
// }
// // convert the strings to raw pointers
// let c_args = args
// .iter()
// .map(|arg| arg.as_ptr())
// .collect::<Vec<*const c_char>>();
// Ok(unsafe { clingo_main(&mut c_app, c_args.as_ptr(), arguments.len(), app as *mut c_void) } )
// }
// pub fn clingo_main(
// application: *mut clingo_application_t,
// arguments: *const *const ::std::os::raw::c_char,
// size: usize,
// data: *mut ::std::os::raw::c_void,
// ) -> ::std::os::raw::c_int;
// }
/// Internalize a string.
///
/// This functions takes a string as input and returns an equal unique string
/// that is (at the moment) not freed until the program is closed.
///
/// # Arguments
///
/// * `string` - the string to internalize
/// * `result` - the internalized string
///
/// # Errors
///
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// - [`ClingoError::Utf8Error`](enum.ClingoError.html#variant.Utf8Error)
pub fn add_string(string: &str) -> Result<&'static str, ClingoError> {
let in_cstr = CString::new(string)?;
let mut out_ptr = std::ptr::null() as *const c_char;
if !unsafe { clingo_add_string(in_cstr.as_ptr(), &mut out_ptr) } {
return Err(ClingoError::new_internal(
"Call to clingo_add_string() failed",
));
}
if out_ptr.is_null() {
return Err(ClingoError::FFIError {
msg: "clingo_add_string returned a null pointer.",
});
}
let out_cstr = unsafe { CStr::from_ptr(out_ptr) };
Ok(out_cstr.to_str()?)
}
fn internalize_string(string: &str) -> Result<*const c_char, ClingoError> {
let in_cstr = CString::new(string)?;
let mut out_ptr = std::ptr::null() as *const c_char;
if !unsafe { clingo_add_string(in_cstr.as_ptr(), &mut out_ptr) } {
return Err(ClingoError::new_internal(
"Call to clingo_add_string() failed",
));
}
if out_ptr.is_null() {
Err(ClingoError::FFIError {
msg: "clingo_add_string returned a null pointer.",
})?
}
Ok(out_ptr)
}
/// Parse a term in string form.
///
/// The result of this function is a symbol. The input term can contain
/// unevaluated functions, which are evaluated during parsing.
///
/// # Arguments
///
/// * `string` - the string to parse
///
/// # Errors
///
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `string` contains a nul byte
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if parsing fails
pub fn parse_term(string: &str) -> Result<Symbol, ClingoError> {
let c_str = CString::new(string)?;
let mut symbol = 0;
if !unsafe { clingo_parse_term(c_str.as_ptr(), None, std::ptr::null_mut(), 0, &mut symbol) } {
return Err(ClingoError::new_internal(
"Call to clingo_parse_term() failed",
));
}
Ok(Symbol(symbol))
}
/// Parse a term in string form.
///
/// The result of this function is a symbol. The input term can contain
/// unevaluated functions, which are evaluated during parsing.
///
/// # Arguments
///
/// * `string` - the string to parse
/// * `logger` - logger to report warnings during parsing
/// * `message_limit` - maximum number of times to call the logger
///
/// # Errors
///
/// - [`ClingoError::NulError`](enum.ClingoError.html#variant.NulError) - if `string` contains a nul byte
/// - [`ClingoError::InternalError`](enum.ClingoError.html#variant.InternalError) with [`ErrorCode::BadAlloc`](enum.ErrorCode.html#variant.BadAlloc)
/// or [`ErrorCode::Runtime`](enum.ErrorCode.html#variant.Runtime) if parsing fails
pub fn parse_term_with_logger<L: Logger>(
string: &str,
logger: &mut L,
message_limit: u32,
) -> Result<Symbol, ClingoError> {
let c_str = CString::new(string)?;
let logger = logger as *mut L;
let mut symbol = 0;
if !unsafe {
clingo_parse_term(
c_str.as_ptr(),
Some(unsafe_logging_callback::<L> as LoggingCallback),
logger as *mut c_void,
message_limit,
&mut symbol,
)
} {
return Err(ClingoError::new_internal(
"Call to clingo_parse_term() failed",
));
}
Ok(Symbol(symbol))
}
/// An instance of this struct has to be registered with a solver to observe ground directives as they are passed to the solver.
///
/// **Note:** This interface is closely modeled after the aspif format.
/// For more information please refer to the specification of the aspif format.
///
/// Not all callbacks have to be implemented and can be set to NULL if not needed.
/// If one of the callbacks in the struct fails, grounding is stopped.
/// If a non-recoverable clingo API call fails, a callback must return false.
/// Otherwise ::clingo_error_unknown should be set and false returned.
///
// See [`Control::register_observer`](struct.Control.html#method.register_observer).
pub trait GroundProgramObserver {
/// Called once in the beginning.
///
/// If the incremental flag is true, there can be multiple calls to
/// [`Control::solve()`](struct.Control.html#method.solve).
///
/// # Arguments
///
/// * `incremental` - whether the program is incremental
///
/// **Returns** whether the call was successful
fn init_program(&mut self, _incremental: bool) -> bool {
true
}
/// Marks the beginning of a block of directives passed to the solver.
///
/// **See:** [`end_step()`](trait.GroundProgramObserver.html#tymethod.end_step)
///
/// **Returns** whether the call was successful
fn begin_step(&mut self) -> bool {
true
}
/// Marks the end of a block of directives passed to the solver.
///
/// This function is called before solving starts.
///
/// **See:** [`begin_step()`](trait.GroundProgramObserver.html#tymethod.begin_step)
///
/// **Returns** whether the call was successful
fn end_step(&mut self) -> bool {
true
}
/// Observe rules passed to the solver.
///
/// # Arguments
///
/// * `choice` - determines if the head is a choice or a disjunction
/// * `head` - the head atoms
/// * `body` - the body literals
///
/// **Returns** whether the call was successful
fn rule(&mut self, _choice: bool, _head: &[Atom], _body: &[SolverLiteral]) -> bool {
true
}
/// Observe weight rules passed to the solver.
///
/// # Arguments
///
/// * `choice` - determines if the head is a choice or a disjunction
/// * `head` - the head atoms
/// * `lower_bound` - the lower bound of the weight rule
/// * `body` - the weighted body literals
///
/// **Returns** whether the call was successful
fn weight_rule(
&mut self,
_choice: bool,
_head: &[Atom],
_lower_bound: i32,
_body: &[WeightedLiteral],
) -> bool {
true
}
/// Observe minimize constraints (or weak constraints) passed to the solver.
///
/// # Arguments
///
/// * `priority` - the priority of the constraint
/// * `literals` - the weighted literals whose sum to minimize
///
/// **Returns** whether the call was successful
fn minimize(&mut self, _priority: i32, _literals: &[WeightedLiteral]) -> bool {
true
}
/// Observe projection directives passed to the solver.
///
/// # Arguments
///
/// * `atoms` - the atoms to project on
///
/// **Returns** whether the call was successful
fn project(&mut self, _atoms: &[Atom]) -> bool {
true
}
/// Observe shown atoms passed to the solver.
///
/// **Note:** Facts do not have an associated aspif atom.
/// The value of the atom is set to zero.
///
/// # Arguments
///
/// * `symbol` - the symbolic representation of the atom
/// * `atom` - the aspif atom (0 for facts)
///
/// **Returns** whether the call was successful
fn output_atom(&mut self, _symbol: Symbol, _atom: Atom) -> bool {
true
}
/// Observe shown terms passed to the solver.
///
/// # Arguments
///
/// * `symbol` - the symbolic representation of the term
/// * `condition` - the literals of the condition
///
/// **Returns** whether the call was successful
fn output_term(&mut self, _symbol: Symbol, _condition: &[SolverLiteral]) -> bool {
true
}
/// Observe shown csp variables passed to the solver.
///
/// # Arguments
///
/// * `symbol` - the symbolic representation of the variable
/// * `value` - the value of the variable
/// * `condition` - the literals of the condition
///
/// **Returns** whether the call was successful
fn output_csp(&mut self, _symbol: Symbol, _value: i32, _condition: &[SolverLiteral]) -> bool {
true
}
/// Observe external statements passed to the solver.
///
/// # Arguments
///
/// * `atom` - the external atom
/// * `etype` - the type of the external statement
///
/// **Returns** whether the call was successful
fn external(&mut self, _atom: Atom, _type_: ExternalType) -> bool {
true
}
/// Observe assumption directives passed to the solver.
///
/// # Arguments
///
/// * `literals` - the literals to assume (positive literals are true and negative literals
/// false for the next solve call)
///
/// **Returns** whether the call was successful
fn assume(&mut self, _literals: &[SolverLiteral]) -> bool {
true
}
/// Observe heuristic directives passed to the solver.
///
/// # Arguments
///
/// * `atom` - the target atom
/// * `htype` - the type of the heuristic modification
/// * `bias` - the heuristic bias
/// * `priority` - the heuristic priority
/// * `condition` - the condition under which to apply the heuristic modification
///
/// **Returns** whether the call was successful
fn heuristic(
&mut self,
_atom: Atom,
_type_: HeuristicType,
_bias: i32,
_priority: u32,
_condition: &[SolverLiteral],
) -> bool {
true
}
/// Observe edge directives passed to the solver.
///
/// # Arguments
///
/// * `node_u` - the start vertex of the edge
/// * `node_v` - the end vertex of the edge
/// * `condition` - the condition under which the edge is part of the graph
///
/// **Returns** whether the call was successful
fn acyc_edge(&mut self, _node_u: i32, _node_v: i32, _condition: &[SolverLiteral]) -> bool {
true
}
/// Observe numeric theory terms.
///
/// # Arguments
///
/// * `term_id` - the id of the term
/// * `number` - the value of the term
///
/// **Returns** whether the call was successful
fn theory_term_number(&mut self, _term_id: Id, _number: i32) -> bool {
true
}
/// Observe string theory terms.
///
/// # Arguments
///
/// * `term_id` - the id of the term
/// * `name` - the value of the term
///
/// **Returns** whether the call was successful
fn theory_term_string(&mut self, _term_id: Id, _name: &str) -> bool {
true
}
/// Observe compound theory terms.
///
/// The name_id_or_type gives the type of the compound term:
/// - if it is -1, then it is a tuple
/// - if it is -2, then it is a set
/// - if it is -3, then it is a list
/// - otherwise, it is a function and name_id_or_type refers to the id of the name (in form of a
/// string term)
///
/// # Arguments
///
/// * `term_id` - the id of the term
/// * `name_id_or_type` - the name or type of the term
/// * `arguments` - the arguments of the term
///
/// **Returns** whether the call was successful
fn theory_term_compound(
&mut self,
_term_id: Id,
_name_id_or_type: i32,
_arguments: &[Id],
) -> bool {
true
}
/// Observe theory elements.
///
/// # Arguments
///
/// * `element_id` - the id of the element
/// * `terms` - the term tuple of the element
/// * `condition` - the condition of the element
///
/// **Returns** whether the call was successful
fn theory_element(
&mut self,
_element_id: Id,
_terms: &[Id],
_condition: &[SolverLiteral],
) -> bool {
true
}
/// Observe theory atoms without guard.
///
/// # Arguments
///
/// * `atom_id_or_zero` - the id of the atom or zero for directives
/// * `term_id` - the term associated with the atom
/// * `elements` - the elements of the atom
///
/// **Returns** whether the call was successful
fn theory_atom(&mut self, _atom_id_or_zero: Id, _term_id: Id, _elements: &[Id]) -> bool {
true
}
/// Observe theory atoms with guard.
///
/// # Arguments
///
/// * `atom_id_or_zero` - the id of the atom or zero for directives
/// * `term_id` - the term associated with the atom
/// * `elements` - the elements of the atom
/// * `operator_id` - the id of the operator (a string term)
/// * `right_hand_side_id` - the id of the term on the right hand side of the atom
///
/// **Returns** whether the call was successful
fn theory_atom_with_guard(
&mut self,
_atom_id_or_zero: Id,
_term_id: Id,
_elements: &[Id],
_operator_id: Id,
_right_hand_side_id: Id,
) -> bool {
true
}
}
unsafe extern "C" fn unsafe_init_program<T: GroundProgramObserver>(
incremental: bool,
gpo: *mut c_void,
) -> bool {
if let Some(gpo) = (gpo as *mut T).as_mut() {
gpo.init_program(incremental)
} else {
set_internal_error(
ErrorType::Runtime,
"unsafe_init_program tried casting a null pointer to &mut GroundProgramObserver.",
);
false
}
}
unsafe extern "C" fn unsafe_begin_step<T: GroundProgramObserver>(gpo: *mut c_void) -> bool {
if let Some(gpo) = (gpo as *mut T).as_mut() {
gpo.begin_step()
} else {
set_internal_error(
ErrorType::Runtime,
"unsafe_begin_step tried casting a null pointer to &mut GroundProgramObserver.",
);
false
}
}
unsafe extern "C" fn unsafe_end_step<T: GroundProgramObserver>(gpo: *mut c_void) -> bool {
if let Some(gpo) = (gpo as *mut T).as_mut() {
gpo.end_step()
} else {
set_internal_error(
ErrorType::Runtime,
"unsafe_end_step tried casting a null pointer to &mut GroundProgramObserver.",
);
false
}
}
unsafe extern "C" fn unsafe_rule<T: GroundProgramObserver>(
choice: bool,
head: *const clingo_atom_t,
head_size: usize,
body: *const clingo_literal_t,
body_size: usize,
gpo: *mut c_void,
) -> bool {
// check for null pointers
if (head_size > 0 && head.is_null()) | (body_size > 0 && body.is_null()) | gpo.is_null() {
set_internal_error(ErrorType::Runtime, "unsafe_rule() got a null pointer.");
return false;
}
let head = std::slice::from_raw_parts(head as *const Atom, head_size);
let body = std::slice::from_raw_parts(body as *const SolverLiteral, body_size);
let gpo = &mut *(gpo as *mut T);
gpo.rule(choice, head, body)
}
unsafe extern "C" fn unsafe_minimize<T: GroundProgramObserver>(
priority: clingo_weight_t,
literals: *const clingo_weighted_literal_t,
size: usize,
gpo: *mut c_void,
) -> bool {
// check for null pointers
if (size > 0 && literals.is_null()) | gpo.is_null() {
set_internal_error(ErrorType::Runtime, "unsafe_minimize() got a null pointer.");
return false;
}
let literals = std::slice::from_raw_parts(literals as *const WeightedLiteral, size);
let gpo = &mut *(gpo as *mut T);
gpo.minimize(priority, literals)
}
unsafe extern "C" fn unsafe_project<T: GroundProgramObserver>(
atoms: *const clingo_atom_t,
size: usize,
gpo: *mut c_void,
) -> bool {
// check for null pointers
if (size > 0 && atoms.is_null()) | gpo.is_null() {
set_internal_error(ErrorType::Runtime, "unsafe_project() got a null pointer.");
return false;
}
let atoms = std::slice::from_raw_parts(atoms as *const Atom, size);
let gpo = &mut *(gpo as *mut T);
gpo.project(atoms)
}
unsafe extern "C" fn unsafe_weight_rule<T: GroundProgramObserver>(
choice: bool,
head: *const clingo_atom_t,
head_size: usize,
lower_bound: clingo_weight_t,
body: *const clingo_weighted_literal_t,
body_size: usize,
gpo: *mut c_void,
) -> bool {
// check for null pointers
if (head_size > 0 && head.is_null()) | (body_size > 0 && body.is_null()) | gpo.is_null() {
set_internal_error(
ErrorType::Runtime,
"unsafe_weight_rule() got a null pointer.",
);
return false;
}
let head = std::slice::from_raw_parts(head as *const Atom, head_size);
let body = std::slice::from_raw_parts(body as *const WeightedLiteral, body_size);
let gpo = &mut *(gpo as *mut T);
gpo.weight_rule(choice, head, lower_bound, body)
}
unsafe extern "C" fn unsafe_output_atom<T: GroundProgramObserver>(
symbol: clingo_symbol_t,
atom: clingo_atom_t,
gpo: *mut c_void,
) -> bool {
if let Some(gpo) = (gpo as *mut T).as_mut() {
gpo.output_atom(Symbol(symbol), Atom(atom))
} else {
set_internal_error(
ErrorType::Runtime,
"unsafe_output_atom() tried casting a null pointer to &mut GroundProgramObserver.",
);
false
}
}
unsafe extern "C" fn unsafe_output_term<T: GroundProgramObserver>(
symbol: clingo_symbol_t,
condition: *const clingo_literal_t,
size: usize,
gpo: *mut c_void,
) -> bool {
// check for null pointers
if (size > 0 && condition.is_null()) | gpo.is_null() {
set_internal_error(
ErrorType::Runtime,
"unsafe_output_term() got a null pointer.",
);
return false;
}
let condition = std::slice::from_raw_parts(condition as *const SolverLiteral, size);
let gpo = &mut *(gpo as *mut T);
gpo.output_term(Symbol(symbol), condition)
}
unsafe extern "C" fn unsafe_output_csp<T: GroundProgramObserver>(
symbol: clingo_symbol_t,
value: ::std::os::raw::c_int,
condition: *const clingo_literal_t,
size: usize,
gpo: *mut c_void,
) -> bool {
// check for null pointers
if (size > 0 && condition.is_null()) | gpo.is_null() {
set_internal_error(
ErrorType::Runtime,
"unsafe_output_csp() got a null pointer.",
);
return false;
}
let condition = std::slice::from_raw_parts(condition as *const SolverLiteral, size);
let gpo = &mut *(gpo as *mut T);
gpo.output_csp(Symbol(symbol), value, condition)
}
unsafe extern "C" fn unsafe_external<T: GroundProgramObserver>(
atom: clingo_atom_t,
etype: clingo_external_type_t,
gpo: *mut c_void,
) -> bool {
// check for null pointers
if gpo.is_null() {
set_internal_error(ErrorType::Runtime, "unsafe_external() got a null pointer.");
return false;
}
let gpo = &mut *(gpo as *mut T);
match ExternalType::try_from(etype as u32) {
Err(e) => {
eprintln!("Error in unsafe_external(): {}.", e);
set_internal_error(ErrorType::Runtime, "Error in unsafe_external().");
false
}
Ok(etype) => gpo.external(Atom(atom), etype),
}
}
unsafe extern "C" fn unsafe_assume<T: GroundProgramObserver>(
literals: *const clingo_literal_t,
size: usize,
gpo: *mut c_void,
) -> bool {
// check for null pointers
if (size > 0 && literals.is_null()) | gpo.is_null() {
set_internal_error(ErrorType::Runtime, "unsafe_assume() got a null pointer.");
return false;
}
let literals = std::slice::from_raw_parts(literals as *const SolverLiteral, size);
let gpo = &mut *(gpo as *mut T);
gpo.assume(literals)
}
unsafe extern "C" fn unsafe_heuristic<T: GroundProgramObserver>(
atom: clingo_atom_t,
htype: clingo_heuristic_type_t,
bias: ::std::os::raw::c_int,
priority: ::std::os::raw::c_uint,
condition: *const clingo_literal_t,
size: usize,
gpo: *mut c_void,
) -> bool {
// check for null pointers
if (size > 0 && condition.is_null()) | gpo.is_null() {
set_internal_error(ErrorType::Runtime, "unsafe_heuristic() got a null pointer.");
return false;
}
let condition = std::slice::from_raw_parts(condition as *const SolverLiteral, size);
let gpo = &mut *(gpo as *mut T);
match HeuristicType::try_from(htype as u32) {
Err(e) => {
eprintln!("Error in unsafe_heuristic(): {}.", e);
set_internal_error(ErrorType::Runtime, "Error in unsafe_heuristic().");
false
}
Ok(htype) => gpo.heuristic(Atom(atom), htype, bias, priority, condition),
}
}
unsafe extern "C" fn unsafe_acyc_edge<T: GroundProgramObserver>(
node_u: ::std::os::raw::c_int,
node_v: ::std::os::raw::c_int,
condition: *const clingo_literal_t,
size: usize,
gpo: *mut c_void,
) -> bool {
// check for null pointers
if (size > 0 && condition.is_null()) | gpo.is_null() {
set_internal_error(ErrorType::Runtime, "unsafe_heuristic() got a null pointer.");
return false;
}
let condition = std::slice::from_raw_parts(condition as *const SolverLiteral, size);
let gpo = &mut *(gpo as *mut T);
gpo.acyc_edge(node_u, node_v, condition)
}
unsafe extern "C" fn unsafe_theory_term_number<T: GroundProgramObserver>(
term_id: clingo_id_t,
number: ::std::os::raw::c_int,
gpo: *mut c_void,
) -> bool {
if let Some(gpo) = (gpo as *mut T).as_mut() {
gpo.theory_term_number(Id(term_id), number)
} else {
set_internal_error(
ErrorType::Runtime,
"unsafe_theory_term_number tried casting a null pointer to &mut GroundProgramObserver.",
);
false
}
}
unsafe extern "C" fn unsafe_theory_term_string<T: GroundProgramObserver>(
term_id: clingo_id_t,
name: *const c_char,
gpo: *mut c_void,
) -> bool {
// check for null pointers
if name.is_null() | gpo.is_null() {
set_internal_error(
ErrorType::Runtime,
"unsafe_theory_term_string() got a null pointer.",
);
return false;
}
let name = CStr::from_ptr(name);
let gpo = &mut *(gpo as *mut T);
match name.to_str() {
Ok(name) => gpo.theory_term_string(Id(term_id), name),
Err(e) => {
eprintln!("Utf8Error in unsafe theory_term_string: {}", e);
set_internal_error(
ErrorType::Runtime,
"Utf8Error in unsafe theory_term_string.",
);
false
}
}
}
unsafe extern "C" fn unsafe_theory_term_compound<T: GroundProgramObserver>(
term_id: clingo_id_t,
name_id_or_type: ::std::os::raw::c_int,
arguments: *const clingo_id_t,
size: usize,
gpo: *mut c_void,
) -> bool {
// check for null pointers
if (size > 0 && arguments.is_null()) | gpo.is_null() {
set_internal_error(
ErrorType::Runtime,
"unsafe_theory_term_compound() got a null pointer.",
);
return false;
}
let arguments = std::slice::from_raw_parts(arguments as *const Id, size);
let gpo = &mut *(gpo as *mut T);
gpo.theory_term_compound(Id(term_id), name_id_or_type, arguments)
}
unsafe extern "C" fn unsafe_theory_element<T: GroundProgramObserver>(
element_id: clingo_id_t,
terms: *const clingo_id_t,
terms_size: usize,
condition: *const clingo_literal_t,
condition_size: usize,
gpo: *mut c_void,
) -> bool {
// check for null pointers
if (terms_size > 0 && terms.is_null())
| (condition_size > 0 && condition.is_null())
| gpo.is_null()
{
set_internal_error(
ErrorType::Runtime,
"unsafe_theory_element() got a null pointer.",
);
return false;
}
let terms = std::slice::from_raw_parts(terms as *const Id, terms_size);
let condition = std::slice::from_raw_parts(condition as *const SolverLiteral, condition_size);
let gpo = &mut *(gpo as *mut T);
gpo.theory_element(Id(element_id), terms, condition)
}
unsafe extern "C" fn unsafe_theory_atom<T: GroundProgramObserver>(
atom_id_or_zero: clingo_id_t,
term_id: clingo_id_t,
elements: *const clingo_id_t,
size: usize,
gpo: *mut c_void,
) -> bool {
// check for null pointers
if (size > 0 && elements.is_null()) | gpo.is_null() {
set_internal_error(
ErrorType::Runtime,
"unsafe_theory_atom() got a null pointer.",
);
return false;
}
let elements = std::slice::from_raw_parts(elements as *const Id, size);
let gpo = &mut *(gpo as *mut T);
gpo.theory_atom(Id(atom_id_or_zero), Id(term_id), elements)
}
unsafe extern "C" fn unsafe_theory_atom_with_guard<T: GroundProgramObserver>(
atom_id_or_zero: clingo_id_t,
term_id: clingo_id_t,
elements: *const clingo_id_t,
size: usize,
operator_id: clingo_id_t,
right_hand_side_id: clingo_id_t,
gpo: *mut c_void,
) -> bool {
// check for null pointers
if (size > 0 && elements.is_null()) | gpo.is_null() {
set_internal_error(
ErrorType::Runtime,
"unsafe_theory_atom_with_guard() got a null pointer.",
);
return false;
}
let elements = std::slice::from_raw_parts(elements as *const Id, size);
let gpo = &mut *(gpo as *mut T);
gpo.theory_atom_with_guard(
Id(atom_id_or_zero),
Id(term_id),
elements,
Id(operator_id),
Id(right_hand_side_id),
)
}
/// helper types and traits to simplify conversion from structs to clingo symbols
pub trait ToSymbol {
fn symbol(&self) -> Result<Symbol, ClingoError>;
}
impl ToSymbol for Symbol {
fn symbol(&self) -> Result<Symbol, ClingoError> {
Ok(*self)
}
}
// Due to a temporary restriction in Rust's type system, these function are only implemented on tuples of arity 12 or less.
// In the future, this may change.
impl ToSymbol for () {
fn symbol(&self) -> Result<Symbol, ClingoError> {
Symbol::create_function("", &[], true)
}
}
impl<A: ToSymbol, B: ToSymbol> ToSymbol for (A, B) {
fn symbol(&self) -> Result<Symbol, ClingoError> {
Symbol::create_function("", &[self.0.symbol()?, self.1.symbol()?], true)
}
}
impl<A: ToSymbol, B: ToSymbol, C: ToSymbol> ToSymbol for (A, B, C) {
fn symbol(&self) -> Result<Symbol, ClingoError> {
let tempvec = vec![self.0.symbol()?, self.1.symbol()?, self.2.symbol()?];
Symbol::create_function("", &tempvec, true)
}
}
impl<A: ToSymbol, B: ToSymbol, C: ToSymbol, D: ToSymbol> ToSymbol for (A, B, C, D) {
fn symbol(&self) -> Result<Symbol, ClingoError> {
let tempvec = vec![
self.0.symbol()?,
self.1.symbol()?,
self.2.symbol()?,
self.3.symbol()?,
];
Symbol::create_function("", &tempvec, true)
}
}
impl<A: ToSymbol, B: ToSymbol, C: ToSymbol, D: ToSymbol, E: ToSymbol> ToSymbol for (A, B, C, D, E) {
fn symbol(&self) -> Result<Symbol, ClingoError> {
let tempvec = vec![
self.0.symbol()?,
self.1.symbol()?,
self.2.symbol()?,
self.3.symbol()?,
self.4.symbol()?,
];
Symbol::create_function("", &tempvec, true)
}
}
impl<A: ToSymbol, B: ToSymbol, C: ToSymbol, D: ToSymbol, E: ToSymbol, F: ToSymbol> ToSymbol
for (A, B, C, D, E, F)
{
fn symbol(&self) -> Result<Symbol, ClingoError> {
let tempvec = vec![
self.0.symbol()?,
self.1.symbol()?,
self.2.symbol()?,
self.3.symbol()?,
self.4.symbol()?,
self.5.symbol()?,
];
Symbol::create_function("", &tempvec, true)
}
}
impl<A: ToSymbol, B: ToSymbol, C: ToSymbol, D: ToSymbol, E: ToSymbol, F: ToSymbol, G: ToSymbol>
ToSymbol for (A, B, C, D, E, F, G)
{
fn symbol(&self) -> Result<Symbol, ClingoError> {
let tempvec = vec![
self.0.symbol()?,
self.1.symbol()?,
self.2.symbol()?,
self.3.symbol()?,
self.4.symbol()?,
self.5.symbol()?,
self.6.symbol()?,
];
Symbol::create_function("", &tempvec, true)
}
}
impl<
A: ToSymbol,
B: ToSymbol,
C: ToSymbol,
D: ToSymbol,
E: ToSymbol,
F: ToSymbol,
G: ToSymbol,
H: ToSymbol,
> ToSymbol for (A, B, C, D, E, F, G, H)
{
fn symbol(&self) -> Result<Symbol, ClingoError> {
let tempvec = vec![
self.0.symbol()?,
self.1.symbol()?,
self.2.symbol()?,
self.3.symbol()?,
self.4.symbol()?,
self.5.symbol()?,
self.6.symbol()?,
self.7.symbol()?,
];
Symbol::create_function("", &tempvec, true)
}
}
impl<
A: ToSymbol,
B: ToSymbol,
C: ToSymbol,
D: ToSymbol,
E: ToSymbol,
F: ToSymbol,
G: ToSymbol,
H: ToSymbol,
I: ToSymbol,
> ToSymbol for (A, B, C, D, E, F, G, H, I)
{
fn symbol(&self) -> Result<Symbol, ClingoError> {
let tempvec = vec![
self.0.symbol()?,
self.1.symbol()?,
self.2.symbol()?,
self.3.symbol()?,
self.4.symbol()?,
self.5.symbol()?,
self.6.symbol()?,
self.7.symbol()?,
self.8.symbol()?,
];
Symbol::create_function("", &tempvec, true)
}
}
impl<
A: ToSymbol,
B: ToSymbol,
C: ToSymbol,
D: ToSymbol,
E: ToSymbol,
F: ToSymbol,
G: ToSymbol,
H: ToSymbol,
I: ToSymbol,
J: ToSymbol,
> ToSymbol for (A, B, C, D, E, F, G, H, I, J)
{
fn symbol(&self) -> Result<Symbol, ClingoError> {
let tempvec = vec![
self.0.symbol()?,
self.1.symbol()?,
self.2.symbol()?,
self.3.symbol()?,
self.4.symbol()?,
self.5.symbol()?,
self.6.symbol()?,
self.7.symbol()?,
self.8.symbol()?,
self.9.symbol()?,
];
Symbol::create_function("", &tempvec, true)
}
}
impl<
A: ToSymbol,
B: ToSymbol,
C: ToSymbol,
D: ToSymbol,
E: ToSymbol,
F: ToSymbol,
G: ToSymbol,
H: ToSymbol,
I: ToSymbol,
J: ToSymbol,
K: ToSymbol,
> ToSymbol for (A, B, C, D, E, F, G, H, I, J, K)
{
fn symbol(&self) -> Result<Symbol, ClingoError> {
let tempvec = vec![
self.0.symbol()?,
self.1.symbol()?,
self.2.symbol()?,
self.3.symbol()?,
self.4.symbol()?,
self.5.symbol()?,
self.6.symbol()?,
self.7.symbol()?,
self.8.symbol()?,
self.9.symbol()?,
self.10.symbol()?,
];
Symbol::create_function("", &tempvec, true)
}
}
impl<
A: ToSymbol,
B: ToSymbol,
C: ToSymbol,
D: ToSymbol,
E: ToSymbol,
F: ToSymbol,
G: ToSymbol,
H: ToSymbol,
I: ToSymbol,
J: ToSymbol,
K: ToSymbol,
L: ToSymbol,
> ToSymbol for (A, B, C, D, E, F, G, H, I, J, K, L)
{
fn symbol(&self) -> Result<Symbol, ClingoError> {
let tempvec = vec![
self.0.symbol()?,
self.1.symbol()?,
self.2.symbol()?,
self.3.symbol()?,
self.4.symbol()?,
self.5.symbol()?,
self.6.symbol()?,
self.7.symbol()?,
self.8.symbol()?,
self.9.symbol()?,
self.10.symbol()?,
self.11.symbol()?,
];
Symbol::create_function("", &tempvec, true)
}
}
impl ToSymbol for bool {
fn symbol(&self) -> Result<Symbol, ClingoError> {
if *self {
Symbol::create_id("true", true)
} else {
Symbol::create_id("false", true)
}
}
}
impl ToSymbol for u8 {
fn symbol(&self) -> Result<Symbol, ClingoError> {
Ok(Symbol::create_number(i32::from(*self)))
}
}
impl ToSymbol for i8 {
fn symbol(&self) -> Result<Symbol, ClingoError> {
Ok(Symbol::create_number(i32::from(*self)))
}
}
impl ToSymbol for u16 {
fn symbol(&self) -> Result<Symbol, ClingoError> {
Ok(Symbol::create_number(i32::from(*self)))
}
}
impl ToSymbol for i16 {
fn symbol(&self) -> Result<Symbol, ClingoError> {
Ok(Symbol::create_number(i32::from(*self)))
}
}
impl ToSymbol for u32 {
fn symbol(&self) -> Result<Symbol, ClingoError> {
Ok(Symbol::create_number(*self as i32))
}
}
impl ToSymbol for i32 {
fn symbol(&self) -> Result<Symbol, ClingoError> {
Ok(Symbol::create_number(*self))
}
}
impl ToSymbol for String {
fn symbol(&self) -> Result<Symbol, ClingoError> {
Symbol::create_string(self)
}
}
impl ToSymbol for str {
fn symbol(&self) -> Result<Symbol, ClingoError> {
Symbol::create_string(self)
}
}
impl<T: ToSymbol> ToSymbol for &T {
fn symbol(&self) -> Result<Symbol, ClingoError> {
(*self).symbol()
}
}
pub trait FromSymbol: Sized {
type Error;
fn from_symbol(symbol: Symbol) -> Result<Self, Self::Error>;
}
impl FromSymbol for Symbol {
type Error = Infallible;
fn from_symbol(symbol: Symbol) -> Result<Self, Self::Error> {
Ok(symbol)
}
}
impl FromSymbol for u8 {
type Error = ClingoError;
fn from_symbol(symbol: Symbol) -> Result<Self, Self::Error> {
symbol
.number()?
.try_into()
.map_err(|_| ClingoError::new_external("Could not convert to u8"))
}
}
impl FromSymbol for i8 {
type Error = ClingoError;
fn from_symbol(symbol: Symbol) -> Result<Self, Self::Error> {
symbol
.number()?
.try_into()
.map_err(|_| ClingoError::new_external("Could not convert to i8"))
}
}
impl FromSymbol for u16 {
type Error = ClingoError;
fn from_symbol(symbol: Symbol) -> Result<Self, Self::Error> {
symbol
.number()?
.try_into()
.map_err(|_| ClingoError::new_external("Could not convert to u16"))
}
}
impl FromSymbol for i16 {
type Error = ClingoError;
fn from_symbol(symbol: Symbol) -> Result<Self, Self::Error> {
symbol
.number()?
.try_into()
.map_err(|_| ClingoError::new_external("Could not convert to i16"))
}
}
impl FromSymbol for u32 {
type Error = ClingoError;
fn from_symbol(symbol: Symbol) -> Result<Self, Self::Error> {
symbol
.number()?
.try_into()
.map_err(|_| ClingoError::new_external("Could not convert to u32"))
}
}
impl FromSymbol for i32 {
type Error = ClingoError;
fn from_symbol(symbol: Symbol) -> Result<Self, Self::Error> {
symbol.number()
}
}
impl FromSymbol for u64 {
type Error = ClingoError;
fn from_symbol(symbol: Symbol) -> Result<Self, Self::Error> {
symbol
.number()?
.try_into()
.map_err(|_| ClingoError::new_external("Could not convert to u64"))
}
}
impl FromSymbol for i64 {
type Error = ClingoError;
fn from_symbol(symbol: Symbol) -> Result<Self, Self::Error> {
Ok(symbol.number()? as i64)
}
}
impl FromSymbol for u128 {
type Error = ClingoError;
fn from_symbol(symbol: Symbol) -> Result<Self, Self::Error> {
symbol
.number()?
.try_into()
.map_err(|_| ClingoError::new_external("Could not convert to u128"))
}
}
impl FromSymbol for i128 {
type Error = ClingoError;
fn from_symbol(symbol: Symbol) -> Result<Self, Self::Error> {
Ok(symbol.number()? as i128)
}
}
impl FromSymbol for String {
type Error = ClingoError;
fn from_symbol(symbol: Symbol) -> Result<Self, Self::Error> {
Ok(symbol.string()?.into())
}
}
impl FromSymbol for &'static str {
type Error = ClingoError;
fn from_symbol(symbol: Symbol) -> Result<Self, Self::Error> {
symbol.string()
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct FactBase {
facts: HashSet<Symbol>,
}
impl FactBase {
pub fn new() -> FactBase {
FactBase {
facts: HashSet::new(),
}
}
pub fn len(&self) -> usize {
self.facts.len()
}
pub fn is_empty(&self) -> bool {
self.facts.is_empty()
}
pub fn iter(&self) -> std::collections::hash_set::Iter<'_, Symbol> {
self.facts.iter()
}
pub fn insert(&mut self, fact: &dyn ToSymbol) {
self.facts.insert(fact.symbol().unwrap());
// self.facts.sort();
}
pub fn union(&mut self, facts: &FactBase) {
for s in &facts.facts {
self.facts.insert(*s);
}
}
pub fn print(&self) {
for fact in &self.facts {
print!("{}.", fact.to_string());
}
println!();
}
}
// #[doc = "! Custom scripting language to run functions during grounding."]
// #[repr(C)]
// #[derive(Debug, Copy, Clone)]
// pub struct clingo_script {
// #[doc = "! Evaluate the given source code."]
// #[doc = "! @param[in] location the location in the logic program of the source code"]
// #[doc = "! @param[in] code the code to evaluate"]
// #[doc = "! @param[in] data user data as given when registering the script"]
// #[doc = "! @return whether the function call was successful"]
// pub execute: ::std::option::Option<
// unsafe extern "C" fn(
// location: *const clingo_location_t,
// code: *const ::std::os::raw::c_char,
// data: *mut ::std::os::raw::c_void,
// ) -> bool,
// >,
// #[doc = "! Call the function with the given name and arguments."]
// #[doc = "! @param[in] location the location in the logic program of the function call"]
// #[doc = "! @param[in] name the name of the function"]
// #[doc = "! @param[in] arguments the arguments to the function"]
// #[doc = "! @param[in] arguments_size the number of arguments"]
// #[doc = "! @param[in] symbol_callback callback to return a pool of symbols"]
// #[doc = "! @param[in] symbol_callback_data user data for the symbol callback"]
// #[doc = "! @param[in] data user data as given when registering the script"]
// #[doc = "! @return whether the function call was successful"]
// pub call: ::std::option::Option<
// unsafe extern "C" fn(
// location: *const clingo_location_t,
// name: *const ::std::os::raw::c_char,
// arguments: *const clingo_symbol_t,
// arguments_size: usize,
// symbol_callback: clingo_symbol_callback_t,
// symbol_callback_data: *mut ::std::os::raw::c_void,
// data: *mut ::std::os::raw::c_void,
// ) -> bool,
// >,
// #[doc = "! Check if the given function is callable."]
// #[doc = "! @param[in] name the name of the function"]
// #[doc = "! @param[out] result whether the function is callable"]
// #[doc = "! @param[in] data user data as given when registering the script"]
// #[doc = "! @return whether the function call was successful"]
// pub callable: ::std::option::Option<
// unsafe extern "C" fn(
// name: *const ::std::os::raw::c_char,
// result: *mut bool,
// data: *mut ::std::os::raw::c_void,
// ) -> bool,
// >,
// #[doc = "! Run the main function."]
// #[doc = "! @param[in] control the control object to pass to the main function"]
// #[doc = "! @param[in] data user data as given when registering the script"]
// #[doc = "! @return whether the function call was successful"]
// pub main: ::std::option::Option<
// unsafe extern "C" fn(
// control: *mut clingo_control_t,
// data: *mut ::std::os::raw::c_void,
// ) -> bool,
// >,
// #[doc = "! This function is called once when the script is deleted."]
// #[doc = "! @param[in] data user data as given when registering the script"]
// pub free: ::std::option::Option<unsafe extern "C" fn(data: *mut ::std::os::raw::c_void)>,
// pub version: *const ::std::os::raw::c_char,
// }
// #[doc = "! Custom scripting language to run functions during grounding."]
// pub type clingo_script_t = clingo_script;
// extern "C" {
// #[doc = "! Add a custom scripting language to clingo."]
// #[doc = "!"]
// #[doc = "! @param[in] name the name of the scripting language"]
// #[doc = "! @param[in] script struct with functions implementing the language"]
// #[doc = "! @param[in] data user data to pass to callbacks in the script"]
// #[doc = "! @return whether the call was successful"]
// pub fn clingo_register_script(
// name: *const ::std::os::raw::c_char,
// script: *const clingo_script_t,
// data: *mut ::std::os::raw::c_void,
// ) -> bool;
// }
// extern "C" {
// #[doc = "! Get the version of the registered scripting language."]
// #[doc = "!"]
// #[doc = "! @param[in] name the name of the scripting language"]
// #[doc = "! @return the version"]
// pub fn clingo_script_version(
// name: *const ::std::os::raw::c_char,
// ) -> *const ::std::os::raw::c_char;
// }
// Re-export #[derive(ToSymbol)].
#[cfg(feature = "derive")]
#[allow(unused_imports)]
pub use clingo_derive::*;
impl From<Symbol> for clingo_symbol_t {
fn from(symbol: Symbol) -> Self {
symbol.0
}
}
impl From<clingo_symbol_t> for Symbol {
fn from(symbol: clingo_symbol_t) -> Self {
Symbol(symbol)
}
}
impl From<Id> for clingo_id_t {
fn from(id: Id) -> Self {
id.0
}
}
impl From<Options> for clingo_options_t {
fn from(options: Options) -> Self {
options.0
}
}
impl From<&mut Options> for *mut clingo_options_t {
fn from(options: &mut Options) -> Self {
&mut options.0
}
}
impl From<Statistics> for clingo_statistic {
fn from(stats: Statistics) -> Self {
stats.0
}
}
impl From<&mut Statistics> for *mut clingo_statistic {
fn from(stats: &mut Statistics) -> Self {
&mut stats.0
}
}
impl From<Model> for clingo_model {
fn from(model: Model) -> Self {
model.0
}
}
impl From<&mut Model> for *mut clingo_model {
fn from(model: &mut Model) -> Self {
&mut model.0
}
}
impl<L: Logger, P: Propagator, O: GroundProgramObserver, F: FunctionHandler>
From<GenericControl<L, P, O, F>> for NonNull<clingo_control>
{
fn from(control: GenericControl<L, P, O, F>) -> Self {
control.ctl
}
}
impl<L: Logger, P: Propagator, O: GroundProgramObserver, F: FunctionHandler>
From<&mut GenericControl<L, P, O, F>> for NonNull<clingo_control>
{
fn from(control: &mut GenericControl<L, P, O, F>) -> Self {
control.ctl
}
}