3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-22 16:45:31 +00:00
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2017-01-30 09:39:23 -08:00
commit a412a554eb
21 changed files with 334 additions and 86 deletions

View file

@ -1816,6 +1816,7 @@ namespace z3 {
fmls,
fml));
}
param_descrs get_param_descrs() { return param_descrs(ctx(), Z3_solver_get_param_descrs(ctx(), m_solver)); }
};

View file

@ -2662,6 +2662,12 @@ class RatNumRef(ArithRef):
return self.denominator().as_long()
def is_int(self):
return False
def is_real(self):
return True
def is_int_value(self):
return self.denominator().is_int() and self.denominator_as_long() == 1
def as_long(self):

View file

@ -77,6 +77,7 @@ namespace sat {
m_burst_search = p.burst_search();
m_max_conflicts = p.max_conflicts();
m_num_parallel = p.parallel_threads();
// These parameters are not exposed
m_simplify_mult1 = _p.get_uint("simplify_mult1", 300);

View file

@ -57,6 +57,7 @@ namespace sat {
unsigned m_random_seed;
unsigned m_burst_search;
unsigned m_max_conflicts;
unsigned m_num_parallel;
unsigned m_simplify_mult1;
double m_simplify_mult2;

View file

@ -23,7 +23,7 @@ Notes:
namespace sat {
mus::mus(solver& s):s(s), m_is_active(false),m_restart(0), m_max_restarts(0) {}
mus::mus(solver& s):s(s), m_is_active(false), m_max_num_restarts(UINT_MAX) {}
mus::~mus() {}
@ -31,8 +31,6 @@ namespace sat {
m_core.reset();
m_mus.reset();
m_model.reset();
m_max_restarts = (s.m_stats.m_restart - m_restart) + 10;
m_restart = s.m_stats.m_restart;
}
void mus::set_core() {
@ -49,12 +47,12 @@ namespace sat {
}
lbool mus::operator()() {
m_max_num_restarts = s.m_config.m_core_minimize_partial ? s.num_restarts() + 10 : UINT_MAX;
flet<bool> _disable_min(s.m_config.m_core_minimize, false);
flet<bool> _is_active(m_is_active, true);
IF_VERBOSE(3, verbose_stream() << "(sat.mus " << s.get_core() << ")\n";);
IF_VERBOSE(3, verbose_stream() << "(sat.mus size: " << s.get_core().size() << " core: [" << s.get_core() << "])\n";);
reset();
lbool r = mus1();
m_restart = s.m_stats.m_restart;
return r;
}
@ -63,13 +61,13 @@ namespace sat {
TRACE("sat", tout << "old core: " << s.get_core() << "\n";);
literal_vector& core = get_core();
literal_vector& mus = m_mus;
if (core.size() > 64) {
if (!minimize_partial && core.size() > 64) {
return mus2();
}
unsigned delta_time = 0;
unsigned core_miss = 0;
while (!core.empty()) {
IF_VERBOSE(3, verbose_stream() << "(opt.mus reducing core: " << core.size() << " mus: " << mus.size() << ")\n";);
IF_VERBOSE(1, verbose_stream() << "(sat.mus num-to-process: " << core.size() << " mus: " << mus.size();
if (minimize_partial) verbose_stream() << " max-restarts: " << m_max_num_restarts;
verbose_stream() << ")\n";);
TRACE("sat",
tout << "core: " << core << "\n";
tout << "mus: " << mus << "\n";);
@ -78,34 +76,35 @@ namespace sat {
set_core();
return l_undef;
}
if (minimize_partial && 3*delta_time > core.size() && core.size() < mus.size()) {
break;
}
unsigned num_literals = core.size() + mus.size();
if (num_literals <= 2) {
// IF_VERBOSE(0, verbose_stream() << "num literals: " << core << " " << mus << "\n";);
break;
}
if (s.m_config.m_core_minimize_partial && s.m_stats.m_restart - m_restart > m_max_restarts) {
IF_VERBOSE(1, verbose_stream() << "(sat restart budget exceeded)\n";);
set_core();
return l_true;
}
literal lit = core.back();
core.pop_back();
lbool is_sat;
{
flet<unsigned> _restart_bound(s.m_config.m_restart_max, m_max_num_restarts);
scoped_append _sa(mus, core);
mus.push_back(~lit);
is_sat = s.check(mus.size(), mus.c_ptr());
TRACE("sat", tout << "mus: " << mus << "\n";);
}
IF_VERBOSE(1, verbose_stream() << "(sat.mus " << is_sat << ")\n";);
switch (is_sat) {
case l_undef:
core.push_back(lit);
set_core();
return l_undef;
if (!s.canceled()) {
// treat restart max as sat, so literal is in the mus
mus.push_back(lit);
}
else {
core.push_back(lit);
set_core();
return l_undef;
}
break;
case l_true: {
SASSERT(value_at(lit, s.get_model()) == l_false);
mus.push_back(lit);
@ -115,11 +114,9 @@ namespace sat {
case l_false:
literal_vector const& new_core = s.get_core();
if (new_core.contains(~lit)) {
IF_VERBOSE(3, verbose_stream() << "miss core " << lit << "\n";);
++core_miss;
IF_VERBOSE(3, verbose_stream() << "(sat.mus unit reduction, literal is in both cores " << lit << ")\n";);
}
else {
core_miss = 0;
TRACE("sat", tout << "core: " << new_core << " mus: " << mus << "\n";);
core.reset();
for (unsigned i = 0; i < new_core.size(); ++i) {
@ -131,14 +128,6 @@ namespace sat {
}
break;
}
unsigned new_num_literals = core.size() + mus.size();
if (new_num_literals == num_literals) {
delta_time++;
}
else {
delta_time = 0;
}
}
set_core();
IF_VERBOSE(3, verbose_stream() << "(sat.mus.new " << s.m_core << ")\n";);
@ -159,13 +148,9 @@ namespace sat {
lbool mus::qx(literal_set& assignment, literal_set& support, bool has_support) {
lbool is_sat = l_true;
if (s.m_config.m_core_minimize_partial && s.m_stats.m_restart - m_restart > m_max_restarts) {
IF_VERBOSE(1, verbose_stream() << "(sat restart budget exceeded)\n";);
return l_true;
}
if (has_support) {
scoped_append _sa(m_mus, support.to_vector());
is_sat = s.check(m_mus.size(), m_mus.c_ptr());
is_sat = s.check(m_mus.size(), m_mus.c_ptr());
switch (is_sat) {
case l_false: {
literal_set core(s.get_core());
@ -173,7 +158,7 @@ namespace sat {
assignment.reset();
return l_true;
}
case l_undef:
case l_undef:
return l_undef;
case l_true:
update_model();

View file

@ -26,8 +26,7 @@ namespace sat {
literal_vector m_mus;
bool m_is_active;
model m_model; // model obtained during minimal unsat core
unsigned m_restart;
unsigned m_max_restarts;
unsigned m_max_num_restarts;
public:

45
src/sat/sat_par.cpp Normal file
View file

@ -0,0 +1,45 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
sat_par.cpp
Abstract:
Utilities for parallel SAT solving.
Author:
Nikolaj Bjorner (nbjorner) 2017-1-29.
Revision History:
--*/
#include "sat_par.h"
namespace sat {
par::par() {}
void par::exchange(literal_vector const& in, unsigned& limit, literal_vector& out) {
#pragma omp critical (par_solver)
{
if (limit < m_units.size()) {
// this might repeat some literals.
out.append(m_units.size() - limit, m_units.c_ptr() + limit);
}
for (unsigned i = 0; i < in.size(); ++i) {
literal lit = in[i];
if (!m_unit_set.contains(lit.index())) {
m_unit_set.insert(lit.index());
m_units.push_back(lit);
}
}
limit = m_units.size();
}
}
};

39
src/sat/sat_par.h Normal file
View file

@ -0,0 +1,39 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
sat_par.h
Abstract:
Utilities for parallel SAT solving.
Author:
Nikolaj Bjorner (nbjorner) 2017-1-29.
Revision History:
--*/
#ifndef SAT_PAR_H_
#define SAT_PAR_H_
#include"sat_types.h"
#include"hashtable.h"
#include"map.h"
namespace sat {
class par {
typedef hashtable<unsigned, u_hash, u_eq> index_set;
literal_vector m_units;
index_set m_unit_set;
public:
par();
void exchange(literal_vector const& in, unsigned& limit, literal_vector& out);
};
};
#endif

View file

@ -22,4 +22,5 @@ def_module_params('sat',
('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'),
('core.minimize', BOOL, False, 'minimize computed core'),
('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'),
('parallel_threads', UINT, 1, 'number of parallel threads to use'),
('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks')))

View file

@ -896,7 +896,7 @@ namespace sat {
unsigned idx = l.index();
if (m_queue.contains(idx))
m_queue.decreased(idx);
else
else
m_queue.insert(idx);
}
literal next() { SASSERT(!empty()); return to_literal(m_queue.erase_min()); }
@ -918,16 +918,19 @@ namespace sat {
}
void insert(literal l) {
bool_var v = l.var();
if (s.is_external(v) || s.was_eliminated(v))
return;
m_queue.insert(l);
}
bool process_var(bool_var v) {
return !s.is_external(v) && !s.was_eliminated(v);
}
void operator()(unsigned num_vars) {
for (bool_var v = 0; v < num_vars; v++) {
insert(literal(v, false));
insert(literal(v, true));
if (process_var(v)) {
insert(literal(v, false));
insert(literal(v, true));
}
}
while (!m_queue.empty()) {
s.checkpoint();
@ -941,9 +944,9 @@ namespace sat {
void process(literal l) {
TRACE("blocked_clause", tout << "processing: " << l << "\n";);
model_converter::entry * new_entry = 0;
if (s.is_external(l.var()) || s.was_eliminated(l.var()))
if (!process_var(l.var())) {
return;
}
{
m_to_remove.reset();
{
@ -963,8 +966,10 @@ namespace sat {
mc.insert(*new_entry, c);
unsigned sz = c.size();
for (unsigned i = 0; i < sz; i++) {
if (c[i] != l)
m_queue.decreased(~c[i]);
literal lit = c[i];
if (lit != l && process_var(lit.var())) {
m_queue.decreased(~lit);
}
}
}
s.unmark_all(c);

View file

@ -35,6 +35,7 @@ namespace sat {
m_rlimit(l),
m_config(p),
m_ext(ext),
m_par(0),
m_cleaner(*this),
m_simplifier(*this, p),
m_scc(*this, p),
@ -72,6 +73,8 @@ namespace sat {
void solver::copy(solver const & src) {
SASSERT(m_mc.empty() && src.m_mc.empty());
SASSERT(scope_lvl() == 0);
SASSERT(src.scope_lvl() == 0);
// create new vars
if (num_vars() < src.num_vars()) {
for (bool_var v = num_vars(); v < src.num_vars(); v++) {
@ -81,19 +84,25 @@ namespace sat {
VERIFY(v == mk_var(ext, dvar));
}
}
unsigned sz = src.scope_lvl() == 0 ? src.m_trail.size() : src.m_scopes[0].m_trail_lim;
for (unsigned i = 0; i < sz; ++i) {
assign(src.m_trail[i], justification());
}
{
// copy binary clauses
vector<watch_list>::const_iterator it = src.m_watches.begin();
vector<watch_list>::const_iterator end = src.m_watches.begin();
for (unsigned l_idx = 0; it != end; ++it, ++l_idx) {
watch_list const & wlist = *it;
unsigned sz = src.m_watches.size();
for (unsigned l_idx = 0; l_idx < sz; ++l_idx) {
literal l = ~to_literal(l_idx);
watch_list::const_iterator it2 = wlist.begin();
watch_list::const_iterator end2 = wlist.end();
for (; it2 != end2; ++it2) {
if (!it2->is_binary_non_learned_clause())
watch_list const & wlist = src.m_watches[l_idx];
watch_list::const_iterator it = wlist.begin();
watch_list::const_iterator end = wlist.end();
for (; it != end; ++it) {
if (!it->is_binary_non_learned_clause())
continue;
literal l2 = it->get_literal();
if (l.index() > l2.index())
continue;
literal l2 = it2->get_literal();
mk_clause_core(l, l2);
}
}
@ -711,6 +720,9 @@ namespace sat {
pop_to_base_level();
IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";);
SASSERT(scope_lvl() == 0);
if (m_config.m_num_parallel > 0 && !m_par) {
return check_par(num_lits, lits);
}
#ifdef CLONE_BEFORE_SOLVING
if (m_mc.empty()) {
m_clone = alloc(solver, m_params, 0 /* do not clone extension */);
@ -759,6 +771,7 @@ namespace sat {
restart();
simplify_problem();
exchange_par();
if (check_inconsistent()) return l_false;
gc();
@ -774,6 +787,121 @@ namespace sat {
}
}
enum par_exception_kind {
DEFAULT_EX,
ERROR_EX
};
lbool solver::check_par(unsigned num_lits, literal const* lits) {
int num_threads = static_cast<int>(m_config.m_num_parallel);
scoped_limits scoped_rlimit(rlimit());
vector<reslimit> rlims(num_threads);
ptr_vector<sat::solver> solvers(num_threads);
sat::par par;
for (int i = 0; i < num_threads; ++i) {
m_params.set_uint("random_seed", i);
solvers[i] = alloc(sat::solver, m_params, rlims[i], 0);
solvers[i]->copy(*this);
solvers[i]->set_par(&par);
scoped_rlimit.push_child(&solvers[i]->rlimit());
}
int finished_id = -1;
std::string ex_msg;
par_exception_kind ex_kind;
unsigned error_code = 0;
lbool result = l_undef;
#pragma omp parallel for
for (int i = 0; i < num_threads; ++i) {
try {
lbool r = solvers[i]->check(num_lits, lits);
bool first = false;
#pragma omp critical (par_solver)
{
if (finished_id == UINT_MAX) {
finished_id = i;
first = true;
result = r;
}
}
if (first) {
if (r == l_true) {
set_model(solvers[i]->get_model());
}
else if (r == l_false) {
m_core.reset();
m_core.append(solvers[i]->get_core());
}
for (int j = 0; j < num_threads; ++j) {
if (i != j) {
rlims[j].cancel();
}
}
}
}
catch (z3_error & err) {
if (i == 0) {
error_code = err.error_code();
ex_kind = ERROR_EX;
}
}
catch (z3_exception & ex) {
if (i == 0) {
ex_msg = ex.msg();
ex_kind = DEFAULT_EX;
}
}
}
for (int i = 0; i < num_threads; ++i) {
dealloc(solvers[i]);
}
if (finished_id == -1) {
switch (ex_kind) {
case ERROR_EX: throw z3_error(error_code);
default: throw default_exception(ex_msg.c_str());
}
}
return result;
}
/*
\brief import lemmas/units from parallel sat solvers.
*/
void solver::exchange_par() {
if (m_par && scope_lvl() == 0) {
unsigned num_in = 0, num_out = 0;
SASSERT(scope_lvl() == 0); // parallel with assumptions is TBD
literal_vector in, out;
for (unsigned i = m_par_limit_out; i < m_trail.size(); ++i) {
literal lit = m_trail[i];
if (lit.var() < m_par_num_vars) {
++num_out;
out.push_back(lit);
}
}
m_par_limit_out = m_trail.size();
m_par->exchange(out, m_par_limit_in, in);
for (unsigned i = 0; !inconsistent() && i < in.size(); ++i) {
literal lit = in[i];
SASSERT(lit.var() < m_par_num_vars);
if (lvl(lit.var()) != 0 || value(lit) != l_true) {
++num_in;
assign(lit, justification());
}
}
if (num_in > 0 || num_out > 0) {
IF_VERBOSE(1, verbose_stream() << "(sat-sync out: " << num_out << " in: " << num_in << ")\n";);
}
}
}
void solver::set_par(par* p) {
m_par = p;
m_par_num_vars = num_vars();
m_par_limit_in = 0;
m_par_limit_out = 0;
}
bool_var solver::next_var() {
bool_var next;

View file

@ -33,6 +33,7 @@ Revision History:
#include"sat_iff3_finder.h"
#include"sat_probing.h"
#include"sat_mus.h"
#include"sat_par.h"
#include"params.h"
#include"statistics.h"
#include"stopwatch.h"
@ -74,6 +75,7 @@ namespace sat {
config m_config;
stats m_stats;
extension * m_ext;
par* m_par;
random_gen m_rand;
clause_allocator m_cls_allocator;
cleaner m_cleaner;
@ -128,6 +130,10 @@ namespace sat {
literal_set m_assumption_set; // set of enabled assumptions
literal_vector m_core; // unsat core
unsigned m_par_limit_in;
unsigned m_par_limit_out;
unsigned m_par_num_vars;
void del_clauses(clause * const * begin, clause * const * end);
friend class integrity_checker;
@ -209,6 +215,7 @@ namespace sat {
bool inconsistent() const { return m_inconsistent; }
unsigned num_vars() const { return m_level.size(); }
unsigned num_clauses() const;
unsigned num_restarts() const { return m_restarts; }
bool is_external(bool_var v) const { return m_external[v] != 0; }
bool was_eliminated(bool_var v) const { return m_eliminated[v] != 0; }
unsigned scope_lvl() const { return m_scope_lvl; }
@ -240,7 +247,9 @@ namespace sat {
m_num_checkpoints = 0;
if (memory::get_allocation_size() > m_config.m_max_memory) throw solver_exception(Z3_MAX_MEMORY_MSG);
}
void set_par(par* p);
bool canceled() { return !m_rlimit.inc(); }
config const& get_config() { return m_config; }
typedef std::pair<literal, literal> bin_clause;
protected:
watch_list & get_wlist(literal l) { return m_watches[l.index()]; }
@ -316,6 +325,8 @@ namespace sat {
bool check_model(model const & m) const;
void restart();
void sort_watch_lits();
void exchange_par();
lbool check_par(unsigned num_lits, literal const* lits);
// -----------------------
//

View file

@ -140,6 +140,7 @@ public:
if (r != l_true) return r;
r = m_solver.check(m_asms.size(), m_asms.c_ptr());
switch (r) {
case l_true:
if (sz > 0) {
@ -276,6 +277,8 @@ public:
return r;
}
virtual lbool find_mutexes(expr_ref_vector const& vars, vector<expr_ref_vector>& mutexes) {
sat::literal_vector ls;
u_map<expr*> lit2var;

View file

@ -63,5 +63,6 @@ def_module_params(module_name='smt',
('dack.threshold', UINT, 10, ' number of times the congruence rule must be used before Leibniz\'s axiom is expanded'),
('core.validate', BOOL, False, 'validate unsat core produced by SMT context'),
('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context'),
('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances')
('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances'),
('core.extend_patterns.max_distance', UINT, UINT_MAX, 'limits the distance of a pattern-extended unsat core')
))

View file

@ -2040,11 +2040,13 @@ namespace smt {
v.shrink(old_size);
}
#if 0
void context::mark_as_deleted(clause * cls) {
SASSERT(!cls->deleted());
remove_cls_occs(cls);
cls->mark_as_deleted(m_manager);
}
#endif
/**
\brief Undo variable assignments.

View file

@ -37,6 +37,7 @@ namespace smt {
symbol m_logic;
bool m_minimizing_core;
bool m_core_extend_patterns;
unsigned m_core_extend_patterns_max_distance;
obj_map<expr, expr*> m_name2assertion;
public:
@ -46,12 +47,14 @@ namespace smt {
m_params(p),
m_context(m, m_smt_params),
m_minimizing_core(false),
m_core_extend_patterns(false) {
m_core_extend_patterns(false),
m_core_extend_patterns_max_distance(UINT_MAX) {
m_logic = l;
if (m_logic != symbol::null)
m_context.set_logic(m_logic);
smt_params_helper smth(p);
m_core_extend_patterns = smth.core_extend_patterns();
m_core_extend_patterns_max_distance = smth.core_extend_patterns_max_distance();
}
virtual solver * translate(ast_manager & m, params_ref const & p) {
@ -119,7 +122,8 @@ namespace smt {
SASSERT(n <= lvl);
unsigned new_lvl = lvl - n;
unsigned old_sz = m_scopes[new_lvl];
for (unsigned i = cur_sz - 1; i >= old_sz; i--) {
for (unsigned i = cur_sz; i > old_sz; ) {
--i;
expr * key = m_assumptions[i].get();
SASSERT(m_name2assertion.contains(key));
expr * value = m_name2assertion.find(key);
@ -283,7 +287,7 @@ namespace smt {
func_decl_set pattern_fds;
vector<func_decl_set> assrtn_fds;
do {
for (unsigned d = 0; d < m_core_extend_patterns_max_distance; d++) {
new_core_literals.reset();
unsigned sz = core.size();
@ -308,8 +312,10 @@ namespace smt {
}
core.append(new_core_literals.size(), new_core_literals.c_ptr());
if (new_core_literals.empty())
break;
}
while (!new_core_literals.empty());
}
};
};

View file

@ -2940,8 +2940,8 @@ void theory_seq::deque_axiom(expr* n) {
encode that s is not contained in of xs1
where s1 is all of s, except the last element.
lit or s = "" or s = s1*(unit c)
lit or s = "" or !contains(x*s1, s)
s = "" or s = s1*(unit c)
s = "" or !contains(x*s1, s)
*/
void theory_seq::tightest_prefix(expr* s, expr* x) {
expr_ref s1 = mk_first(s);
@ -2958,22 +2958,19 @@ void theory_seq::tightest_prefix(expr* s, expr* x) {
let i = Index(t, s, offset):
offset >= len(t) => i = -1
offset fixed to 0:
len(t) != 0 & !contains(t, s) => i = -1
len(t) != 0 & contains(t, s) => t = xsy & i = len(x)
offset = 0 & len(t) != 0 & contains(t, s) => t = xsy & i = len(x)
tightest_prefix(x, s)
offset not fixed:
0 <= offset < len(t) => xy = t &
len(x) = offset &
(-1 = indexof(y, s, 0) => -1 = i) &
(indexof(y, s, 0) >= 0 => indexof(t, s, 0) + offset = i)
if offset < 0
under specified
offset < 0 => i = -1
optional lemmas:
(len(s) > len(t) -> i = -1)
@ -2987,17 +2984,19 @@ void theory_seq::add_indexof_axiom(expr* i) {
expr_ref minus_one(m_autil.mk_int(-1), m);
expr_ref zero(m_autil.mk_int(0), m);
expr_ref xsy(m);
literal cnt = mk_literal(m_util.str.mk_contains(t, s));
literal i_eq_m1 = mk_eq(i, minus_one, false);
add_axiom(cnt, i_eq_m1);
literal s_eq_empty = mk_eq_empty(s);
add_axiom(~s_eq_empty, mk_eq(i, zero, false));
add_axiom(s_eq_empty, ~mk_eq_empty(t), i_eq_m1);
if (!offset || (m_autil.is_numeral(offset, r) && r.is_zero())) {
expr_ref x = mk_skolem(m_indexof_left, t, s);
expr_ref y = mk_skolem(m_indexof_right, t, s);
xsy = mk_concat(x, s, y);
expr_ref lenx(m_util.str.mk_length(x), m);
literal cnt = mk_literal(m_util.str.mk_contains(t, s));
literal s_eq_empty = mk_eq_empty(s);
add_axiom(cnt, mk_eq(i, minus_one, false));
add_axiom(~s_eq_empty, mk_eq(i, zero, false));
add_axiom(s_eq_empty, ~mk_eq_empty(t), mk_eq(i, minus_one, false));
add_axiom(~cnt, s_eq_empty, mk_seq_eq(t, xsy));
add_axiom(~cnt, s_eq_empty, mk_eq(i, lenx, false));
tightest_prefix(s, x);
@ -3024,10 +3023,13 @@ void theory_seq::add_indexof_axiom(expr* i) {
add_axiom(~offset_ge_0, offset_ge_len, mk_seq_eq(t, mk_concat(x, y)));
add_axiom(~offset_ge_0, offset_ge_len, mk_eq(m_util.str.mk_length(x), offset, false));
add_axiom(~offset_ge_0, offset_ge_len,
~mk_eq(indexof0, minus_one, false), mk_eq(i, minus_one, false));
~mk_eq(indexof0, minus_one, false), i_eq_m1);
add_axiom(~offset_ge_0, offset_ge_len,
~mk_literal(m_autil.mk_ge(indexof0, zero)),
mk_eq(offset_p_indexof0, i, false));
// offset < 0 => -1 = i
add_axiom(offset_ge_0, i_eq_m1);
}
}
@ -3817,6 +3819,15 @@ void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) {
solve_eqs(m_eqs.size()-1);
enforce_length_coherence(n1, n2);
}
else if (n1 != n2 && m_util.is_re(n1->get_owner())) {
warning_msg("equality between regular expressions is not yet supported");
eautomaton* a1 = get_automaton(n1->get_owner());
eautomaton* a2 = get_automaton(n2->get_owner());
// eautomaton* b1 = mk_difference(*a1, *a2);
// eautomaton* b2 = mk_difference(*a2, *a1);
// eautomaton* c = mk_union(*b1, *b2);
// then some emptiness check.
}
}
void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) {

View file

@ -461,13 +461,6 @@ enum par_exception_kind {
class par_tactical : public or_else_tactical {
struct scoped_limits {
reslimit& m_limit;
unsigned m_sz;
scoped_limits(reslimit& lim): m_limit(lim), m_sz(0) {}
~scoped_limits() { for (unsigned i = 0; i < m_sz; ++i) m_limit.pop_child(); }
void push_child(reslimit* lim) { m_limit.push_child(lim); ++m_sz; }
};
public:
par_tactical(unsigned num, tactic * const * ts):or_else_tactical(num, ts) {}

View file

@ -61,4 +61,13 @@ public:
};
struct scoped_limits {
reslimit& m_limit;
unsigned m_sz;
scoped_limits(reslimit& lim): m_limit(lim), m_sz(0) {}
~scoped_limits() { for (unsigned i = 0; i < m_sz; ++i) m_limit.pop_child(); }
void push_child(reslimit* lim) { m_limit.push_child(lim); ++m_sz; }
};
#endif