3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-10-04 06:53:58 +00:00
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2012-12-10 14:07:59 -08:00
commit 265bdbe757
76 changed files with 3991 additions and 1422 deletions

View file

@ -38,13 +38,6 @@ struct arith_decl_plugin::algebraic_numbers_wrapper {
unsigned mk_id(algebraic_numbers::anum const & val) {
SASSERT(!m_amanager.is_rational(val));
// TODO: avoid linear scan. Use hashtable based on the floor of val
unsigned sz = m_nums.size();
for (unsigned i = 0; i < sz; i++) {
algebraic_numbers::anum const & other = m_nums.get(i);
if (m_amanager.eq(val, other))
return i;
}
unsigned new_id = m_id_gen.mk();
m_nums.reserve(new_id+1);
m_amanager.set(m_nums[new_id], val);
@ -71,13 +64,13 @@ struct arith_decl_plugin::algebraic_numbers_wrapper {
};
arith_decl_plugin::algebraic_numbers_wrapper & arith_decl_plugin::aw() {
arith_decl_plugin::algebraic_numbers_wrapper & arith_decl_plugin::aw() const {
if (m_aw == 0)
m_aw = alloc(algebraic_numbers_wrapper);
const_cast<arith_decl_plugin*>(this)->m_aw = alloc(algebraic_numbers_wrapper);
return *m_aw;
}
algebraic_numbers::manager & arith_decl_plugin::am() {
algebraic_numbers::manager & arith_decl_plugin::am() const {
return aw().m_amanager;
}
@ -509,16 +502,43 @@ void arith_decl_plugin::get_op_names(svector<builtin_name>& op_names, symbol con
}
}
bool arith_decl_plugin::is_value(app* e) const {
return is_app_of(e, m_family_id, OP_NUM);
bool arith_decl_plugin::is_value(app * e) const {
return
is_app_of(e, m_family_id, OP_NUM) ||
is_app_of(e, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM) ||
is_app_of(e, m_family_id, OP_PI) ||
is_app_of(e, m_family_id, OP_E);
}
bool arith_decl_plugin::are_distinct(app* a, app* b) const {
bool arith_decl_plugin::is_unique_value(app * e) const {
return
is_app_of(e, m_family_id, OP_NUM) ||
is_app_of(e, m_family_id, OP_PI) ||
is_app_of(e, m_family_id, OP_E);
}
bool arith_decl_plugin::are_equal(app * a, app * b) const {
if (decl_plugin::are_equal(a, b)) {
return true;
}
if (is_app_of(a, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM) && is_app_of(b, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM)) {
return am().eq(aw().to_anum(a->get_decl()), aw().to_anum(b->get_decl()));
}
return false;
}
bool arith_decl_plugin::are_distinct(app * a, app * b) const {
TRACE("are_distinct_bug", tout << mk_ismt2_pp(a, *m_manager) << "\n" << mk_ismt2_pp(b, *m_manager) << "\n";);
if (decl_plugin::are_distinct(a,b)) {
return true;
}
if (is_app_of(a, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM) && is_app_of(b, m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM)) {
return am().neq(aw().to_anum(a->get_decl()), aw().to_anum(b->get_decl()));
}
#define is_non_zero(e) is_app_of(e,m_family_id, OP_NUM) && !to_app(e)->get_decl()->get_parameter(0).get_rational().is_zero()
if (is_app_of(a, m_family_id, OP_ADD) &&

View file

@ -141,8 +141,8 @@ public:
virtual ~arith_decl_plugin();
virtual void finalize();
algebraic_numbers::manager & am();
algebraic_numbers_wrapper & aw();
algebraic_numbers::manager & am() const;
algebraic_numbers_wrapper & aw() const;
virtual void del(parameter const & p);
virtual parameter translate(parameter const & p, decl_plugin & target);
@ -159,9 +159,13 @@ public:
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned num_args, expr * const * args, sort * range);
virtual bool is_value(app* e) const;
virtual bool is_value(app * e) const;
virtual bool are_distinct(app* a, app* b) const;
virtual bool is_unique_value(app * e) const;
virtual bool are_equal(app * a, app * b) const;
virtual bool are_distinct(app * a, app * b) const;
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
@ -180,7 +184,7 @@ public:
virtual expr * get_some_value(sort * s);
void set_cancel(bool f);
virtual void set_cancel(bool f);
};
class arith_util {

View file

@ -872,6 +872,10 @@ bool basic_decl_plugin::is_value(app* a) const {
return a->get_decl() == m_true_decl || a->get_decl() == m_false_decl;
}
bool basic_decl_plugin::is_unique_value(app* a) const {
return is_value(a);
}
void basic_decl_plugin::finalize() {
#define DEC_REF(FIELD) if (FIELD) { m_manager->dec_ref(FIELD); }
#define DEC_ARRAY_REF(FIELD) m_manager->dec_array_ref(FIELD.size(), FIELD.begin())
@ -1151,6 +1155,10 @@ bool model_value_decl_plugin::is_value(app* n) const {
return is_app_of(n, m_family_id, OP_MODEL_VALUE);
}
bool model_value_decl_plugin::is_unique_value(app* n) const {
return is_value(n);
}
// -----------------------------------
//
// user_sort_plugin
@ -1328,6 +1336,12 @@ ast_manager::~ast_manager() {
}
}
void ast_manager::set_cancel(bool f) {
for (unsigned i = 0; i < m_plugins.size(); i++) {
m_plugins[i]->set_cancel(f);
}
}
void ast_manager::compact_memory() {
m_alloc.consolidate();
unsigned capacity = m_ast_table.capacity();
@ -1442,6 +1456,27 @@ bool ast_manager::is_value(expr* e) const {
return false;
}
bool ast_manager::is_unique_value(expr* e) const {
decl_plugin const * p = 0;
if (is_app(e)) {
p = get_plugin(to_app(e)->get_family_id());
return p && p->is_unique_value(to_app(e));
}
return false;
}
bool ast_manager::are_equal(expr * a, expr * b) const {
if (is_app(a) && is_app(b)) {
app* ap = to_app(a), *bp = to_app(b);
decl_plugin const * p = get_plugin(ap->get_family_id());
if (!p) {
p = get_plugin(bp->get_family_id());
}
return p && p->are_equal(ap, bp);
}
return false;
}
bool ast_manager::are_distinct(expr* a, expr* b) const {
if (is_app(a) && is_app(b)) {
app* ap = to_app(a), *bp = to_app(b);

View file

@ -921,6 +921,8 @@ public:
virtual ~decl_plugin() {}
virtual void finalize() {}
virtual void set_cancel(bool f) {}
virtual decl_plugin * mk_fresh() = 0;
family_id get_family_id() const { return m_family_id; }
@ -933,9 +935,39 @@ public:
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const* parameters,
unsigned num_args, expr * const * args, sort * range);
virtual bool is_value(app*) const { return false; }
/**
\brief Return true if the plugin can decide whether two
interpreted constants are equal or not.
For all a, b:
If is_value(a) and is_value(b)
Then,
are_equal(a, b) != are_distinct(a, b)
The may be much more expensive than checking a pointer.
virtual bool are_distinct(app* a, app* b) const { return a != b && is_value(a) && is_value(b); }
We need this because some plugin values are too expensive too canonize.
*/
virtual bool is_value(app * a) const { return false; }
/**
\brief Return true if \c a is a unique plugin value.
The following property should hold for unique theory values:
For all a, b:
If is_unique_value(a) and is_unique_value(b)
Then,
a == b (pointer equality)
IFF
the interpretations of these theory terms are equal.
\remark This is a stronger version of is_value.
*/
virtual bool is_unique_value(app * a) const { return false; }
virtual bool are_equal(app * a, app * b) const { return a == b && is_unique_value(a) && is_unique_value(b); }
virtual bool are_distinct(app * a, app * b) const { return a != b && is_unique_value(a) && is_unique_value(b); }
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic = symbol()) {}
@ -1080,6 +1112,8 @@ public:
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);
virtual bool is_value(app* a) const;
virtual bool is_unique_value(app* a) const;
sort * mk_bool_sort() const { return m_bool_sort; }
sort * mk_proof_sort() const { return m_proof_sort; }
@ -1116,7 +1150,6 @@ public:
virtual decl_plugin * mk_fresh() { return alloc(label_decl_plugin); }
virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters);
/**
@ -1198,6 +1231,8 @@ public:
unsigned arity, sort * const * domain, sort * range);
virtual bool is_value(app* n) const;
virtual bool is_unique_value(app* a) const;
};
// -----------------------------------
@ -1367,6 +1402,9 @@ public:
ast_manager(ast_manager const & src, bool disable_proofs = false);
~ast_manager();
// propagate cancellation signal to decl_plugins
void set_cancel(bool f);
bool has_trace_stream() const { return m_trace_stream != 0; }
std::ostream & trace_stream() { SASSERT(has_trace_stream()); return *m_trace_stream; }
@ -1442,9 +1480,13 @@ public:
*/
void set_next_expr_id(unsigned id);
bool is_value(expr* e) const;
bool is_value(expr * e) const;
bool is_unique_value(expr * e) const;
bool are_distinct(expr* a, expr* b) const;
bool are_equal(expr * a, expr * b) const;
bool are_distinct(expr * a, expr * b) const;
bool contains(ast * a) const { return m_ast_table.contains(a); }

View file

@ -260,8 +260,10 @@ public:
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned num_args, expr * const * args, sort * range);
virtual bool is_value(app* e) const;
virtual bool is_value(app * e) const;
virtual bool is_unique_value(app * e) const { return is_value(e); }
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);

View file

@ -146,6 +146,9 @@ public:
virtual bool is_fully_interp(sort const * s) const;
virtual bool is_value(app* e) const;
virtual bool is_unique_value(app * e) const { return is_value(e); }
private:
bool is_value_visit(expr * arg, ptr_buffer<app> & todo) const;
};

View file

@ -130,7 +130,8 @@ namespace datalog {
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);
virtual bool is_value(app* e) const { return is_app_of(e, m_family_id, OP_DL_CONSTANT); }
virtual bool is_value(app * e) const { return is_app_of(e, m_family_id, OP_DL_CONSTANT); }
virtual bool is_unique_value(app * e) const { return is_value(e); }
};

View file

@ -49,21 +49,24 @@ struct expr2polynomial::imp {
polynomial::polynomial_ref_vector m_presult_stack;
polynomial::scoped_numeral_vector m_dresult_stack;
bool m_use_var_idxs;
volatile bool m_cancel;
imp(expr2polynomial & w, ast_manager & am, polynomial::manager & pm, expr2var * e2v):
imp(expr2polynomial & w, ast_manager & am, polynomial::manager & pm, expr2var * e2v, bool use_var_idxs):
m_wrapper(w),
m_am(am),
m_autil(am),
m_pm(pm),
m_expr2var(e2v == 0 ? alloc(expr2var, am) : e2v),
m_expr2var_owner(e2v == 0),
m_expr2var(e2v == 0 && !use_var_idxs ? alloc(expr2var, am) : e2v),
m_expr2var_owner(e2v == 0 && !use_var_idxs),
m_var2expr(am),
m_cached_domain(am),
m_cached_polynomials(pm),
m_cached_denominators(pm.m()),
m_presult_stack(pm),
m_dresult_stack(pm.m()),
m_use_var_idxs(use_var_idxs),
m_cancel(false) {
}
@ -95,6 +98,14 @@ struct expr2polynomial::imp {
cooperate("expr2polynomial");
}
void throw_not_polynomial() {
throw default_exception("the given expression is not a polynomial");
}
void throw_no_int_var() {
throw default_exception("integer variables are not allowed in the given polynomial");
}
void push_frame(app * t) {
m_frame_stack.push_back(frame(t));
}
@ -127,14 +138,26 @@ struct expr2polynomial::imp {
}
void store_var_poly(expr * t) {
polynomial::var x = m_expr2var->to_var(t);
if (x == UINT_MAX) {
bool is_int = m_autil.is_int(t);
x = m_wrapper.mk_var(is_int);
m_expr2var->insert(t, x);
if (x >= m_var2expr.size())
m_var2expr.resize(x+1, 0);
m_var2expr.set(x, t);
polynomial::var x;
if (m_use_var_idxs) {
SASSERT(::is_var(t));
if (m_autil.is_int(t))
throw_no_int_var();
unsigned idx = to_var(t)->get_idx();
while (idx >= m_pm.num_vars())
m_pm.mk_var();
x = static_cast<polynomial::var>(idx);
}
else {
x = m_expr2var->to_var(t);
if (x == UINT_MAX) {
bool is_int = m_autil.is_int(t);
x = m_wrapper.mk_var(is_int);
m_expr2var->insert(t, x);
if (x >= m_var2expr.size())
m_var2expr.resize(x+1, 0);
m_var2expr.set(x, t);
}
}
polynomial::numeral one(1);
store_result(t, pm().mk_polynomial(x), one);
@ -160,7 +183,10 @@ struct expr2polynomial::imp {
rational k;
SASSERT(t->get_num_args() == 2);
if (!m_autil.is_numeral(t->get_arg(1), k) || !k.is_int() || !k.is_unsigned()) {
store_var_poly(t);
if (m_use_var_idxs)
throw_not_polynomial();
else
store_var_poly(t);
return true;
}
push_frame(t);
@ -168,6 +194,8 @@ struct expr2polynomial::imp {
}
default:
// can't handle operator
if (m_use_var_idxs)
throw_not_polynomial();
store_var_poly(t);
return true;
}
@ -190,6 +218,8 @@ struct expr2polynomial::imp {
SASSERT(is_app(t));
if (!m_autil.is_arith_expr(t)) {
if (m_use_var_idxs)
throw_not_polynomial();
store_var_poly(t);
return true;
}
@ -378,19 +408,25 @@ struct expr2polynomial::imp {
for (unsigned i = 0; i < sz; i++) {
margs.reset();
polynomial::monomial * m = pm().get_monomial(p, i);
polynomial::monomial * _m = pm().get_monomial(p, i);
polynomial::numeral const & a = pm().coeff(p, i);
if (!nm().is_one(a)) {
margs.push_back(m_autil.mk_numeral(rational(a), is_int));
}
unsigned msz = pm().size(m);
unsigned msz = pm().size(_m);
for (unsigned j = 0; j < msz; j++) {
polynomial::var x = pm().get_var(m, j);
expr * t = m_var2expr.get(x);
if (m_wrapper.is_int(x) && !is_int) {
t = m_autil.mk_to_real(t);
polynomial::var x = pm().get_var(_m, j);
expr * t;
if (m_use_var_idxs) {
t = m().mk_var(x, m_autil.mk_real());
}
unsigned d = pm().degree(m, j);
else {
t = m_var2expr.get(x);
if (m_wrapper.is_int(x) && !is_int) {
t = m_autil.mk_to_real(t);
}
}
unsigned d = pm().degree(_m, j);
if (use_power && d > 1) {
margs.push_back(m_autil.mk_power(t, m_autil.mk_numeral(rational(d), is_int)));
}
@ -426,8 +462,8 @@ struct expr2polynomial::imp {
}
};
expr2polynomial::expr2polynomial(ast_manager & am, polynomial::manager & pm, expr2var * e2v) {
m_imp = alloc(imp, *this, am, pm, e2v);
expr2polynomial::expr2polynomial(ast_manager & am, polynomial::manager & pm, expr2var * e2v, bool use_var_idxs) {
m_imp = alloc(imp, *this, am, pm, e2v, use_var_idxs);
}
expr2polynomial::~expr2polynomial() {
@ -451,10 +487,12 @@ void expr2polynomial::to_expr(polynomial::polynomial_ref const & p, bool use_pow
}
bool expr2polynomial::is_var(expr * t) const {
SASSERT(!m_imp->m_use_var_idxs);
return m_imp->m_expr2var->is_var(t);
}
expr2var const & expr2polynomial::get_mapping() const {
SASSERT(!m_imp->m_use_var_idxs);
return *(m_imp->m_expr2var);
}

View file

@ -29,7 +29,24 @@ class expr2polynomial {
struct imp;
imp * m_imp;
public:
expr2polynomial(ast_manager & am, polynomial::manager & pm, expr2var * e2v);
expr2polynomial(ast_manager & am,
polynomial::manager & pm,
expr2var * e2v,
/*
If true, the expressions converted into
polynomials should only contain Z3 free variables.
A Z3 variable x, with idx i, is converted into
the variable i of the polynomial manager pm.
An exception is thrown if there is a mismatch between
the sorts x and the variable in the polynomial manager.
The argument e2v is ignored when use_var_idxs is true.
Moreover, only real variables are allowed.
*/
bool use_var_idxs = false
);
virtual ~expr2polynomial();
ast_manager & m() const;
@ -63,6 +80,8 @@ public:
/**
\brief Return the mapping from expressions to variables
\pre the object was created using use_var_idxs = false.
*/
expr2var const & get_mapping() const;
@ -74,10 +93,10 @@ public:
/**
\brief Return true if the variable is associated with an expression of integer sort.
*/
virtual bool is_int(polynomial::var x) const = 0;
virtual bool is_int(polynomial::var x) const { UNREACHABLE(); return false; }
protected:
virtual polynomial::var mk_var(bool is_int) = 0;
virtual polynomial::var mk_var(bool is_int) { UNREACHABLE(); return polynomial::null_var; }
};
class default_expr2polynomial : public expr2polynomial {

View file

@ -141,6 +141,7 @@ public:
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);
virtual bool is_value(app* e) const;
virtual bool is_unique_value(app* e) const { return is_value(e); }
mpf_manager & fm() { return m_fm; }
func_decl * mk_value_decl(mpf const & v);

View file

@ -5,7 +5,7 @@ def_module_params(class_name='pattern_inference_params_helper',
params=(('max_multi_patterns', UINT, 0, 'when patterns are not provided, the prover uses a heuristic to infer them, this option sets the threshold on the number of extra multi-patterns that can be created; by default, the prover creates at most one multi-pattern when there is no unary pattern'),
('block_loop_patterns', BOOL, True, 'block looping patterns during pattern inference'),
('arith', UINT, 1, '0 - do not infer patterns with arithmetic terms, 1 - use patterns with arithmetic terms if there is no other pattern, 2 - always use patterns with arithmetic terms'),
('use_database', BOOL, True, 'use pattern database'),
('use_database', BOOL, False, 'use pattern database'),
('arith_weight', UINT, 5, 'default weight for quantifiers where the only available pattern has nested arithmetic terms'),
('non_nested_arith_weight', UINT, 10, 'default weight for quantifiers where the only available pattern has non nested arithmetic terms'),
('pull_quantifiers', BOOL, True, 'pull nested quantifiers, if no pattern was found'),

View file

@ -732,7 +732,7 @@ br_status bool_rewriter::mk_distinct_core(unsigned num_args, expr * const * args
return BR_DONE;
}
visited.mark(arg);
if (!m().is_value(arg))
if (!m().is_unique_value(arg))
all_value = false;
}
if (all_value) {

View file

@ -200,7 +200,12 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
expr * mk_eq_value(expr * lhs, expr * value) {
SASSERT(m().is_value(value));
if (m().is_value(lhs)) {
return lhs == value ? m().mk_true() : m().mk_false();
if (m().are_equal(lhs, value)) {
return m().mk_true();
}
else if (m().are_distinct(lhs, value)) {
return m().mk_false();
}
}
return m().mk_eq(lhs, value);
}

View file

@ -112,7 +112,10 @@ public:
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);
virtual bool is_value(app* e) const;
virtual bool is_value(app * e) const;
virtual bool is_unique_value(app * e) const { return is_value(e); }
};

View file

@ -293,7 +293,7 @@ bool array_simplifier_plugin::all_const_array(unsigned num_args, expr* const* ar
bool array_simplifier_plugin::all_values(unsigned num_args, expr* const* args) const {
for (unsigned i = 0; i < num_args; ++i) {
if (!m_manager.is_value(args[i])) {
if (!m_manager.is_unique_value(args[i])) {
return false;
}
}
@ -331,7 +331,7 @@ lbool array_simplifier_plugin::eq_default(expr* def, unsigned arity, unsigned nu
if (st[i][arity] == def) {
continue;
}
if (m_manager.is_value(st[i][arity]) && m_manager.is_value(def)) {
if (m_manager.is_unique_value(st[i][arity]) && m_manager.is_unique_value(def)) {
return l_false;
}
return l_undef;
@ -342,7 +342,7 @@ lbool array_simplifier_plugin::eq_default(expr* def, unsigned arity, unsigned nu
bool array_simplifier_plugin::insert_table(expr* def, unsigned arity, unsigned num_st, expr*const* const* st, arg_table& table) {
for (unsigned i = 0; i < num_st; ++i ) {
for (unsigned j = 0; j < arity; ++j) {
if (!m_manager.is_value(st[i][j])) {
if (!m_manager.is_unique_value(st[i][j])) {
return false;
}
}
@ -380,12 +380,12 @@ lbool array_simplifier_plugin::eq_stores(expr* def, unsigned arity, unsigned num
table2.erase(e1);
continue;
}
if (m_manager.is_value(v1) && m_manager.is_value(v2)) {
if (m_manager.is_unique_value(v1) && m_manager.is_unique_value(v2)) {
return l_false;
}
return l_undef;
}
else if (m_manager.is_value(v1) && m_manager.is_value(def) && v1 != def) {
else if (m_manager.is_unique_value(v1) && m_manager.is_unique_value(def) && v1 != def) {
return l_false;
}
}
@ -394,7 +394,7 @@ lbool array_simplifier_plugin::eq_stores(expr* def, unsigned arity, unsigned num
for (; it != end; ++it) {
args_entry const & e = *it;
expr* v = e.m_args[arity];
if (m_manager.is_value(v) && m_manager.is_value(def) && v != def) {
if (m_manager.is_unique_value(v) && m_manager.is_unique_value(def) && v != def) {
return l_false;
}
}
@ -431,7 +431,7 @@ bool array_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & resul
return false;
}
}
else if (m_manager.is_value(c1) && m_manager.is_value(c2)) {
else if (m_manager.is_unique_value(c1) && m_manager.is_unique_value(c2)) {
result = m_manager.mk_false();
return true;
}
@ -464,7 +464,7 @@ array_simplifier_plugin::mk_select_const(expr* m, app* index, expr_ref& result)
//
// Unfold and cache the store while searching for value of index.
//
while (is_store(a) && m_manager.is_value(to_app(a)->get_arg(1))) {
while (is_store(a) && m_manager.is_unique_value(to_app(a)->get_arg(1))) {
app* b = to_app(a);
app* c = to_app(b->get_arg(1));
@ -728,7 +728,7 @@ void array_simplifier_plugin::mk_select(unsigned num_args, expr * const * args,
return;
}
bool is_const_select = num_args == 2 && m_manager.is_value(args[1]);
bool is_const_select = num_args == 2 && m_manager.is_unique_value(args[1]);
app* const_index = is_const_select?to_app(args[1]):0;
unsigned num_const_stores = 0;
expr_ref tmp(m_manager);
@ -766,7 +766,7 @@ void array_simplifier_plugin::mk_select(unsigned num_args, expr * const * args,
expr * else_branch = 0;
entry[0] = nested_array;
if (is_const_select) {
if (m_manager.is_value(to_app(m)->get_arg(1))) {
if (m_manager.is_unique_value(to_app(m)->get_arg(1))) {
app* const_index2 = to_app(to_app(m)->get_arg(1));
//
// we found the value, all other stores are different.