3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 09:05:31 +00:00

synchronizing with main repository

This commit is contained in:
nilsbecker 2019-02-22 00:19:43 +01:00
commit ec76efedbe
386 changed files with 10027 additions and 8346 deletions

View file

@ -17,6 +17,7 @@ z3_add_component(ast
csp_decl_plugin.cpp
datatype_decl_plugin.cpp
decl_collector.cpp
display_dimacs.cpp
dl_decl_plugin.cpp
expr2polynomial.cpp
expr2var.cpp

View file

@ -73,11 +73,9 @@ void act_cache::init() {
}
void act_cache::dec_refs() {
map::iterator it = m_table.begin();
map::iterator end = m_table.end();
for (; it != end; ++it) {
m_manager.dec_ref((*it).m_key);
m_manager.dec_ref(UNTAG(expr*, (*it).m_value));
for (auto & kv : m_table) {
m_manager.dec_ref(kv.m_key.first);
m_manager.dec_ref(UNTAG(expr*, kv.m_value));
}
}
@ -105,18 +103,18 @@ act_cache::~act_cache() {
void act_cache::del_unused() {
unsigned sz = m_queue.size();
while (m_qhead < sz) {
expr * k = m_queue[m_qhead];
entry_t const& e = m_queue[m_qhead];
m_qhead++;
SASSERT(m_table.contains(k));
map::key_value * entry = m_table.find_core(k);
SASSERT(m_table.contains(e));
map::key_value * entry = m_table.find_core(e);
SASSERT(entry);
if (GET_TAG(entry->m_value) == 0) {
// Key k was never accessed by client code.
// That is, find(k) was never executed by client code.
m_unused--;
expr * v = entry->m_value;
m_table.erase(k);
m_manager.dec_ref(k);
m_table.erase(e);
m_manager.dec_ref(e.first);
m_manager.dec_ref(v);
break;
}
@ -135,12 +133,13 @@ void act_cache::del_unused() {
/**
\brief Insert a new entry k -> v into the cache.
*/
void act_cache::insert(expr * k, expr * v) {
void act_cache::insert(expr * k, unsigned offset, expr * v) {
SASSERT(k);
entry_t e(k, offset);
if (m_unused >= m_max_unused)
del_unused();
expr * dummy = reinterpret_cast<expr*>(1);
map::key_value & entry = m_table.insert_if_not_there(k, dummy);
map::key_value & entry = m_table.insert_if_not_there(e, dummy);
#if 0
unsigned static counter = 0;
counter++;
@ -156,7 +155,7 @@ void act_cache::insert(expr * k, expr * v) {
m_manager.inc_ref(k);
m_manager.inc_ref(v);
entry.m_value = v;
m_queue.push_back(k);
m_queue.push_back(e);
m_unused++;
DEBUG_CODE(expected_tag = 0;); // new entry
}
@ -175,7 +174,7 @@ void act_cache::insert(expr * k, expr * v) {
}
DEBUG_CODE({
expr * v2;
SASSERT(m_table.find(k, v2));
SASSERT(m_table.find(e, v2));
SASSERT(v == UNTAG(expr*, v2));
SASSERT(expected_tag == GET_TAG(v2));
});
@ -185,8 +184,9 @@ void act_cache::insert(expr * k, expr * v) {
\brief Search for key k in the cache.
If entry k -> (v, tag) is found, we set tag to 1.
*/
expr * act_cache::find(expr * k) {
map::key_value * entry = m_table.find_core(k);
expr * act_cache::find(expr * k, unsigned offset) {
entry_t e(k, offset);
map::key_value * entry = m_table.find_core(e);
if (entry == nullptr)
return nullptr;
if (GET_TAG(entry->m_value) == 0) {
@ -196,7 +196,7 @@ expr * act_cache::find(expr * k) {
m_unused--;
DEBUG_CODE({
expr * v;
SASSERT(m_table.find(k, v));
SASSERT(m_table.find(e, v));
SASSERT(GET_TAG(v) == 1);
});
}

View file

@ -26,9 +26,15 @@ Notes:
class act_cache {
ast_manager & m_manager;
typedef cmap<expr*, expr*, obj_ptr_hash<expr>, default_eq<expr*> > map;
typedef std::pair<expr*, unsigned> entry_t;
struct entry_hash {
unsigned operator()(entry_t const& e) const {
return e.first->hash() + e.second;
}
};
typedef cmap<entry_t, expr*, entry_hash, default_eq<entry_t> > map;
map m_table;
ptr_vector<expr> m_queue; // recently created queue
svector<entry_t> m_queue; // recently created queue
unsigned m_qhead;
unsigned m_unused;
unsigned m_max_unused;
@ -42,8 +48,10 @@ public:
act_cache(ast_manager & m);
act_cache(ast_manager & m, unsigned max_unused);
~act_cache();
void insert(expr * k, expr * v);
expr * find(expr * k);
void insert(expr * k, expr * v) { insert(k, 0, v); }
expr * find(expr * k) { return find(k, 0); }
void insert(expr * k, unsigned offset, expr * v);
expr * find(expr * k, unsigned offset);
void reset();
void cleanup();
unsigned size() const { return m_table.size(); }

View file

@ -571,6 +571,11 @@ func_decl * array_recognizers::get_as_array_func_decl(expr * n) const {
return to_func_decl(to_app(n)->get_decl()->get_parameter(0).get_ast());
}
func_decl * array_recognizers::get_as_array_func_decl(func_decl * f) const {
SASSERT(is_as_array(f));
return to_func_decl(f->get_parameter(0).get_ast());
}
array_util::array_util(ast_manager& m):
array_recognizers(m.mk_family_id("array")),
m_manager(m) {

View file

@ -149,7 +149,9 @@ public:
bool is_const(func_decl* f) const { return is_decl_of(f, m_fid, OP_CONST_ARRAY); }
bool is_map(func_decl* f) const { return is_decl_of(f, m_fid, OP_ARRAY_MAP); }
bool is_as_array(func_decl* f) const { return is_decl_of(f, m_fid, OP_AS_ARRAY); }
bool is_as_array(func_decl* f, func_decl*& g) const { return is_decl_of(f, m_fid, OP_AS_ARRAY) && (g = get_as_array_func_decl(f), true); }
func_decl * get_as_array_func_decl(expr * n) const;
func_decl * get_as_array_func_decl(func_decl* f) const;
};
class array_util : public array_recognizers {

View file

@ -1407,6 +1407,7 @@ ast_manager::ast_manager(ast_manager const & src, bool disable_proofs):
m_format_manager = alloc(ast_manager, PGM_DISABLED, m_trace_stream, true);
init();
copy_families_plugins(src);
update_fresh_id(src);
}
void ast_manager::update_fresh_id(ast_manager const& m) {
@ -2156,7 +2157,6 @@ app * ast_manager::mk_app_core(func_decl * decl, unsigned num_args, expr * const
app * new_node = nullptr;
unsigned sz = app::get_obj_size(num_args);
void * mem = allocate_node(sz);
try {
if (m_int_real_coercions && coercion_needed(decl, num_args, args)) {
expr_ref_buffer new_args(*this);

View file

@ -238,7 +238,7 @@ format * smt2_pp_environment::pp_float_literal(app * t, bool use_bv_lits, bool u
string_buffer<> buf;
VERIFY(get_futil().is_numeral(t, v));
if (fm.is_nan(v)) {
buf << "(_ NaN " << v.get().get_ebits() << " " << v.get().get_sbits() << ")";
buf << "(_ NaN " << v.get().get_ebits() << " " << v.get().get_sbits() << ")";
return mk_string(m, buf.c_str());
}
else if (fm.is_pinf(v)) {

View file

@ -399,12 +399,12 @@ class smt_printer {
pp_marked_expr(n->get_arg(0));
m_out << ") (_ bv1 1))";
}
else if (m_manager.is_label(n, pos, names) && names.size() >= 1) {
else if (m_manager.is_label(n, pos, names) && !names.empty()) {
m_out << "(! ";
pp_marked_expr(n->get_arg(0));
m_out << (pos?":lblpos":":lblneg") << " " << m_renaming.get_symbol(names[0], false) << ")";
}
else if (m_manager.is_label_lit(n, names) && names.size() >= 1) {
else if (m_manager.is_label_lit(n, names) && !names.empty()) {
m_out << "(! true :lblpos " << m_renaming.get_symbol(names[0], false) << ")";
}
else if (num_args == 0) {
@ -952,7 +952,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
if (m_logic != symbol::null && m_logic != symbol("")) {
strm << "(set-logic " << m_logic << ")\n";
}
if (m_attributes.size() > 0) {
if (!m_attributes.empty()) {
strm << "; " << m_attributes.c_str();
}

View file

@ -558,11 +558,15 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
case OP_ROTATE_LEFT:
if (arity != 1)
m_manager->raise_exception("rotate left expects one argument");
if (num_parameters != 1 || !parameters[0].is_int())
m_manager->raise_exception("rotate left expects one integer parameter");
return m_manager->mk_func_decl(m_rotate_left_sym, arity, domain, domain[0],
func_decl_info(m_family_id, k, num_parameters, parameters));
case OP_ROTATE_RIGHT:
if (arity != 1)
m_manager->raise_exception("rotate right expects one argument");
if (num_parameters != 1 || !parameters[0].is_int())
m_manager->raise_exception("rotate right expects one integer parameter");
return m_manager->mk_func_decl(m_rotate_right_sym, arity, domain, domain[0],
func_decl_info(m_family_id, k, num_parameters, parameters));
case OP_REPEAT:

View file

@ -148,7 +148,7 @@ public:
bool is_resource(expr* e, unsigned& r);
bool is_makespan(expr* e, unsigned& r);
bool is_add_resource_available(expr * e, expr *& res, unsigned& loadpct, unsigned& cap_time, uint64_t& start, uint64_t& end, svector<symbol>& properites);
bool is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& loadpct, uint64_t& capacity, uint64_t& end, svector<symbol>& properites);
bool is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& loadpct, uint64_t& capacity, uint64_t& finite_capacity_end, svector<symbol>& properites);
bool is_set_preemptable(expr* e, expr *& job);
bool is_model(expr* e) const { return is_app_of(e, m_fid, OP_JS_MODEL); }
bool is_js_properties(expr* e, svector<symbol>& properties);

View file

@ -143,7 +143,77 @@ namespace datatype {
}
return r;
}
size* size::mk_power(size* a1, size* a2) { return alloc(power, a1, a2); }
size* size::mk_power(size* a1, size* a2) {
return alloc(power, a1, a2);
}
sort_size plus::eval(obj_map<sort, sort_size> const& S) {
rational r(0);
ptr_vector<size> todo;
todo.push_back(m_arg1);
todo.push_back(m_arg2);
while (!todo.empty()) {
size* s = todo.back();
todo.pop_back();
plus* p = dynamic_cast<plus*>(s);
if (p) {
todo.push_back(p->m_arg1);
todo.push_back(p->m_arg2);
}
else {
sort_size sz = s->eval(S);
if (sz.is_infinite()) return sz;
if (sz.is_very_big()) return sz;
r += rational(sz.size(), rational::ui64());
}
}
return sort_size(r);
}
size* plus::subst(obj_map<sort,size*>& S) {
return mk_plus(m_arg1->subst(S), m_arg2->subst(S));
}
sort_size times::eval(obj_map<sort, sort_size> const& S) {
sort_size s1 = m_arg1->eval(S);
sort_size s2 = m_arg2->eval(S);
if (s1.is_infinite()) return s1;
if (s2.is_infinite()) return s2;
if (s1.is_very_big()) return s1;
if (s2.is_very_big()) return s2;
rational r = rational(s1.size(), rational::ui64()) * rational(s2.size(), rational::ui64());
return sort_size(r);
}
size* times::subst(obj_map<sort,size*>& S) {
return mk_times(m_arg1->subst(S), m_arg2->subst(S));
}
sort_size power::eval(obj_map<sort, sort_size> const& S) {
sort_size s1 = m_arg1->eval(S);
sort_size s2 = m_arg2->eval(S);
// s1^s2
if (s1.is_infinite()) return s1;
if (s2.is_infinite()) return s2;
if (s1.is_very_big()) return s1;
if (s2.is_very_big()) return s2;
if (s1.size() == 1) return s1;
if (s2.size() == 1) return s1;
if (s1.size() > (2 << 20) || s2.size() > 10) return sort_size::mk_very_big();
rational r = ::power(rational(s1.size(), rational::ui64()), static_cast<unsigned>(s2.size()));
return sort_size(r);
}
size* power::subst(obj_map<sort,size*>& S) {
return mk_power(m_arg1->subst(S), m_arg2->subst(S));
}
size* sparam::subst(obj_map<sort, size*>& S) {
return S[m_param];
}
}
namespace decl {
@ -625,13 +695,14 @@ namespace datatype {
param_size::size* sz;
obj_map<sort, param_size::size*> S;
unsigned n = get_datatype_num_parameter_sorts(s);
def & d = get_def(s->get_name());
SASSERT(n == d.params().size());
for (unsigned i = 0; i < n; ++i) {
sort* ps = get_datatype_parameter_sort(s, i);
sz = get_sort_size(params, ps);
sz->inc_ref();
S.insert(ps, sz);
}
def & d = get_def(s->get_name());
sz->inc_ref();
S.insert(d.params().get(i), sz);
}
sz = d.sort_size()->subst(S);
for (auto & kv : S) {
kv.m_value->dec_ref();
@ -708,7 +779,7 @@ namespace datatype {
continue;
}
ptr_vector<param_size::size> s_add;
ptr_vector<param_size::size> s_add;
for (constructor const* c : d) {
ptr_vector<param_size::size> s_mul;
for (accessor const* a : *c) {
@ -723,7 +794,7 @@ namespace datatype {
/**
\brief Return true if the inductive datatype is well-founded.
Pre-condition: The given argument constains the parameters of an inductive datatype.
Pre-condition: The given argument constrains the parameters of an inductive datatype.
*/
bool util::is_well_founded(unsigned num_types, sort* const* sorts) {
buffer<bool> well_founded(num_types, false);

View file

@ -132,71 +132,28 @@ namespace datatype {
size* m_arg1, *m_arg2;
plus(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref();}
~plus() override { m_arg1->dec_ref(); m_arg2->dec_ref(); }
size* subst(obj_map<sort,size*>& S) override { return mk_plus(m_arg1->subst(S), m_arg2->subst(S)); }
sort_size eval(obj_map<sort, sort_size> const& S) override {
rational r(0);
ptr_vector<size> todo;
todo.push_back(m_arg1);
todo.push_back(m_arg2);
while (!todo.empty()) {
size* s = todo.back();
todo.pop_back();
plus* p = dynamic_cast<plus*>(s);
if (p) {
todo.push_back(p->m_arg1);
todo.push_back(p->m_arg2);
}
else {
sort_size sz = s->eval(S);
if (sz.is_infinite()) return sz;
if (sz.is_very_big()) return sz;
r += rational(sz.size(), rational::ui64());
}
}
return sort_size(r);
}
size* subst(obj_map<sort,size*>& S) override;
sort_size eval(obj_map<sort, sort_size> const& S) override;
};
struct times : public size {
size* m_arg1, *m_arg2;
times(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); }
~times() override { m_arg1->dec_ref(); m_arg2->dec_ref(); }
size* subst(obj_map<sort,size*>& S) override { return mk_times(m_arg1->subst(S), m_arg2->subst(S)); }
sort_size eval(obj_map<sort, sort_size> const& S) override {
sort_size s1 = m_arg1->eval(S);
sort_size s2 = m_arg2->eval(S);
if (s1.is_infinite()) return s1;
if (s2.is_infinite()) return s2;
if (s1.is_very_big()) return s1;
if (s2.is_very_big()) return s2;
rational r = rational(s1.size(), rational::ui64()) * rational(s2.size(), rational::ui64());
return sort_size(r);
}
size* subst(obj_map<sort,size*>& S) override;
sort_size eval(obj_map<sort, sort_size> const& S) override;
};
struct power : public size {
size* m_arg1, *m_arg2;
power(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); }
~power() override { m_arg1->dec_ref(); m_arg2->dec_ref(); }
size* subst(obj_map<sort,size*>& S) override { return mk_power(m_arg1->subst(S), m_arg2->subst(S)); }
sort_size eval(obj_map<sort, sort_size> const& S) override {
sort_size s1 = m_arg1->eval(S);
sort_size s2 = m_arg2->eval(S);
// s1^s2
if (s1.is_infinite()) return s1;
if (s2.is_infinite()) return s2;
if (s1.is_very_big()) return s1;
if (s2.is_very_big()) return s2;
if (s1.size() == 1) return s1;
if (s2.size() == 1) return s1;
if (s1.size() > (2 << 20) || s2.size() > 10) return sort_size::mk_very_big();
rational r = ::power(rational(s1.size(), rational::ui64()), static_cast<unsigned>(s2.size()));
return sort_size(r);
}
size* subst(obj_map<sort,size*>& S) override;
sort_size eval(obj_map<sort, sort_size> const& S) override;
};
struct sparam : public size {
sort_ref m_param;
sparam(sort_ref& p): m_param(p) {}
~sparam() override {}
size* subst(obj_map<sort,size*>& S) override { return S[m_param]; }
size* subst(obj_map<sort, size*>& S) override;
sort_size eval(obj_map<sort, sort_size> const& S) override { return S[m_param]; }
};
};

View file

@ -0,0 +1,81 @@
/*++
Copyright (c) 2019 Microsoft Corporation
Module Name:
display_dimacs.h
Abstract:
Display expressions in DIMACS format.
Author:
Nikolaj Bjorner (nbjorner0 2019-01-24
Revision History:
--*/
#include "ast.h"
#include "display_dimacs.h"
std::ostream& display_dimacs(std::ostream& out, expr_ref_vector const& fmls) {
ast_manager& m = fmls.m();
unsigned_vector expr2var;
ptr_vector<expr> exprs;
unsigned num_vars = 0;
unsigned num_cls = fmls.size();
for (expr * f : fmls) {
unsigned num_lits;
expr * const * lits;
if (m.is_or(f)) {
num_lits = to_app(f)->get_num_args();
lits = to_app(f)->get_args();
}
else {
num_lits = 1;
lits = &f;
}
for (unsigned j = 0; j < num_lits; j++) {
expr * l = lits[j];
if (m.is_not(l))
l = to_app(l)->get_arg(0);
if (expr2var.get(l->get_id(), UINT_MAX) == UINT_MAX) {
num_vars++;
expr2var.setx(l->get_id(), num_vars, UINT_MAX);
exprs.setx(l->get_id(), l, nullptr);
}
}
}
out << "p cnf " << num_vars << " " << num_cls << "\n";
for (expr* f : fmls) {
unsigned num_lits;
expr * const * lits;
if (m.is_or(f)) {
num_lits = to_app(f)->get_num_args();
lits = to_app(f)->get_args();
}
else {
num_lits = 1;
lits = &f;
}
for (unsigned j = 0; j < num_lits; j++) {
expr * l = lits[j];
if (m.is_not(l)) {
out << "-";
l = to_app(l)->get_arg(0);
}
SASSERT(exprs[l->get_id()]);
out << expr2var[l->get_id()] << " ";
}
out << "0\n";
}
for (expr* e : exprs) {
if (e && is_app(e)) {
symbol const& n = to_app(e)->get_decl()->get_name();
out << "c " << expr2var[e->get_id()] << " " << n << "\n";
}
}
return out;
}

26
src/ast/display_dimacs.h Normal file
View file

@ -0,0 +1,26 @@
/*++
Copyright (c) 2019 Microsoft Corporation
Module Name:
display_dimacs.h
Abstract:
Display expressions in DIMACS format.
Author:
Nikolaj Bjorner (nbjorner0 2019-01-24
Revision History:
--*/
#ifndef DISPLAY_DIMACS_H_
#define DISPLAY_DIMACS_H_
#include "ast.h"
std::ostream& display_dimacs(std::ostream& out, expr_ref_vector const& fmls);
#endif /* DISPLAY_DIMACS_H__ */

View file

@ -147,7 +147,7 @@ namespace datalog {
for (unsigned i = 0; i < n; ++i) {
parameter const& p = r->get_parameter(i);
if (!p.is_ast() || !is_sort(p.get_ast())) {
m_manager->raise_exception("exptected sort parameter");
m_manager->raise_exception("expected sort parameter");
return false;
}
sorts.push_back(to_sort(p.get_ast()));
@ -185,7 +185,7 @@ namespace datalog {
verbose_stream() << "Domain: " << mk_pp(domain[0], m) << "\n" <<
mk_pp(sorts[i], m) << "\n" <<
mk_pp(domain[i+1], m) << "\n";);
m_manager->raise_exception("sort miss-match for relational access");
m_manager->raise_exception("sort mismatch for relational access");
return nullptr;
}
}
@ -252,7 +252,7 @@ namespace datalog {
func_decl * dl_decl_plugin::mk_unionw(decl_kind k, sort* s1, sort* s2) {
ast_manager& m = *m_manager;
if (s1 != s2) {
m_manager->raise_exception("sort miss-match for arguments to union");
m_manager->raise_exception("sort mismatch for arguments to union");
return nullptr;
}
if (!is_rel_sort(s1)) {
@ -298,7 +298,7 @@ namespace datalog {
return nullptr;
}
if (sorts[idx] != m.get_sort(e)) {
m_manager->raise_exception("sort miss-match in filter");
m_manager->raise_exception("sort mismatch in filter");
return nullptr;
}
break;
@ -391,7 +391,7 @@ namespace datalog {
return nullptr;
}
if (sorts1[i1] != sorts2[i2]) {
m_manager->raise_exception("sort miss-match in join");
m_manager->raise_exception("sort mismatch in join");
return nullptr;
}
}
@ -435,7 +435,7 @@ namespace datalog {
return nullptr;
}
if (sorts1[i1] != sorts2[i2]) {
m_manager->raise_exception("sort miss-match in join");
m_manager->raise_exception("sort mismatch in join");
return nullptr;
}
}

View file

@ -436,7 +436,7 @@ struct expr2polynomial::imp {
margs.push_back(t);
}
}
if (margs.size() == 0) {
if (margs.empty()) {
args.push_back(m_autil.mk_numeral(rational(1), is_int));
}
else if (margs.size() == 1) {
@ -447,7 +447,7 @@ struct expr2polynomial::imp {
}
}
if (args.size() == 0) {
if (args.empty()) {
r = m_autil.mk_numeral(rational(0), is_int);
}
else if (args.size() == 1) {

View file

@ -29,8 +29,17 @@ void expr2var::insert(expr * n, var v) {
TRACE("expr2var", tout << "interpreted:\n" << mk_ismt2_pp(n, m()) << "\n";);
m_interpreted_vars = true;
}
m().inc_ref(n);
m_mapping.insert(n, v);
unsigned idx = m_id2map.get(n->get_id(), UINT_MAX);
if (idx == UINT_MAX) {
m().inc_ref(n);
idx = m_mapping.size();
m_mapping.push_back(key_value(n, v));
m_id2map.setx(n->get_id(), idx, UINT_MAX);
}
else {
m_mapping[idx] = key_value(n, v);
}
m_recent_exprs.push_back(n);
}
@ -40,20 +49,22 @@ expr2var::expr2var(ast_manager & m):
}
expr2var::~expr2var() {
dec_ref_map_keys(m(), m_mapping);
for (auto & kv : m_mapping) {
m().dec_ref(kv.m_key);
}
}
expr2var::var expr2var::to_var(expr * n) const {
var v = UINT_MAX;
m_mapping.find(n, v);
var v = m_id2map.get(n->get_id(), UINT_MAX);
if (v != UINT_MAX) {
v = m_mapping[v].m_value;
}
return v;
}
void expr2var::display(std::ostream & out) const {
obj_map<expr, var>::iterator it = m_mapping.begin();
obj_map<expr, var>::iterator end = m_mapping.end();
for (; it != end; ++it) {
out << mk_ismt2_pp(it->m_key, m()) << " -> " << it->m_value << "\n";
for (auto const& kv : m_mapping) {
out << mk_ismt2_pp(kv.m_key, m()) << " -> " << kv.m_value << "\n";
}
}
@ -68,8 +79,11 @@ void expr2var::mk_inv(expr_ref_vector & var2expr) const {
}
void expr2var::reset() {
dec_ref_map_keys(m(), m_mapping);
SASSERT(m_mapping.empty());
for (auto & kv : m_mapping) {
m().dec_ref(kv.m_key);
}
m_mapping.reset();
m_id2map.reset();
m_recent_exprs.reset();
m_recent_lim.reset();
m_interpreted_vars = false;
@ -83,8 +97,15 @@ void expr2var::pop(unsigned num_scopes) {
if (num_scopes > 0) {
unsigned sz = m_recent_lim[m_recent_lim.size() - num_scopes];
for (unsigned i = sz; i < m_recent_exprs.size(); ++i) {
m_mapping.erase(m_recent_exprs[i]);
m().dec_ref(m_recent_exprs[i]);
expr* n = m_recent_exprs[i];
unsigned idx = m_id2map[n->get_id()];
if (idx + 1 != m_mapping.size()) {
m_id2map[m_mapping.back().m_key->get_id()] = idx;
m_mapping[idx] = m_mapping.back();
}
m_id2map[n->get_id()] = UINT_MAX;
m_mapping.pop_back();
m().dec_ref(n);
}
m_recent_exprs.shrink(sz);
m_recent_lim.shrink(m_recent_lim.size() - num_scopes);

View file

@ -32,12 +32,14 @@ Notes:
class expr2var {
public:
typedef unsigned var;
typedef obj_map<expr, var> expr2var_mapping;
typedef expr2var_mapping::iterator iterator;
typedef obj_map<expr, var>::key_data key_value;
typedef key_value const* iterator;
typedef ptr_vector<expr>::const_iterator recent_iterator;
protected:
ast_manager & m_manager;
expr2var_mapping m_mapping;
unsigned_vector m_id2map;
svector<key_value> m_mapping;
ptr_vector<expr> m_recent_exprs;
unsigned_vector m_recent_lim;
bool m_interpreted_vars;
@ -51,7 +53,7 @@ public:
var to_var(expr * n) const;
bool is_var(expr * n) const { return m_mapping.contains(n); }
bool is_var(expr * n) const { return m_id2map.get(n->get_id(), UINT_MAX) != UINT_MAX; }
void display(std::ostream & out) const;

View file

@ -3300,11 +3300,11 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
ll = m_bv_util.mk_sign_extend(3, m_bv_util.mk_concat(bv1, m_bv_util.mk_numeral(0, bv_sz-1)));
ul = m_bv_util.mk_zero_extend(4, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, bv_sz-1)));
ovfl = m.mk_or(ovfl, m_bv_util.mk_sle(pre_rounded, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, bv_sz + 3))));
pre_rounded = m.mk_ite(x_is_neg, m_bv_util.mk_bv_neg(pre_rounded), pre_rounded);
in_range = m.mk_and(m.mk_not(ovfl),
m_bv_util.mk_sle(ll, pre_rounded),
m_bv_util.mk_sle(pre_rounded, ul));
dbg_decouple("fpa2bv_to_bv_in_range_ll", ll);
pre_rounded = m.mk_ite(x_is_neg, m_bv_util.mk_bv_neg(pre_rounded), pre_rounded);
}
dbg_decouple("fpa2bv_to_bv_in_range_ovfl", ovfl);
dbg_decouple("fpa2bv_to_bv_in_range_ul", ul);

View file

@ -594,7 +594,6 @@ bool pattern_inference_cfg::reduce_quantifier(
unsigned new_weight;
if (m_database.match_quantifier(q, new_patterns, new_weight)) {
DEBUG_CODE(for (unsigned i = 0; i < new_patterns.size(); i++) { SASSERT(is_well_sorted(m, new_patterns.get(i))); });
quantifier_ref new_q(m);
if (q->get_num_patterns() > 0) {
// just update the weight...
TRACE("pattern_inference", tout << "updating weight to: " << new_weight << "\n" << mk_pp(q, m) << "\n";);
@ -604,10 +603,10 @@ bool pattern_inference_cfg::reduce_quantifier(
quantifier_ref tmp(m);
tmp = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), q->get_expr());
result = m.update_quantifier_weight(tmp, new_weight);
TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(new_q, m) << "\n";);
TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(result, m) << "\n";);
}
if (m.proofs_enabled())
result_pr = m.mk_rewrite(q, new_q);
result_pr = m.mk_rewrite(q, result);
return true;
}
}

View file

@ -238,7 +238,7 @@ class reduce_hypotheses {
{ args.push_back(fact); }
if (args.size() == 0) { return pf; }
if (args.empty()) { return pf; }
else if (args.size() == 1) {
lemma = args.get(0);
} else {

View file

@ -68,7 +68,7 @@ namespace recfun {
struct ite_find_p : public i_expr_pred {
ast_manager & m;
ite_find_p(ast_manager & m) : m(m) {}
virtual bool operator()(expr * e) { return m.is_ite(e); }
bool operator()(expr * e) override { return m.is_ite(e); }
};
// ignore ites under quantifiers.
// this is redundant as the code
@ -331,7 +331,7 @@ namespace recfun {
struct is_imm_pred : is_immediate_pred {
util & u;
is_imm_pred(util & u) : u(u) {}
bool operator()(expr * rhs) {
bool operator()(expr * rhs) override {
// find an `app` that is an application of a defined function
struct find : public i_expr_pred {
util & u;

View file

@ -56,7 +56,7 @@ namespace recfun {
friend class def;
func_decl_ref m_pred; //<! predicate used for this case
expr_ref_vector m_guards; //<! conjunction that is equivalent to this case
expr_ref m_rhs; //<! if guard is true, `f(t1tn) = rhs` holds
expr_ref m_rhs; //<! if guard is true, `f(t1...tn) = rhs` holds
def * m_def; //<! definition this is a part of
bool m_immediate; //<! does `rhs` contain no defined_fun/case_pred?

View file

@ -19,6 +19,7 @@ z3_add_component(rewriter
factor_equivs.cpp
factor_rewriter.cpp
fpa_rewriter.cpp
hoist_rewriter.cpp
inj_axiom.cpp
label_rewriter.cpp
maximize_ac_sharing.cpp

View file

@ -861,7 +861,8 @@ bool arith_rewriter::divides(expr* num, expr* den, expr_ref& result) {
if (m_util.is_numeral(arg, num_r)) num_e = arg;
}
for (expr* arg : args2) {
if (mark.is_marked(arg)) {
// dont remove divisor on (div (* -1 x) (* -1 y)) because rewriting would diverge.
if (mark.is_marked(arg) && (!m_util.is_numeral(arg, num_r) || !num_r.is_minus_one())) {
result = remove_divisor(arg, num, den);
return true;
}
@ -900,7 +901,14 @@ expr_ref arith_rewriter::remove_divisor(expr* arg, expr* num, expr* den) {
expr_ref zero(m_util.mk_int(0), m());
num = args1.empty() ? m_util.mk_int(1) : m_util.mk_mul(args1.size(), args1.c_ptr());
den = args2.empty() ? m_util.mk_int(1) : m_util.mk_mul(args2.size(), args2.c_ptr());
return expr_ref(m().mk_ite(m().mk_eq(zero, arg), m_util.mk_idiv(zero, zero), m_util.mk_idiv(num, den)), m());
expr_ref d(m_util.mk_idiv(num, den), m());
expr_ref nd(m_util.mk_idiv(m_util.mk_uminus(num), m_util.mk_uminus(den)), m());
return expr_ref(m().mk_ite(m().mk_eq(zero, arg),
m_util.mk_idiv(zero, zero),
m().mk_ite(m_util.mk_ge(arg, zero),
d,
nd)),
m());
}
void arith_rewriter::flat_mul(expr* e, ptr_buffer<expr>& args) {

View file

@ -75,9 +75,23 @@ bool bit_blaster_tpl<Cfg>::is_minus_one(unsigned sz, expr * const * bits) const
static void _num2bits(ast_manager & m, rational const & v, unsigned sz, expr_ref_vector & out_bits) {
SASSERT(v.is_nonneg());
rational aux = v;
rational two(2);
rational two(2), base32(1ull << 32ull, rational::ui64());
for (unsigned i = 0; i < sz; i++) {
if ((aux % two).is_zero())
if (i + 32 < sz) {
unsigned u = (aux % base32).get_unsigned();
for (unsigned j = 0; j < 32; ++j) {
if (0 != (u & (1 << j))) {
out_bits.push_back(m.mk_true());
}
else {
out_bits.push_back(m.mk_false());
}
}
aux = div(aux, base32);
i += 31;
continue;
}
else if ((aux % two).is_zero())
out_bits.push_back(m.mk_false());
else
out_bits.push_back(m.mk_true());

View file

@ -628,7 +628,7 @@ bool bv_bounds::is_sat_core(app * v) {
numeral new_hi = lower - one;
numeral ptr = lower;
if (has_neg_intervals) {
SASSERT(negative_intervals != NULL);
SASSERT(negative_intervals != nullptr);
std::sort(negative_intervals->begin(), negative_intervals->end(), interval_comp);
intervals::const_iterator e = negative_intervals->end();
for (intervals::const_iterator i = negative_intervals->begin(); i != e; ++i) {

View file

@ -196,6 +196,9 @@ br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
return mk_bv_comp(args[0], args[1], result);
case OP_MKBV:
return mk_mkbv(num_args, args, result);
case OP_BIT2BOOL:
SASSERT(num_args == 1);
return mk_bit2bool(args[0], f->get_parameter(0).get_int(), result);
case OP_BSMUL_NO_OVFL:
return mk_bvsmul_no_overflow(num_args, args, result);
case OP_BUMUL_NO_OVFL:
@ -779,10 +782,11 @@ br_status bv_rewriter::mk_extract(unsigned high, unsigned low, expr * arg, expr_
}
}
if (m().is_ite(arg)) {
result = m().mk_ite(to_app(arg)->get_arg(0),
m_mk_extract(high, low, to_app(arg)->get_arg(1)),
m_mk_extract(high, low, to_app(arg)->get_arg(2)));
expr* c = nullptr, *t = nullptr, *e = nullptr;
if (m().is_ite(arg, c, t, e) &&
(t->get_ref_count() == 1 || !m().is_ite(t)) &&
(e->get_ref_count() == 1 || !m().is_ite(e))) {
result = m().mk_ite(c, m_mk_extract(high, low, t), m_mk_extract(high, low, e));
return BR_REWRITE2;
}
@ -2202,6 +2206,19 @@ br_status bv_rewriter::mk_bv_mul(unsigned num_args, expr * const * args, expr_re
return st;
}
br_status bv_rewriter::mk_bit2bool(expr * n, int idx, expr_ref & result) {
rational v, bit;
unsigned sz = 0;
if (!is_numeral(n, v, sz))
return BR_FAILED;
if (idx < 0 || idx >= static_cast<int>(sz))
return BR_FAILED;
div(v, rational::power_of_two(idx), bit);
mod(bit, rational(2), bit);
result = m().mk_bool_val(bit.is_one());
return BR_DONE;
}
br_status bv_rewriter::mk_bit2bool(expr * lhs, expr * rhs, expr_ref & result) {
unsigned sz = get_bv_size(lhs);
if (sz != 1)

View file

@ -134,6 +134,7 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
br_status mk_bv_redand(expr * arg, expr_ref & result);
br_status mk_bv_comp(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_bit2bool(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_bit2bool(expr * lhs, int idx, expr_ref & result);
br_status mk_blast_eq_value(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_mkbv(unsigned num, expr * const * args, expr_ref & result);

View file

@ -364,7 +364,7 @@ struct bv_trailing::imp {
}
void reset_cache(const unsigned condition) {
SASSERT(m_count_cache[0] == NULL);
SASSERT(m_count_cache[0] == nullptr);
for (unsigned i = 1; i <= TRAILING_DEPTH; ++i) {
if (m_count_cache[i] == nullptr) continue;
TRACE("bv-trailing", tout << "may reset cache " << i << " " << condition << "\n";);

View file

@ -374,13 +374,11 @@ void der::apply_substitution(quantifier * q, expr_ref & r) {
expr_ref_buffer new_patterns(m_manager);
expr_ref_buffer new_no_patterns(m_manager);
for (unsigned j = 0; j < q->get_num_patterns(); j++) {
expr_ref new_pat = m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
new_patterns.push_back(new_pat);
new_patterns.push_back(m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr()));
}
for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
expr_ref new_nopat = m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
new_no_patterns.push_back(new_nopat);
new_no_patterns.push_back(m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr()));
}
r = m_manager.update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(),

View file

@ -126,8 +126,7 @@ void distribute_forall::reduce1_quantifier(quantifier * q) {
br.mk_not(arg, not_arg);
quantifier_ref tmp_q(m_manager);
tmp_q = m_manager.update_quantifier(q, not_arg);
expr_ref new_q = elim_unused_vars(m_manager, tmp_q, params_ref());
new_args.push_back(new_q);
new_args.push_back(elim_unused_vars(m_manager, tmp_q, params_ref()));
}
expr_ref result(m_manager);
// m_bsimp.mk_and actually constructs a (not (or ...)) formula,

View file

@ -0,0 +1,201 @@
/*++
Copyright (c) 2019 Microsoft Corporation
Module Name:
hoist_rewriter.cpp
Abstract:
Hoist predicates over disjunctions
Author:
Nikolaj Bjorner (nbjorner) 2019-2-4
Notes:
--*/
#include "ast/rewriter/hoist_rewriter.h"
#include "ast/ast_util.h"
#include "ast/rewriter/expr_safe_replace.h"
#include "ast/ast_pp.h"
hoist_rewriter::hoist_rewriter(ast_manager & m, params_ref const & p):
m_manager(m), m_args1(m), m_args2(m) {
updt_params(p);
}
br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref & result) {
if (num_args < 2) {
return BR_FAILED;
}
for (unsigned i = 0; i < num_args; ++i) {
if (!is_and(es[i], nullptr)) {
return BR_FAILED;
}
}
bool turn = false;
m_preds1.reset();
m_preds2.reset();
m_uf1.reset();
m_uf2.reset();
m_expr2var.reset();
m_var2expr.reset();
basic_union_find* uf[2] = { &m_uf1, &m_uf2 };
obj_hashtable<expr>* preds[2] = { &m_preds1, &m_preds2 };
expr_ref_vector* args[2] = { &m_args1, &m_args2 };
VERIFY(is_and(es[0], args[turn]));
expr* e1, *e2;
for (expr* e : *(args[turn])) {
if (m().is_eq(e, e1, e2)) {
(*uf)[turn].merge(mk_var(e1), mk_var(e2));
}
else {
(*preds)[turn].insert(e);
}
}
unsigned round = 0;
for (unsigned j = 1; j < num_args; ++j) {
++round;
m_es.reset();
m_mark.reset();
bool last = turn;
turn = !turn;
(*preds)[turn].reset();
reset(m_uf0);
VERIFY(is_and(es[j], args[turn]));
for (expr* e : *args[turn]) {
if (m().is_eq(e, e1, e2)) {
m_es.push_back(e1);
m_uf0.merge(mk_var(e1), mk_var(e2));
}
else if ((*preds)[last].contains(e)) {
(*preds)[turn].insert(e);
}
}
if ((*preds)[turn].empty() && m_es.empty()) {
return BR_FAILED;
}
m_eqs.reset();
for (expr* e : m_es) {
if (m_mark.is_marked(e)) {
continue;
}
unsigned u = mk_var(e);
unsigned v = u;
m_roots.reset();
do {
m_mark.mark(e);
unsigned r = (*uf)[last].find(v);
if (m_roots.find(r, e2)) {
m_eqs.push_back(std::make_pair(e, e2));
}
else {
m_roots.insert(r, e);
}
v = m_uf0.next(v);
e = mk_expr(v);
}
while (u != v);
}
reset((*uf)[turn]);
for (auto const& p : m_eqs) {
(*uf)[turn].merge(mk_var(p.first), mk_var(p.second));
}
if ((*preds)[turn].empty() && m_eqs.empty()) {
return BR_FAILED;
}
}
// p & eqs & (or fmls)
expr_ref_vector fmls(m()), ors(m());
expr_safe_replace subst(m());
for (expr * p : (*preds)[turn]) {
expr* q = nullptr;
if (m().is_not(p, q)) {
subst.insert(q, m().mk_false());
}
else {
subst.insert(p, m().mk_true());
}
fmls.push_back(p);
}
for (auto const& p : m_eqs) {
subst.insert(p.first, p.second);
fmls.push_back(m().mk_eq(p.first, p.second));
}
for (unsigned i = 0; i < num_args; ++i) {
expr_ref tmp(m());
subst(es[i], tmp);
ors.push_back(tmp);
}
fmls.push_back(m().mk_or(ors.size(), ors.c_ptr()));
result = m().mk_and(fmls.size(), fmls.c_ptr());
TRACE("hoist",
for (unsigned i = 0; i < num_args; ++i) {
tout << mk_pp(es[i], m()) << "\n";
}
tout << "=>\n";
tout << result << "\n";);
return BR_DONE;
}
unsigned hoist_rewriter::mk_var(expr* e) {
unsigned v = 0;
if (m_expr2var.find(e, v)) {
return v;
}
v = m_uf1.mk_var();
v = m_uf2.mk_var();
SASSERT(v == m_var2expr.size());
m_expr2var.insert(e, v);
m_var2expr.push_back(e);
return v;
}
br_status hoist_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
switch (f->get_decl_kind()) {
case OP_OR:
return mk_or(num_args, args, result);
default:
return BR_FAILED;
}
}
bool hoist_rewriter::is_and(expr * e, expr_ref_vector* args) {
if (m().is_and(e)) {
if (args) {
args->reset();
args->append(to_app(e)->get_num_args(), to_app(e)->get_args());
}
return true;
}
if (m().is_not(e, e) && m().is_or(e)) {
if (args) {
args->reset();
for (expr* arg : *to_app(e)) {
args->push_back(::mk_not(m(), arg));
}
}
return true;
}
return false;
}
void hoist_rewriter::reset(basic_union_find& uf) {
uf.reset();
for (expr* e : m_var2expr) {
(void)e;
uf.mk_var();
}
}

View file

@ -0,0 +1,80 @@
/*++
Copyright (c) 2019 Microsoft Corporation
Module Name:
hoist_rewriter.h
Abstract:
Hoist predicates over disjunctions
Author:
Nikolaj Bjorner (nbjorner) 2019-2-4
Notes:
--*/
#ifndef HOIST_REWRITER_H_
#define HOIST_REWRITER_H_
#include "ast/ast.h"
#include "ast/rewriter/rewriter.h"
#include "util/params.h"
#include "util/union_find.h"
#include "util/obj_hashtable.h"
class hoist_rewriter {
ast_manager & m_manager;
expr_ref_vector m_args1, m_args2;
obj_hashtable<expr> m_preds1, m_preds2;
basic_union_find m_uf1, m_uf2, m_uf0;
ptr_vector<expr> m_es;
svector<std::pair<expr*,expr*>> m_eqs;
u_map<expr*> m_roots;
obj_map<expr, unsigned> m_expr2var;
ptr_vector<expr> m_var2expr;
expr_mark m_mark;
br_status mk_or(unsigned num_args, expr * const * args, expr_ref & result);
bool is_and(expr* e, expr_ref_vector* args);
bool is_var(expr* e) { return m_expr2var.contains(e); }
expr* mk_expr(unsigned v) { return m_var2expr[v]; }
unsigned mk_var(expr* e);
void reset(basic_union_find& uf);
public:
hoist_rewriter(ast_manager & m, params_ref const & p = params_ref());
ast_manager& m() const { return m_manager; }
family_id get_fid() const { return m().get_basic_family_id(); }
bool is_eq(expr * t) const { return m().is_eq(t); }
void updt_params(params_ref const & p) {}
static void get_param_descrs(param_descrs & r) {}
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
};
struct hoist_rewriter_cfg : public default_rewriter_cfg {
hoist_rewriter m_r;
bool rewrite_patterns() const { return false; }
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
result_pr = nullptr;
if (f->get_family_id() != m_r.get_fid())
return BR_FAILED;
return m_r.mk_app_core(f, num, args, result);
}
hoist_rewriter_cfg(ast_manager & m, params_ref const & p):m_r(m, p) {}
};
class hoist_rewriter_star : public rewriter_tpl<hoist_rewriter_cfg> {
hoist_rewriter_cfg m_cfg;
public:
hoist_rewriter_star(ast_manager & m, params_ref const & p = params_ref()):
rewriter_tpl<hoist_rewriter_cfg>(m, false, m_cfg),
m_cfg(m, p) {}
};
#endif

View file

@ -323,7 +323,7 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
break;
}
}
TRACE("pb",
TRACE("pb_verbose",
expr_ref tmp(m);
tmp = m.mk_app(f, num_args, args);
tout << tmp << "\n";

View file

@ -42,7 +42,7 @@ void rewriter_core::del_cache_stack() {
}
}
void rewriter_core::cache_result(expr * k, expr * v) {
void rewriter_core::cache_shifted_result(expr * k, unsigned offset, expr * v) {
#if 0
// trace for tracking cache usage
verbose_stream() << "1 " << k->get_id() << std::endl;
@ -53,7 +53,7 @@ void rewriter_core::cache_result(expr * k, expr * v) {
SASSERT(m().get_sort(k) == m().get_sort(v));
m_cache->insert(k, v);
m_cache->insert(k, offset, v);
#if 0
static unsigned num_cached = 0;
num_cached ++;

View file

@ -90,8 +90,10 @@ protected:
void init_cache_stack();
void del_cache_stack();
void reset_cache();
void cache_result(expr * k, expr * v);
void cache_result(expr * k, expr * v) { cache_shifted_result(k, 0, v); }
void cache_shifted_result(expr * k, unsigned offset, expr * v);
expr * get_cached(expr * k) const { return m_cache->find(k); }
expr * get_cached(expr* k, unsigned offset) const { return m_cache->find(k, offset); }
void cache_result(expr * k, expr * v, proof * pr);
proof * get_cached_pr(expr * k) const { return static_cast<proof*>(m_cache_pr->find(k)); }

View file

@ -38,9 +38,10 @@ void rewriter_tpl<Config>::process_var(var * v) {
if (!ProofGen) {
// bindings are only used when Proof Generation is not enabled.
unsigned idx = v->get_idx();
if (idx < m_bindings.size()) {
unsigned index = m_bindings.size() - idx - 1;
var * r = (var*)(m_bindings[index]);
expr * r = m_bindings[index];
if (r != nullptr) {
CTRACE("rewriter", v->get_sort() != m().get_sort(r),
tout << expr_ref(v, m()) << ":" << sort_ref(v->get_sort(), m()) << " != " << expr_ref(r, m()) << ":" << sort_ref(m().get_sort(r), m());
@ -50,11 +51,18 @@ void rewriter_tpl<Config>::process_var(var * v) {
if (!is_ground(r) && m_shifts[index] != m_bindings.size()) {
unsigned shift_amount = m_bindings.size() - m_shifts[index];
expr* c = get_cached(r, shift_amount);
if (c) {
result_stack().push_back(c);
set_new_child_flag(v);
return;
}
expr_ref tmp(m());
m_shifter(r, shift_amount, tmp);
result_stack().push_back(tmp);
TRACE("rewriter", tout << "shift: " << shift_amount << " idx: " << idx << " --> " << tmp << "\n";
display_bindings(tout););
cache_shifted_result(r, shift_amount, tmp);
}
else {
result_stack().push_back(r);
@ -380,7 +388,6 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
TRACE("get_macro", display_bindings(tout););
begin_scope();
m_num_qvars += num_args;
//m_num_qvars = 0;
m_root = def;
push_frame(def, false, RW_UNBOUNDED_DEPTH);
return;
@ -480,7 +487,7 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
m_root = q->get_expr();
unsigned sz = m_bindings.size();
for (unsigned i = 0; i < num_decls; i++) {
m_bindings.push_back(0);
m_bindings.push_back(nullptr);
m_shifts.push_back(sz);
}
}
@ -514,7 +521,12 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
}
if (ProofGen) {
quantifier_ref new_q(m().update_quantifier(q, num_pats, new_pats.c_ptr(), num_no_pats, new_no_pats.c_ptr(), new_body), m());
m_pr = q == new_q ? nullptr : m().mk_quant_intro(q, new_q, result_pr_stack().get(fr.m_spos));
m_pr = nullptr;
if (q != new_q) {
m_pr = result_pr_stack().get(fr.m_spos);
m_pr = m().mk_bind_proof(q, m_pr);
m_pr = m().mk_quant_intro(q, new_q, m_pr);
}
m_r = new_q;
proof_ref pr2(m());
if (m_cfg.reduce_quantifier(new_q, new_body, new_pats.c_ptr(), new_no_pats.c_ptr(), m_r, pr2)) {

View file

@ -33,30 +33,32 @@ Notes:
expr_ref sym_expr::accept(expr* e) {
ast_manager& m = m_t.get_manager();
expr_ref result(m);
var_subst subst(m);
seq_util u(m);
unsigned r1, r2, r3;
switch (m_ty) {
case t_pred: {
var_subst subst(m);
case t_pred:
result = subst(m_t, 1, &e);
break;
case t_not:
result = m_expr->accept(e);
result = m.mk_not(result);
break;
}
case t_char:
SASSERT(m.get_sort(e) == m.get_sort(m_t));
SASSERT(m.get_sort(e) == m_sort);
result = m.mk_eq(e, m_t);
break;
case t_range: {
bv_util bv(m);
rational r1, r2, r3;
unsigned sz;
if (bv.is_numeral(m_t, r1, sz) && bv.is_numeral(e, r2, sz) && bv.is_numeral(m_s, r3, sz)) {
case t_range:
if (u.is_const_char(m_t, r1) && u.is_const_char(e, r2) && u.is_const_char(m_s, r3)) {
result = m.mk_bool_val((r1 <= r2) && (r2 <= r3));
}
else {
result = m.mk_and(bv.mk_ule(m_t, e), bv.mk_ule(e, m_s));
result = m.mk_and(u.mk_le(m_t, e), u.mk_le(e, m_s));
}
break;
}
}
return result;
}
@ -65,6 +67,7 @@ std::ostream& sym_expr::display(std::ostream& out) const {
case t_char: return out << m_t;
case t_range: return out << m_t << ":" << m_s;
case t_pred: return out << m_t;
case t_not: return m_expr->display(out << "not ");
}
return out << "expression type not recognized";
}
@ -80,10 +83,11 @@ struct display_expr1 {
class sym_expr_boolean_algebra : public boolean_algebra<sym_expr*> {
ast_manager& m;
expr_solver& m_solver;
expr_ref m_var;
typedef sym_expr* T;
public:
sym_expr_boolean_algebra(ast_manager& m, expr_solver& s):
m(m), m_solver(s) {}
m(m), m_solver(s), m_var(m) {}
T mk_false() override {
expr_ref fml(m.mk_false(), m);
@ -94,6 +98,7 @@ public:
return sym_expr::mk_pred(fml, m.mk_bool_sort());
}
T mk_and(T x, T y) override {
seq_util u(m);
if (x->is_char() && y->is_char()) {
if (x->get_char() == y->get_char()) {
return x;
@ -103,6 +108,21 @@ public:
return sym_expr::mk_pred(fml, x->get_sort());
}
}
unsigned lo1, hi1, lo2, hi2;
if (x->is_range() && y->is_range() &&
u.is_const_char(x->get_lo(), lo1) && u.is_const_char(x->get_hi(), hi1) &&
u.is_const_char(y->get_lo(), lo2) && u.is_const_char(y->get_hi(), hi2)) {
lo1 = std::max(lo1, lo2);
hi1 = std::min(hi1, hi2);
if (lo1 > hi1) {
expr_ref fml(m.mk_false(), m);
return sym_expr::mk_pred(fml, x->get_sort());
}
expr_ref _start(u.mk_char(lo1), m);
expr_ref _stop(u.mk_char(hi1), m);
return sym_expr::mk_range(_start, _stop);
}
sort* s = x->get_sort();
if (m.is_bool(s)) s = y->get_sort();
var_ref v(m.mk_var(0, s), m);
@ -111,13 +131,29 @@ public:
if (m.is_true(fml1)) {
return y;
}
if (m.is_true(fml2)) return x;
if (fml1 == fml2) return x;
if (m.is_true(fml2)) {
return x;
}
if (fml1 == fml2) {
return x;
}
if (is_complement(fml1, fml2)) {
expr_ref ff(m.mk_false(), m);
return sym_expr::mk_pred(ff, x->get_sort());
}
bool_rewriter br(m);
expr_ref fml(m);
br.mk_and(fml1, fml2, fml);
return sym_expr::mk_pred(fml, x->get_sort());
}
bool is_complement(expr* f1, expr* f2) {
expr* f = nullptr;
return
(m.is_not(f1, f) && f == f2) ||
(m.is_not(f2, f) && f == f1);
}
T mk_or(T x, T y) override {
if (x->is_char() && y->is_char() &&
x->get_char() == y->get_char()) {
@ -148,6 +184,7 @@ public:
}
}
}
T mk_or(unsigned sz, T const* ts) override {
switch (sz) {
case 0: return mk_false();
@ -161,15 +198,24 @@ public:
}
}
}
lbool is_sat(T x) override {
unsigned lo, hi;
seq_util u(m);
if (x->is_char()) {
return l_true;
}
if (x->is_range()) {
// TBD check lower is below upper.
if (x->is_range() && u.is_const_char(x->get_lo(), lo) && u.is_const_char(x->get_hi(), hi)) {
return (lo <= hi) ? l_true : l_false;
}
expr_ref v(m.mk_fresh_const("x", x->get_sort()), m);
expr_ref fml = x->accept(v);
if (x->is_not() && x->get_arg()->is_range() && u.is_const_char(x->get_arg()->get_lo(), lo) && 0 < lo) {
return l_true;
}
if (!m_var || m.get_sort(m_var) != x->get_sort()) {
m_var = m.mk_fresh_const("x", x->get_sort());
}
expr_ref fml = x->accept(m_var);
if (m.is_true(fml)) {
return l_true;
}
@ -178,19 +224,14 @@ public:
}
return m_solver.check_sat(fml);
}
T mk_not(T x) override {
var_ref v(m.mk_var(0, x->get_sort()), m);
expr_ref fml(m.mk_not(x->accept(v)), m);
return sym_expr::mk_pred(fml, x->get_sort());
return sym_expr::mk_not(m, x);
}
/*virtual vector<std::pair<vector<bool>, T>> generate_min_terms(vector<T> constraints){
return 0;
}*/
};
re2automaton::re2automaton(ast_manager& m): m(m), u(m), bv(m), m_ba(nullptr), m_sa(nullptr) {}
re2automaton::re2automaton(ast_manager& m): m(m), u(m), m_ba(nullptr), m_sa(nullptr) {}
re2automaton::~re2automaton() {}
@ -248,9 +289,8 @@ eautomaton* re2automaton::re2aut(expr* e) {
s1.length() == 1 && s2.length() == 1) {
unsigned start = s1[0];
unsigned stop = s2[0];
unsigned nb = s1.num_bits();
expr_ref _start(bv.mk_numeral(start, nb), m);
expr_ref _stop(bv.mk_numeral(stop, nb), m);
expr_ref _start(u.mk_char(start), m);
expr_ref _stop(u.mk_char(stop), m);
TRACE("seq", tout << "Range: " << start << " " << stop << "\n";);
a = alloc(eautomaton, sm, sym_expr::mk_range(_start, _stop));
return a.detach();
@ -309,6 +349,9 @@ eautomaton* re2automaton::re2aut(expr* e) {
else if (u.re.is_intersection(e, e1, e2) && m_sa && (a = re2aut(e1)) && (b = re2aut(e2))) {
return m_sa->mk_product(*a, *b);
}
else {
TRACE("seq", tout << "not handled " << mk_pp(e, m) << "\n";);
}
return nullptr;
}
@ -343,9 +386,9 @@ eautomaton* re2automaton::seq2aut(expr* e) {
br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(f->get_family_id() == get_fid());
br_status st = BR_FAILED;
switch(f->get_decl_kind()) {
case OP_SEQ_UNIT:
SASSERT(num_args == 1);
return mk_seq_unit(args[0], result);
@ -356,16 +399,19 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
return mk_re_plus(args[0], result);
case OP_RE_STAR:
SASSERT(num_args == 1);
return mk_re_star(args[0], result);
st = mk_re_star(args[0], result);
break;
case OP_RE_OPTION:
SASSERT(num_args == 1);
return mk_re_opt(args[0], result);
case OP_RE_CONCAT:
if (num_args == 1) {
result = args[0]; return BR_DONE;
result = args[0];
return BR_DONE;
}
SASSERT(num_args == 2);
return mk_re_concat(args[0], args[1], result);
st = mk_re_concat(args[0], args[1], result);
break;
case OP_RE_UNION:
if (num_args == 1) {
result = args[0]; return BR_DONE;
@ -405,13 +451,19 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
return mk_seq_length(args[0], result);
case OP_SEQ_EXTRACT:
SASSERT(num_args == 3);
return mk_seq_extract(args[0], args[1], args[2], result);
st = mk_seq_extract(args[0], args[1], args[2], result);
break;
case OP_SEQ_CONTAINS:
SASSERT(num_args == 2);
return mk_seq_contains(args[0], args[1], result);
case OP_SEQ_AT:
SASSERT(num_args == 2);
return mk_seq_at(args[0], args[1], result);
#if 0
case OP_SEQ_NTH:
SASSERT(num_args == 2);
return mk_seq_nth(args[0], args[1], result);
#endif
case OP_SEQ_PREFIX:
SASSERT(num_args == 2);
return mk_seq_prefix(args[0], args[1], result);
@ -456,21 +508,20 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
case _OP_STRING_STRIDOF:
UNREACHABLE();
}
return BR_FAILED;
CTRACE("seq", st != BR_FAILED, tout << result << "\n";);
return st;
}
/*
* (seq.unit (_ BitVector 8)) ==> String constant
*/
br_status seq_rewriter::mk_seq_unit(expr* e, expr_ref& result) {
bv_util bvu(m());
rational n_val;
unsigned int n_size;
unsigned ch;
// specifically we want (_ BitVector 8)
if (bvu.is_bv(e) && bvu.is_numeral(e, n_val, n_size) && n_size == 8) {
if (m_util.is_const_char(e, ch)) {
// convert to string constant
zstring str(n_val.get_unsigned());
TRACE("seq_verbose", tout << "rewrite seq.unit of 8-bit value " << n_val.to_string() << " to string constant \"" << str<< "\"" << std::endl;);
zstring str(ch);
TRACE("seq_verbose", tout << "rewrite seq.unit of 8-bit value " << ch << " to string constant \"" << str<< "\"" << std::endl;);
result = m_util.str.mk_string(str);
return BR_DONE;
}
@ -566,6 +617,7 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
bool constantPos = m_autil.is_numeral(b, pos);
bool constantLen = m_autil.is_numeral(c, len);
// case 1: pos<0 or len<=0
// rewrite to ""
if ( (constantPos && pos.is_neg()) || (constantLen && !len.is_pos()) ) {
@ -574,7 +626,7 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
}
// case 1.1: pos >= length(base)
// rewrite to ""
if (constantBase && constantPos && pos >= rational(s.length())) {
if (constantPos && constantBase && pos >= rational(s.length())) {
result = m_util.str.mk_empty(m().get_sort(a));
return BR_DONE;
}
@ -582,52 +634,73 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
constantPos &= pos.is_unsigned();
constantLen &= len.is_unsigned();
if (constantBase && constantPos && constantLen) {
if (pos.get_unsigned() + len.get_unsigned() >= s.length()) {
// case 2: pos+len goes past the end of the string
unsigned _len = s.length() - pos.get_unsigned() + 1;
result = m_util.str.mk_string(s.extract(pos.get_unsigned(), _len));
} else {
// case 3: pos+len still within string
result = m_util.str.mk_string(s.extract(pos.get_unsigned(), len.get_unsigned()));
}
return BR_DONE;
}
if (constantPos && constantLen) {
if (constantPos && constantLen && constantBase) {
unsigned _pos = pos.get_unsigned();
unsigned _len = len.get_unsigned();
SASSERT(_len > 0);
expr_ref_vector as(m()), bs(m());
m_util.str.get_concat(a, as);
if (as.empty()) {
result = a;
return BR_DONE;
}
for (unsigned i = 0; i < as.size() && _len > 0; ++i) {
if (m_util.str.is_unit(as[i].get())) {
if (_pos == 0) {
bs.push_back(as[i].get());
--_len;
}
else {
--_pos;
}
}
else {
return BR_FAILED;
}
}
if (bs.empty()) {
result = m_util.str.mk_empty(m().get_sort(a));
}
else {
result = m_util.str.mk_concat(bs);
if (_pos + _len >= s.length()) {
// case 2: pos+len goes past the end of the string
unsigned _len = s.length() - _pos + 1;
result = m_util.str.mk_string(s.extract(_pos, _len));
} else {
// case 3: pos+len still within string
result = m_util.str.mk_string(s.extract(_pos, _len));
}
return BR_DONE;
}
return BR_FAILED;
expr_ref_vector as(m()), bs(m());
m_util.str.get_concat_units(a, as);
if (as.empty()) {
result = m_util.str.mk_empty(m().get_sort(a));
return BR_DONE;
}
if (!constantPos) {
return BR_FAILED;
}
unsigned _pos = pos.get_unsigned();
// (extract s 0 (len s)) = s
expr* a2 = nullptr;
if (_pos == 0 && m_util.str.is_length(c, a2) && a == a2) {
result = a;
return BR_DONE;
}
unsigned offset = 0;
for (; offset < as.size() && m_util.str.is_unit(as.get(offset)) && offset < _pos; ++offset) {};
if (offset == 0 && _pos > 0) {
return BR_FAILED;
}
if (_pos == 0 && !constantLen) {
return BR_FAILED;
}
// (extract (++ (unit x) (unit y)) 3 c) = empty
if (offset == as.size()) {
result = m_util.str.mk_empty(m().get_sort(a));
return BR_DONE;
}
SASSERT(offset != 0 || _pos == 0);
if (constantLen && _pos == offset) {
unsigned _len = len.get_unsigned();
// (extract (++ (unit a) (unit b) (unit c) x) 1 2) = (++ (unit b) (unit c))
unsigned i = offset;
for (; i < as.size() && m_util.str.is_unit(as.get(i)) && i - offset < _len; ++i);
if (i - offset == _len) {
result = m_util.str.mk_concat(_len, as.c_ptr() + offset);
return BR_DONE;
}
}
if (offset == 0) {
return BR_FAILED;
}
expr_ref pos1(m());
pos1 = m_autil.mk_sub(b, m_autil.mk_int(offset));
result = m_util.str.mk_concat(as.size() - offset, as.c_ptr() + offset);
result = m_util.str.mk_substr(result, pos1, c);
return BR_REWRITE3;
}
bool seq_rewriter::cannot_contain_suffix(expr* a, expr* b) {
@ -809,6 +882,32 @@ br_status seq_rewriter::mk_seq_at(expr* a, expr* b, expr_ref& result) {
return BR_DONE;
}
br_status seq_rewriter::mk_seq_nth(expr* a, expr* b, expr_ref& result) {
zstring c;
rational r;
if (!m_autil.is_numeral(b, r) || !r.is_unsigned()) {
return BR_FAILED;
}
unsigned len = r.get_unsigned();
expr_ref_vector as(m());
m_util.str.get_concat_units(a, as);
for (unsigned i = 0; i < as.size(); ++i) {
expr* a = as.get(i), *u = nullptr;
if (m_util.str.is_unit(a, u)) {
if (len == i) {
result = u;
return BR_DONE;
}
}
else {
return BR_FAILED;
}
}
return BR_FAILED;
}
br_status seq_rewriter::mk_seq_index(expr* a, expr* b, expr* c, expr_ref& result) {
zstring s1, s2;
rational r;
@ -1238,6 +1337,7 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
scoped_ptr<eautomaton> aut;
expr_ref_vector seq(m());
if (!(aut = m_re2aut(b))) {
TRACE("seq", tout << "not translated to automaton " << mk_pp(b, m()) << "\n";);
return BR_FAILED;
}
@ -1254,6 +1354,7 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
}
if (!is_sequence(a, seq)) {
TRACE("seq", tout << "not a sequence " << mk_pp(a, m()) << "\n";);
return BR_FAILED;
}
@ -1305,17 +1406,16 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
}
}
u_map<expr*> const& frontier = maps[select_map];
u_map<expr*>::iterator it = frontier.begin(), end = frontier.end();
expr_ref_vector ors(m());
for (; it != end; ++it) {
for (auto const& kv : frontier) {
unsigned_vector states;
bool has_final = false;
aut->get_epsilon_closure(it->m_key, states);
aut->get_epsilon_closure(kv.m_key, states);
for (unsigned i = 0; i < states.size() && !has_final; ++i) {
has_final = aut->is_final_state(states[i]);
}
if (has_final) {
ors.push_back(it->m_value);
ors.push_back(kv.m_value);
}
}
result = mk_or(ors);
@ -1434,6 +1534,14 @@ br_status seq_rewriter::mk_re_inter(expr* a, expr* b, expr_ref& result) {
result = a;
return BR_DONE;
}
expr* ac = nullptr, *bc = nullptr;
if ((m_util.re.is_complement(a, ac) && ac == b) ||
(m_util.re.is_complement(b, bc) && bc == a)) {
sort* seq_sort = nullptr;
VERIFY(m_util.is_re(a, seq_sort));
result = m_util.re.mk_empty(seq_sort);
return BR_DONE;
}
return BR_FAILED;
}
@ -1977,15 +2085,13 @@ bool seq_rewriter::min_length(unsigned n, expr* const* es, unsigned& len) {
bool seq_rewriter::is_string(unsigned n, expr* const* es, zstring& s) const {
zstring s1;
expr* e;
bv_util bv(m());
rational val;
unsigned sz;
unsigned ch;
for (unsigned i = 0; i < n; ++i) {
if (m_util.str.is_string(es[i], s1)) {
s = s + s1;
}
else if (m_util.str.is_unit(es[i], e) && bv.is_numeral(e, val, sz)) {
s = s + zstring(val.get_unsigned());
else if (m_util.str.is_unit(es[i], e) && m_util.is_const_char(e, ch)) {
s = s + zstring(ch);
}
else {
return false;

View file

@ -31,31 +31,38 @@ class sym_expr {
enum ty {
t_char,
t_pred,
t_not,
t_range
};
ty m_ty;
sort* m_sort;
expr_ref m_t;
expr_ref m_s;
unsigned m_ref;
sym_expr(ty ty, expr_ref& t, expr_ref& s, sort* srt) : m_ty(ty), m_sort(srt), m_t(t), m_s(s), m_ref(0) {}
ty m_ty;
sort* m_sort;
sym_expr* m_expr;
expr_ref m_t;
expr_ref m_s;
unsigned m_ref;
sym_expr(ty ty, expr_ref& t, expr_ref& s, sort* srt, sym_expr* e) :
m_ty(ty), m_sort(srt), m_expr(e), m_t(t), m_s(s), m_ref(0) {}
public:
~sym_expr() { if (m_expr) m_expr->dec_ref(); }
expr_ref accept(expr* e);
static sym_expr* mk_char(expr_ref& t) { return alloc(sym_expr, t_char, t, t, t.get_manager().get_sort(t)); }
static sym_expr* mk_char(expr_ref& t) { return alloc(sym_expr, t_char, t, t, t.get_manager().get_sort(t), nullptr); }
static sym_expr* mk_char(ast_manager& m, expr* t) { expr_ref tr(t, m); return mk_char(tr); }
static sym_expr* mk_pred(expr_ref& t, sort* s) { return alloc(sym_expr, t_pred, t, t, s); }
static sym_expr* mk_range(expr_ref& lo, expr_ref& hi) { return alloc(sym_expr, t_range, lo, hi, lo.get_manager().get_sort(hi)); }
static sym_expr* mk_pred(expr_ref& t, sort* s) { return alloc(sym_expr, t_pred, t, t, s, nullptr); }
static sym_expr* mk_range(expr_ref& lo, expr_ref& hi) { return alloc(sym_expr, t_range, lo, hi, lo.get_manager().get_sort(hi), nullptr); }
static sym_expr* mk_not(ast_manager& m, sym_expr* e) { expr_ref f(m); e->inc_ref(); return alloc(sym_expr, t_not, f, f, e->get_sort(), e); }
void inc_ref() { ++m_ref; }
void dec_ref() { --m_ref; if (m_ref == 0) dealloc(this); }
std::ostream& display(std::ostream& out) const;
bool is_char() const { return m_ty == t_char; }
bool is_pred() const { return !is_char(); }
bool is_range() const { return m_ty == t_range; }
bool is_not() const { return m_ty == t_not; }
sort* get_sort() const { return m_sort; }
expr* get_char() const { SASSERT(is_char()); return m_t; }
expr* get_pred() const { SASSERT(is_pred()); return m_t; }
expr* get_lo() const { SASSERT(is_range()); return m_t; }
expr* get_hi() const { SASSERT(is_range()); return m_s; }
sym_expr* get_arg() const { SASSERT(is_not()); return m_expr; }
};
class sym_expr_manager {
@ -77,7 +84,6 @@ class re2automaton {
ast_manager& m;
sym_expr_manager sm;
seq_util u;
bv_util bv;
scoped_ptr<expr_solver> m_solver;
scoped_ptr<boolean_algebra_t> m_ba;
scoped_ptr<symbolic_automata_t> m_sa;
@ -108,6 +114,7 @@ class seq_rewriter {
br_status mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& result);
br_status mk_seq_contains(expr* a, expr* b, expr_ref& result);
br_status mk_seq_at(expr* a, expr* b, expr_ref& result);
br_status mk_seq_nth(expr* a, expr* b, expr_ref& result);
br_status mk_seq_index(expr* a, expr* b, expr* c, expr_ref& result);
br_status mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& result);
br_status mk_seq_prefix(expr* a, expr* b, expr_ref& result);

View file

@ -135,17 +135,14 @@ expr_ref unused_vars_eliminator::operator()(quantifier* q) {
return result;
}
expr_ref tmp(m);
expr_ref_buffer new_patterns(m);
expr_ref_buffer new_no_patterns(m);
for (unsigned i = 0; i < num_patterns; i++) {
tmp = m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr());
new_patterns.push_back(tmp);
new_patterns.push_back(m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr()));
}
for (unsigned i = 0; i < num_no_patterns; i++) {
tmp = m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr());
new_no_patterns.push_back(tmp);
new_no_patterns.push_back(m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr()));
}
result = m.mk_quantifier(q->get_kind(),

View file

@ -20,6 +20,7 @@ Revision History:
#include "ast/arith_decl_plugin.h"
#include "ast/array_decl_plugin.h"
#include "ast/ast_pp.h"
#include "ast/bv_decl_plugin.h"
#include <sstream>
static bool is_hex_digit(char ch, unsigned& d) {
@ -68,14 +69,14 @@ static bool is_escape_char(char const *& s, unsigned& result) {
}
/* 2 octal digits */
if (is_octal_digit(*(s + 1), d1) && is_octal_digit(*(s + 2), d2) &&
!is_octal_digit(*(s + 3), d3)) {
!is_octal_digit(*(s + 3), d3)) {
result = d1 * 8 + d2;
s += 3;
return true;
}
/* 3 octal digits */
if (is_octal_digit(*(s + 1), d1) && is_octal_digit(*(s + 2), d2) &&
is_octal_digit(*(s + 3), d3)) {
is_octal_digit(*(s + 3), d3)) {
result = d1*64 + d2*8 + d3;
s += 4;
return true;
@ -295,13 +296,10 @@ bool zstring::operator==(const zstring& other) const {
return false;
}
for (unsigned i = 0; i < length(); ++i) {
unsigned Xi = m_buffer[i];
unsigned Yi = other[i];
if (Xi != Yi) {
if (m_buffer[i] != other[i]) {
return false;
}
}
return true;
}
@ -324,19 +322,14 @@ bool operator<(const zstring& lhs, const zstring& rhs) {
unsigned Ri = rhs[i];
if (Li < Ri) {
return true;
} else if (Li > Ri) {
}
else if (Li > Ri) {
return false;
} else {
continue;
}
}
}
// at this point, all compared characters are equal,
// so decide based on the relative lengths
if (lhs.length() < rhs.length()) {
return true;
} else {
return false;
}
return lhs.length() < rhs.length();
}
@ -377,8 +370,8 @@ bool seq_decl_plugin::match(ptr_vector<sort>& binding, sort* s, sort* sP) {
if (s->get_family_id() == sP->get_family_id() &&
s->get_decl_kind() == sP->get_decl_kind() &&
s->get_num_parameters() == sP->get_num_parameters()) {
for (unsigned i = 0, sz = s->get_num_parameters(); i < sz; ++i) {
parameter const& p = s->get_parameter(i);
for (unsigned i = 0, sz = s->get_num_parameters(); i < sz; ++i) {
parameter const& p = s->get_parameter(i);
if (p.is_ast() && is_sort(p.get_ast())) {
parameter const& p2 = sP->get_parameter(i);
if (!match(binding, to_sort(p.get_ast()), to_sort(p2.get_ast()))) return false;
@ -435,7 +428,7 @@ void seq_decl_plugin::match_right_assoc(psig& sig, unsigned dsz, sort *const* do
}
void seq_decl_plugin::match(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
ptr_vector<sort> binding;
m_binding.reset();
ast_manager& m = *m_manager;
if (sig.m_dom.size() != dsz) {
std::ostringstream strm;
@ -445,10 +438,10 @@ void seq_decl_plugin::match(psig& sig, unsigned dsz, sort *const* dom, sort* ran
}
bool is_match = true;
for (unsigned i = 0; is_match && i < dsz; ++i) {
is_match = match(binding, dom[i], sig.m_dom[i].get());
is_match = match(m_binding, dom[i], sig.m_dom[i].get());
}
if (range && is_match) {
is_match = match(binding, range, sig.m_range);
is_match = match(m_binding, range, sig.m_range);
}
if (!is_match) {
std::ostringstream strm;
@ -474,7 +467,7 @@ void seq_decl_plugin::match(psig& sig, unsigned dsz, sort *const* dom, sort* ran
strm << "is ambiguous. Function takes no arguments and sort of range has not been constrained";
m.raise_exception(strm.str().c_str());
}
range_out = apply_binding(binding, sig.m_range);
range_out = apply_binding(m_binding, sig.m_range);
SASSERT(range_out);
}
@ -555,7 +548,7 @@ void seq_decl_plugin::init() {
m_sigs[OP_RE_OF_PRED] = alloc(psig, m, "re.of.pred", 1, 1, &predA, reA);
m_sigs[OP_SEQ_TO_RE] = alloc(psig, m, "seq.to.re", 1, 1, &seqA, reA);
m_sigs[OP_SEQ_IN_RE] = alloc(psig, m, "seq.in.re", 1, 2, seqAreA, boolT);
m_sigs[OP_STRING_CONST] = 0;
m_sigs[OP_STRING_CONST] = nullptr;
m_sigs[_OP_STRING_STRIDOF] = alloc(psig, m, "str.indexof", 0, 3, str2TintT, intT);
m_sigs[_OP_STRING_STRREPL] = alloc(psig, m, "str.replace", 0, 3, str3T, strT);
m_sigs[OP_STRING_ITOS] = alloc(psig, m, "int.to.str", 0, 1, &intT, strT);
@ -967,6 +960,24 @@ app* seq_util::str::mk_char(char ch) const {
return mk_char(s, 0);
}
bool seq_util::is_const_char(expr* e, unsigned& c) const {
bv_util bv(m);
rational r;
unsigned sz;
return bv.is_numeral(e, r, sz) && sz == 8 && r.is_unsigned() && (c = r.get_unsigned(), true);
}
app* seq_util::mk_char(unsigned ch) const {
bv_util bv(m);
return bv.mk_numeral(rational(ch), 8);
}
app* seq_util::mk_le(expr* ch1, expr* ch2) const {
bv_util bv(m);
return bv.mk_ule(ch1, ch2);
}
bool seq_util::str::is_string(expr const* n, zstring& s) const {
if (is_string(n)) {
s = zstring(to_app(n)->get_decl()->get_parameter(0).get_symbol().bare_str());
@ -1044,7 +1055,6 @@ app* seq_util::re::mk_empty(sort* s) {
return m.mk_app(m_fid, OP_RE_EMPTY_SET, 0, nullptr, 0, nullptr, s);
}
bool seq_util::re::is_loop(expr const* n, expr*& body, unsigned& lo, unsigned& hi) {
if (is_loop(n)) {
app const* a = to_app(n);

View file

@ -22,7 +22,6 @@ Revision History:
#define SEQ_DECL_PLUGIN_H_
#include "ast/ast.h"
#include "ast/bv_decl_plugin.h"
enum seq_sort_kind {
@ -140,6 +139,7 @@ class seq_decl_plugin : public decl_plugin {
};
ptr_vector<psig> m_sigs;
ptr_vector<sort> m_binding;
bool m_init;
symbol m_stringc_sym;
symbol m_charc_sym;
@ -220,6 +220,9 @@ public:
bool is_re(expr* e) const { return is_re(m.get_sort(e)); }
bool is_re(expr* e, sort*& seq) const { return is_re(m.get_sort(e), seq); }
bool is_char(expr* e) const { return is_char(m.get_sort(e)); }
bool is_const_char(expr* e, unsigned& c) const;
app* mk_char(unsigned ch) const;
app* mk_le(expr* ch1, expr* ch2) const;
app* mk_skolem(symbol const& name, unsigned n, expr* const* args, sort* range);
bool is_skolem(expr const* e) const { return is_app_of(e, m_fid, _OP_SEQ_SKOLEM); }

View file

@ -21,13 +21,11 @@ Revision History:
#include "util/ref_util.h"
inline void shared_occs::insert(expr * t) {
obj_hashtable<expr>::entry * dummy;
if (m_shared.insert_if_not_there_core(t, dummy))
m.inc_ref(t);
m_shared.reserve(t->get_id() + 1);
m_shared[t->get_id()] = t;
}
void shared_occs::reset() {
dec_ref_collection_values(m, m_shared);
m_shared.reset();
}
@ -132,9 +130,15 @@ void shared_occs::operator()(expr * t) {
}
void shared_occs::display(std::ostream & out, ast_manager & m) const {
iterator it = begin_shared();
iterator end = end_shared();
for (; it != end; ++it) {
out << mk_ismt2_pp(*it, m) << "\n";
for (expr* s : m_shared) {
if (s) {
out << mk_ismt2_pp(s, m) << "\n";
}
}
}
unsigned shared_occs::num_shared() const{
unsigned count = 0;
for (expr* s : m_shared) if (s) count++;
return count;
}

View file

@ -53,7 +53,7 @@ class shared_occs {
bool m_track_atomic;
bool m_visit_quantifiers;
bool m_visit_patterns;
obj_hashtable<expr> m_shared;
expr_ref_vector m_shared;
typedef std::pair<expr*, unsigned> frame;
svector<frame> m_stack;
bool process(expr * t, shared_occs_mark & visited);
@ -64,15 +64,14 @@ public:
m(_m),
m_track_atomic(track_atomic),
m_visit_quantifiers(visit_quantifiers),
m_visit_patterns(visit_patterns) {
m_visit_patterns(visit_patterns),
m_shared(m) {
}
~shared_occs();
void operator()(expr * t);
void operator()(expr * t, shared_occs_mark & visited);
bool is_shared(expr * t) const { return m_shared.contains(t); }
unsigned num_shared() const { return m_shared.size(); }
iterator begin_shared() const { return m_shared.begin(); }
iterator end_shared() const { return m_shared.end(); }
bool is_shared(expr * t) const { return m_shared.get(t->get_id(), nullptr) != nullptr; }
unsigned num_shared() const;
void reset();
void cleanup();
void display(std::ostream & out, ast_manager & mgr) const;