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:
commit
ec76efedbe
386 changed files with 10027 additions and 8346 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]; }
|
||||
};
|
||||
};
|
||||
|
|
81
src/ast/display_dimacs.cpp
Normal file
81
src/ast/display_dimacs.cpp
Normal 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
26
src/ast/display_dimacs.h
Normal 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__ */
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(t1…tn) = 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?
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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";);
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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,
|
||||
|
|
201
src/ast/rewriter/hoist_rewriter.cpp
Normal file
201
src/ast/rewriter/hoist_rewriter.cpp
Normal 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();
|
||||
}
|
||||
}
|
80
src/ast/rewriter/hoist_rewriter.h
Normal file
80
src/ast/rewriter/hoist_rewriter.h
Normal 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
|
|
@ -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";
|
||||
|
|
|
@ -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 ++;
|
||||
|
|
|
@ -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)); }
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue