#[allow(unused_imports)]
use crate::prelude::*;
use num_bigint::BigInt;
use num_rational::BigRational;
use crate::{Sort, Term, TermId};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ModelValue {
Bool(bool),
Int(BigInt),
Rational(BigRational),
BitVector(usize, BigInt),
Array {
default: Box<ModelValue>,
entries: Vec<(ModelValue, ModelValue)>,
},
Datatype {
constructor: String,
fields: Vec<ModelValue>,
},
Uninterpreted(Sort, usize),
Function {
domain: Vec<Sort>,
codomain: Sort,
mappings: Vec<(Vec<ModelValue>, ModelValue)>,
default: Option<Box<ModelValue>>,
},
}
impl ModelValue {
pub fn is_bool(&self) -> bool {
matches!(self, ModelValue::Bool(_))
}
pub fn as_bool(&self) -> Option<bool> {
match self {
ModelValue::Bool(b) => Some(*b),
_ => None,
}
}
pub fn as_int(&self) -> Option<&BigInt> {
match self {
ModelValue::Int(i) => Some(i),
_ => None,
}
}
pub fn as_rational(&self) -> Option<&BigRational> {
match self {
ModelValue::Rational(r) => Some(r),
_ => None,
}
}
pub fn compatible_with_sort(&self, sort: &Sort) -> bool {
true
}
}
#[derive(Debug, Clone)]
pub struct ValueManagerConfig {
pub normalize_values: bool,
pub enable_caching: bool,
pub max_uninterpreted_id: usize,
}
impl Default for ValueManagerConfig {
fn default() -> Self {
Self {
normalize_values: true,
enable_caching: true,
max_uninterpreted_id: 100000,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct ValueManagerStats {
pub values_created: u64,
pub conversions: u64,
pub cache_hits: u64,
pub cache_misses: u64,
}
pub struct ValueManager {
config: ValueManagerConfig,
stats: ValueManagerStats,
term_values: FxHashMap<TermId, ModelValue>,
next_uninterp_id: FxHashMap<Sort, usize>,
cache: FxHashMap<ModelValue, ModelValue>,
}
impl ValueManager {
pub fn new(config: ValueManagerConfig) -> Self {
Self {
config,
stats: ValueManagerStats::default(),
term_values: FxHashMap::default(),
next_uninterp_id: FxHashMap::default(),
cache: FxHashMap::default(),
}
}
pub fn default_config() -> Self {
Self::new(ValueManagerConfig::default())
}
pub fn mk_bool(&mut self, value: bool) -> ModelValue {
self.stats.values_created += 1;
ModelValue::Bool(value)
}
pub fn mk_int(&mut self, value: BigInt) -> ModelValue {
self.stats.values_created += 1;
let val = ModelValue::Int(value);
if self.config.normalize_values {
self.normalize(val)
} else {
val
}
}
pub fn mk_rational(&mut self, value: BigRational) -> ModelValue {
self.stats.values_created += 1;
let val = ModelValue::Rational(value);
if self.config.normalize_values {
self.normalize(val)
} else {
val
}
}
pub fn mk_bitvector(&mut self, width: usize, value: BigInt) -> ModelValue {
self.stats.values_created += 1;
let mask = (BigInt::from(1) << width) - 1;
let masked_value = value & mask;
ModelValue::BitVector(width, masked_value)
}
pub fn mk_uninterpreted(&mut self, sort: Sort) -> ModelValue {
self.stats.values_created += 1;
let id = *self.next_uninterp_id.entry(sort.clone()).or_insert(0);
self.next_uninterp_id.insert(sort.clone(), id + 1);
ModelValue::Uninterpreted(sort, id)
}
pub fn mk_array(
&mut self,
default: ModelValue,
entries: Vec<(ModelValue, ModelValue)>,
) -> ModelValue {
self.stats.values_created += 1;
ModelValue::Array {
default: Box::new(default),
entries,
}
}
pub fn mk_datatype(&mut self, constructor: String, fields: Vec<ModelValue>) -> ModelValue {
self.stats.values_created += 1;
ModelValue::Datatype { constructor, fields }
}
fn normalize(&mut self, value: ModelValue) -> ModelValue {
if !self.config.enable_caching {
return value;
}
if let Some(cached) = self.cache.get(&value) {
self.stats.cache_hits += 1;
return cached.clone();
}
self.stats.cache_misses += 1;
let normalized = match &value {
ModelValue::Rational(r) => {
value.clone()
}
ModelValue::BitVector(w, v) => {
let mask = (BigInt::from(1) << w) - 1;
ModelValue::BitVector(*w, v & mask)
}
_ => value.clone(),
};
self.cache.insert(value, normalized.clone());
normalized
}
pub fn assign(&mut self, term: TermId, value: ModelValue) {
self.term_values.insert(term, value);
}
pub fn get_value(&self, term: TermId) -> Option<&ModelValue> {
self.term_values.get(&term)
}
pub fn value_to_term(&mut self, value: &ModelValue) -> Option<TermId> {
self.stats.conversions += 1;
None
}
pub fn eval(&self, term: TermId) -> Option<ModelValue> {
self.term_values.get(&term).cloned()
}
pub fn check_type(&self, value: &ModelValue, sort: &Sort) -> bool {
value.compatible_with_sort(sort)
}
pub fn num_assignments(&self) -> usize {
self.term_values.len()
}
pub fn clear(&mut self) {
self.term_values.clear();
self.cache.clear();
}
pub fn stats(&self) -> &ValueManagerStats {
&self.stats
}
pub fn reset_stats(&mut self) {
self.stats = ValueManagerStats::default();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_manager_creation() {
let manager = ValueManager::default_config();
assert_eq!(manager.stats().values_created, 0);
}
#[test]
fn test_create_bool() {
let mut manager = ValueManager::default_config();
let val = manager.mk_bool(true);
assert_eq!(val.as_bool(), Some(true));
assert_eq!(manager.stats().values_created, 1);
}
#[test]
fn test_create_int() {
let mut manager = ValueManager::default_config();
let val = manager.mk_int(BigInt::from(42));
assert_eq!(val.as_int(), Some(&BigInt::from(42)));
}
#[test]
fn test_create_bitvector() {
let mut manager = ValueManager::default_config();
let val = manager.mk_bitvector(8, BigInt::from(255));
if let ModelValue::BitVector(width, value) = val {
assert_eq!(width, 8);
assert_eq!(value, BigInt::from(255));
} else {
panic!("expected bitvector");
}
}
#[test]
fn test_bitvector_masking() {
let mut manager = ValueManager::default_config();
let val = manager.mk_bitvector(4, BigInt::from(255));
if let ModelValue::BitVector(width, value) = val {
assert_eq!(width, 4);
assert_eq!(value, BigInt::from(15)); } else {
panic!("expected bitvector");
}
}
#[test]
fn test_uninterpreted() {
let mut manager = ValueManager::default_config();
let sort = Sort::Uninterpreted("A".to_string());
let val1 = manager.mk_uninterpreted(sort.clone());
let val2 = manager.mk_uninterpreted(sort.clone());
if let (ModelValue::Uninterpreted(_, id1), ModelValue::Uninterpreted(_, id2)) =
(&val1, &val2)
{
assert_ne!(id1, id2);
} else {
panic!("expected uninterpreted values");
}
}
#[test]
fn test_assign_and_get() {
let mut manager = ValueManager::default_config();
let term = TermId::new(0);
let value = manager.mk_bool(true);
manager.assign(term, value.clone());
assert_eq!(manager.get_value(term), Some(&value));
assert_eq!(manager.num_assignments(), 1);
}
#[test]
fn test_clear() {
let mut manager = ValueManager::default_config();
let term = TermId::new(0);
let value = manager.mk_bool(false);
manager.assign(term, value);
assert_eq!(manager.num_assignments(), 1);
manager.clear();
assert_eq!(manager.num_assignments(), 0);
}
}