Skip to content

Commit d241156

Browse files
add projection with witnesses
expose model based projection with witness creation
1 parent b7b611d commit d241156

File tree

6 files changed

+106
-13
lines changed

6 files changed

+106
-13
lines changed

src/api/api_qe.cpp

+41
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Module Name:
2626
#include "api/api_ast_map.h"
2727
#include "api/api_ast_vector.h"
2828
#include "qe/lite/qe_lite_tactic.h"
29+
#include "qe/qe_mbp.h"
2930
#include "muz/spacer/spacer_util.h"
3031

3132
extern "C"
@@ -104,6 +105,46 @@ extern "C"
104105
Z3_CATCH_RETURN(nullptr);
105106
}
106107

108+
Z3_ast Z3_API Z3_qe_model_project_with_witness (Z3_context c,
109+
Z3_model mdl,
110+
unsigned num_bounds,
111+
Z3_app const bound[],
112+
Z3_ast body,
113+
Z3_ast_map map)
114+
{
115+
Z3_TRY;
116+
LOG_Z3_qe_model_project_with_witness (c, mdl, num_bounds, bound, body, map);
117+
RESET_ERROR_CODE();
118+
119+
ast_manager& m = mk_c(c)->m();
120+
app_ref_vector vars(m);
121+
if (!to_apps(num_bounds, bound, vars)) {
122+
RETURN_Z3(nullptr);
123+
}
124+
125+
expr_ref_vector fmls(m);
126+
fmls.push_back(to_expr(body));
127+
model_ref model (to_model_ref (mdl));
128+
vector<mbp::def> defs;
129+
qe::mbproj proj(m);
130+
131+
proj(true, vars, *model, fmls, &defs);
132+
expr_ref result (m);
133+
result = m.mk_and(fmls);
134+
mk_c(c)->save_ast_trail(result);
135+
136+
obj_map<ast, ast*> &map_z3 = to_ast_map_ref(map);
137+
138+
for (auto& [v, t] : defs) {
139+
m.inc_ref(v);
140+
m.inc_ref(t);
141+
map_z3.insert(v, t);
142+
}
143+
144+
return of_expr (result);
145+
Z3_CATCH_RETURN(nullptr);
146+
}
147+
107148
Z3_ast Z3_API Z3_model_extrapolate (Z3_context c,
108149
Z3_model m,
109150
Z3_ast fml)

src/api/python/z3/z3.py

+29-2
Original file line numberDiff line numberDiff line change
@@ -6732,16 +6732,43 @@ def translate(self, target):
67326732
model = Z3_model_translate(self.ctx.ref(), self.model, target.ref())
67336733
return ModelRef(model, target)
67346734

6735+
def project(self, vars, fml):
6736+
"""Perform model-based projection on fml with respect to vars.
6737+
Assume that the model satisfies fml. Then compute a projection fml_p, such
6738+
that vars do not occur free in fml_p, fml_p is true in the model and
6739+
fml_p => exists vars . fml
6740+
"""
6741+
ctx = self.ctx.ref()
6742+
_vars = (Ast * len(vars))()
6743+
for i in range(len(vars)):
6744+
_vars[i] = vars[i].as_ast()
6745+
return _to_expr_ref(Z3_qe_model_project(ctx, self.model, len(vars), _vars, fml.ast), self.ctx)
6746+
6747+
def project_with_witness(self, vars, fml):
6748+
"""Perform model-based projection, but also include realizer terms for the projected variables"""
6749+
ctx = self.ctx.ref()
6750+
_vars = (Ast * len(vars))()
6751+
for i in range(len(vars)):
6752+
_vars[i] = vars[i].as_ast()
6753+
defs = AstMap()
6754+
result = Z3_qe_model_project_with_witness(ctx, self.model, len(vars), _vars, fml.ast, defs.map)
6755+
result = _to_expr_ref(result, self.ctx)
6756+
return result, defs
6757+
6758+
67356759
def __copy__(self):
67366760
return self.translate(self.ctx)
67376761

67386762
def __deepcopy__(self, memo={}):
67396763
return self.translate(self.ctx)
67406764

67416765

6742-
def Model(ctx=None):
6766+
def Model(ctx=None, eval = {}):
67436767
ctx = _get_ctx(ctx)
6744-
return ModelRef(Z3_mk_model(ctx.ref()), ctx)
6768+
mdl = ModelRef(Z3_mk_model(ctx.ref()), ctx)
6769+
for k, v in eval.items():
6770+
mdl.update_value(k, v)
6771+
return mdl
67456772

67466773

67476774
def is_as_array(n):

src/api/z3_spacer.h

+16
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,22 @@ extern "C" {
112112
Z3_ast body,
113113
Z3_ast_map map);
114114

115+
/**
116+
\brief Project with witness extraction.
117+
118+
The returned map contains a binding of variables to terms that such that when the binding
119+
is used for the formula, it remains true within the model.
120+
121+
def_API('Z3_qe_model_project_with_witness', AST, (_in(CONTEXT), _in(MODEL), _in(UINT), _in_array(2, APP), _in(AST), _in(AST_MAP)))
122+
*/
123+
Z3_ast Z3_API Z3_qe_model_project_with_witness
124+
(Z3_context c,
125+
Z3_model m,
126+
unsigned num_bounds,
127+
Z3_app const bound[],
128+
Z3_ast body,
129+
Z3_ast_map map);
130+
115131
/**
116132
\brief Extrapolates a model of a formula
117133

src/qe/mbp/mbp_plugin.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Revision History:
2828

2929
namespace mbp {
3030

31-
struct cant_project {};
31+
struct cant_project : public std::exception {};
3232

3333
struct def {
3434
expr_ref var, term;

src/qe/qe_mbp.cpp

+16-9
Original file line numberDiff line numberDiff line change
@@ -418,12 +418,12 @@ class mbproj::impl {
418418
e = mk_and(fmls);
419419
return any_of(subterms::all(e), [&](expr* c) { return seq.is_char(c) || seq.is_seq(c); });
420420
}
421-
void operator()(bool force_elim, app_ref_vector& vars, model& model, expr_ref_vector& fmls) {
421+
void operator()(bool force_elim, app_ref_vector& vars, model& model, expr_ref_vector& fmls, vector<mbp::def>* defs = nullptr) {
422422
//don't use mbp_qel on some theories where model evaluation is
423423
//incomplete This is not a limitation of qel. Fix this either by
424424
//making mbp choices less dependent on the model evaluation methods
425425
//or fix theory rewriters to make terms evaluation complete
426-
if (m_use_qel && !has_unsupported_th(fmls)) {
426+
if (m_use_qel && !has_unsupported_th(fmls) && !defs) {
427427
bool dsub = m_dont_sub;
428428
m_dont_sub = !force_elim;
429429
expr_ref fml(m);
@@ -434,11 +434,11 @@ class mbproj::impl {
434434
m_dont_sub = dsub;
435435
}
436436
else {
437-
mbp(force_elim, vars, model, fmls);
437+
mbp(force_elim, vars, model, fmls, defs);
438438
}
439439
}
440440

441-
void mbp(bool force_elim, app_ref_vector& vars, model& model, expr_ref_vector& fmls) {
441+
void mbp(bool force_elim, app_ref_vector& vars, model& model, expr_ref_vector& fmls, vector<mbp::def>* defs) {
442442
SASSERT(validate_model(model, fmls));
443443
expr_ref val(m), tmp(m);
444444
app_ref var(m);
@@ -451,10 +451,15 @@ class mbproj::impl {
451451
app_ref_vector new_vars(m);
452452
progress = false;
453453
for (mbp::project_plugin* p : m_plugins) {
454-
if (p)
454+
if (defs && p) {
455+
unsigned sz = defs->size();
456+
p->project(model, vars, fmls, *defs);
457+
progress |= sz < defs->size();
458+
}
459+
else if (p)
455460
(*p)(model, vars, fmls);
456461
}
457-
while (!vars.empty() && !fmls.empty() && m.limit().inc()) {
462+
while (!vars.empty() && !fmls.empty() && !defs && m.limit().inc()) {
458463
var = vars.back();
459464
vars.pop_back();
460465
mbp::project_plugin* p = get_plugin(var);
@@ -471,6 +476,8 @@ class mbproj::impl {
471476
expr_safe_replace sub(m);
472477
val = model(var);
473478
sub.insert(var, val);
479+
if (defs)
480+
defs->push_back(mbp::def(expr_ref(var, m), val));
474481
unsigned j = 0;
475482
for (expr* f : fmls) {
476483
sub(f, tmp);
@@ -562,7 +569,7 @@ class mbproj::impl {
562569
expr_ref_vector fmls(m);
563570
flatten_and(fml, fmls);
564571

565-
mbp(false, other_vars, mdl, fmls);
572+
mbp(false, other_vars, mdl, fmls, nullptr);
566573
fml = mk_and(fmls);
567574
m_rw(fml);
568575

@@ -704,9 +711,9 @@ void mbproj::get_param_descrs(param_descrs& r) {
704711
r.insert("use_qel", CPK_BOOL, "(default: true) use egraph based QEL");
705712
}
706713

707-
void mbproj::operator()(bool force_elim, app_ref_vector& vars, model& mdl, expr_ref_vector& fmls) {
714+
void mbproj::operator()(bool force_elim, app_ref_vector& vars, model& mdl, expr_ref_vector& fmls, vector<mbp::def>* defs) {
708715
scoped_no_proof _sp(fmls.get_manager());
709-
(*m_impl)(force_elim, vars, mdl, fmls);
716+
(*m_impl)(force_elim, vars, mdl, fmls, defs);
710717
}
711718

712719
void mbproj::spacer(app_ref_vector& vars, model& mdl, expr_ref& fml) {

src/qe/qe_mbp.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Revision History:
2424
#include "util/params.h"
2525
#include "model/model.h"
2626
#include "math/simplex/model_based_opt.h"
27+
#include "qe/mbp/mbp_plugin.h"
2728

2829

2930
namespace qe {
@@ -45,7 +46,7 @@ namespace qe {
4546
Apply model-based qe on constants provided as vector of variables.
4647
Return the updated formula and updated set of variables that were not eliminated.
4748
*/
48-
void operator()(bool force_elim, app_ref_vector& vars, model& mdl, expr_ref_vector& fmls);
49+
void operator()(bool force_elim, app_ref_vector& vars, model& mdl, expr_ref_vector& fmls, vector<mbp::def>* defs = nullptr);
4950

5051
/**
5152
\brief
@@ -70,3 +71,4 @@ namespace qe {
7071
};
7172
}
7273

74+

0 commit comments

Comments
 (0)