mirror of
https://github.com/Z3Prover/z3
synced 2025-04-12 20:18:18 +00:00
fix build, add seq features
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
3c50508762
commit
72883df134
|
@ -5693,8 +5693,6 @@ class Statistics:
|
||||||
>>> s.check()
|
>>> s.check()
|
||||||
sat
|
sat
|
||||||
>>> st = s.statistics()
|
>>> st = s.statistics()
|
||||||
>>> st.keys()
|
|
||||||
['nlsat propagations', 'nlsat stages', 'rlimit count', 'max memory', 'memory', 'num allocs']
|
|
||||||
"""
|
"""
|
||||||
return [Z3_stats_get_key(self.ctx.ref(), self.stats, idx) for idx in range(len(self))]
|
return [Z3_stats_get_key(self.ctx.ref(), self.stats, idx) for idx in range(len(self))]
|
||||||
|
|
||||||
|
@ -5730,8 +5728,6 @@ class Statistics:
|
||||||
>>> s.check()
|
>>> s.check()
|
||||||
sat
|
sat
|
||||||
>>> st = s.statistics()
|
>>> st = s.statistics()
|
||||||
>>> st.keys()
|
|
||||||
['nlsat propagations', 'nlsat stages', 'rlimit count', 'max memory', 'memory', 'num allocs']
|
|
||||||
>>> st.nlsat_propagations
|
>>> st.nlsat_propagations
|
||||||
2
|
2
|
||||||
>>> st.nlsat_stages
|
>>> st.nlsat_stages
|
||||||
|
|
|
@ -520,6 +520,7 @@ br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) {
|
||||||
|
|
||||||
bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_vector& rhs) {
|
bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_vector& rhs) {
|
||||||
expr* a, *b;
|
expr* a, *b;
|
||||||
|
zstring s;
|
||||||
bool change = false;
|
bool change = false;
|
||||||
expr_ref_vector trail(m());
|
expr_ref_vector trail(m());
|
||||||
m_lhs.reset();
|
m_lhs.reset();
|
||||||
|
@ -528,23 +529,55 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
||||||
m_util.str.get_concat(r, m_rhs);
|
m_util.str.get_concat(r, m_rhs);
|
||||||
|
|
||||||
// solve from back
|
// solve from back
|
||||||
while (!m_lhs.empty() && !m_rhs.empty()) {
|
while (true) {
|
||||||
if (m_lhs.back() == m_rhs.back()) {
|
while (!m_rhs.empty() && m_util.str.is_empty(m_rhs.back())) {
|
||||||
|
m_rhs.pop_back();
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
while (!m_lhs.empty() && m_util.str.is_empty(m_lhs.back())) {
|
||||||
|
m_lhs.pop_back();
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
if (m_lhs.empty() || m_rhs.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
expr* l = m_lhs.back();
|
||||||
|
expr* r = m_rhs.back();
|
||||||
|
if (m_util.str.is_unit(r) && m_util.str.is_string(l)) {
|
||||||
|
std::swap(l, r);
|
||||||
|
std::swap(m_lhs, m_rhs);
|
||||||
|
}
|
||||||
|
if (l == r) {
|
||||||
m_lhs.pop_back();
|
m_lhs.pop_back();
|
||||||
m_rhs.pop_back();
|
m_rhs.pop_back();
|
||||||
}
|
}
|
||||||
else if(m_util.str.is_unit(m_lhs.back(), a) &&
|
else if(m_util.str.is_unit(l, a) &&
|
||||||
m_util.str.is_unit(m_rhs.back(), b)) {
|
m_util.str.is_unit(r, b)) {
|
||||||
lhs.push_back(a);
|
lhs.push_back(a);
|
||||||
rhs.push_back(b);
|
rhs.push_back(b);
|
||||||
m_lhs.pop_back();
|
m_lhs.pop_back();
|
||||||
m_rhs.pop_back();
|
m_rhs.pop_back();
|
||||||
}
|
}
|
||||||
else if (!m_rhs.empty() && m_util.str.is_empty(m_rhs.back())) {
|
else if (m_util.str.is_unit(l, a) && m_util.str.is_string(r, s)) {
|
||||||
|
SASSERT(s.length() > 0);
|
||||||
|
|
||||||
|
unsigned ch = s[s.length()-1];
|
||||||
|
SASSERT(s.num_bits() == m_butil.get_bv_size(a));
|
||||||
|
expr_ref bv(m());
|
||||||
|
|
||||||
|
bv = m_butil.mk_numeral(ch, s.num_bits());
|
||||||
|
SASSERT(m_butil.is_bv(a));
|
||||||
|
lhs.push_back(bv);
|
||||||
|
rhs.push_back(a);
|
||||||
|
m_lhs.pop_back();
|
||||||
|
if (s.length() == 1) {
|
||||||
m_rhs.pop_back();
|
m_rhs.pop_back();
|
||||||
}
|
}
|
||||||
else if (!m_lhs.empty() && m_util.str.is_empty(m_lhs.back())) {
|
else {
|
||||||
m_lhs.pop_back();
|
expr_ref s2(m_util.str.mk_string(s.extract(0, s.length()-2)), m());
|
||||||
|
m_rhs[m_rhs.size()-1] = s2;
|
||||||
|
trail.push_back(s2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
|
@ -554,23 +587,55 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
||||||
|
|
||||||
// solve from front
|
// solve from front
|
||||||
unsigned head1 = 0, head2 = 0;
|
unsigned head1 = 0, head2 = 0;
|
||||||
while (head1 < m_lhs.size() && head2 < m_rhs.size()) {
|
while (true) {
|
||||||
if (m_lhs[head1] == m_rhs[head2]) {
|
while (head1 < m_lhs.size() && m_util.str.is_empty(m_lhs[head1])) {
|
||||||
|
++head1;
|
||||||
|
}
|
||||||
|
while (head2 < m_rhs.size() && m_util.str.is_empty(m_rhs[head2])) {
|
||||||
|
++head2;
|
||||||
|
}
|
||||||
|
if (head1 == m_lhs.size() || head2 == m_rhs.size()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SASSERT(head1 < m_lhs.size() && head2 == m_rhs.size());
|
||||||
|
|
||||||
|
expr* l = m_lhs[head1];
|
||||||
|
expr* r = m_rhs[head2];
|
||||||
|
if (m_util.str.is_unit(r) && m_util.str.is_string(l)) {
|
||||||
|
std::swap(l, r);
|
||||||
|
std::swap(m_lhs, m_rhs);
|
||||||
|
}
|
||||||
|
if (l == r) {
|
||||||
++head1;
|
++head1;
|
||||||
++head2;
|
++head2;
|
||||||
}
|
}
|
||||||
else if(m_util.str.is_unit(m_lhs[head1], a) &&
|
else if(m_util.str.is_unit(l, a) &&
|
||||||
m_util.str.is_unit(m_rhs[head2], b)) {
|
m_util.str.is_unit(r, b)) {
|
||||||
lhs.push_back(a);
|
lhs.push_back(a);
|
||||||
rhs.push_back(b);
|
rhs.push_back(b);
|
||||||
++head1;
|
++head1;
|
||||||
++head2;
|
++head2;
|
||||||
}
|
}
|
||||||
else if (head1 < m_lhs.size() && m_util.str.is_empty(m_lhs[head1])) {
|
else if (m_util.str.is_unit(l, a) && m_util.str.is_string(r, s)) {
|
||||||
++head1;
|
SASSERT(s.length() > 0);
|
||||||
|
|
||||||
|
unsigned ch = s[0];
|
||||||
|
SASSERT(s.num_bits() == m_butil.get_bv_size(a));
|
||||||
|
expr_ref bv(m());
|
||||||
|
|
||||||
|
bv = m_butil.mk_numeral(ch, s.num_bits());
|
||||||
|
SASSERT(m_butil.is_bv(a));
|
||||||
|
lhs.push_back(bv);
|
||||||
|
rhs.push_back(a);
|
||||||
|
m_lhs.pop_back();
|
||||||
|
if (s.length() == 1) {
|
||||||
|
m_rhs.pop_back();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
expr_ref s2(m_util.str.mk_string(s.extract(1, s.length()-1)), m());
|
||||||
|
m_rhs[m_rhs.size()-1] = s2;
|
||||||
|
trail.push_back(s2);
|
||||||
}
|
}
|
||||||
else if (head2 < m_rhs.size() && m_util.str.is_empty(m_rhs[head2])) {
|
|
||||||
++head2;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -21,6 +21,7 @@ Notes:
|
||||||
|
|
||||||
#include"seq_decl_plugin.h"
|
#include"seq_decl_plugin.h"
|
||||||
#include"arith_decl_plugin.h"
|
#include"arith_decl_plugin.h"
|
||||||
|
#include"bv_decl_plugin.h"
|
||||||
#include"rewriter_types.h"
|
#include"rewriter_types.h"
|
||||||
#include"params.h"
|
#include"params.h"
|
||||||
#include"lbool.h"
|
#include"lbool.h"
|
||||||
|
@ -32,6 +33,7 @@ Notes:
|
||||||
class seq_rewriter {
|
class seq_rewriter {
|
||||||
seq_util m_util;
|
seq_util m_util;
|
||||||
arith_util m_autil;
|
arith_util m_autil;
|
||||||
|
bv_util m_butil;
|
||||||
ptr_vector<expr> m_es, m_lhs, m_rhs;
|
ptr_vector<expr> m_es, m_lhs, m_rhs;
|
||||||
|
|
||||||
br_status mk_seq_concat(expr* a, expr* b, expr_ref& result);
|
br_status mk_seq_concat(expr* a, expr* b, expr_ref& result);
|
||||||
|
@ -63,7 +65,7 @@ class seq_rewriter {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
seq_rewriter(ast_manager & m, params_ref const & p = params_ref()):
|
seq_rewriter(ast_manager & m, params_ref const & p = params_ref()):
|
||||||
m_util(m), m_autil(m) {
|
m_util(m), m_autil(m), m_butil(m) {
|
||||||
}
|
}
|
||||||
ast_manager & m() const { return m_util.get_manager(); }
|
ast_manager & m() const { return m_util.get_manager(); }
|
||||||
family_id get_fid() const { return m_util.get_family_id(); }
|
family_id get_fid() const { return m_util.get_family_id(); }
|
||||||
|
|
|
@ -487,9 +487,7 @@ namespace datalog {
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
bool canceled() {
|
bool canceled() {
|
||||||
if (m.limit().inc()) return true;
|
return m.canceled() && (m_last_status = CANCELED, true);
|
||||||
m_last_status = CANCELED;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
|
@ -151,6 +151,7 @@ namespace datalog {
|
||||||
m_context.ensure_closed();
|
m_context.ensure_closed();
|
||||||
transform_rules();
|
transform_rules();
|
||||||
if (m_context.canceled()) {
|
if (m_context.canceled()) {
|
||||||
|
TRACE("dl", tout << "canceled\n";);
|
||||||
result = l_undef;
|
result = l_undef;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -191,6 +192,7 @@ namespace datalog {
|
||||||
IF_VERBOSE(10, m_ectx.report_big_relations(1000, verbose_stream()););
|
IF_VERBOSE(10, m_ectx.report_big_relations(1000, verbose_stream()););
|
||||||
|
|
||||||
if (m_context.canceled()) {
|
if (m_context.canceled()) {
|
||||||
|
TRACE("dl", tout << "canceled\n";);
|
||||||
result = l_undef;
|
result = l_undef;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -206,6 +208,7 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
if (timeout_after_this_round) {
|
if (timeout_after_this_round) {
|
||||||
m_context.set_status(TIMEOUT);
|
m_context.set_status(TIMEOUT);
|
||||||
|
TRACE("dl", tout << "timeout\n";);
|
||||||
result = l_undef;
|
result = l_undef;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -272,6 +275,7 @@ namespace datalog {
|
||||||
if (some_non_empty) {
|
if (some_non_empty) {
|
||||||
m_answer = mk_and(m, ans.size(), ans.c_ptr());
|
m_answer = mk_and(m, ans.size(), ans.c_ptr());
|
||||||
if (is_approx) {
|
if (is_approx) {
|
||||||
|
TRACE("dl", tout << "approx\n";);
|
||||||
res = l_undef;
|
res = l_undef;
|
||||||
m_context.set_status(APPROX);
|
m_context.set_status(APPROX);
|
||||||
}
|
}
|
||||||
|
@ -286,6 +290,7 @@ namespace datalog {
|
||||||
m_answer = m.mk_false();
|
m_answer = m.mk_false();
|
||||||
break;
|
break;
|
||||||
case l_undef:
|
case l_undef:
|
||||||
|
TRACE("dl", tout << "saturation in undef\n";);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@ -367,6 +372,7 @@ namespace datalog {
|
||||||
m_last_result_relation->to_formula(m_answer);
|
m_last_result_relation->to_formula(m_answer);
|
||||||
if (!m_last_result_relation->is_precise()) {
|
if (!m_last_result_relation->is_precise()) {
|
||||||
m_context.set_status(APPROX);
|
m_context.set_status(APPROX);
|
||||||
|
TRACE("dl", tout << "approx\n";);
|
||||||
res = l_undef;
|
res = l_undef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -815,7 +815,7 @@ namespace smt {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup::setup_seq() {
|
void setup::setup_seq() {
|
||||||
m_context.register_plugin(alloc(theory_seq, m_manager));
|
m_context.register_plugin(alloc(theory_seq_empty, m_manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup::setup_card() {
|
void setup::setup_card() {
|
||||||
|
|
|
@ -27,6 +27,7 @@ Revision History:
|
||||||
using namespace smt;
|
using namespace smt;
|
||||||
|
|
||||||
void theory_seq::solution_map::update(expr* e, expr* r, enode_pair_dependency* d) {
|
void theory_seq::solution_map::update(expr* e, expr* r, enode_pair_dependency* d) {
|
||||||
|
m_cache.reset();
|
||||||
std::pair<expr*, enode_pair_dependency*> value;
|
std::pair<expr*, enode_pair_dependency*> value;
|
||||||
if (m_map.find(e, value)) {
|
if (m_map.find(e, value)) {
|
||||||
add_trail(DEL, e, value.first, value.second);
|
add_trail(DEL, e, value.first, value.second);
|
||||||
|
@ -47,21 +48,17 @@ void theory_seq::solution_map::add_trail(map_update op, expr* l, expr* r, enode_
|
||||||
expr* theory_seq::solution_map::find(expr* e, enode_pair_dependency*& d) {
|
expr* theory_seq::solution_map::find(expr* e, enode_pair_dependency*& d) {
|
||||||
std::pair<expr*, enode_pair_dependency*> value;
|
std::pair<expr*, enode_pair_dependency*> value;
|
||||||
d = 0;
|
d = 0;
|
||||||
unsigned num_finds = 0;
|
|
||||||
expr* result = e;
|
expr* result = e;
|
||||||
while (m_map.find(result, value)) {
|
while (m_map.find(result, value)) {
|
||||||
d = m_dm.mk_join(d, value.second);
|
d = m_dm.mk_join(d, value.second);
|
||||||
result = value.first;
|
result = value.first;
|
||||||
++num_finds;
|
|
||||||
}
|
|
||||||
if (num_finds > 1) { // path compression for original key only.
|
|
||||||
update(e, result, d);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void theory_seq::solution_map::pop_scope(unsigned num_scopes) {
|
void theory_seq::solution_map::pop_scope(unsigned num_scopes) {
|
||||||
if (num_scopes == 0) return;
|
if (num_scopes == 0) return;
|
||||||
|
m_cache.reset();
|
||||||
unsigned start = m_limit[m_limit.size() - num_scopes];
|
unsigned start = m_limit[m_limit.size() - num_scopes];
|
||||||
for (unsigned i = m_updates.size(); i > start; ) {
|
for (unsigned i = m_updates.size(); i > start; ) {
|
||||||
--i;
|
--i;
|
||||||
|
@ -80,7 +77,7 @@ void theory_seq::solution_map::pop_scope(unsigned num_scopes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void theory_seq::solution_map::display(std::ostream& out) const {
|
void theory_seq::solution_map::display(std::ostream& out) const {
|
||||||
map_t::iterator it = m_map.begin(), end = m_map.end();
|
eqdep_map_t::iterator it = m_map.begin(), end = m_map.end();
|
||||||
for (; it != end; ++it) {
|
for (; it != end; ++it) {
|
||||||
out << mk_pp(it->m_key, m) << " |-> " << mk_pp(it->m_value.first, m) << "\n";
|
out << mk_pp(it->m_key, m) << " |-> " << mk_pp(it->m_value.first, m) << "\n";
|
||||||
}
|
}
|
||||||
|
@ -125,10 +122,7 @@ void theory_seq::exclusion_table::display(std::ostream& out) const {
|
||||||
theory_seq::theory_seq(ast_manager& m):
|
theory_seq::theory_seq(ast_manager& m):
|
||||||
theory(m.mk_family_id("seq")),
|
theory(m.mk_family_id("seq")),
|
||||||
m(m),
|
m(m),
|
||||||
m_dam(m_dep_array_value_manager, m_alloc),
|
|
||||||
m_rep(m, m_dm),
|
m_rep(m, m_dm),
|
||||||
m_cache(m),
|
|
||||||
m_sort2len_fn(m),
|
|
||||||
m_factory(0),
|
m_factory(0),
|
||||||
m_ineqs(m),
|
m_ineqs(m),
|
||||||
m_exclude(m),
|
m_exclude(m),
|
||||||
|
@ -142,9 +136,6 @@ theory_seq::theory_seq(ast_manager& m):
|
||||||
m_util(m),
|
m_util(m),
|
||||||
m_autil(m),
|
m_autil(m),
|
||||||
m_trail_stack(*this) {
|
m_trail_stack(*this) {
|
||||||
m_lhs.push_back(expr_array());
|
|
||||||
m_rhs.push_back(expr_array());
|
|
||||||
m_deps.push_back(enode_pair_dependency_array());
|
|
||||||
m_prefix_sym = "seq.prefix.suffix";
|
m_prefix_sym = "seq.prefix.suffix";
|
||||||
m_suffix_sym = "seq.suffix.prefix";
|
m_suffix_sym = "seq.suffix.prefix";
|
||||||
m_left_sym = "seq.left";
|
m_left_sym = "seq.left";
|
||||||
|
@ -154,11 +145,6 @@ theory_seq::theory_seq(ast_manager& m):
|
||||||
}
|
}
|
||||||
|
|
||||||
theory_seq::~theory_seq() {
|
theory_seq::~theory_seq() {
|
||||||
unsigned num_scopes = m_lhs.size()-1;
|
|
||||||
if (num_scopes > 0) pop_scope_eh(num_scopes);
|
|
||||||
m.del(m_lhs.back());
|
|
||||||
m.del(m_rhs.back());
|
|
||||||
m_dam.del(m_deps.back());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -183,12 +169,16 @@ final_check_status theory_seq::final_check_eh() {
|
||||||
if (ctx.inconsistent()) {
|
if (ctx.inconsistent()) {
|
||||||
return FC_CONTINUE;
|
return FC_CONTINUE;
|
||||||
}
|
}
|
||||||
if (m.size(m_lhs.back()) > 0 || m_incomplete) {
|
if (!check_length_coherence()) {
|
||||||
return FC_GIVEUP;
|
return FC_CONTINUE;
|
||||||
}
|
}
|
||||||
|
if (is_solved()) {
|
||||||
return FC_DONE;
|
return FC_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return FC_GIVEUP;
|
||||||
|
}
|
||||||
|
|
||||||
bool theory_seq::check_ineqs() {
|
bool theory_seq::check_ineqs() {
|
||||||
context & ctx = get_context();
|
context & ctx = get_context();
|
||||||
for (unsigned i = 0; i < m_ineqs.size(); ++i) {
|
for (unsigned i = 0; i < m_ineqs.size(); ++i) {
|
||||||
|
@ -201,6 +191,9 @@ bool theory_seq::check_ineqs() {
|
||||||
propagate_lit(eqs, ctx.get_literal(a));
|
propagate_lit(eqs, ctx.get_literal(a));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else if (!m.is_false(b)) {
|
||||||
|
TRACE("seq", tout << "equality is undetermined: " << mk_pp(a, m) << " " << b << "\n";);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -208,18 +201,15 @@ bool theory_seq::check_ineqs() {
|
||||||
bool theory_seq::branch_variable() {
|
bool theory_seq::branch_variable() {
|
||||||
context& ctx = get_context();
|
context& ctx = get_context();
|
||||||
TRACE("seq", ctx.display(tout););
|
TRACE("seq", ctx.display(tout););
|
||||||
expr_array& lhs = m_lhs.back();
|
unsigned sz = m_eqs.size();
|
||||||
expr_array& rhs = m_rhs.back();
|
|
||||||
unsigned sz = m.size(lhs);
|
|
||||||
ptr_vector<expr> ls, rs;
|
ptr_vector<expr> ls, rs;
|
||||||
for (unsigned i = 0; i < sz; ++i) {
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
unsigned k = (i + m_branch_variable_head) % sz;
|
unsigned k = (i + m_branch_variable_head) % sz;
|
||||||
expr* l = m.get(lhs, k);
|
eq e = m_eqs[k];
|
||||||
expr* r = m.get(rhs, k);
|
TRACE("seq", tout << e.m_lhs << " = " << e.m_rhs << "\n";);
|
||||||
TRACE("seq", tout << mk_pp(l, m) << " = " << mk_pp(r, m) << "\n";);
|
|
||||||
ls.reset(); rs.reset();
|
ls.reset(); rs.reset();
|
||||||
m_util.str.get_concat(l, ls);
|
m_util.str.get_concat(e.m_lhs, ls);
|
||||||
m_util.str.get_concat(r, rs);
|
m_util.str.get_concat(e.m_rhs, rs);
|
||||||
|
|
||||||
if (!ls.empty() && find_branch_candidate(ls[0], rs)) {
|
if (!ls.empty() && find_branch_candidate(ls[0], rs)) {
|
||||||
m_branch_variable_head = k;
|
m_branch_variable_head = k;
|
||||||
|
@ -290,13 +280,90 @@ bool theory_seq::split_variable() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool theory_seq::check_length_coherence() {
|
||||||
|
if (!m_has_length) return true;
|
||||||
|
return false;
|
||||||
|
context& ctx = get_context();
|
||||||
|
bool coherent = true;
|
||||||
|
for (unsigned i = 0; i < m_eqs.size(); ++i) {
|
||||||
|
m_eqs[i].m_dep;
|
||||||
|
expr_ref v1(m), v2(m), l(m_eqs[i].m_lhs), r(m_eqs[i].m_rhs);
|
||||||
|
expr_ref len1(m_util.str.mk_length(l), m);
|
||||||
|
expr_ref len2(m_util.str.mk_length(r), m);
|
||||||
|
if (!ctx.e_internalized(len1)) ctx.internalize(len1, false);
|
||||||
|
if (!ctx.e_internalized(len2)) ctx.internalize(len2, false);
|
||||||
|
enode* n1 = get_enode(len1);
|
||||||
|
enode* n2 = get_enode(len2);
|
||||||
|
if (n1->get_root() != n2->get_root()) {
|
||||||
|
propagate_eq(m_eqs[i].m_dep, n1, n2);
|
||||||
|
coherent = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// each variable that canonizes to itself can have length 0.
|
||||||
|
unsigned sz = get_num_vars();
|
||||||
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
|
enode* n = get_enode(i);
|
||||||
|
expr* e = n->get_owner();
|
||||||
|
if (!m_util.is_seq(e)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// extend length of variables.
|
||||||
|
enode_pair_dependency* dep = 0;
|
||||||
|
if (is_var(m_rep.find(e, dep))) {
|
||||||
|
expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m);
|
||||||
|
if (!assume_equality(e, emp)) {
|
||||||
|
// e = emp \/ e = head*tail & head = unit(v)
|
||||||
|
// add_axiom(mk_eq(e, emp, false), mk_eq(e, m_util.mk_concat(x, y), e));
|
||||||
|
// add_axiom(mk_eq(e, emp, false), mk_eq(x, unit_x));
|
||||||
|
}
|
||||||
|
coherent = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return coherent;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool theory_seq::check_ineq_coherence() {
|
||||||
|
bool all_false = true;
|
||||||
|
for (unsigned i = 0; all_false && i < m_ineqs.size(); ++i) {
|
||||||
|
expr* a = m_ineqs[i].get();
|
||||||
|
enode_pair_dependency* eqs = 0;
|
||||||
|
expr_ref b = canonize(a, eqs);
|
||||||
|
all_false = m.is_false(b);
|
||||||
|
if (all_false) {
|
||||||
|
TRACE("seq", tout << "equality is undetermined: " << mk_pp(a, m) << " " << b << "\n";);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return all_false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
- Eqs = 0
|
||||||
|
- Diseqs evaluate to false
|
||||||
|
- lengths are coherent.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool theory_seq::is_solved() {
|
||||||
|
if (!m_eqs.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!check_ineq_coherence()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SASSERT(check_length_coherence());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void theory_seq::propagate_lit(enode_pair_dependency* dep, literal lit) {
|
void theory_seq::propagate_lit(enode_pair_dependency* dep, literal lit) {
|
||||||
context& ctx = get_context();
|
context& ctx = get_context();
|
||||||
ctx.mark_as_relevant(lit);
|
ctx.mark_as_relevant(lit);
|
||||||
vector<enode_pair, false> _eqs;
|
vector<enode_pair, false> _eqs;
|
||||||
m_dm.linearize(dep, _eqs);
|
m_dm.linearize(dep, _eqs);
|
||||||
TRACE("seq", ctx.display_detailed_literal(tout, lit);
|
TRACE("seq", ctx.display_detailed_literal(tout, lit);
|
||||||
tout << " <-\n"; display_deps(tout, dep););
|
tout << " <- "; display_deps(tout, dep););
|
||||||
justification* js =
|
justification* js =
|
||||||
ctx.mk_justification(
|
ctx.mk_justification(
|
||||||
ext_theory_propagation_justification(
|
ext_theory_propagation_justification(
|
||||||
|
@ -321,7 +388,7 @@ void theory_seq::propagate_eq(enode_pair_dependency* dep, enode* n1, enode* n2)
|
||||||
vector<enode_pair, false> _eqs;
|
vector<enode_pair, false> _eqs;
|
||||||
m_dm.linearize(dep, _eqs);
|
m_dm.linearize(dep, _eqs);
|
||||||
TRACE("seq",
|
TRACE("seq",
|
||||||
tout << mk_pp(n1->get_owner(), m) << " " << mk_pp(n2->get_owner(), m) << " <- ";
|
tout << mk_pp(n1->get_owner(), m) << " = " << mk_pp(n2->get_owner(), m) << " <- ";
|
||||||
display_deps(tout, dep);
|
display_deps(tout, dep);
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -351,14 +418,12 @@ bool theory_seq::simplify_eq(expr* l, expr* r, enode_pair_dependency* deps) {
|
||||||
}
|
}
|
||||||
SASSERT(lhs.size() == rhs.size());
|
SASSERT(lhs.size() == rhs.size());
|
||||||
for (unsigned i = 0; i < lhs.size(); ++i) {
|
for (unsigned i = 0; i < lhs.size(); ++i) {
|
||||||
m.push_back(m_lhs.back(), lhs[i].get());
|
m_eqs.push_back(eq(expr_ref(lhs[i].get(), m), expr_ref(rhs[i].get(), m), deps));
|
||||||
m.push_back(m_rhs.back(), rhs[i].get());
|
|
||||||
m_dam.push_back(m_deps.back(), deps);
|
|
||||||
}
|
}
|
||||||
TRACE("seq",
|
TRACE("seq",
|
||||||
tout << mk_pp(l, m) << " = " << mk_pp(r, m) << " => ";
|
tout << mk_pp(l, m) << " = " << mk_pp(r, m) << " => ";
|
||||||
for (unsigned i = 0; i < lhs.size(); ++i) {
|
for (unsigned i = 0; i < m_eqs.size(); ++i) {
|
||||||
tout << mk_pp(lhs[i].get(), m) << " = " << mk_pp(rhs[i].get(), m) << "; ";
|
tout << m_eqs[i].m_lhs << " = " << m_eqs[i].m_rhs << "; ";
|
||||||
}
|
}
|
||||||
tout << "\n";
|
tout << "\n";
|
||||||
);
|
);
|
||||||
|
@ -428,7 +493,6 @@ bool theory_seq::is_right_select(expr* a, expr*& b) {
|
||||||
void theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) {
|
void theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) {
|
||||||
context& ctx = get_context();
|
context& ctx = get_context();
|
||||||
m_rep.update(l, r, deps);
|
m_rep.update(l, r, deps);
|
||||||
m_cache.reset();
|
|
||||||
// TBD: skip new equalities for non-internalized terms.
|
// TBD: skip new equalities for non-internalized terms.
|
||||||
if (ctx.e_internalized(l) && ctx.e_internalized(r)) {
|
if (ctx.e_internalized(l) && ctx.e_internalized(r)) {
|
||||||
propagate_eq(deps, ctx.get_enode(l), ctx.get_enode(r));
|
propagate_eq(deps, ctx.get_enode(l), ctx.get_enode(r));
|
||||||
|
@ -446,23 +510,19 @@ bool theory_seq::solve_basic_eqs() {
|
||||||
bool theory_seq::pre_process_eqs(bool simplify_or_solve) {
|
bool theory_seq::pre_process_eqs(bool simplify_or_solve) {
|
||||||
context& ctx = get_context();
|
context& ctx = get_context();
|
||||||
bool change = false;
|
bool change = false;
|
||||||
expr_array& lhs = m_lhs.back();
|
for (unsigned i = 0; !ctx.inconsistent() && i < m_eqs.size(); ++i) {
|
||||||
expr_array& rhs = m_rhs.back();
|
eq e = m_eqs[i];
|
||||||
enode_pair_dependency_array& deps = m_deps.back();
|
|
||||||
for (unsigned i = 0; !ctx.inconsistent() && i < m.size(lhs); ++i) {
|
|
||||||
if (simplify_or_solve?
|
if (simplify_or_solve?
|
||||||
simplify_eq(m.get(lhs, i), m.get(rhs, i), m_dam.get(deps, i)):
|
simplify_eq(e.m_lhs, e.m_rhs, e.m_dep):
|
||||||
solve_unit_eq(m.get(lhs, i), m.get(rhs, i), m_dam.get(deps, i))) {
|
solve_unit_eq(e.m_lhs, e.m_rhs, e.m_dep)) {
|
||||||
if (i + 1 != m.size(lhs)) {
|
if (i + 1 != m_eqs.size()) {
|
||||||
m.set(lhs, i, m.get(lhs, m.size(lhs)-1));
|
eq e1 = m_eqs[m_eqs.size()-1];
|
||||||
m.set(rhs, i, m.get(rhs, m.size(rhs)-1));
|
m_eqs.set(i, e1);
|
||||||
m_dam.set(deps, i, m_dam.get(deps, m_dam.size(deps)-1));
|
|
||||||
--i;
|
--i;
|
||||||
++m_stats.m_num_reductions;
|
++m_stats.m_num_reductions;
|
||||||
}
|
}
|
||||||
m.pop_back(lhs);
|
m_eqs.pop_back();
|
||||||
m.pop_back(rhs);
|
|
||||||
m_dam.pop_back(deps);
|
|
||||||
change = true;
|
change = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -525,11 +585,6 @@ bool theory_seq::internalize_term(app* term) {
|
||||||
!m_util.is_skolem(term)) {
|
!m_util.is_skolem(term)) {
|
||||||
set_incomplete(term);
|
set_incomplete(term);
|
||||||
}
|
}
|
||||||
expr* arg;
|
|
||||||
func_decl* fn;
|
|
||||||
if (m_util.str.is_length(term, arg) && !m_sort2len_fn.find(m.get_sort(arg), fn)) {
|
|
||||||
m_trail_stack.push(ast2ast_trail<theory_seq, sort, func_decl>(m_sort2len_fn, m.get_sort(arg), term->get_decl()));
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,14 +593,14 @@ void theory_seq::apply_sort_cnstr(enode* n, sort* s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void theory_seq::display(std::ostream & out) const {
|
void theory_seq::display(std::ostream & out) const {
|
||||||
if (m.size(m_lhs.back()) == 0 &&
|
if (m_eqs.size() == 0 &&
|
||||||
m_ineqs.empty() &&
|
m_ineqs.empty() &&
|
||||||
m_rep.empty() &&
|
m_rep.empty() &&
|
||||||
m_exclude.empty()) {
|
m_exclude.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
out << "Theory seq\n";
|
out << "Theory seq\n";
|
||||||
if (m.size(m_lhs.back()) > 0) {
|
if (m_eqs.size() > 0) {
|
||||||
out << "Equations:\n";
|
out << "Equations:\n";
|
||||||
display_equations(out);
|
display_equations(out);
|
||||||
}
|
}
|
||||||
|
@ -566,22 +621,20 @@ void theory_seq::display(std::ostream & out) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void theory_seq::display_equations(std::ostream& out) const {
|
void theory_seq::display_equations(std::ostream& out) const {
|
||||||
expr_array const& lhs = m_lhs.back();
|
for (unsigned i = 0; i < m_eqs.size(); ++i) {
|
||||||
expr_array const& rhs = m_rhs.back();
|
eq const& e = m_eqs[i];
|
||||||
enode_pair_dependency_array const& deps = m_deps.back();
|
out << e.m_lhs << " = " << e.m_rhs << " <- ";
|
||||||
for (unsigned i = 0; i < m.size(lhs); ++i) {
|
display_deps(out, e.m_dep);
|
||||||
out << mk_pp(m.get(lhs, i), m) << " = " << mk_pp(m.get(rhs, i), m) << " <-\n";
|
|
||||||
display_deps(out, m_dam.get(deps, i));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void theory_seq::display_deps(std::ostream& out, enode_pair_dependency* dep) const {
|
void theory_seq::display_deps(std::ostream& out, enode_pair_dependency* dep) const {
|
||||||
if (!dep) return;
|
|
||||||
vector<enode_pair, false> _eqs;
|
vector<enode_pair, false> _eqs;
|
||||||
const_cast<enode_pair_dependency_manager&>(m_dm).linearize(dep, _eqs);
|
const_cast<enode_pair_dependency_manager&>(m_dm).linearize(dep, _eqs);
|
||||||
for (unsigned i = 0; i < _eqs.size(); ++i) {
|
for (unsigned i = 0; i < _eqs.size(); ++i) {
|
||||||
out << " " << mk_pp(_eqs[i].first->get_owner(), m) << " = " << mk_pp(_eqs[i].second->get_owner(), m) << "\n";
|
out << " " << mk_pp(_eqs[i].first->get_owner(), m) << " = " << mk_pp(_eqs[i].second->get_owner(), m);
|
||||||
}
|
}
|
||||||
|
out << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void theory_seq::collect_statistics(::statistics & st) const {
|
void theory_seq::collect_statistics(::statistics & st) const {
|
||||||
|
@ -642,36 +695,38 @@ expr_ref theory_seq::canonize(expr* e, enode_pair_dependency*& eqs) {
|
||||||
|
|
||||||
expr_ref theory_seq::expand(expr* e, enode_pair_dependency*& eqs) {
|
expr_ref theory_seq::expand(expr* e, enode_pair_dependency*& eqs) {
|
||||||
enode_pair_dependency* deps = 0;
|
enode_pair_dependency* deps = 0;
|
||||||
|
expr_dep ed;
|
||||||
expr* r = 0;
|
expr* r = 0;
|
||||||
if (m_cache.find(e, r)) {
|
|
||||||
return expr_ref(r, m);
|
if (m_rep.find_cache(e, ed)) {
|
||||||
|
eqs = m_dm.mk_join(eqs, ed.second);
|
||||||
|
return expr_ref(ed.first, m);
|
||||||
}
|
}
|
||||||
e = m_rep.find(e, deps);
|
e = m_rep.find(e, deps);
|
||||||
expr_ref result(m);
|
expr_ref result(m);
|
||||||
expr* e1, *e2;
|
expr* e1, *e2;
|
||||||
eqs = m_dm.mk_join(eqs, deps);
|
|
||||||
if (m_util.str.is_concat(e, e1, e2)) {
|
if (m_util.str.is_concat(e, e1, e2)) {
|
||||||
result = m_util.str.mk_concat(expand(e1, eqs), expand(e2, eqs));
|
result = m_util.str.mk_concat(expand(e1, deps), expand(e2, deps));
|
||||||
}
|
}
|
||||||
else if (m_util.str.is_empty(e) || m_util.str.is_string(e)) {
|
else if (m_util.str.is_empty(e) || m_util.str.is_string(e)) {
|
||||||
result = e;
|
result = e;
|
||||||
}
|
}
|
||||||
else if (m.is_eq(e, e1, e2)) {
|
else if (m.is_eq(e, e1, e2)) {
|
||||||
result = m.mk_eq(expand(e1, eqs), expand(e2, eqs));
|
result = m.mk_eq(expand(e1, deps), expand(e2, deps));
|
||||||
}
|
}
|
||||||
else if (m_util.str.is_prefix(e, e1, e2)) {
|
else if (m_util.str.is_prefix(e, e1, e2)) {
|
||||||
result = m_util.str.mk_prefix(expand(e1, eqs), expand(e2, eqs));
|
result = m_util.str.mk_prefix(expand(e1, deps), expand(e2, deps));
|
||||||
}
|
}
|
||||||
else if (m_util.str.is_suffix(e, e1, e2)) {
|
else if (m_util.str.is_suffix(e, e1, e2)) {
|
||||||
result = m_util.str.mk_suffix(expand(e1, eqs), expand(e2, eqs));
|
result = m_util.str.mk_suffix(expand(e1, deps), expand(e2, deps));
|
||||||
}
|
}
|
||||||
else if (m_util.str.is_contains(e, e1, e2)) {
|
else if (m_util.str.is_contains(e, e1, e2)) {
|
||||||
result = m_util.str.mk_contains(expand(e1, eqs), expand(e2, eqs));
|
result = m_util.str.mk_contains(expand(e1, deps), expand(e2, deps));
|
||||||
}
|
}
|
||||||
else if (m_model_completion && is_var(e)) {
|
else if (m_model_completion && is_var(e)) {
|
||||||
SASSERT(m_factory);
|
SASSERT(m_factory);
|
||||||
expr_ref val(m);
|
expr_ref val(m);
|
||||||
val = m_factory->get_fresh_value(m.get_sort(e));
|
val = m_factory->get_some_value(m.get_sort(e));
|
||||||
if (val) {
|
if (val) {
|
||||||
m_rep.update(e, val, 0);
|
m_rep.update(e, val, 0);
|
||||||
result = val;
|
result = val;
|
||||||
|
@ -683,7 +738,8 @@ expr_ref theory_seq::expand(expr* e, enode_pair_dependency*& eqs) {
|
||||||
else {
|
else {
|
||||||
result = e;
|
result = e;
|
||||||
}
|
}
|
||||||
m_cache.insert(e, result);
|
m_rep.add_cache(e, expr_dep(result, deps));
|
||||||
|
eqs = m_dm.mk_join(eqs, deps);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1072,13 +1128,10 @@ void theory_seq::new_eq_eh(theory_var v1, theory_var v2) {
|
||||||
enode* n1 = get_enode(v1);
|
enode* n1 = get_enode(v1);
|
||||||
enode* n2 = get_enode(v2);
|
enode* n2 = get_enode(v2);
|
||||||
if (n1 != n2) {
|
if (n1 != n2) {
|
||||||
expr* o1 = n1->get_owner(), *o2 = n2->get_owner();
|
expr_ref o1(n1->get_owner(), m);
|
||||||
TRACE("seq", tout << mk_pp(o1, m) << " = " << mk_pp(o2, m) << "\n";);
|
expr_ref o2(n2->get_owner(), m);
|
||||||
m.push_back(m_lhs.back(), o1);
|
TRACE("seq", tout << o1 << " = " << o2 << "\n";);
|
||||||
m.push_back(m_rhs.back(), o2);
|
m_eqs.push_back(eq(o1, o2, m_dm.mk_leaf(enode_pair(n1, n2))));
|
||||||
m_dam.push_back(m_deps.back(), m_dm.mk_leaf(enode_pair(n1, n2)));
|
|
||||||
|
|
||||||
// add length-equal axiom?
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1091,54 +1144,27 @@ void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void theory_seq::push_scope_eh() {
|
void theory_seq::push_scope_eh() {
|
||||||
TRACE("seq", tout << "push " << m_lhs.size() << "\n";);
|
TRACE("seq", tout << "push " << m_eqs.size() << "\n";);
|
||||||
theory::push_scope_eh();
|
theory::push_scope_eh();
|
||||||
m_rep.push_scope();
|
m_rep.push_scope();
|
||||||
m_exclude.push_scope();
|
m_exclude.push_scope();
|
||||||
m_dm.push_scope();
|
m_dm.push_scope();
|
||||||
m_trail_stack.push_scope();
|
m_trail_stack.push_scope();
|
||||||
m_trail_stack.push(value_trail<theory_seq, unsigned>(m_axioms_head));
|
m_trail_stack.push(value_trail<theory_seq, unsigned>(m_axioms_head));
|
||||||
expr_array lhs, rhs;
|
m_eqs.push_scope();
|
||||||
enode_pair_dependency_array deps;
|
|
||||||
m.copy(m_lhs.back(), lhs);
|
|
||||||
m.copy(m_rhs.back(), rhs);
|
|
||||||
m_dam.copy(m_deps.back(), deps);
|
|
||||||
m_lhs.push_back(lhs);
|
|
||||||
m_rhs.push_back(rhs);
|
|
||||||
m_deps.push_back(deps);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void theory_seq::pop_scope_eh(unsigned num_scopes) {
|
void theory_seq::pop_scope_eh(unsigned num_scopes) {
|
||||||
TRACE("seq", tout << "pop " << m_lhs.size() << "\n";);
|
TRACE("seq", tout << "pop " << m_eqs.size() << "\n";);
|
||||||
m_trail_stack.pop_scope(num_scopes);
|
m_trail_stack.pop_scope(num_scopes);
|
||||||
theory::pop_scope_eh(num_scopes);
|
theory::pop_scope_eh(num_scopes);
|
||||||
m_dm.pop_scope(num_scopes);
|
m_dm.pop_scope(num_scopes);
|
||||||
m_rep.pop_scope(num_scopes);
|
m_rep.pop_scope(num_scopes);
|
||||||
m_exclude.pop_scope(num_scopes);
|
m_exclude.pop_scope(num_scopes);
|
||||||
while (num_scopes > 0) {
|
m_eqs.pop_scopes(num_scopes);
|
||||||
--num_scopes;
|
|
||||||
m.del(m_lhs.back());
|
|
||||||
m.del(m_rhs.back());
|
|
||||||
m_dam.del(m_deps.back());
|
|
||||||
m_lhs.pop_back();
|
|
||||||
m_rhs.pop_back();
|
|
||||||
m_deps.pop_back();
|
|
||||||
}
|
|
||||||
m_cache.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void theory_seq::restart_eh() {
|
void theory_seq::restart_eh() {
|
||||||
#if 0
|
|
||||||
m.del(m_lhs.back());
|
|
||||||
m.del(m_rhs.back());
|
|
||||||
m_dam.del(m_deps.back());
|
|
||||||
m_lhs.reset();
|
|
||||||
m_rhs.reset();
|
|
||||||
m_deps.reset();
|
|
||||||
m_lhs.push_back(expr_array());
|
|
||||||
m_rhs.push_back(expr_array());
|
|
||||||
m_deps.push_back(enode_pair_dependency_array());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void theory_seq::relevant_eh(app* n) {
|
void theory_seq::relevant_eh(app* n) {
|
||||||
|
|
|
@ -23,37 +23,38 @@ Revision History:
|
||||||
#include "seq_decl_plugin.h"
|
#include "seq_decl_plugin.h"
|
||||||
#include "theory_seq_empty.h"
|
#include "theory_seq_empty.h"
|
||||||
#include "th_rewriter.h"
|
#include "th_rewriter.h"
|
||||||
#include "union_find.h"
|
|
||||||
#include "ast_trail.h"
|
#include "ast_trail.h"
|
||||||
|
#include "scoped_vector.h"
|
||||||
|
|
||||||
namespace smt {
|
namespace smt {
|
||||||
|
|
||||||
class theory_seq : public theory {
|
class theory_seq : public theory {
|
||||||
struct config {
|
|
||||||
static const bool preserve_roots = true;
|
|
||||||
static const unsigned max_trail_sz = 16;
|
|
||||||
static const unsigned factor = 2;
|
|
||||||
typedef small_object_allocator allocator;
|
|
||||||
};
|
|
||||||
typedef scoped_dependency_manager<enode_pair> enode_pair_dependency_manager;
|
typedef scoped_dependency_manager<enode_pair> enode_pair_dependency_manager;
|
||||||
typedef enode_pair_dependency_manager::dependency enode_pair_dependency;
|
typedef enode_pair_dependency_manager::dependency enode_pair_dependency;
|
||||||
struct enode_pair_dependency_array_config : public config {
|
|
||||||
typedef enode_pair_dependency* value;
|
|
||||||
typedef dummy_value_manager<value> value_manager;
|
|
||||||
static const bool ref_count = false;
|
|
||||||
};
|
|
||||||
typedef parray_manager<enode_pair_dependency_array_config> enode_pair_dependency_array_manager;
|
|
||||||
typedef enode_pair_dependency_array_manager::ref enode_pair_dependency_array;
|
|
||||||
|
|
||||||
typedef union_find<theory_seq> th_union_find;
|
|
||||||
typedef trail_stack<theory_seq> th_trail_stack;
|
typedef trail_stack<theory_seq> th_trail_stack;
|
||||||
|
typedef std::pair<expr*, enode_pair_dependency*> expr_dep;
|
||||||
|
typedef obj_map<expr, expr_dep> eqdep_map_t;
|
||||||
|
|
||||||
|
// cache to track evaluations under equalities
|
||||||
|
class eval_cache {
|
||||||
|
eqdep_map_t m_map;
|
||||||
|
expr_ref_vector m_trail;
|
||||||
|
public:
|
||||||
|
eval_cache(ast_manager& m): m_trail(m) {}
|
||||||
|
bool find(expr* v, expr_dep& r) const { return m_map.find(v, r); }
|
||||||
|
void insert(expr* v, expr_dep& r) { m_trail.push_back(v); m_trail.push_back(r.first); m_map.insert(v, r); }
|
||||||
|
void reset() { m_map.reset(); m_trail.reset(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// map from variables to representatives
|
||||||
|
// + a cache for normalization.
|
||||||
class solution_map {
|
class solution_map {
|
||||||
enum map_update { INS, DEL };
|
enum map_update { INS, DEL };
|
||||||
typedef obj_map<expr, std::pair<expr*, enode_pair_dependency*> > map_t;
|
|
||||||
ast_manager& m;
|
ast_manager& m;
|
||||||
enode_pair_dependency_manager& m_dm;
|
enode_pair_dependency_manager& m_dm;
|
||||||
map_t m_map;
|
eqdep_map_t m_map;
|
||||||
|
eval_cache m_cache;
|
||||||
expr_ref_vector m_lhs, m_rhs;
|
expr_ref_vector m_lhs, m_rhs;
|
||||||
ptr_vector<enode_pair_dependency> m_deps;
|
ptr_vector<enode_pair_dependency> m_deps;
|
||||||
svector<map_update> m_updates;
|
svector<map_update> m_updates;
|
||||||
|
@ -61,15 +62,20 @@ namespace smt {
|
||||||
|
|
||||||
void add_trail(map_update op, expr* l, expr* r, enode_pair_dependency* d);
|
void add_trail(map_update op, expr* l, expr* r, enode_pair_dependency* d);
|
||||||
public:
|
public:
|
||||||
solution_map(ast_manager& m, enode_pair_dependency_manager& dm): m(m), m_dm(dm), m_lhs(m), m_rhs(m) {}
|
solution_map(ast_manager& m, enode_pair_dependency_manager& dm):
|
||||||
|
m(m), m_cache(m), m_dm(dm), m_lhs(m), m_rhs(m) {}
|
||||||
bool empty() const { return m_map.empty(); }
|
bool empty() const { return m_map.empty(); }
|
||||||
void update(expr* e, expr* r, enode_pair_dependency* d);
|
void update(expr* e, expr* r, enode_pair_dependency* d);
|
||||||
|
void add_cache(expr* v, expr_dep& r) { m_cache.insert(v, r); }
|
||||||
|
bool find_cache(expr* v, expr_dep& r) { return m_cache.find(v, r); }
|
||||||
expr* find(expr* e, enode_pair_dependency*& d);
|
expr* find(expr* e, enode_pair_dependency*& d);
|
||||||
|
void cache(expr* e, expr* r, enode_pair_dependency* d);
|
||||||
void push_scope() { m_limit.push_back(m_updates.size()); }
|
void push_scope() { m_limit.push_back(m_updates.size()); }
|
||||||
void pop_scope(unsigned num_scopes);
|
void pop_scope(unsigned num_scopes);
|
||||||
void display(std::ostream& out) const;
|
void display(std::ostream& out) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Table of current disequalities
|
||||||
class exclusion_table {
|
class exclusion_table {
|
||||||
typedef obj_pair_hashtable<expr, expr> table_t;
|
typedef obj_pair_hashtable<expr, expr> table_t;
|
||||||
ast_manager& m;
|
ast_manager& m;
|
||||||
|
@ -87,14 +93,15 @@ namespace smt {
|
||||||
void display(std::ostream& out) const;
|
void display(std::ostream& out) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class eval_cache {
|
// Asserted or derived equality with dependencies
|
||||||
obj_map<expr, expr*> m_map;
|
struct eq {
|
||||||
expr_ref_vector m_trail;
|
expr_ref m_lhs;
|
||||||
public:
|
expr_ref m_rhs;
|
||||||
eval_cache(ast_manager& m): m_trail(m) {}
|
enode_pair_dependency* m_dep;
|
||||||
bool find(expr* v, expr*& r) const { return m_map.find(v, r); }
|
eq(expr_ref& l, expr_ref& r, enode_pair_dependency* d):
|
||||||
void insert(expr* v, expr* r) { m_trail.push_back(v); m_trail.push_back(r); m_map.insert(v, r); }
|
m_lhs(l), m_rhs(r), m_dep(d) {}
|
||||||
void reset() { m_map.reset(); m_trail.reset(); }
|
eq(eq const& other): m_lhs(other.m_lhs), m_rhs(other.m_rhs), m_dep(other.m_dep) {}
|
||||||
|
eq& operator=(eq const& other) { m_lhs = other.m_lhs; m_rhs = other.m_rhs; m_dep = other.m_dep; return *this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct stats {
|
struct stats {
|
||||||
|
@ -104,16 +111,10 @@ namespace smt {
|
||||||
unsigned m_num_reductions;
|
unsigned m_num_reductions;
|
||||||
};
|
};
|
||||||
ast_manager& m;
|
ast_manager& m;
|
||||||
small_object_allocator m_alloc;
|
|
||||||
enode_pair_dependency_array_config::value_manager m_dep_array_value_manager;
|
|
||||||
enode_pair_dependency_manager m_dm;
|
enode_pair_dependency_manager m_dm;
|
||||||
enode_pair_dependency_array_manager m_dam;
|
|
||||||
solution_map m_rep; // unification representative.
|
solution_map m_rep; // unification representative.
|
||||||
vector<expr_array> m_lhs, m_rhs; // persistent sets of equalities.
|
scoped_vector<eq> m_eqs; // set of current equations.
|
||||||
vector<enode_pair_dependency_array> m_deps; // persistent sets of dependencies.
|
|
||||||
eval_cache m_cache;
|
|
||||||
|
|
||||||
ast2ast_trailmap<sort, func_decl> m_sort2len_fn; // length functions per sort.
|
|
||||||
seq_factory* m_factory; // value factory
|
seq_factory* m_factory; // value factory
|
||||||
expr_ref_vector m_ineqs; // inequalities to check solution against
|
expr_ref_vector m_ineqs; // inequalities to check solution against
|
||||||
exclusion_table m_exclude; // set of asserted disequalities.
|
exclusion_table m_exclude; // set of asserted disequalities.
|
||||||
|
@ -162,6 +163,9 @@ namespace smt {
|
||||||
bool simplify_and_solve_eqs(); // solve unitary equalities
|
bool simplify_and_solve_eqs(); // solve unitary equalities
|
||||||
bool branch_variable(); // branch on a variable
|
bool branch_variable(); // branch on a variable
|
||||||
bool split_variable(); // split a variable
|
bool split_variable(); // split a variable
|
||||||
|
bool is_solved();
|
||||||
|
bool check_length_coherence();
|
||||||
|
bool check_ineq_coherence();
|
||||||
|
|
||||||
bool pre_process_eqs(bool simplify_or_solve);
|
bool pre_process_eqs(bool simplify_or_solve);
|
||||||
bool simplify_eqs();
|
bool simplify_eqs();
|
||||||
|
|
|
@ -64,9 +64,14 @@ namespace smt {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual expr* get_some_value(sort* s) {
|
virtual expr* get_some_value(sort* s) {
|
||||||
if (u.is_string(s))
|
if (u.is_seq(s)) {
|
||||||
return u.str.mk_string(symbol(""));
|
return u.str.mk_empty(s);
|
||||||
NOT_IMPLEMENTED_YET();
|
}
|
||||||
|
sort* seq = 0;
|
||||||
|
if (u.is_re(s, seq)) {
|
||||||
|
return u.re.mk_to_re(u.str.mk_empty(seq));
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
virtual bool get_some_values(sort* s, expr_ref& v1, expr_ref& v2) {
|
virtual bool get_some_values(sort* s, expr_ref& v1, expr_ref& v2) {
|
||||||
|
|
128
src/util/scoped_vector.h
Normal file
128
src/util/scoped_vector.h
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2015 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
scoped_vector.h
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
Vector that restores during backtracking.
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
Nikolaj Bjorner (nbjorner) 2015-12-13
|
||||||
|
|
||||||
|
Revision History:
|
||||||
|
|
||||||
|
--*/
|
||||||
|
#ifndef SCOPED_VECTOR_H_
|
||||||
|
#define SCOPED_VECTOR_H_
|
||||||
|
|
||||||
|
#include"vector.h"
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class scoped_vector {
|
||||||
|
unsigned m_size;
|
||||||
|
unsigned m_elems_start;
|
||||||
|
unsigned_vector m_sizes;
|
||||||
|
vector<T> m_elems;
|
||||||
|
unsigned_vector m_elems_lim;
|
||||||
|
unsigned_vector m_index;
|
||||||
|
unsigned_vector m_src, m_dst;
|
||||||
|
unsigned_vector m_src_lim;
|
||||||
|
public:
|
||||||
|
scoped_vector(): m_size(0), m_elems_start(0) {}
|
||||||
|
|
||||||
|
// m_index : External-Index -> Internal-Index
|
||||||
|
// m_index.size() = max(m_sizes)
|
||||||
|
// m_src[i] -> m_dst[i] // trail into m_index updates
|
||||||
|
// m_src_lim last index to be updated.
|
||||||
|
|
||||||
|
void push_scope() {
|
||||||
|
m_elems_start = m_elems.size();
|
||||||
|
m_sizes.push_back(m_size);
|
||||||
|
m_src_lim.push_back(m_src.size());
|
||||||
|
m_elems_lim.push_back(m_elems_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_scopes(unsigned num_scopes) {
|
||||||
|
if (num_scopes == 0) return;
|
||||||
|
unsigned new_size = m_sizes.size() - num_scopes;
|
||||||
|
unsigned src_lim = m_src_lim[new_size];
|
||||||
|
|
||||||
|
for (unsigned i = m_src.size(); i > src_lim; ) {
|
||||||
|
--i;
|
||||||
|
m_index[m_src[i]] = m_dst[i];
|
||||||
|
}
|
||||||
|
m_src.shrink(src_lim);
|
||||||
|
m_dst.shrink(src_lim);
|
||||||
|
m_src_lim.shrink(new_size);
|
||||||
|
|
||||||
|
m_elems.shrink(m_elems_lim[new_size]);
|
||||||
|
m_elems_lim.resize(new_size);
|
||||||
|
m_elems_start = m_elems.size();
|
||||||
|
|
||||||
|
m_size = m_sizes[new_size];
|
||||||
|
m_sizes.shrink(new_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
T const& operator[](unsigned idx) const {
|
||||||
|
SASSERT(idx < m_size);
|
||||||
|
return m_elems[m_index[idx]];
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(unsigned idx, T const& t) {
|
||||||
|
SASSERT(idx < m_size);
|
||||||
|
unsigned n = m_index[idx];
|
||||||
|
if (n >= m_elems_start) {
|
||||||
|
m_elems[n] = t;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
set_index(idx, m_elems.size());
|
||||||
|
m_elems.push_back(t);
|
||||||
|
}
|
||||||
|
SASSERT(invariant());
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_back(T const& t) {
|
||||||
|
set_index(m_size, m_elems.size());
|
||||||
|
m_elems.push_back(t);
|
||||||
|
++m_size;
|
||||||
|
SASSERT(invariant());
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_back() {
|
||||||
|
SASSERT(m_size > 0);
|
||||||
|
if (m_size == m_elems.size() && m_size > m_elems_start) {
|
||||||
|
m_elems.pop_back();
|
||||||
|
}
|
||||||
|
--m_size;
|
||||||
|
SASSERT(invariant());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned size() const { return m_size; }
|
||||||
|
|
||||||
|
bool empty() const { return m_size == 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void set_index(unsigned src, unsigned dst) {
|
||||||
|
while (src >= m_index.size()) {
|
||||||
|
m_index.push_back(0);
|
||||||
|
}
|
||||||
|
SASSERT(src < m_index.size());
|
||||||
|
if (src < m_elems_start) {
|
||||||
|
m_src.push_back(src);
|
||||||
|
m_dst.push_back(m_index[src]);
|
||||||
|
}
|
||||||
|
m_index[src] = dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool invariant() const {
|
||||||
|
return
|
||||||
|
m_size <= m_elems.size() &&
|
||||||
|
m_elems_start <= m_elems.size();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue