Skip to content

Commit 854e42c

Browse files
committed
Implement AST evaluation functions for Bool, Int, Real types
1 parent 6197986 commit 854e42c

File tree

2 files changed

+144
-7
lines changed

2 files changed

+144
-7
lines changed

z3rro/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ thiserror = "1.0"
1515
im-rc = "15"
1616
enum-map = "2.7.3"
1717
itertools = "0.14.0"
18+
smtlib-lowlevel = "0.3.0"
1819

1920
[features]
2021
datatype-eureal = []

z3rro/src/model.rs

Lines changed: 143 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,43 @@ use std::{
77
};
88

99
use num::{BigInt, BigRational};
10+
11+
use smtlib_lowlevel::{
12+
ast::{
13+
FunctionDef, GetModelResponse, Identifier, ModelResponse, QualIdentifier, SpecConstant,
14+
Term,
15+
},
16+
lexicon::{Decimal, Symbol},
17+
};
18+
1019
use thiserror::Error;
20+
1121
use z3::{
1222
ast::{Ast, Bool, Dynamic, Int, Real},
1323
FuncDecl, FuncInterp, Model,
1424
};
1525

26+
#[derive(Debug)]
27+
pub enum ModelSource<'ctx> {
28+
Z3Model(Model<'ctx>),
29+
SwineModel(GetModelResponse<'ctx>),
30+
}
31+
1632
/// A [`z3::Model`] which keeps track of the accessed constants. This is useful
1733
/// to later print those constants which were not accessed by any of the
1834
/// [`SmtEval`] implementations (e.g. stuff generated by Z3 we don't know
1935
/// about). This way, we can print the whole model and pretty-print everything
2036
/// we know, and then print the rest of the assignments in the model as well.
2137
#[derive(Debug)]
2238
pub struct InstrumentedModel<'ctx> {
23-
model: Model<'ctx>,
39+
model: ModelSource<'ctx>,
2440
// TODO: turn this into a HashSet of FuncDecls when the type implements Hash
2541
accessed_decls: RefCell<im_rc::HashSet<String>>,
2642
accessed_exprs: RefCell<im_rc::HashSet<Dynamic<'ctx>>>,
2743
}
2844

2945
impl<'ctx> InstrumentedModel<'ctx> {
30-
pub fn new(model: Model<'ctx>) -> Self {
46+
pub fn new(model: ModelSource<'ctx>) -> Self {
3147
InstrumentedModel {
3248
model,
3349
accessed_decls: Default::default(),
@@ -57,14 +73,129 @@ impl<'ctx> InstrumentedModel<'ctx> {
5773
/// the model.
5874
pub fn eval<T: Ast<'ctx>>(&self, ast: &T, model_completion: bool) -> Option<T> {
5975
self.add_children_accessed(Dynamic::from_ast(ast));
60-
let res = self.model.eval(ast, model_completion)?;
61-
Some(res)
76+
match &self.model {
77+
ModelSource::Z3Model(model) => {
78+
let res = model.eval(ast, model_completion)?;
79+
Some(res)
80+
}
81+
ModelSource::SwineModel(_) => todo!(),
82+
}
83+
}
84+
85+
pub fn eval_ast_bool(&self, ast: &Bool<'ctx>) -> Option<Bool<'ctx>> {
86+
let name = ast.decl().name();
87+
88+
if let ModelSource::SwineModel(s_model) = &self.model {
89+
match Self::find_fun_def(s_model, &name) {
90+
Some(fun_def) => match fun_def.3 {
91+
Term::Identifier(QualIdentifier::Identifier(Identifier::Simple(Symbol(
92+
"true",
93+
)))) => Some(Bool::from_bool(ast.get_ctx(), true)),
94+
Term::Identifier(QualIdentifier::Identifier(Identifier::Simple(Symbol(
95+
"false",
96+
)))) => Some(Bool::from_bool(ast.get_ctx(), false)),
97+
_ => None,
98+
},
99+
None => None,
100+
}
101+
} else {
102+
None
103+
}
104+
}
105+
106+
pub fn eval_ast_int(&self, ast: &Int<'ctx>) -> Option<Int<'ctx>> {
107+
let name = ast.decl().name();
108+
109+
if let ModelSource::SwineModel(s_model) = &self.model {
110+
match Self::find_fun_def(s_model, &name) {
111+
Some(fun_def) => match fun_def.3 {
112+
Term::SpecConstant(SpecConstant::Numeral(numeral)) => {
113+
if let Ok(n) = numeral.into_u128() {
114+
let n_str = n.to_string();
115+
Int::from_str(ast.get_ctx(), &n_str)
116+
} else {
117+
None
118+
}
119+
}
120+
_ => None,
121+
},
122+
None => None,
123+
}
124+
} else {
125+
None
126+
}
127+
}
128+
129+
pub fn eval_ast_real(&self, ast: &Real<'ctx>) -> Option<Real<'ctx>> {
130+
let name = ast.decl().name();
131+
132+
if let ModelSource::SwineModel(s_model) = &self.model {
133+
match Self::find_fun_def(s_model, &name) {
134+
Some(fun_def) => match fun_def.3 {
135+
Term::SpecConstant(SpecConstant::Decimal(Decimal(d_str))) => {
136+
if let Some((num, den)) = Self::from_str_to_num_den(d_str) {
137+
Real::from_real_str(ast.get_ctx(), &num, &den)
138+
} else {
139+
None
140+
}
141+
}
142+
_ => None,
143+
},
144+
None => None,
145+
}
146+
} else {
147+
None
148+
}
149+
}
150+
151+
/// Convert a decimal string `d_str` into a pair of a numerator (`num`) and
152+
/// a denominator (`den`) in the form of '[numeral]' strings such that:
153+
/// d_str = num / den
154+
pub fn from_str_to_num_den(d_str: &str) -> Option<(String, String)> {
155+
if d_str.is_empty() {
156+
return None;
157+
}
158+
159+
if let Some(pos) = d_str.find('.') {
160+
let den = "1".to_string() + &"0".repeat(d_str.len() - pos - 1);
161+
162+
let mut num = d_str.to_string();
163+
num.remove(pos);
164+
num.trim_start_matches('0');
165+
166+
if num.is_empty() {
167+
num = "0".to_string();
168+
}
169+
170+
Some((num, den))
171+
} else {
172+
Some((d_str.to_string(), "1".to_string()))
173+
}
174+
}
175+
176+
/// Find a `FunctionDef` object defined for a given symbol `symbol` within the `model_res`.
177+
pub fn find_fun_def(
178+
model_res: &GetModelResponse<'ctx>,
179+
symbol: &str,
180+
) -> Option<&'ctx FunctionDef<'ctx>> {
181+
model_res.0.iter().find_map(|m_res| {
182+
if let ModelResponse::DefineFun(fun_def) = m_res {
183+
if fun_def.0.0 == symbol {
184+
Some(fun_def)
185+
} else {
186+
None
187+
}
188+
} else {
189+
None
190+
}
191+
})
62192
}
63193

64194
/// Get the function interpretation for this `f`.
65195
pub fn get_func_interp(&self, f: &FuncDecl<'ctx>) -> Option<FuncInterp<'ctx>> {
66196
self.accessed_decls.borrow_mut().insert(f.name());
67-
self.model.get_func_interp(f)
197+
todo!()
198+
// self.model.get_func_interp(f)
68199
}
69200

70201
/// Add this ast node and all its children to the accessed set.
@@ -89,9 +220,12 @@ impl<'ctx> InstrumentedModel<'ctx> {
89220
/// Iterate over all function declarations that were not accessed using
90221
/// `eval` so far.
91222
pub fn iter_unaccessed(&self) -> impl Iterator<Item = FuncDecl<'ctx>> + '_ {
223+
todo!()
224+
/*
92225
self.model
93226
.iter()
94227
.filter(|decl| !self.accessed_decls.borrow().contains(&decl.name()))
228+
*/
95229
}
96230

97231
/// Reset the internally tracked accessed declarations and expressions.
@@ -101,15 +235,17 @@ impl<'ctx> InstrumentedModel<'ctx> {
101235
}
102236

103237
pub fn into_model(self) -> Model<'ctx> {
104-
self.model
238+
todo!()
239+
// self.model
105240
}
106241
}
107242

108243
/// The [`Display`] implementation simply defers to the underlying
109244
/// [`z3::Model`]'s implementation.
110245
impl Display for InstrumentedModel<'_> {
111246
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112-
f.write_fmt(format_args!("{}", &self.model))
247+
todo!()
248+
// f.write_fmt(format_args!("{}", &self.model))
113249
}
114250
}
115251

0 commit comments

Comments
 (0)