Import and update boolector to fix the Windows build

* Boolector project it's no longer maintained
* So we just keep a copy with fixes for Windows
This commit is contained in:
pancake authored and pancake committed 2026-03-23 11:20:06 +01:00
1 parent b55bce5b8c
commit 9a67eeefae
11 files changed
+3027 -1

No files matched your search

+5
View File
@@ -14,7 +14,12 @@ members = [
"examples/ollvm",
"examples/statically-linked"
]
exclude = ["vendor/boolector"]
[profile.release]
lto = true
opt-level=3
[patch.crates-io]
# boolector 0.4.3 compares ftell() output against an i64 constant, which fails on Windows.
boolector = { path = "vendor/boolector" }
+7 -1
View File
@@ -19,7 +19,13 @@ rand = "0.8.4"
colored = "2.0.0"
[features]
default = ["boolector/vendor-lgl"]
default = []
[target.'cfg(not(windows))'.dependencies]
boolector = { version = "0.4.3", features = ["vendor-lgl"] }
[target.'cfg(windows)'.dependencies]
boolector = "0.4.3"
[package.metadata.docs.rs]
no-default-features = true
+170
View File
@@ -0,0 +1,170 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "boolector"
version = "0.4.3"
dependencies = [
"boolector-sys",
"libc",
]
[[package]]
name = "boolector-sys"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17f0c2f69c37174fb92110f2949c79ad87f6ab48bf45e2e3220b669c10698093"
dependencies = [
"cc",
"cmake",
"copy_dir",
"libc",
]
[[package]]
name = "cc"
version = "1.2.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
dependencies = [
"find-msvc-tools",
"shlex",
]
[[package]]
name = "cmake"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d"
dependencies = [
"cc",
]
[[package]]
name = "copy_dir"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "543d1dd138ef086e2ff05e3a48cf9da045da2033d16f8538fd76b86cd49b2ca3"
dependencies = [
"walkdir",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
[[package]]
name = "libc"
version = "0.2.182"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "winapi-util"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+29
View File
@@ -0,0 +1,29 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "boolector"
version = "0.4.3"
authors = ["Craig Disselkoen <[email protected]>"]
description = "Safe high-level bindings for the Boolector SMT solver"
documentation = "https://docs.rs/boolector"
keywords = ["boolector", "smt", "ffi", "bindings"]
license = "MIT"
repository = "https://github.com/cdisselkoen/boolector-rs"
[dependencies.boolector-sys]
version = "0.7.1"
[dependencies.libc]
version = "0.2.73"
[features]
vendor-lgl = ["boolector-sys/vendor-lgl"]
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Craig Disselkoen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+797
View File
@@ -0,0 +1,797 @@
use crate::node::{Array, BV};
use crate::option::BtorOption;
use crate::option::*;
use crate::timeout::{self, TimeoutState};
use boolector_sys::*;
use std::borrow::Borrow;
use std::ffi::{CStr, CString};
use std::fmt;
use std::os::raw::{c_char, c_void};
use std::pin::Pin;
/// A `Btor` represents an instance of the Boolector solver.
/// Each `BV` and `Array` is created in a particular `Btor` instance.
pub struct Btor {
btor: *mut boolector_sys::Btor,
pub(crate) timeout_state: Pin<Box<timeout::TimeoutState>>, // needs to be `Pin`, because the Boolector callback will expect to continue to find the `TimeoutState` at the same location
}
// Two `Btor`s are equal if they have the same underlying Btor pointer.
// We disregard the `timeout_state` for this purpose.
impl PartialEq for Btor {
fn eq(&self, other: &Self) -> bool {
self.btor == other.btor
}
}
impl Eq for Btor {}
impl fmt::Debug for Btor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<btor {:?}>", self.btor)
}
}
/// According to
/// https://groups.google.com/forum/#!msg/boolector/itYGgJxU3mY/AC2O0898BAAJ,
/// the Boolector library is thread-safe, so we make `Btor` both `Send` and
/// `Sync`. (Note that `TimeoutState` is also careful to be both `Send` and
/// `Sync`.)
unsafe impl Send for Btor {}
unsafe impl Sync for Btor {}
impl Btor {
/// Create a new `Btor` instance with no variables and no constraints.
pub fn new() -> Self {
Self {
btor: unsafe { boolector_new() },
timeout_state: Pin::new(Box::new(timeout::TimeoutState::new())),
}
}
pub(crate) fn as_raw(&self) -> *mut boolector_sys::Btor {
self.btor
}
/// Set an option to a particular value.
#[allow(clippy::cognitive_complexity)]
pub fn set_opt(&self, opt: BtorOption) {
match opt {
BtorOption::ModelGen(mg) => {
let val = match mg {
ModelGen::Disabled => 0,
ModelGen::Asserted => 1,
ModelGen::All => 2,
};
unsafe { boolector_set_opt(self.as_raw(), BTOR_OPT_MODEL_GEN, val) }
},
BtorOption::Incremental(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_INCREMENTAL, if b { 1 } else { 0 })
},
BtorOption::IncrementalSMT1(ismt1) => {
let val = match ismt1 {
IncrementalSMT1::Basic => BTOR_INCREMENTAL_SMT1_BASIC,
IncrementalSMT1::Continue => BTOR_INCREMENTAL_SMT1_CONTINUE,
};
unsafe { boolector_set_opt(self.as_raw(), BTOR_OPT_INCREMENTAL_SMT1, val) }
},
BtorOption::InputFileFormat(iff) => {
let val = match iff {
InputFileFormat::Autodetect => BTOR_INPUT_FORMAT_NONE,
InputFileFormat::Btor => BTOR_INPUT_FORMAT_BTOR,
InputFileFormat::Btor2 => BTOR_INPUT_FORMAT_BTOR2,
InputFileFormat::SMTLIBv1 => BTOR_INPUT_FORMAT_SMT1,
InputFileFormat::SMTLIBv2 => BTOR_INPUT_FORMAT_SMT2,
};
unsafe { boolector_set_opt(self.as_raw(), BTOR_OPT_INPUT_FORMAT, val) }
},
BtorOption::OutputNumberFormat(nf) => {
let val = match nf {
NumberFormat::Binary => BTOR_OUTPUT_BASE_BIN,
NumberFormat::Decimal => BTOR_OUTPUT_BASE_DEC,
NumberFormat::Hexadecimal => BTOR_OUTPUT_BASE_HEX,
};
unsafe { boolector_set_opt(self.as_raw(), BTOR_OPT_OUTPUT_NUMBER_FORMAT, val) }
},
BtorOption::OutputFileFormat(off) => {
let val = match off {
OutputFileFormat::BTOR => BTOR_OUTPUT_FORMAT_BTOR,
OutputFileFormat::SMTLIBv2 => BTOR_OUTPUT_FORMAT_SMT2,
OutputFileFormat::AigerASCII => BTOR_OUTPUT_FORMAT_AIGER_ASCII,
OutputFileFormat::AigerBinary => BTOR_OUTPUT_FORMAT_AIGER_BINARY,
};
unsafe { boolector_set_opt(self.as_raw(), BTOR_OPT_OUTPUT_FORMAT, val) }
},
BtorOption::SolverTimeout(duration) => {
self.timeout_state.set_timeout_duration(duration);
match duration {
None => {
// remove any existing timeout
unsafe { boolector_set_term(self.as_raw(), None, std::ptr::null_mut()) }
},
Some(_) => {
let ptr_to_ts: Pin<&TimeoutState> = (&self.timeout_state).as_ref();
let raw_ptr_to_ts: *const TimeoutState =
Pin::into_inner(ptr_to_ts) as *const TimeoutState;
let void_ptr_to_ts: *mut c_void = raw_ptr_to_ts as *mut c_void;
unsafe {
boolector_set_term(
self.as_raw(),
Some(timeout::callback),
void_ptr_to_ts,
)
}
},
}
},
BtorOption::SolverEngine(se) => {
let val = match se {
SolverEngine::Fun => BTOR_ENGINE_FUN,
SolverEngine::SLS => BTOR_ENGINE_SLS,
SolverEngine::Prop => BTOR_ENGINE_PROP,
SolverEngine::AIGProp => BTOR_ENGINE_AIGPROP,
SolverEngine::Quant => BTOR_ENGINE_QUANT,
};
unsafe { boolector_set_opt(self.as_raw(), BTOR_OPT_ENGINE, val) }
},
BtorOption::SatEngine(se) => {
let val = match se {
SatEngine::CaDiCaL => BTOR_SAT_ENGINE_CADICAL,
SatEngine::CMS => BTOR_SAT_ENGINE_CMS,
SatEngine::Lingeling => BTOR_SAT_ENGINE_LINGELING,
SatEngine::MiniSAT => BTOR_SAT_ENGINE_MINISAT,
SatEngine::PicoSAT => BTOR_SAT_ENGINE_PICOSAT,
};
unsafe { boolector_set_opt(self.as_raw(), BTOR_OPT_SAT_ENGINE, val) }
},
BtorOption::AutoCleanup(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_AUTO_CLEANUP, if b { 1 } else { 0 })
},
BtorOption::PrettyPrint(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_PRETTY_PRINT, if b { 1 } else { 0 })
},
BtorOption::Seed(u) => unsafe { boolector_set_opt(self.as_raw(), BTOR_OPT_SEED, u) },
BtorOption::RewriteLevel(rl) => {
let val = match rl {
RewriteLevel::None => 0,
RewriteLevel::TermLevel => 1,
RewriteLevel::More => 2,
RewriteLevel::Full => 3,
};
unsafe { boolector_set_opt(self.as_raw(), BTOR_OPT_REWRITE_LEVEL, val) }
},
BtorOption::SkeletonPreproc(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_SKELETON_PREPROC,
if b { 1 } else { 0 },
)
},
BtorOption::Ackermann(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_ACKERMANN, if b { 1 } else { 0 })
},
BtorOption::BetaReduce(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_BETA_REDUCE, if b { 1 } else { 0 })
},
BtorOption::EliminateSlices(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_ELIMINATE_SLICES,
if b { 1 } else { 0 },
)
},
BtorOption::VariableSubst(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_VAR_SUBST, if b { 1 } else { 0 })
},
BtorOption::UnconstrainedOpt(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_UCOPT, if b { 1 } else { 0 })
},
BtorOption::MergeLambdas(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_MERGE_LAMBDAS, if b { 1 } else { 0 })
},
BtorOption::ExtractLambdas(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_EXTRACT_LAMBDAS,
if b { 1 } else { 0 },
)
},
BtorOption::Normalize(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_NORMALIZE, if b { 1 } else { 0 })
},
BtorOption::NormalizeAdd(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_NORMALIZE_ADD, if b { 1 } else { 0 })
},
BtorOption::FunPreProp(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_FUN_PREPROP, if b { 1 } else { 0 })
},
BtorOption::FunPreSLS(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_FUN_PRESLS, if b { 1 } else { 0 })
},
BtorOption::FunDualProp(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_FUN_DUAL_PROP, if b { 1 } else { 0 })
},
BtorOption::FunDualPropQsortOrder(dpqo) => {
let val = match dpqo {
DualPropQsortOrder::Just => BTOR_DP_QSORT_JUST,
DualPropQsortOrder::Asc => BTOR_DP_QSORT_ASC,
DualPropQsortOrder::Desc => BTOR_DP_QSORT_DESC,
};
unsafe { boolector_set_opt(self.as_raw(), BTOR_OPT_FUN_DUAL_PROP_QSORT, val) }
},
BtorOption::FunJustification(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_FUN_JUST, if b { 1 } else { 0 })
},
BtorOption::FunJustificationHeuristic(jh) => {
let val = match jh {
JustificationHeuristic::Left => BTOR_JUST_HEUR_BRANCH_LEFT,
JustificationHeuristic::MinApp => BTOR_JUST_HEUR_BRANCH_MIN_APP,
JustificationHeuristic::MinDepth => BTOR_JUST_HEUR_BRANCH_MIN_DEP,
};
unsafe { boolector_set_opt(self.as_raw(), BTOR_OPT_FUN_JUST_HEURISTIC, val) }
},
BtorOption::FunLazySynthesize(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_FUN_LAZY_SYNTHESIZE,
if b { 1 } else { 0 },
)
},
BtorOption::FunEagerLemmas(el) => {
let val = match el {
EagerLemmas::None => BTOR_FUN_EAGER_LEMMAS_NONE,
EagerLemmas::Conf => BTOR_FUN_EAGER_LEMMAS_CONF,
EagerLemmas::All => BTOR_FUN_EAGER_LEMMAS_ALL,
};
unsafe { boolector_set_opt(self.as_raw(), BTOR_OPT_FUN_EAGER_LEMMAS, val) }
},
BtorOption::SLSNumFlips(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_SLS_NFLIPS, u)
},
BtorOption::SLSMoveStrategy(sms) => {
let val = match sms {
SLSMoveStrategy::BestMove => 0,
SLSMoveStrategy::RandomWalk => 1,
SLSMoveStrategy::FirstBestMove => 2,
SLSMoveStrategy::BestSameMove => 3,
SLSMoveStrategy::AlwaysProp => 4,
};
unsafe { boolector_set_opt(self.as_raw(), BTOR_OPT_SLS_STRATEGY, val) }
},
BtorOption::SLSJustification(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_SLS_JUST, if b { 1 } else { 0 })
},
BtorOption::SLSGroupWiseMoves(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_SLS_MOVE_GW, if b { 1 } else { 0 })
},
BtorOption::SLSRangeWiseMoves(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_SLS_MOVE_RANGE,
if b { 1 } else { 0 },
)
},
BtorOption::SLSSegmentWiseMoves(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_SLS_MOVE_SEGMENT,
if b { 1 } else { 0 },
)
},
BtorOption::SLSRandomWalkMoves(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_SLS_MOVE_RAND_WALK,
if b { 1 } else { 0 },
)
},
BtorOption::SLSRandomWalkProbability(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_SLS_PROB_MOVE_RAND_WALK, u)
},
BtorOption::SLSRandomizeAll(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_SLS_MOVE_RAND_ALL,
if b { 1 } else { 0 },
)
},
BtorOption::SLSRandomizeRange(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_SLS_MOVE_RAND_RANGE,
if b { 1 } else { 0 },
)
},
BtorOption::SLSPropagationMoves(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_SLS_MOVE_PROP, if b { 1 } else { 0 })
},
BtorOption::SLSPropagationMovesNumProp(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_SLS_MOVE_PROP_N_PROP, u)
},
BtorOption::SLSPropagationMovesNumRegular(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_SLS_MOVE_PROP_N_SLS, u)
},
BtorOption::SLSForceRandomWalks(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_SLS_MOVE_PROP_FORCE_RW,
if b { 1 } else { 0 },
)
},
BtorOption::SLSIncMoveTest(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_SLS_MOVE_INC_MOVE_TEST,
if b { 1 } else { 0 },
)
},
BtorOption::SLSRestarts(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_SLS_USE_RESTARTS,
if b { 1 } else { 0 },
)
},
BtorOption::SLSBanditScheme(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_SLS_USE_BANDIT,
if b { 1 } else { 0 },
)
},
BtorOption::PropNumSteps(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_PROP_NPROPS, u)
},
BtorOption::PropRestarts(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_PROP_USE_RESTARTS,
if b { 1 } else { 0 },
)
},
BtorOption::PropBanditScheme(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_PROP_USE_BANDIT,
if b { 1 } else { 0 },
)
},
BtorOption::PropPathSelectionMode(pathsel) => {
let val = match pathsel {
PropPathSelection::Controlling => BTOR_PROP_PATH_SEL_CONTROLLING,
PropPathSelection::Essential => BTOR_PROP_PATH_SEL_ESSENTIAL,
PropPathSelection::Random => BTOR_PROP_PATH_SEL_RANDOM,
};
unsafe { boolector_set_opt(self.as_raw(), BTOR_OPT_PROP_PATH_SEL, val) }
},
BtorOption::PropInvValueProbability(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_PROP_PROB_USE_INV_VALUE, u)
},
BtorOption::PropFlipConditionProbability(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_PROP_PROB_FLIP_COND, u)
},
BtorOption::PropFlipConditionProbabilityConstant(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_PROP_PROB_FLIP_COND_CONST, u)
},
BtorOption::PropFlipConditionNumPaths(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_PROP_FLIP_COND_CONST_NPATHSEL, u)
},
BtorOption::PropFlipConditionProbabilityConstantDelta(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_PROP_FLIP_COND_CONST_DELTA, u)
},
BtorOption::PropSliceKeepDCProbability(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_PROP_PROB_SLICE_KEEP_DC, u)
},
BtorOption::PropConcatFlipProbability(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_PROP_PROB_CONC_FLIP, u)
},
BtorOption::PropSliceFlipProbability(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_PROP_PROB_SLICE_FLIP, u)
},
BtorOption::PropEqFlipProbability(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_PROP_PROB_EQ_FLIP, u)
},
BtorOption::PropAndFlipProbability(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_PROP_PROB_AND_FLIP, u)
},
BtorOption::AIGPropUseRestarts(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_AIGPROP_USE_RESTARTS,
if b { 1 } else { 0 },
)
},
BtorOption::AIGPropQuantSynthesis(pqs) => {
let val = match pqs {
AIGPropQuantSynthesis::None => BTOR_QUANT_SYNTH_NONE,
AIGPropQuantSynthesis::EL => BTOR_QUANT_SYNTH_EL,
AIGPropQuantSynthesis::ELMC => BTOR_QUANT_SYNTH_ELMC,
AIGPropQuantSynthesis::ELELMC => BTOR_QUANT_SYNTH_EL_ELMC,
AIGPropQuantSynthesis::ELMR => BTOR_QUANT_SYNTH_ELMR,
};
unsafe { boolector_set_opt(self.as_raw(), BTOR_OPT_QUANT_SYNTH, val) }
},
BtorOption::AIGPropQuantDualSolver(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_QUANT_DUAL_SOLVER,
if b { 1 } else { 0 },
)
},
BtorOption::AIGPropQuantSynthLimit(u) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_QUANT_SYNTH_LIMIT, u)
},
BtorOption::AIGPropSynthQI(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_QUANT_SYNTH_QI,
if b { 1 } else { 0 },
)
},
BtorOption::AIGPropQuantDER(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_QUANT_DER, if b { 1 } else { 0 })
},
BtorOption::AIGPropQuantCER(b) => unsafe {
boolector_set_opt(self.as_raw(), BTOR_OPT_QUANT_CER, if b { 1 } else { 0 })
},
BtorOption::AIGPropQuantMiniscope(b) => unsafe {
boolector_set_opt(
self.as_raw(),
BTOR_OPT_QUANT_MINISCOPE,
if b { 1 } else { 0 },
)
},
}
}
/// Solve the current input (defined by the constraints which have been added
/// via [`BV::assert()`](struct.BV.html#method.assert) and
/// [`BV::assume()`](struct.BV.html#method.assume)). All assertions and
/// assumptions are implicitly combined via Boolean `and`.
///
/// Calling this function multiple times requires incremental usage to be
/// enabled via [`Btor::set_opt()`](struct.Btor.html#method.set_opt).
/// If incremental usage is not enabled, this function may only be called
/// once.
///
/// ```
/// # use boolector::{Btor, BV, SolverResult};
/// # use boolector::option::{BtorOption, ModelGen};
/// # use std::rc::Rc;
/// let btor = Rc::new(Btor::new());
/// btor.set_opt(BtorOption::Incremental(true));
///
/// // An 8-bit unconstrained `BV` with the symbol "foo"
/// let foo = BV::new(btor.clone(), 8, Some("foo"));
///
/// // Assert that "foo" must be greater than `3`
/// foo.ugt(&BV::from_u32(btor.clone(), 3, 8)).assert();
///
/// // This state is satisfiable
/// assert_eq!(btor.sat(), SolverResult::Sat);
///
/// // Assert that "foo" must also be less than `2`
/// foo.ult(&BV::from_u32(btor.clone(), 2, 8)).assert();
///
/// // State is now unsatisfiable
/// assert_eq!(btor.sat(), SolverResult::Unsat);
///
/// // Repeat the first step above with the solver timeout set to something
/// // extremely high (say, 200 sec) - should still be `Sat`
/// # use std::time::Duration;
/// let btor = Rc::new(Btor::new());
/// btor.set_opt(BtorOption::Incremental(true));
/// btor.set_opt(BtorOption::SolverTimeout(Some(Duration::from_secs(200))));
/// let foo = BV::new(btor.clone(), 8, Some("foo"));
/// foo.ugt(&BV::from_u32(btor.clone(), 3, 8)).assert();
/// assert_eq!(btor.sat(), SolverResult::Sat);
///
/// // But, if we make the second assertion and then set the solver timeout to
/// // something extremely low (say, 2 ns), we'll get `SolverResult::Unknown`
/// foo.ugt(&BV::from_u32(btor.clone(), 5, 8)).assert();
/// btor.set_opt(BtorOption::SolverTimeout(Some(Duration::from_nanos(2))));
/// assert_eq!(btor.sat(), SolverResult::Unknown);
/// ```
pub fn sat(&self) -> SolverResult {
self.timeout_state.restart_timer();
#[allow(non_upper_case_globals)]
match unsafe { boolector_sat(self.as_raw()) } as u32 {
BtorSolverResult_BTOR_RESULT_SAT => SolverResult::Sat,
BtorSolverResult_BTOR_RESULT_UNSAT => SolverResult::Unsat,
BtorSolverResult_BTOR_RESULT_UNKNOWN => SolverResult::Unknown,
u => panic!("Unexpected return value from boolector_sat(): {}", u),
}
}
/// Push `n` context levels. `n` must be at least 1.
pub fn push(&self, n: u32) {
unsafe { boolector_push(self.as_raw(), n) }
}
/// Pop `n` context levels. `n` must be at least 1.
pub fn pop(&self, n: u32) {
unsafe { boolector_pop(self.as_raw(), n) }
}
/// Duplicate a `Btor` instance. This will copy all variables, assertions,
/// etc into the new instance.
///
/// Each `BV` or `Array` may only be used with the `Btor` it was originally
/// created for. If you have a `BV` for one `Btor` and want to find the
/// corresponding `BV` in another `Btor`, use
/// [`Btor::get_matching_bv()`](struct.Btor.html#method.get_matching_bv) or
/// [`Btor::get_bv_by_symbol()`](struct.Btor.html#method.get_bv_by_symbol).
///
/// With [`SatEngine::Lingeling`](option/enum.SatEngine.html), this can be
/// called at any time; but with `SatEngine::PicoSAT` or
/// `SatEngine::MiniSAT`, this can only be called prior to the first
/// `Btor::sat()` call.
///
/// The Boolector API docs refer to this operation as "clone", but we use
/// `duplicate()` to avoid confusion.
///
/// # Example
///
/// ```
/// # use boolector::{Btor, BV, SolverResult};
/// # use boolector::option::{BtorOption, ModelGen};
/// # use std::rc::Rc;
/// let btor = Rc::new(Btor::new());
/// btor.set_opt(BtorOption::ModelGen(ModelGen::All));
///
/// // `x` is an 8-bit `BV` less than `42`
/// let x = BV::new(btor.clone(), 8, Some("x"));
/// x.ult(&BV::from_u32(btor.clone(), 42, 8)).assert();
///
/// // `y` is equal to `x + 7`
/// let y = x.add(&BV::from_u32(btor.clone(), 7, 8));
///
/// // We duplicate the `Btor` instance
/// let btor_2 = Rc::new(btor.duplicate());
///
/// // The duplicated instance has copied versions of
/// // `x` and `y` which are distinct from the original
/// // `x` and `y` but still have the corresponding
/// // relationship (i.e., `y_2 = x_2 + 7`)
/// let x_2 = Btor::get_matching_bv(btor_2.clone(), &x).unwrap();
/// let y_2 = Btor::get_matching_bv(btor_2.clone(), &y).unwrap();
///
/// // The instances are totally independent now. In the
/// // original instance, we'll assert that `x > 3`, while
/// // in the new instance, we'll assert that `x < 3`.
/// // Note that we're careful to create constants with the
/// // correct `Btor` instance.
/// x.ugt(&BV::from_u32(btor.clone(), 3, 8)).assert();
/// x_2.ult(&BV::from_u32(btor_2.clone(), 3, 8)).assert();
///
/// // Each instance is satisfiable by itself
/// assert_eq!(btor.sat(), SolverResult::Sat);
/// assert_eq!(btor_2.sat(), SolverResult::Sat);
///
/// // In the first instance, `y > 10`, while in the second,
/// // `y < 10`
/// let y_solution = y.get_a_solution().as_u64().unwrap();
/// assert!(y_solution > 10);
/// let y_2_solution = y_2.get_a_solution().as_u64().unwrap();
/// assert!(y_2_solution < 10);
/// ```
pub fn duplicate(&self) -> Self {
let duplicated = Self {
btor: unsafe { boolector_clone(self.as_raw()) },
timeout_state: Pin::new(Box::new(TimeoutState::with_timeout_duration(
self.timeout_state.get_timeout_duration(),
))),
};
// we need to inform the callback about the new location of the `TimeoutState`
let ptr_to_ts: Pin<&TimeoutState> = (&self.timeout_state).as_ref();
let raw_ptr_to_ts: *const TimeoutState = Pin::into_inner(ptr_to_ts) as *const TimeoutState;
let void_ptr_to_ts: *mut c_void = raw_ptr_to_ts as *mut c_void;
unsafe { boolector_set_term(self.as_raw(), Some(timeout::callback), void_ptr_to_ts) }
duplicated
}
/// Given a `BV` originally created for any `Btor`, get the corresponding
/// `BV` in the given `btor`. This only works if the `BV` was created before
/// the relevant `Btor::duplicate()` was called; that is, it is intended to
/// be used to find the copied version of a given `BV` in the new `Btor`.
///
/// It's also fine to call this with a `BV` created for the given `Btor`
/// itself, in which case you'll just get back `Some(bv.clone())`.
///
/// For a code example, see
/// [`Btor::duplicate()`](struct.Btor.html#method.duplicate).
#[allow(clippy::if_same_then_else)]
pub fn get_matching_bv<R: Borrow<Btor> + Clone>(btor: R, bv: &BV<R>) -> Option<BV<R>> {
let node = unsafe { boolector_match_node(btor.borrow().as_raw(), bv.node) };
if node.is_null() {
None
} else if unsafe { boolector_is_array(btor.borrow().as_raw(), node) } {
None
} else {
Some(BV { btor, node })
}
}
/// Given an `Array` originally created for any `Btor`, get the corresponding
/// `Array` in the given `btor`. This only works if the `Array` was created
/// before the relevant `Btor::duplicate()` was called; that is, it is
/// intended to be used to find the copied version of a given `Array` in the
/// new `Btor`.
///
/// It's also fine to call this with an `Array` created for the given `Btor`
/// itself, in which case you'll just get back `Some(array.clone())`.
pub fn get_matching_array<R: Borrow<Btor> + Clone>(
btor: R,
array: &Array<R>,
) -> Option<Array<R>> {
let node = unsafe { boolector_match_node(btor.borrow().as_raw(), array.node) };
if node.is_null() {
None
} else if unsafe { boolector_is_array(btor.borrow().as_raw(), node) } {
Some(Array { btor, node })
} else {
None
}
}
/// Given a symbol, find the `BV` in the given `Btor` which has that symbol.
///
/// Since `Btor::duplicate()` copies all `BV`s to the new `Btor` including
/// their symbols, this can also be used to find the copied version of a
/// given `BV` in the new `Btor`.
#[allow(clippy::if_same_then_else)]
pub fn get_bv_by_symbol<R: Borrow<Btor> + Clone>(btor: R, symbol: &str) -> Option<BV<R>> {
let cstring = CString::new(symbol).unwrap();
let symbol = cstring.as_ptr() as *const c_char;
let node = unsafe { boolector_match_node_by_symbol(btor.borrow().as_raw(), symbol) };
if node.is_null() {
None
} else if unsafe { boolector_is_array(btor.borrow().as_raw(), node) } {
None
} else {
Some(BV { btor, node })
}
}
/// Given a symbol, find the `Array` in the given `Btor` which has that
/// symbol.
///
/// Since `Btor::duplicate()` copies all `Array`s to the new `Btor` including
/// their symbols, this can also be used to find the copied version of a
/// given `Array` in the new `Btor`.
pub fn get_array_by_symbol<R: Borrow<Btor> + Clone>(btor: R, symbol: &str) -> Option<Array<R>> {
let cstring = CString::new(symbol).unwrap();
let symbol = cstring.as_ptr() as *const c_char;
let node = unsafe { boolector_match_node_by_symbol(btor.borrow().as_raw(), symbol) };
if node.is_null() {
None
} else if unsafe { boolector_is_array(btor.borrow().as_raw(), node) } {
Some(Array { btor, node })
} else {
None
}
}
/// Add all current assumptions as assertions
pub fn fixate_assumptions(&self) {
unsafe { boolector_fixate_assumptions(self.as_raw()) }
}
/// Remove all added assumptions
pub fn reset_assumptions(&self) {
unsafe { boolector_reset_assumptions(self.as_raw()) }
}
/// Reset all statistics other than time statistics
pub fn reset_stats(&self) {
unsafe { boolector_reset_stats(self.as_raw()) }
}
/// Reset time statistics
pub fn reset_time(&self) {
unsafe { boolector_reset_time(self.as_raw()) }
}
/// Get a `String` describing the current constraints
pub fn print_constraints(&self) -> String {
unsafe {
let tmpfile: *mut libc::FILE = libc::tmpfile();
if tmpfile.is_null() {
panic!("Failed to create a temp file");
}
// Write the data to `tmpfile`
boolector_dump_smt2(self.as_raw(), tmpfile);
// Seek to the end of `tmpfile`
assert_eq!(libc::fseek(tmpfile, 0, libc::SEEK_END), 0);
// Get the length of `tmpfile`
let length = libc::ftell(tmpfile);
if length < 0 {
panic!("ftell() returned a negative value");
}
// Seek back to the beginning of `tmpfile`
assert_eq!(libc::fseek(tmpfile, 0, libc::SEEK_SET), 0);
let mut buffer = Vec::with_capacity(length as usize);
libc::fread(
buffer.as_mut_ptr() as *mut c_void,
1,
length as usize,
tmpfile,
);
libc::fclose(tmpfile);
buffer.set_len(length as usize);
String::from_utf8_unchecked(buffer)
}
}
/// Get a `String` describing the current model, including a set of
/// satisfying assignments for all variables
pub fn print_model(&self) -> String {
unsafe {
let tmpfile: *mut libc::FILE = libc::tmpfile();
if tmpfile.is_null() {
panic!("Failed to create a temp file");
}
// Write the data to `tmpfile`
let format_cstring = CString::new("btor").unwrap();
boolector_print_model(
self.as_raw(),
format_cstring.as_ptr() as *mut c_char,
tmpfile,
);
// Seek to the end of `tmpfile`
assert_eq!(libc::fseek(tmpfile, 0, libc::SEEK_END), 0);
// Get the length of `tmpfile`
let length = libc::ftell(tmpfile);
if length < 0 {
panic!("ftell() returned a negative value");
}
// Seek back to the beginning of `tmpfile`
assert_eq!(libc::fseek(tmpfile, 0, libc::SEEK_SET), 0);
let mut buffer = Vec::with_capacity(length as usize);
libc::fread(
buffer.as_mut_ptr() as *mut c_void,
1,
length as usize,
tmpfile,
);
libc::fclose(tmpfile);
buffer.set_len(length as usize);
String::from_utf8_unchecked(buffer)
}
}
/// Get Boolector's version string
pub fn get_version(&self) -> String {
let cstr = unsafe { CStr::from_ptr(boolector_version(self.as_raw())) };
cstr.to_str().unwrap().to_owned()
}
/// Get Boolector's copyright notice
pub fn get_copyright(&self) -> String {
let cstr = unsafe { CStr::from_ptr(boolector_copyright(self.as_raw())) };
cstr.to_str().unwrap().to_owned()
}
}
impl Default for Btor {
fn default() -> Self {
Self::new()
}
}
impl Drop for Btor {
fn drop(&mut self) {
unsafe {
boolector_release_all(self.as_raw());
assert_eq!(boolector_get_refs(self.as_raw()) as i32, 0);
boolector_delete(self.as_raw());
}
}
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum SolverResult {
Sat,
Unsat,
Unknown,
}
+13
View File
@@ -0,0 +1,13 @@
// this ensures that crate users generating docs with --no-deps will still
// properly get links to the public docs for boolector's types
#![doc(html_root_url = "https://docs.rs/boolector/0.4.2")]
mod btor;
pub use btor::{Btor, SolverResult};
mod node;
pub use node::Array;
pub use node::BVSolution;
pub use node::BV;
pub mod option;
mod sort;
mod timeout;
+1476
View File
File diff suppressed because it is too large. Load diff
+364
View File
@@ -0,0 +1,364 @@
//! This module exposes options which can be set on a `Btor` instance.
/// Documentation for individual options and their possible values are
/// more-or-less taken verbatim from the Boolector 3.0.0 docs.
pub enum BtorOption {
/// Whether to generate a model (set of concrete solution values) for
/// satisfiable instances
ModelGen(ModelGen),
/// Enable/disable incremental mode. Note that the Boolector 3.0.0 docs say
/// that "disabling incremental usage is currently not supported".
Incremental(bool),
/// Set incremental mode for SMT-LIB v1 input. The default is
/// `IncrementalSMT1::Basic`.
IncrementalSMT1(IncrementalSMT1),
/// Input file format. The default is `InputFileFormat::Autodetect`.
InputFileFormat(InputFileFormat),
/// Format to output numbers in. The default is `NumberFormat::Binary`.
OutputNumberFormat(NumberFormat),
/// Output file format. The default is `FileFormat::BTOR`.
OutputFileFormat(OutputFileFormat),
/// Solver timeout. If `Some`, then operations lasting longer than the given
/// `Duration` will be aborted and return `SolverResult::Unknown`.
///
/// If `None`, then any previously set solver timeout will be removed, and
/// there will be no time limit to solver operations.
SolverTimeout(Option<std::time::Duration>),
/// Solver engine. The default is `SolverEngine::Fun`.
SolverEngine(SolverEngine),
/// SAT solver. Each option requires that Boolector was compiled with support
/// for the corresponding solver.
SatEngine(SatEngine),
/// Enable/disable auto cleanup of all references held on exit.
AutoCleanup(bool),
/// Enable/disable pretty printing when dumping.
PrettyPrint(bool),
/// Seed for Boolector's internal random number generator. The default is 0.
Seed(u32),
/// Rewrite level. The default is `RewriteLevel::Full`.
///
/// Boolector's docs say to not change this setting after creating expressions.
RewriteLevel(RewriteLevel),
/// Enable/disable skeleton preprocessing during simplification.
SkeletonPreproc(bool),
/// Enable/disable the eager addition of Ackermann constraints for function
/// applications.
Ackermann(bool),
/// Enable/disable the eager elimination of lambda expressions via beta
/// reduction.
BetaReduce(bool),
/// Enable/disable slice elimination on bit vector variables.
EliminateSlices(bool),
/// Enable/disable variable substitution during simplification.
VariableSubst(bool),
/// Enable/disable unconstrained optimization.
UnconstrainedOpt(bool),
/// Enable/disable merging of lambda expressions.
MergeLambdas(bool),
/// Enable/disable extraction of common array patterns as lambda terms.
ExtractLambdas(bool),
/// Enable/disable normalization of addition, multiplication, and bitwise
/// `and`.
Normalize(bool),
/// Enable/disable normalization of addition.
NormalizeAdd(bool),
/// For `SolverEngine::Fun`, enable/disable Prop engine preprocessing step
/// within sequential portfolio setting.
FunPreProp(bool),
/// For `SolverEngine::Fun`, enable/disable SLS engine preprocessing step
/// within sequential portfolio setting.
FunPreSLS(bool),
/// For `SolverEngine::Fun`, enable/disable dual propagation optimization.
FunDualProp(bool),
/// For `SolverEngine::Fun`, set the order in which inputs are assumed in
/// dual propagation clone. The default is `DualPropQsortOrder::Just`.
FunDualPropQsortOrder(DualPropQsortOrder),
/// For `SolverEngine::Fun`, enable/disable justification optimization.
FunJustification(bool),
/// For `SolverEngine::Fun`, set the path selection heuristic for
/// justification optimization. The default is
/// `JustificationHeuristic::MinApp`.
FunJustificationHeuristic(JustificationHeuristic),
/// For `SolverEngine::Fun`, enable/disable lazy synthesis of bitvector
/// expressions.
FunLazySynthesize(bool),
/// For `SolverEngine::Fun`, enable/disable eager generation of lemmas.
FunEagerLemmas(EagerLemmas),
/// For `SolverEngine::SLS`, set the number of bit flips used as a limit.
/// `0` indicates no limit.
SLSNumFlips(u32),
/// For `SolverEngine::SLS`, set the move strategy. The default is
/// `SLSMoveStrategy::BestMove`.
SLSMoveStrategy(SLSMoveStrategy),
/// For `SolverEngine::SLS`, enable/disable justification-based path
/// selection during candidate selection.
SLSJustification(bool),
/// For `SolverEngine::SLS`, enable/disable group-wise moves, where rather
/// than changing the assignment of one single candidate variable, all
/// candidate variables are set at the same time (using the same strategy).
SLSGroupWiseMoves(bool),
/// For `SolverEngine::SLS`, enable/disable range-wise bitflip moves, where
/// the bits within all ranges from 2 to the bitwidth (starting from the LSB)
/// are flipped at once.
SLSRangeWiseMoves(bool),
/// For `SolverEngine::SLS`, enable/disable segment-wise bitflip moves, where
/// the bits within segments of multiples of 2 are flipped at once.
SLSSegmentWiseMoves(bool),
/// For `SolverEngine::SLS`, enable/disable random walk moves, where one out
/// of all possible neighbors is randomly selected for a randomly selected
/// candidate variable.
SLSRandomWalkMoves(bool),
/// For `SolverEngine::SLS`, set the probability with which a random walk is
/// chosen if `SLSRandomWalkMoves` is enabled.
SLSRandomWalkProbability(u32),
/// For `SolverEngine::SLS`, enable/disable the randomization of all
/// candidate variables (rather than a single randomly selected candidate
/// variable) in case no best move has been found.
SLSRandomizeAll(bool),
/// For `SolverEngine::SLS`, enable/disable the randomization of bit ranges
/// (rather than all bits) of candidate variable(s) to be randomized in case
/// no best move has been found.
SLSRandomizeRange(bool),
/// For `SolverEngine::SLS`, enable/disable propagation moves.
SLSPropagationMoves(bool),
/// For `SolverEngine::SLS` when propagation moves are enabled, set the
/// number of propagation moves to be performed (this forms a ratio with
/// `SLSPropagationMovesNumRegular`).
SLSPropagationMovesNumProp(u32),
/// For `SolverEngine::SLS` when propagation moves are enabled, set the
/// number of regular moves to be performed (this forms a ratio with
/// `SLSPropagationMovesNumProp`).
SLSPropagationMovesNumRegular(u32),
/// For `SolverEngine::SLS`, enable/disable forcibly choosing random walks as
/// recovery moves when conflicts occur after a propagation move.
SLSForceRandomWalks(bool),
/// For `SolverEngine::SLS`, enable/disable that during best move selection,
/// if the current candidate variable with a previous neighbor yields the
/// currently best score, this neighbor assignment is used as a base for
/// further neighborhood exploration (rather than its current assignment).
SLSIncMoveTest(bool),
/// For `SolverEngine::SLS`, enable/disable restarts.
SLSRestarts(bool),
/// For `SolverEngine::SLS`, enable/disable the "bandit scheme" for selecting
/// root constraints. If disabled, candidate root constraints are selected
/// randomly.
SLSBanditScheme(bool),
/// For `SolverEngine::Prop`, set the number of propagation steps used as a
/// limit. `0` indicates no limit.
PropNumSteps(u32),
/// For `SolverEngine::Prop`, enable/disable restarts.
PropRestarts(bool),
/// For `SolverEngine::Prop`, enable/disable the "bandit scheme" for
/// selecting root constraints. If disabled, candidate root constraints are
/// selected randomly.
PropBanditScheme(bool),
/// For `SolverEngine::Prop`, choose the mode for path selection.
/// The default is `PropPathSelection::Essential`.
PropPathSelectionMode(PropPathSelection),
/// For `SolverEngine::Prop`, set the probability with which to choose
/// inverse values over consistent values.
PropInvValueProbability(u32),
/// For `SolverEngine::Prop`, set the probability with which to select the
/// path to the condition (in case of an if-then-else operation) rather than
/// the enabled branch during down propagation.
PropFlipConditionProbability(u32),
/// Like `PropFlipConditionProbability`, but for the case that either the
/// 'then' or 'else' branch is constant.
PropFlipConditionProbabilityConstant(u32),
/// For `SolverEngine::Prop`, set the limit for how often the path to the
/// condition may be selected before `PropFlipConditionProbabilityConstant`
/// is decreased or increased by `PropFlipConditionProbabilityConstantDelta`.
PropFlipConditionNumPaths(u32),
/// For `SolverEngine::Prop`, set the delta by which
/// `PropFlipConditionProbabilityConstant` is decreased or increased after
/// `PropFlipConditionNumPaths` is reached.
PropFlipConditionProbabilityConstantDelta(u32),
/// For `SolverEngine::Prop`, set the probability with which to keep the
/// current value of the don't care bits of a slice operation (rather than
/// fully randomizing all of them) when selecting an inverse or consistent
/// value.
PropSliceKeepDCProbability(u32),
/// For `SolverEngine::Prop`, set the probability with which to use the
/// corresponding slice of the current assignment with at most one of its
/// bits flipped as the result of consistent value selection for concats.
PropConcatFlipProbability(u32),
/// For `SolverEngine::Prop`, set the probability with which to use the
/// current assignment of the operand of a slice operation with one of the
/// don't care bits flipped, unless their current assignment is kept by
/// `PropSliceKeepDCProbability`.
PropSliceFlipProbability(u32),
/// For `SolverEngine::Prop`, set the probability with which the current
/// assignment of the selected node with one of its bits flipped (rather than
/// a fully randomized bitvector) is down-propagated in the case of an
/// inequality.
PropEqFlipProbability(u32),
/// For `SolverEngine::Prop`, set the probability with which the current
/// assignment of the don't care bits of the selected node with at most one
/// of its bits flipped in case of an `and` operation.
PropAndFlipProbability(u32),
/// For `SolverEngine::AIGProp`, enable/disable restarts.
AIGPropUseRestarts(bool),
/// For `SolverEngine::AIGProp`, select the synthesis mode for Skolem
/// functions.
AIGPropQuantSynthesis(AIGPropQuantSynthesis),
/// For `SolverEngine::AIGProp`, enable/disable solving the dual (negated)
/// version of the quantified bit-vector formula.
AIGPropQuantDualSolver(bool),
/// For `SolverEngine::AIGProp`, set the limit of enumerated expressions
/// for the enumerative learning synthesis algorithm.
AIGPropQuantSynthLimit(u32),
/// For `SolverEngine::AIGProp`, enable/disable generalization of
/// quantifier instantiations via enumerative learning.
AIGPropSynthQI(bool),
/// For `SolverEngine::AIGProp`, enable/disable destructive equality
/// resolution simplification.
AIGPropQuantDER(bool),
/// For `SolverEngine::AIGProp`, enable/disable constructive equality
/// resolution simplification.
AIGPropQuantCER(bool),
/// For `SolverEngine::AIGProp`, enable/disable miniscoping.
AIGPropQuantMiniscope(bool),
}
pub enum ModelGen {
/// Do not generate models
Disabled,
/// Generate models for asserted expressions only
Asserted,
/// Generate models for all expressions
All,
}
pub enum IncrementalSMT1 {
/// Stop after first satisfiable formula
Basic,
/// Solve all formulas
Continue,
}
pub enum InputFileFormat {
Autodetect,
Btor,
Btor2,
SMTLIBv1,
SMTLIBv2,
}
pub enum NumberFormat {
Binary,
Decimal,
Hexadecimal,
}
pub enum OutputFileFormat {
BTOR,
SMTLIBv2,
AigerASCII,
AigerBinary,
}
pub enum SolverEngine {
/// Default engine for all combinations of QF_AUFBV; uses lemmas on demand
/// for QF_AUFBV and eager bit-blasting for QF_BV
Fun,
/// Score-based local search QF_BV engine
SLS,
/// Propagation-based local search QF_BV engine
Prop,
/// Propagation-based local search QF_BV engine that operates on the bit-blasted formula (the AIG layer)
AIGProp,
/// Quantifier engine (BV only)
Quant,
}
pub enum SatEngine {
/// CaDiCaL
CaDiCaL,
/// CryptoMiniSat
CMS,
/// Lingeling
Lingeling,
/// MiniSAT
MiniSAT,
/// PicoSAT
PicoSAT,
}
pub enum RewriteLevel {
/// "no rewriting"
None,
/// "term level rewriting"
TermLevel,
/// "more simplification techniques"
More,
/// "full rewriting/simplification"
Full,
}
pub enum DualPropQsortOrder {
/// Order by score, highest score first
Just,
/// Order by input id, ascending
Asc,
/// Order by input id, descending
Desc,
}
pub enum JustificationHeuristic {
/// Always choose the left branch
Left,
/// Choose the branch with the minimum number of applies
MinApp,
/// Choose the branch with the minimum depth
MinDepth,
}
pub enum EagerLemmas {
/// Do not generate lemmas eagerly (generate one single lemma per refinement
/// iteration)
None,
/// Only generate lemmas eagerly until the first conflict dependent on
/// another conflict is found
Conf,
/// In each refinement iterations, generate lemmas for all conflicts
All,
}
pub enum SLSMoveStrategy {
/// Always choose the best score improving move
BestMove,
/// Perform a random walk weighted by score
RandomWalk,
/// Always choose the first best move, even if another move may be better
FirstBestMove,
/// Choose a move even if its score is not better but the same as the score
/// of the previous best move
BestSameMove,
/// Always choose propagation move, and recover with SLS move in case of
/// conflict
AlwaysProp,
}
pub enum PropPathSelection {
/// Select path based on controlling inputs
Controlling,
/// Select path based on essential inputs
Essential,
/// Select path based on random inputs
Random,
}
pub enum AIGPropQuantSynthesis {
/// Do not synthesize skolem functions (use model values for instantiation)
None,
/// Use enumerative learning to synthesize skolem functions
EL,
/// Use enumerative learning modulo the predicates in the cone of influence
/// of the existential variables to synthesize skolem functions
ELMC,
/// Chain the `EL` and `ELMC` approaches to synthesize skolem functions
ELELMC,
/// Use enumerative learning modulo the given root constraints to synthesize
/// skolem functions
ELMR,
}
+81
View File
@@ -0,0 +1,81 @@
// We have some methods on `Sort` that we don't use, but still make sense to
// have around for the future
#![allow(dead_code)]
use crate::btor::Btor;
use boolector_sys::*;
use std::borrow::Borrow;
pub struct Sort<R: Borrow<Btor> + Clone> {
btor: R,
sort: BoolectorSort,
}
// According to
// https://groups.google.com/forum/#!msg/boolector/itYGgJxU3mY/AC2O0898BAAJ,
// the Boolector library is thread-safe, meaning `BoolectorSort` can be
// both `Send` and `Sync`.
// So as long as `R` is `Send` and/or `Sync`, we can mark `Sort` as `Send`
// and/or `Sync` respectively.
unsafe impl<R: Borrow<Btor> + Clone + Send> Send for Sort<R> {}
unsafe impl<R: Borrow<Btor> + Clone + Sync> Sync for Sort<R> {}
impl<R: Borrow<Btor> + Clone> Sort<R> {
pub(crate) fn from_raw(btor: R, sort: BoolectorSort) -> Self {
Self { btor, sort }
}
pub(crate) fn as_raw(&self) -> BoolectorSort {
self.sort
}
/// Create a bitvector sort for the given bitwidth.
/// `width` must not be `0`.
pub fn bitvector(btor: R, width: u32) -> Self {
assert!(width > 0, "boolector: cannot create 0-width bitvector sort");
Self::from_raw(btor.clone(), unsafe {
boolector_bitvec_sort(btor.borrow().as_raw(), width)
})
}
/// Create the Boolean sort.
///
/// In Boolector, there is no distinction between Booleans and bitvectors of
/// bitwidth one, so this is equivalent to `Sort::bitvector(btor, 1)`.
pub fn bool(btor: R) -> Self {
Self::from_raw(btor.clone(), unsafe {
boolector_bool_sort(btor.borrow().as_raw())
})
}
/// Create an array sort. An `Array` in Boolector is really just a map
/// which maps items of the `index` sort to the `element` sort.
///
/// Both the `index` and `element` sorts must be bitvector sorts.
pub fn array(btor: R, index: &Sort<R>, element: &Sort<R>) -> Self {
Self::from_raw(btor.clone(), unsafe {
boolector_array_sort(btor.borrow().as_raw(), index.as_raw(), element.as_raw())
})
}
/// Is `self` an array sort?
pub fn is_array_sort(&self) -> bool {
unsafe { boolector_is_array_sort(self.btor.borrow().as_raw(), self.as_raw()) }
}
/// Is `self` a bitvector sort?
pub fn is_bv_sort(&self) -> bool {
unsafe { boolector_is_bitvec_sort(self.btor.borrow().as_raw(), self.as_raw()) }
}
/// Is `self` a function sort?
pub fn is_fun_sort(&self) -> bool {
unsafe { boolector_is_fun_sort(self.btor.borrow().as_raw(), self.as_raw()) }
}
}
impl<R: Borrow<Btor> + Clone> Drop for Sort<R> {
fn drop(&mut self) {
unsafe { boolector_release_sort(self.btor.borrow().as_raw(), self.as_raw()) }
}
}
+64
View File
@@ -0,0 +1,64 @@
use std::sync::RwLock;
use std::time::{Duration, Instant};
#[derive(Debug)]
pub struct TimeoutState {
timeout_duration: RwLock<Option<Duration>>,
current_operation_start_time: RwLock<Instant>,
}
impl TimeoutState {
pub fn new() -> Self {
Self::with_timeout_duration(None)
}
pub fn with_timeout_duration(timeout_duration: Option<Duration>) -> Self {
Self {
timeout_duration: RwLock::new(timeout_duration),
current_operation_start_time: RwLock::new(Instant::now()),
}
}
pub fn get_timeout_duration(&self) -> Option<Duration> {
let guard = self.timeout_duration.read().unwrap();
*guard
}
pub fn set_timeout_duration(&self, timeout_duration: Option<Duration>) {
let mut guard = self.timeout_duration.write().unwrap();
*guard = timeout_duration;
}
pub fn get_current_operation_start_time(&self) -> Instant {
let guard = self.current_operation_start_time.read().unwrap();
*guard
}
pub fn restart_timer(&self) {
let mut guard = self.current_operation_start_time.write().unwrap();
*guard = Instant::now();
}
}
pub extern "C" fn callback(void_ptr_to_ts: *mut std::os::raw::c_void) -> i32 {
let timeout_state = unsafe { &*(void_ptr_to_ts as *const TimeoutState) };
match timeout_state.get_timeout_duration() {
None => 0, // no timeout set, keep going
Some(timeout_duration) => {
let current_operation_start_time = timeout_state.get_current_operation_start_time();
match Instant::now().checked_duration_since(current_operation_start_time) {
None => {
// somehow negative time has elapsed since operation started? Keep going
0
},
Some(duration) => {
if duration > timeout_duration {
1 // terminate
} else {
0 // keep going
}
},
}
},
}
}