3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-24 01:25:31 +00:00

running updates to bv_solver (#4674)

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* dbg

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* bv

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* drat and fresh

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* move ackerman functionality

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* debugability

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* towards debugability

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* missing file

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* na

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* remove csp

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-09-07 20:35:32 -07:00 committed by GitHub
parent 4d1a2a2784
commit d02b0cde7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
63 changed files with 3060 additions and 3095 deletions

View file

@ -14,7 +14,6 @@ z3_add_component(ast
ast_translation.cpp
ast_util.cpp
bv_decl_plugin.cpp
csp_decl_plugin.cpp
datatype_decl_plugin.cpp
decl_collector.cpp
display_dimacs.cpp

View file

@ -1342,6 +1342,17 @@ std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p) {
return out;
}
std::ostream& operator<<(std::ostream& out, mk_ismt2_func const& p) {
smt2_pp_environment_dbg env(p.m);
format_ref r(fm(p.m));
unsigned len = 0;
r = env.pp_fdecl(p.m_fn, len);
params_ref pa;
pp(out, r.get(), p.m, pa);
return out;
}
std::ostream& operator<<(std::ostream& out, expr_ref const& e) {
return out << mk_ismt2_pp(e.get(), e.get_manager());
}
@ -1388,6 +1399,8 @@ std::ostream& operator<<(std::ostream& out, sort_ref_vector const& e) {
return out;
}
#ifdef Z3DEBUG
void pp(expr const * n, ast_manager & m) {
std::cout << mk_ismt2_pp(const_cast<expr*>(n), m) << std::endl;

View file

@ -122,6 +122,7 @@ struct mk_ismt2_pp {
mk_ismt2_pp(ast * t, ast_manager & m, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = nullptr);
};
std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p);
std::ostream& operator<<(std::ostream& out, expr_ref const& e);
@ -136,3 +137,10 @@ std::ostream& operator<<(std::ostream& out, var_ref_vector const& e);
std::ostream& operator<<(std::ostream& out, func_decl_ref_vector const& e);
std::ostream& operator<<(std::ostream& out, sort_ref_vector const& e);
struct mk_ismt2_func {
func_decl* m_fn;
ast_manager &m;
mk_ismt2_func(func_decl* f, ast_manager& m): m_fn(f), m(m) {}
};
std::ostream& operator<<(std::ostream& out, mk_ismt2_func const& f);

View file

@ -131,12 +131,8 @@ void bv_decl_plugin::finalize() {
DEC_REF(m_int2bv);
DEC_REF(m_bv2int);
vector<ptr_vector<func_decl> >::iterator it = m_bit2bool.begin();
vector<ptr_vector<func_decl> >::iterator end = m_bit2bool.end();
for (; it != end; ++it) {
ptr_vector<func_decl> & ds = *it;
for (auto& ds : m_bit2bool)
DEC_REF(ds);
}
DEC_REF(m_mkbv);
}
@ -829,6 +825,14 @@ bool bv_recognizers::is_bv2int(expr const* e, expr*& r) const {
return true;
}
bool bv_recognizers::is_bit2bool(expr* e, expr*& bv, unsigned& idx) const {
if (!is_bit2bool(e))
return false;
bv = to_app(e)->get_arg(0);
idx = to_app(e)->get_parameter(0).get_int();
return true;
}
bool bv_recognizers::mult_inverse(rational const & n, unsigned bv_size, rational & result) {
if (n.is_one()) {
result = n;

View file

@ -368,6 +368,9 @@ public:
MATCH_BINARY(is_bv_sdivi);
MATCH_BINARY(is_bv_udivi);
MATCH_BINARY(is_bv_smodi);
MATCH_UNARY(is_bit2bool);
MATCH_UNARY(is_int2bv);
bool is_bit2bool(expr* e, expr*& bv, unsigned& idx) const;
rational norm(rational const & val, unsigned bv_size, bool is_signed) const ;
rational norm(rational const & val, unsigned bv_size) const { return norm(val, bv_size, false); }
@ -432,6 +435,7 @@ public:
app * mk_bvsmul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_NO_OVFL, n, m); }
app * mk_bvsmul_no_udfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_NO_UDFL, n, m); }
app * mk_bvumul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUMUL_NO_OVFL, n, m); }
app * mk_bit2bool(expr* e, unsigned idx) { parameter p(idx); return m_manager.mk_app(get_fid(), OP_BIT2BOOL, 1, &p, 1, &e); }
private:
void log_bv_from_exprs(app * r, unsigned n, expr* const* es) {

View file

@ -1,386 +0,0 @@
/*++
Copyright (c) 2018 Microsoft Corporation
Module Name:
csp_decl_plugin.h
Abstract:
Declarations used for a job-shop scheduling domain.
Author:
Nikolaj Bjorner (nbjorner) 2018-8-9
Revision History:
--*/
#include "ast/csp_decl_plugin.h"
#include "ast/arith_decl_plugin.h"
void csp_decl_plugin::set_manager(ast_manager* m, family_id fid) {
decl_plugin::set_manager(m, fid);
m_int_sort = nullptr;
m_alist_sort = nullptr;
m_job_sort = nullptr;
m_resource_sort = nullptr;
}
void csp_decl_plugin::init() {
if (!m_int_sort) {
m_int_sort = m_manager->mk_sort(m_manager->mk_family_id("arith"), INT_SORT);
m_alist_sort = m_manager->mk_sort(symbol("AList"), sort_info(m_family_id, ALIST_SORT));
m_job_sort = m_manager->mk_sort(symbol("Job"), sort_info(m_family_id, JOB_SORT));
m_resource_sort = m_manager->mk_sort(symbol("Resource"), sort_info(m_family_id, RESOURCE_SORT));
m_manager->inc_ref(m_int_sort);
m_manager->inc_ref(m_resource_sort);
m_manager->inc_ref(m_job_sort);
m_manager->inc_ref(m_alist_sort);
}
}
void csp_decl_plugin::finalize() {
m_manager->dec_ref(m_alist_sort);
m_manager->dec_ref(m_job_sort);
m_manager->dec_ref(m_resource_sort);
m_manager->dec_ref(m_int_sort);
}
sort * csp_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
init();
if (num_parameters != 0) {
m_manager->raise_exception("no parameters expected with job-shop sort");
}
switch (static_cast<js_sort_kind>(k)) {
case JOB_SORT: return m_job_sort;
case RESOURCE_SORT: return m_resource_sort;
case ALIST_SORT: return m_alist_sort;
default: UNREACHABLE(); return nullptr;
}
}
func_decl * csp_decl_plugin::mk_func_decl(
decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort *) {
init();
symbol name;
sort* rng = nullptr;
switch (static_cast<js_op_kind>(k)) {
case OP_JS_JOB:
check_arity(arity);
check_index1(num_parameters, parameters);
name = symbol("job");
rng = m_job_sort;
break;
case OP_JS_RESOURCE:
check_arity(arity);
check_index1(num_parameters, parameters);
name = symbol("resource");
rng = m_resource_sort;
break;
case OP_JS_RESOURCE_MAKESPAN:
if (arity != 1 || domain[0] != m_resource_sort) m_manager->raise_exception("makespan expects a resource argument");
name = symbol("makespan");
rng = m_int_sort;
break;
case OP_JS_START:
if (arity != 1 || domain[0] != m_job_sort) m_manager->raise_exception("start expects a job argument");
if (num_parameters > 0) m_manager->raise_exception("no parameters");
name = symbol("job-start");
rng = m_int_sort;
break;
case OP_JS_END:
if (arity != 1 || domain[0] != m_job_sort) m_manager->raise_exception("resource expects a job argument");
if (num_parameters > 0) m_manager->raise_exception("no parameters");
name = symbol("job-end");
rng = m_int_sort;
break;
case OP_JS_JOB2RESOURCE:
if (arity != 1 || domain[0] != m_job_sort) m_manager->raise_exception("job2resource expects a job argument");
if (num_parameters > 0) m_manager->raise_exception("no parameters");
name = symbol("job2resource");
rng = m_resource_sort;
break;
case OP_JS_MODEL:
// has no parameters
// all arguments are of sort alist
name = symbol("js-model");
rng = m_manager->mk_bool_sort();
break;
case OP_JS_JOB_RESOURCE:
if (arity != 6) m_manager->raise_exception("add-job-resource expects 6 arguments");
if (domain[0] != m_job_sort) m_manager->raise_exception("first argument of add-job-resource expects should be a job");
if (domain[1] != m_resource_sort) m_manager->raise_exception("second argument of add-job-resource expects should be a resource");
if (domain[2] != m_int_sort) m_manager->raise_exception("3rd argument of add-job-resource expects should be an integer");
if (domain[3] != m_int_sort) m_manager->raise_exception("4th argument of add-job-resource expects should be an integer");
if (domain[4] != m_int_sort) m_manager->raise_exception("5th argument of add-job-resource expects should be an integer");
if (domain[5] != m_alist_sort) m_manager->raise_exception("6th argument of add-job-resource should be a list of properties");
name = symbol("add-job-resource");
rng = m_alist_sort;
break;
case OP_JS_RESOURCE_AVAILABLE:
if (arity != 6) m_manager->raise_exception("add-resource-available expects 6 arguments");
if (domain[0] != m_resource_sort) m_manager->raise_exception("first argument of add-resource-available expects should be a resource");
if (domain[1] != m_int_sort) m_manager->raise_exception("2nd argument of add-resource-available expects should be an integer");
if (domain[2] != m_int_sort) m_manager->raise_exception("3rd argument of add-resource-available expects should be an integer");
if (domain[3] != m_int_sort) m_manager->raise_exception("4th argument of add-resource-available expects should be an integer");
if (domain[4] != m_int_sort) m_manager->raise_exception("5th argument of add-resource-available expects should be an integer");
if (domain[5] != m_alist_sort) m_manager->raise_exception("6th argument of add-resource-available should be a list of properties");
name = symbol("add-resource-available");
rng = m_alist_sort;
break;
case OP_JS_JOB_PREEMPTABLE:
if (arity != 1 || domain[0] != m_job_sort)
m_manager->raise_exception("set-preemptable expects one argument, which is a job");
name = symbol("set-preemptable");
rng = m_alist_sort;
break;
case OP_JS_PROPERTIES:
if (arity != 0) m_manager->raise_exception("js-properties takes no arguments");
for (unsigned i = 0; i < num_parameters; ++i) {
if (!parameters[i].is_symbol()) m_manager->raise_exception("js-properties expects a list of keyword parameters");
}
name = symbol("js-properties");
rng = m_alist_sort;
break;
case OP_JS_JOB_GOAL:
if (arity != 1 || domain[0] != m_job_sort)
m_manager->raise_exception("add-job-goal expects one argument, which is a job");
if (num_parameters != 2 || !parameters[0].is_symbol() || !parameters[1].is_int())
m_manager->raise_exception("add-job-goal expects one symbol and one integer parameter");
name = symbol("add-job-goal");
rng = m_alist_sort;
break;
case OP_JS_OBJECTIVE:
if (arity != 0)
m_manager->raise_exception("add-optimization-objective expects no arguments");
if (num_parameters != 1 || !parameters[0].is_symbol())
m_manager->raise_exception("add-optimization-objective expects one symbol parameter");
name = symbol("add-optimization-objective");
rng = m_alist_sort;
break;
default:
UNREACHABLE();
return nullptr;
}
return m_manager->mk_func_decl(name, arity, domain, rng, func_decl_info(m_family_id, k, num_parameters, parameters));
}
void csp_decl_plugin::check_arity(unsigned arity) {
if (arity > 0)
m_manager->raise_exception("csp variables use parameters only and take no arguments");
}
void csp_decl_plugin::check_index1(unsigned num_parameters, parameter const* ps) {
if (num_parameters != 1 || !ps[0].is_int())
m_manager->raise_exception("csp variable expects a single integer parameter");
}
void csp_decl_plugin::check_index2(unsigned num_parameters, parameter const* ps) {
if (num_parameters != 2 || !ps[0].is_int() || !ps[1].is_int())
m_manager->raise_exception("csp variable expects two integer parameters");
}
bool csp_decl_plugin::is_value(app * e) const {
return is_app_of(e, m_family_id, OP_JS_JOB) || is_app_of(e, m_family_id, OP_JS_RESOURCE);
}
void csp_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
if (logic == symbol("CSP")) {
op_names.push_back(builtin_name("job", OP_JS_JOB));
op_names.push_back(builtin_name("resource", OP_JS_RESOURCE));
op_names.push_back(builtin_name("makespan", OP_JS_RESOURCE_MAKESPAN));
op_names.push_back(builtin_name("job-start", OP_JS_START));
op_names.push_back(builtin_name("job-end", OP_JS_END));
op_names.push_back(builtin_name("job2resource", OP_JS_JOB2RESOURCE));
op_names.push_back(builtin_name("js-model", OP_JS_MODEL));
op_names.push_back(builtin_name("add-job-resource", OP_JS_JOB_RESOURCE));
op_names.push_back(builtin_name("add-resource-available", OP_JS_RESOURCE_AVAILABLE));
op_names.push_back(builtin_name("set-preemptable", OP_JS_JOB_PREEMPTABLE));
op_names.push_back(builtin_name("js-properties", OP_JS_PROPERTIES));
op_names.push_back(builtin_name("add-job-goal", OP_JS_JOB_GOAL));
op_names.push_back(builtin_name("add-optimization-objective", OP_JS_OBJECTIVE));
}
}
void csp_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) {
if (logic == symbol("CSP")) {
sort_names.push_back(builtin_name("Job", JOB_SORT));
sort_names.push_back(builtin_name("Resource", RESOURCE_SORT));
}
}
expr * csp_decl_plugin::get_some_value(sort * s) {
init();
parameter p(0);
if (is_sort_of(s, m_family_id, JOB_SORT))
return m_manager->mk_const(mk_func_decl(OP_JS_JOB, 1, &p, 0, nullptr, nullptr));
if (is_sort_of(s, m_family_id, RESOURCE_SORT))
return m_manager->mk_const(mk_func_decl(OP_JS_RESOURCE, 1, &p, 0, nullptr, nullptr));
UNREACHABLE();
return nullptr;
}
csp_util::csp_util(ast_manager& m): m(m) {
m_fid = m.mk_family_id("csp");
m_plugin = static_cast<csp_decl_plugin*>(m.get_plugin(m_fid));
}
sort* csp_util::mk_job_sort() {
return m_plugin->mk_job_sort();
}
sort* csp_util::mk_resource_sort() {
return m_plugin->mk_resource_sort();
}
app* csp_util::mk_job(unsigned j) {
parameter p(j);
return m.mk_const(m.mk_func_decl(m_fid, OP_JS_JOB, 1, &p, 0, (sort*const*)nullptr, nullptr));
}
unsigned csp_util::job2id(expr* j) {
if (is_app_of(j, m_fid, OP_JS_JOB)) {
return to_app(j)->get_decl()->get_parameter(0).get_int();
}
SASSERT(is_app_of(j, m_fid, OP_JS_START) ||
is_app_of(j, m_fid, OP_JS_END) ||
is_app_of(j, m_fid, OP_JS_JOB2RESOURCE));
return job2id(to_app(j)->get_arg(0));
}
app* csp_util::mk_resource(unsigned r) {
parameter p(r);
return m.mk_const(m.mk_func_decl(m_fid, OP_JS_RESOURCE, 1, &p, 0, (sort*const*)nullptr, nullptr));
}
unsigned csp_util::resource2id(expr* r) {
SASSERT(is_app_of(r, m_fid, OP_JS_RESOURCE));
return to_app(r)->get_decl()->get_parameter(0).get_int();
}
app* csp_util::mk_start(unsigned j) {
app_ref job(mk_job(j), m);
sort* js = m.get_sort(job);
return m.mk_app(m.mk_func_decl(m_fid, OP_JS_START, 0, nullptr, 1, &js, nullptr), job);
}
app* csp_util::mk_end(unsigned j) {
app_ref job(mk_job(j), m);
sort* js = m.get_sort(job);
return m.mk_app(m.mk_func_decl(m_fid, OP_JS_END, 0, nullptr, 1, &js, nullptr), job);
}
app* csp_util::mk_job2resource(unsigned j) {
app_ref job(mk_job(j), m);
sort* js = m.get_sort(job);
return m.mk_app(m.mk_func_decl(m_fid, OP_JS_JOB2RESOURCE, 0, nullptr, 1, &js, nullptr), job);
}
app* csp_util::mk_makespan(unsigned r) {
app_ref resource(mk_resource(r), m);
sort* rs = m.get_sort(resource);
return m.mk_app(m.mk_func_decl(m_fid, OP_JS_RESOURCE_MAKESPAN, 0, nullptr, 1, &rs, nullptr), resource);
}
bool csp_util::is_resource(expr* e, unsigned& r) {
return is_app_of(e, m_fid, OP_JS_RESOURCE) && (r = resource2id(e), true);
}
bool csp_util::is_makespan(expr * e, unsigned& r) {
return is_app_of(e, m_fid, OP_JS_RESOURCE_MAKESPAN) && is_resource(to_app(e)->get_arg(0), r);
}
bool csp_util::is_job(expr* e, unsigned& j) {
return is_app_of(e, m_fid, OP_JS_JOB) && (j = job2id(e), true);
}
bool csp_util::is_job2resource(expr* e, unsigned& j) {
return is_app_of(e, m_fid, OP_JS_JOB2RESOURCE) && (j = job2id(e), true);
}
bool csp_util::is_add_resource_available(expr * e, expr *& res, unsigned& loadpct, unsigned& cap_time, uint64_t& start, uint64_t& end, svector<symbol>& properties) {
if (!is_app_of(e, m_fid, OP_JS_RESOURCE_AVAILABLE)) return false;
res = to_app(e)->get_arg(0);
arith_util a(m);
rational r;
if (!a.is_numeral(to_app(e)->get_arg(1), r) || !r.is_unsigned()) return false;
loadpct = r.get_unsigned();
if (!a.is_numeral(to_app(e)->get_arg(2), r) || !r.is_unsigned()) return false;
cap_time = r.get_unsigned();
if (!a.is_numeral(to_app(e)->get_arg(3), r) || !r.is_uint64()) return false;
start = r.get_uint64();
if (!a.is_numeral(to_app(e)->get_arg(4), r) || !r.is_uint64()) return false;
end = r.get_uint64();
if (!is_js_properties(to_app(e)->get_arg(5), properties)) return false;
return true;
}
bool csp_util::is_add_job_resource(expr * e, expr *& job, expr*& res, unsigned& loadpct, uint64_t& capacity, uint64_t& end, svector<symbol>& properties) {
if (!is_app_of(e, m_fid, OP_JS_JOB_RESOURCE)) return false;
job = to_app(e)->get_arg(0);
res = to_app(e)->get_arg(1);
arith_util a(m);
rational r;
if (!a.is_numeral(to_app(e)->get_arg(2), r) || !r.is_unsigned()) return false;
loadpct = r.get_unsigned();
if (!a.is_numeral(to_app(e)->get_arg(3), r) || !r.is_uint64()) return false;
capacity = r.get_uint64();
if (!a.is_numeral(to_app(e)->get_arg(4), r) || !r.is_uint64()) return false;
end = r.get_uint64();
if (!is_js_properties(to_app(e)->get_arg(5), properties)) return false;
return true;
}
bool csp_util::is_set_preemptable(expr* e, expr *& job) {
if (!is_app_of(e, m_fid, OP_JS_JOB_PREEMPTABLE)) return false;
job = to_app(e)->get_arg(0);
return true;
}
bool csp_util::is_js_properties(expr* e, svector<symbol>& properties) {
if (!is_app_of(e, m_fid, OP_JS_PROPERTIES))
return false;
unsigned sz = to_app(e)->get_decl()->get_num_parameters();
for (unsigned i = 0; i < sz; ++i) {
properties.push_back(to_app(e)->get_decl()->get_parameter(i).get_symbol());
}
return true;
}
bool csp_util::is_job_goal(expr* e, js_job_goal& goal, unsigned& level, expr*& job) {
if (!is_app_of(e, m_fid, OP_JS_JOB_GOAL))
return false;
SASSERT(2 == to_app(e)->get_decl()->get_num_parameters());
SASSERT(1 == to_app(e)->get_num_args());
symbol g = to_app(e)->get_decl()->get_parameter(0).get_symbol();
level = to_app(e)->get_decl()->get_parameter(1).get_int();
if (g == ":earliest-end-time" || g == "earliest-end-time")
goal = JS_JOB_GOAL_EARLIEST_END_TIME;
else if (g == ":latest-start-time" || g == "latest-start-time")
goal = JS_JOB_GOAL_LATEST_START_TIME;
else
return false;
job = to_app(e)->get_arg(0);
return true;
}
bool csp_util::is_objective(expr* e, js_optimization_objective& objective) {
if (!is_app_of(e, m_fid, OP_JS_OBJECTIVE))
return false;
SASSERT(1 == to_app(e)->get_decl()->get_num_parameters());
symbol obj = to_app(e)->get_decl()->get_parameter(0).get_symbol();
if (obj == ":duration" || obj == "duration")
objective = JS_OBJECTIVE_DURATION;
else if (obj == ":priority" || obj == "priority")
objective = JS_OBJECTIVE_PRIORITY;
else
return false;
return true;
}

View file

@ -1,163 +0,0 @@
/*++
Copyright (c) 2018 Microsoft Corporation
Module Name:
csp_decl_plugin.h
Abstract:
Declarations used for a job-shop scheduling domain.
The job-shop domain comprises of constants job(j), resource(r)
It finds values to variables:
- start(j), end(j), job2resource(j)
It assumes a background of:
- resources : Job -> Resource -> Int * LoadPct - time to run job j on resource r assuming LoadPct
- runtime : Job -> Int - time to run job j if not associated with any resource
- capacity : Resource -> Int -> LoadPct - capacity of resource r at time t, given as sequence of time intervals
// assume each job has at least one resource associated with it.
// introduce a dummy resource if needed.
// Theory:
end(j) - start(j) = time-to-execute(j)
time-to-execute(j) := time-to-execute(j, resource(j)) otherwise
time-to-execute(j, r) := (T - start(j))
where capacity(j,r) = sum_{t = start(j)}^{T} load(loadpct(j,r), r, t)
capacity(j, r) := cap where (cap, loadpct) = resources j r
loadpct(j, r) := loadpct where (cap, loadpct) = resources j r
load(loadpct, r, t) := min(capacity r t, loadpct) / loadpct
capacity(r, t) >= sum_{j | job-on-resource(j, r, t) } min(capacity r t, loadpct(j, r))
// Macros:
job-on-resource(j, r) := r = resource(j);
job-on-resource(j, r, t) := (job-on-resource(j, r) & start(j) <= t <= end(j));
start_min(j, t) := start(j) >= t;
end_max(j, t) := end(j) <= t;
job_link(j1, j2, startstart, hard) := start(j1) = start(j2);
job_link(j1, j2, startstart, soft) := start(j1) <= start(j2);
job_link(j1, j2, endend, hard) := end(j1) = end(j2);
job_link(j1, j2, endend, soft) := end(j2) <= end(j1);
job_link(j1, j2, endstart, hard) := end(j1) = start(j2);
job_link(j1, j2, endstart, soft) := end(j2) <= start(j1);
job_link(j1, j2, startend, hard) := end(j2) = start(j1);
job_link(j1, j2, startend, soft) := end(j1) <= start(j2);
job_delay(j1, j2, t) := end(j1) + t <= end(j2);
job_on_same_resource(j1, j2) := resource(j1) = resource(j2);
job_not_on_same_resource(j1, j2) := resource(j1) != resource(j2);
job_time_intersect(j1, j2) := start(j1) <= end(j2) <= end(j1) || start(j2) <= end(j1) <= end(j2);
job-on-resource(j, r, t) => job-property(j) = null or job_property(j) in working_time_property(r, t);
Author:
Nikolaj Bjorner (nbjorner) 2018-8-9
Revision History:
--*/
#pragma once
#include "ast/ast.h"
enum js_sort_kind {
JOB_SORT,
RESOURCE_SORT,
ALIST_SORT
};
enum js_op_kind {
OP_JS_JOB, // value of type job
OP_JS_RESOURCE, // value of type resource
OP_JS_RESOURCE_MAKESPAN, // makespan of resource: the minimal resource time required for assigned jobs.
OP_JS_START, // start time of a job
OP_JS_END, // end time of a job
OP_JS_JOB2RESOURCE, // resource associated with job
OP_JS_MODEL, // jobscheduler model
OP_JS_JOB_RESOURCE, // model declaration for job assignment to resource
OP_JS_JOB_PREEMPTABLE, // model declaration for whether job is pre-emptable
OP_JS_RESOURCE_AVAILABLE, // model declaration for availability intervals of resource
OP_JS_PROPERTIES, // model declaration of a set of properties. Each property is a keyword.
OP_JS_JOB_GOAL, // job goal objective :earliest-end-time or :latest-start-time
OP_JS_OBJECTIVE // duration or completion-time
};
enum js_job_goal {
JS_JOB_GOAL_EARLIEST_END_TIME,
JS_JOB_GOAL_LATEST_START_TIME
};
enum js_optimization_objective {
JS_OBJECTIVE_DURATION,
JS_OBJECTIVE_PRIORITY
};
class csp_decl_plugin : public decl_plugin {
void init();
public:
csp_decl_plugin() {}
~csp_decl_plugin() override {}
void finalize() override;
void set_manager(ast_manager* m, family_id fid) override;
decl_plugin * mk_fresh() override { return alloc(csp_decl_plugin); }
sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override;
func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) override;
bool is_value(app * e) const override;
bool is_unique_value(app * e) const override { return is_value(e); }
void get_op_names(svector<builtin_name> & op_names, symbol const & logic) override;
void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) override;
expr * get_some_value(sort * s) override;
sort * mk_job_sort() const { return m_job_sort; }
sort * mk_resource_sort() const { return m_resource_sort; }
sort * mk_alist_sort() const { return m_alist_sort; }
private:
sort* m_job_sort;
sort* m_resource_sort;
sort* m_alist_sort;
sort* m_int_sort;
void check_arity(unsigned arity);
void check_index1(unsigned n, parameter const* ps);
void check_index2(unsigned n, parameter const* ps);
};
class csp_util {
ast_manager& m;
family_id m_fid;
csp_decl_plugin* m_plugin;
public:
csp_util(ast_manager& m);
sort* mk_job_sort();
sort* mk_resource_sort();
app* mk_job(unsigned j);
app* mk_resource(unsigned r);
app* mk_start(unsigned j);
app* mk_end(unsigned j);
app* mk_job2resource(unsigned j);
app* mk_makespan(unsigned r);
bool is_job(expr* e, unsigned& j);
bool is_job2resource(expr* e, unsigned& j);
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& 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);
bool is_job_goal(expr* e, js_job_goal& goal, unsigned& level, expr*& job);
bool is_objective(expr* e, js_optimization_objective& objective);
private:
unsigned job2id(expr* j);
unsigned resource2id(expr* r);
};

View file

@ -17,52 +17,11 @@ Author:
#include "ast/euf/euf_egraph.h"
#include "ast/ast_pp.h"
#include "ast/ast_ll_pp.h"
#include "ast/ast_translation.h"
namespace euf {
/**
\brief Trail for add_th_var
*/
class add_th_var_trail : public trail<egraph> {
enode * m_enode;
theory_id m_th_id;
public:
add_th_var_trail(enode * n, theory_id th_id):
m_enode(n),
m_th_id(th_id) {
}
void undo(egraph & ctx) override {
theory_var v = m_enode->get_th_var(m_th_id);
SASSERT(v != null_theory_var);
m_enode->del_th_var(m_th_id);
enode * root = m_enode->get_root();
if (root != m_enode && root->get_th_var(m_th_id) == v)
root->del_th_var(m_th_id);
}
};
/**
\brief Trail for replace_th_var
*/
class replace_th_var_trail : public trail<egraph> {
enode * m_enode;
unsigned m_th_id:8;
unsigned m_old_th_var:24;
public:
replace_th_var_trail(enode * n, theory_id th_id, theory_var old_var):
m_enode(n),
m_th_id(th_id),
m_old_th_var(old_var) {
}
void undo(egraph & ctx) override {
SASSERT(m_enode->get_th_var(m_th_id) != null_theory_var);
m_enode->replace_th_var(m_old_th_var, m_th_id);
}
};
void egraph::undo_eq(enode* r1, enode* n1, unsigned r2_num_parents) {
enode* r2 = r1->get_root();
r2->dec_class_size(r1->class_size());
@ -82,6 +41,9 @@ namespace euf {
enode* n = enode::mk(m_region, f, num_args, args);
m_nodes.push_back(n);
m_exprs.push_back(f);
push_node(n);
for (unsigned i = 0; i < num_args; ++i)
set_merge_enabled(args[i], true);
return n;
}
@ -104,8 +66,7 @@ namespace euf {
void egraph::reinsert_equality(enode* p) {
SASSERT(is_equality(p));
if (p->get_arg(0)->get_root() == p->get_arg(1)->get_root()) {
m_new_lits.push_back(enode_bool_pair(p, true));
++m_stats.m_num_eqs;
add_literal(p, true);
}
}
@ -114,19 +75,14 @@ namespace euf {
}
void egraph::force_push() {
if (m_num_scopes == 0)
return;
for (; m_num_scopes > 0; --m_num_scopes) {
scope s;
s.m_inconsistent = m_inconsistent;
s.m_num_eqs = m_eqs.size();
s.m_num_nodes = m_nodes.size();
s.m_trail_sz = m_trail.size();
s.m_new_lits_sz = m_new_lits.size();
s.m_new_th_eqs_sz = m_new_th_eqs.size();
s.m_new_lits_qhead = m_new_lits_qhead;
s.m_new_th_eqs_qhead = m_new_th_eqs_qhead;
m_scopes.push_back(s);
m_scopes.push_back(m_updates.size());
m_region.push_scope();
}
m_updates.push_back(update_record(m_new_lits_qhead, update_record::new_lits_qhead()));
m_updates.push_back(update_record(m_new_th_eqs_qhead, update_record::new_th_eq_qhead()));
}
void egraph::update_children(enode* n) {
@ -147,6 +103,7 @@ namespace euf {
return n;
if (is_equality(n)) {
update_children(n);
reinsert_equality(n);
return n;
}
enode_bool_pair p = m_table.insert(n);
@ -170,6 +127,18 @@ namespace euf {
n->m_parents.finalize();
}
void egraph::add_th_eq(theory_id id, theory_var v1, theory_var v2, enode* c, enode* r) {
m_new_th_eqs.push_back(th_eq(id, v1, v2, c, r));
m_updates.push_back(update_record(update_record::new_th_eq()));
++m_stats.m_num_th_eqs;
}
void egraph::add_literal(enode* n, bool is_eq) {
m_new_lits.push_back(enode_bool_pair(n, is_eq));
m_updates.push_back(update_record(update_record::new_lit()));
if (is_eq) ++m_stats.m_num_eqs; else ++m_stats.m_num_lits;
}
void egraph::add_th_var(enode* n, theory_var v, theory_id id) {
force_push();
theory_var w = n->get_th_var(id);
@ -177,21 +146,37 @@ namespace euf {
if (w == null_theory_var) {
n->add_th_var(v, id, m_region);
m_trail.push_back(new (m_region) add_th_var_trail(n, id));
m_updates.push_back(update_record(n, id, update_record::add_th_var()));
if (r != n) {
theory_var u = r->get_th_var(id);
if (u == null_theory_var)
r->add_th_var(v, id, m_region);
else
m_new_th_eqs.push_back(th_eq(id, v, u, n, r));
add_th_eq(id, v, u, n, r);
}
}
else {
theory_var u = r->get_th_var(id);
SASSERT(u != v && u != null_theory_var);
n->replace_th_var(v, id);
m_trail.push_back(new (m_region) replace_th_var_trail(n, id, u));
m_new_th_eqs.push_back(th_eq(id, v, u, n, r));
m_updates.push_back(update_record(n, id, u, update_record::replace_th_var()));
add_th_eq(id, v, u, n, r);
}
}
void egraph::undo_add_th_var(enode* n, theory_id tid) {
theory_var v = n->get_th_var(tid);
SASSERT(v != null_theory_var);
n->del_th_var(tid);
enode* root = n->get_root();
if (root != n && root->get_th_var(tid) == v)
root->del_th_var(tid);
}
void egraph::set_merge_enabled(enode* n, bool enable_merge) {
if (enable_merge != n->merge_enabled()) {
m_updates.push_back(update_record(n, update_record::toggle_merge()));
n->set_merge_enabled(enable_merge);
}
}
@ -202,29 +187,59 @@ namespace euf {
}
num_scopes -= m_num_scopes;
unsigned old_lim = m_scopes.size() - num_scopes;
scope s = m_scopes[old_lim];
for (unsigned i = m_eqs.size(); i-- > s.m_num_eqs; ) {
auto const& p = m_eqs[i];
undo_eq(p.r1, p.n1, p.r2_num_parents);
}
for (unsigned i = m_nodes.size(); i-- > s.m_num_nodes; ) {
enode* n = m_nodes[i];
unsigned num_updates = m_scopes[old_lim];
auto undo_node = [&](enode* n) {
if (n->num_args() > 1)
m_table.erase(n);
m_expr2enode[n->get_owner_id()] = nullptr;
n->~enode();
}
undo_trail_stack<egraph>(*this, m_trail, s.m_trail_sz);
m_inconsistent = s.m_inconsistent;
m_new_lits_qhead = s.m_new_lits_qhead;
m_new_th_eqs_qhead = s.m_new_th_eqs_qhead;
m_eqs.shrink(s.m_num_eqs);
m_nodes.shrink(s.m_num_nodes);
m_exprs.shrink(s.m_num_nodes);
m_new_lits.shrink(s.m_new_lits_sz);
m_new_th_eqs.shrink(s.m_new_th_eqs_sz);
m_nodes.pop_back();
m_exprs.pop_back();
};
for (unsigned i = m_updates.size(); i-- > num_updates; ) {
auto const& p = m_updates[i];
switch (p.tag) {
case update_record::tag_t::is_add_node:
undo_node(p.r1);
break;
case update_record::tag_t::is_toggle_merge:
p.r1->set_merge_enabled(!p.r1->merge_enabled());
break;
case update_record::tag_t::is_set_parent:
undo_eq(p.r1, p.n1, p.r2_num_parents);
break;
case update_record::tag_t::is_add_th_var:
undo_add_th_var(p.r1, p.r2_num_parents);
break;
case update_record::tag_t::is_replace_th_var:
SASSERT(p.r1->get_th_var(p.m_th_id) != null_theory_var);
p.r1->replace_th_var(p.m_old_th_var, p.m_th_id);
break;
case update_record::tag_t::is_new_lit:
m_new_lits.pop_back();
break;
case update_record::tag_t::is_new_th_eq:
m_new_th_eqs.pop_back();
break;
case update_record::tag_t::is_new_th_eq_qhead:
m_new_th_eqs_qhead = p.qhead;
break;
case update_record::tag_t::is_new_lits_qhead:
m_new_lits_qhead = p.qhead;
break;
case update_record::tag_t::is_inconsistent:
m_inconsistent = p.m_inconsistent;
break;
default:
UNREACHABLE();
break;
}
}
m_updates.shrink(num_updates);
m_scopes.shrink(old_lim);
m_region.pop_scope(num_scopes);
m_worklist.reset();
}
void egraph::merge(enode* n1, enode* n2, justification j) {
@ -245,8 +260,7 @@ namespace euf {
std::swap(n1, n2);
}
if ((m.is_true(r2->get_owner()) || m.is_false(r2->get_owner())) && j.is_congruence()) {
m_new_lits.push_back(enode_bool_pair(n1, false));
++m_stats.m_num_lits;
add_literal(n1, false);
}
for (enode* p : enode_parents(n1))
m_table.erase(p);
@ -268,13 +282,13 @@ namespace euf {
for (auto iv : enode_th_vars(n)) {
theory_id id = iv.get_id();
theory_var v = root->get_th_var(id);
if (v == null_theory_var) {
root->add_th_var(iv.get_var(), id, m_region);
m_trail.push_back(new (m_region) add_th_var_trail(root, id));
if (v == null_theory_var) {
root->add_th_var(iv.get_var(), id, m_region);
m_updates.push_back(update_record(root, id, update_record::add_th_var()));
}
else {
SASSERT(v != iv.get_var());
m_new_th_eqs.push_back(th_eq(id, v, iv.get_var(), n, root));
add_th_eq(id, v, iv.get_var(), n, root);
}
}
}
@ -308,6 +322,7 @@ namespace euf {
if (m_inconsistent)
return;
m_inconsistent = true;
m_updates.push_back(update_record(false, update_record::inconsistent()));
m_n1 = n1;
m_n2 = n2;
m_justification = j;
@ -387,10 +402,19 @@ namespace euf {
}
}
void egraph::begin_explain() {
SASSERT(m_todo.empty());
}
void egraph::end_explain() {
for (enode* n : m_todo)
n->unmark1();
m_todo.reset();
}
template <typename T>
void egraph::explain(ptr_vector<T>& justifications) {
SASSERT(m_inconsistent);
SASSERT(m_todo.empty());
push_todo(m_n1);
push_todo(m_n2);
explain_eq(justifications, m_n1, m_n2, m_justification);
@ -399,7 +423,6 @@ namespace euf {
template <typename T>
void egraph::explain_eq(ptr_vector<T>& justifications, enode* a, enode* b) {
SASSERT(m_todo.empty());
SASSERT(a->get_root() == b->get_root());
enode* lca = find_lca(a, b);
push_to_lca(a, lca);
@ -418,9 +441,6 @@ namespace euf {
explain_eq(justifications, n, n->m_target, n->m_justification);
}
}
for (enode* n : m_todo)
n->unmark1();
m_todo.reset();
}
void egraph::invariant() {
@ -429,25 +449,29 @@ namespace euf {
}
std::ostream& egraph::display(std::ostream& out, unsigned max_args, enode* n) const {
out << std::setw(5)
<< n->get_owner_id() << " := ";
out << n->get_owner_id() << " := ";
if (!n->is_root())
out << "[" << n->get_root()->get_owner_id() << "] ";
expr* f = n->get_owner();
if (is_app(f))
out << to_app(f)->get_decl()->get_name() << " ";
out << mk_bounded_pp(f, m, 1);
else if (is_quantifier(f))
out << "q ";
out << "q:" << f->get_id();
else
out << "v ";
for (enode* arg : enode_args(n))
out << arg->get_owner_id() << " ";
for (unsigned i = n->num_args(); i < max_args; ++i)
out << " ";
out << "\t";
for (enode* p : enode_parents(n))
out << p->get_owner_id() << " ";
out << "v:" << f->get_id();
out << "\n";
if (!n->m_parents.empty()) {
out << " ";
for (enode* p : enode_parents(n))
out << p->get_owner_id() << " ";
out << "\n";
}
if (n->has_th_vars()) {
out << " ";
for (auto v : enode_th_vars(n))
out << v.get_id() << ":" << v.get_var() << " ";
out << "\n";
}
return out;
}
@ -464,8 +488,9 @@ namespace euf {
void egraph::collect_statistics(statistics& st) const {
st.update("euf merge", m_stats.m_num_merge);
st.update("euf conflicts", m_stats.m_num_conflicts);
st.update("euf eq prop", m_stats.m_num_eqs);
st.update("euf lit prop", m_stats.m_num_lits);
st.update("euf equality propagations", m_stats.m_num_eqs);
st.update("euf theory equality propagations", m_stats.m_num_th_eqs);
st.update("euf literal propagations", m_stats.m_num_lits);
}
void egraph::copy_from(egraph const& src, std::function<void*(void*)>& copy_justification) {
@ -504,7 +529,7 @@ template void euf::egraph::explain(ptr_vector<int>& justifications);
template void euf::egraph::explain_todo(ptr_vector<int>& justifications);
template void euf::egraph::explain_eq(ptr_vector<int>& justifications, enode* a, enode* b);
template void euf::egraph::explain(ptr_vector<unsigned>& justifications);
template void euf::egraph::explain_todo(ptr_vector<unsigned>& justifications);
template void euf::egraph::explain_eq(ptr_vector<unsigned>& justifications, enode* a, enode* b);
template void euf::egraph::explain(ptr_vector<size_t>& justifications);
template void euf::egraph::explain_todo(ptr_vector<size_t>& justifications);
template void euf::egraph::explain_eq(ptr_vector<size_t>& justifications, enode* a, enode* b);

View file

@ -31,14 +31,6 @@ Notes:
namespace euf {
struct add_eq_record {
enode* r1;
enode* n1;
unsigned r2_num_parents;
add_eq_record(enode* r1, enode* n1, unsigned r2_num_parents):
r1(r1), n1(n1), r2_num_parents(r2_num_parents) {}
};
/***
\brief store derived theory equalities.
Theory 'id' is notified with the equality of theory variables v1, v2
@ -58,31 +50,66 @@ namespace euf {
class egraph {
typedef ptr_vector<trail<egraph> > trail_stack;
struct scope {
bool m_inconsistent;
unsigned m_num_eqs;
unsigned m_num_nodes;
unsigned m_trail_sz;
unsigned m_new_lits_sz;
unsigned m_new_th_eqs_sz;
unsigned m_new_lits_qhead;
unsigned m_new_th_eqs_qhead;
};
struct stats {
unsigned m_num_merge;
unsigned m_num_th_eqs;
unsigned m_num_lits;
unsigned m_num_eqs;
unsigned m_num_conflicts;
stats() { reset(); }
void reset() { memset(this, 0, sizeof(*this)); }
};
struct update_record {
struct toggle_merge {};
struct add_th_var {};
struct replace_th_var {};
struct new_lit {};
struct new_th_eq {};
struct new_th_eq_qhead {};
struct new_lits_qhead {};
struct inconsistent {};
enum tag_t { is_set_parent, is_add_node, is_toggle_merge,
is_add_th_var, is_replace_th_var, is_new_lit, is_new_th_eq,
is_new_th_eq_qhead, is_new_lits_qhead, is_inconsistent };
tag_t tag;
enode* r1;
enode* n1;
union {
unsigned r2_num_parents;
struct {
unsigned m_th_id : 8;
unsigned m_old_th_var : 24;
};
unsigned qhead;
bool m_inconsistent;
};
update_record(enode* r1, enode* n1, unsigned r2_num_parents) :
tag(tag_t::is_set_parent), r1(r1), n1(n1), r2_num_parents(r2_num_parents) {}
update_record(enode* n) :
tag(tag_t::is_add_node), r1(n), n1(nullptr), r2_num_parents(UINT_MAX) {}
update_record(enode* n, toggle_merge) :
tag(tag_t::is_toggle_merge), r1(n), n1(nullptr), r2_num_parents(UINT_MAX) {}
update_record(enode* n, unsigned id, add_th_var) :
tag(tag_t::is_add_th_var), r1(n), n1(nullptr), r2_num_parents(id) {}
update_record(enode* n, theory_id id, theory_var v, replace_th_var) :
tag(tag_t::is_replace_th_var), r1(n), n1(nullptr), m_th_id(id), m_old_th_var(v) {}
update_record(new_lit) :
tag(tag_t::is_new_lit), r1(nullptr), n1(nullptr), r2_num_parents(0) {}
update_record(new_th_eq) :
tag(tag_t::is_new_th_eq), r1(nullptr), n1(nullptr), r2_num_parents(0) {}
update_record(unsigned qh, new_th_eq_qhead):
tag(tag_t::is_new_th_eq_qhead), r1(nullptr), n1(nullptr), qhead(qh) {}
update_record(unsigned qh, new_lits_qhead):
tag(tag_t::is_new_lits_qhead), r1(nullptr), n1(nullptr), qhead(qh) {}
update_record(bool inc, inconsistent) :
tag(tag_t::is_inconsistent), m_inconsistent(inc) {}
};
ast_manager& m;
trail_stack m_trail;
region m_region;
enode_vector m_worklist;
etable m_table;
svector<add_eq_record> m_eqs;
svector<scope> m_scopes;
region m_region;
svector<update_record> m_updates;
unsigned_vector m_scopes;
enode_vector m_expr2enode;
enode_vector m_nodes;
expr_ref_vector m_exprs;
@ -101,9 +128,14 @@ namespace euf {
std::function<void(app*,app*)> m_used_cc;
void push_eq(enode* r1, enode* n1, unsigned r2_num_parents) {
m_eqs.push_back(add_eq_record(r1, n1, r2_num_parents));
m_updates.push_back(update_record(r1, n1, r2_num_parents));
}
void push_node(enode* n) { m_updates.push_back(update_record(n)); }
void add_th_eq(theory_id id, theory_var v1, theory_var v2, enode* c, enode* r);
void add_literal(enode* n, bool is_eq);
void undo_eq(enode* r1, enode* n1, unsigned r2_num_parents);
void undo_add_th_var(enode* n, theory_id id);
enode* mk_enode(expr* f, unsigned num_args, enode * const* args);
void reinsert(enode* n);
void force_push();
@ -173,10 +205,13 @@ namespace euf {
void add_th_var(enode* n, theory_var v, theory_id id);
void set_merge_enabled(enode* n, bool enable_merge);
void set_used_eq(std::function<void(expr*,expr*,expr*)>& used_eq) { m_used_eq = used_eq; }
void set_used_cc(std::function<void(app*,app*)>& used_cc) { m_used_cc = used_cc; }
void begin_explain();
void end_explain();
template <typename T>
void explain(ptr_vector<T>& justifications);
template <typename T>

View file

@ -36,21 +36,22 @@ namespace euf {
const theory_id null_theory_id = -1;
class enode {
expr* m_owner;
expr* m_owner{ nullptr };
bool m_mark1 { false };
bool m_mark2 { false };
bool m_commutative { false };
bool m_update_children { false };
bool m_interpreted { false };
bool m_merge_enabled { true };
unsigned m_class_size { 1 };
unsigned m_table_id { UINT_MAX };
enode_vector m_parents;
enode* m_next;
enode* m_root;
enode* m_next{ nullptr };
enode* m_root{ nullptr };
enode* m_target { nullptr };
th_var_list m_th_vars;
justification m_justification;
unsigned m_num_args;
unsigned m_num_args { 0 };
enode* m_args[0];
friend class enode_args;
@ -73,6 +74,7 @@ namespace euf {
n->m_root = n;
n->m_commutative = num_args == 2 && is_app(f) && to_app(f)->get_decl()->is_commutative();
n->m_num_args = num_args;
n->m_merge_enabled = true;
for (unsigned i = 0; i < num_args; ++i) {
SASSERT(to_app(f)->get_arg(i) == args[i]->get_owner());
n->m_args[i] = args[i];
@ -86,7 +88,8 @@ namespace euf {
friend class replace_th_var_trail;
void add_th_var(theory_var v, theory_id id, region & r) { m_th_vars.add_var(v, id, r); }
void replace_th_var(theory_var v, theory_id id) { m_th_vars.replace(v, id); }
void del_th_var(theory_id id) { m_th_vars.del_var(id); }
void del_th_var(theory_id id) { m_th_vars.del_var(id); }
void set_merge_enabled(bool m) { m_merge_enabled = m; }
public:
~enode() {
@ -106,6 +109,7 @@ namespace euf {
bool interpreted() const { return m_interpreted; }
bool commutative() const { return m_commutative; }
void mark_interpreted() { SASSERT(num_args() == 0); m_interpreted = true; }
bool merge_enabled() { return m_merge_enabled; }
enode* get_arg(unsigned i) const { SASSERT(i < num_args()); return m_args[i]; }
unsigned hash() const { return m_owner->hash(); }
@ -143,6 +147,7 @@ namespace euf {
unsigned get_owner_id() const { return m_owner->get_id(); }
unsigned get_root_id() const { return m_root->m_owner->get_id(); }
theory_var get_th_var(theory_id id) const { return m_th_vars.find(id); }
bool is_attached_to(theory_id id) const { return get_th_var(id) != null_theory_var; }
bool has_th_vars() const { return !m_th_vars.empty(); }
void inc_class_size(unsigned n) { m_class_size += n; }

View file

@ -45,14 +45,14 @@ class expr_pattern_match {
m_kind(k), m_offset(o), m_next(next), m_app(app), m_count(count) {}
instr_kind m_kind;
unsigned m_offset;
unsigned m_next;
app* m_app;
expr* m_pat;
unsigned m_reg;
unsigned m_other_reg;
unsigned m_count;
unsigned m_num_bound;
unsigned m_offset{ 0 };
unsigned m_next{ 0 };
app* m_app{ nullptr };
expr* m_pat{ nullptr };
unsigned m_reg{ 0 };
unsigned m_other_reg{ 0 };
unsigned m_count{ 0 };
unsigned m_num_bound{ 0 };
};
typedef obj_map<func_decl, unsigned> subst;