mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 16:45:31 +00:00
Merge branch 'unstable' of https://git01.codeplex.com/z3 into unstable
This commit is contained in:
commit
b670f0bb69
50 changed files with 3280 additions and 195 deletions
|
@ -249,6 +249,8 @@ namespace z3 {
|
|||
array & operator=(array const & s);
|
||||
public:
|
||||
array(unsigned sz):m_size(sz) { m_array = new T[sz]; }
|
||||
template<typename T2>
|
||||
array(ast_vector_tpl<T2> const & v);
|
||||
~array() { delete[] m_array; }
|
||||
unsigned size() const { return m_size; }
|
||||
T & operator[](int i) { assert(0 <= i); assert(static_cast<unsigned>(i) < m_size); return m_array[i]; }
|
||||
|
@ -939,49 +941,6 @@ namespace z3 {
|
|||
inline expr udiv(expr const & a, int b) { return udiv(a, a.ctx().num_val(b, a.get_sort())); }
|
||||
inline expr udiv(int a, expr const & b) { return udiv(b.ctx().num_val(a, b.get_sort()), b); }
|
||||
|
||||
// Basic functions for creating quantified formulas.
|
||||
// The C API should be used for creating quantifiers with patterns, weights, many variables, etc.
|
||||
inline expr forall(expr const & x, expr const & b) {
|
||||
check_context(x, b);
|
||||
Z3_app vars[] = {(Z3_app) x};
|
||||
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr forall(expr const & x1, expr const & x2, expr const & b) {
|
||||
check_context(x1, b); check_context(x2, b);
|
||||
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2};
|
||||
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & b) {
|
||||
check_context(x1, b); check_context(x2, b); check_context(x3, b);
|
||||
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 };
|
||||
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) {
|
||||
check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b);
|
||||
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 };
|
||||
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr exists(expr const & x, expr const & b) {
|
||||
check_context(x, b);
|
||||
Z3_app vars[] = {(Z3_app) x};
|
||||
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr exists(expr const & x1, expr const & x2, expr const & b) {
|
||||
check_context(x1, b); check_context(x2, b);
|
||||
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2};
|
||||
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & b) {
|
||||
check_context(x1, b); check_context(x2, b); check_context(x3, b);
|
||||
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 };
|
||||
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) {
|
||||
check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b);
|
||||
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 };
|
||||
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
|
||||
template<typename T> class cast_ast;
|
||||
|
||||
template<> class cast_ast<ast> {
|
||||
|
@ -1043,6 +1002,67 @@ namespace z3 {
|
|||
friend std::ostream & operator<<(std::ostream & out, ast_vector_tpl const & v) { out << Z3_ast_vector_to_string(v.ctx(), v); return out; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template<typename T2>
|
||||
array<T>::array(ast_vector_tpl<T2> const & v) {
|
||||
m_array = new T[v.size()];
|
||||
m_size = v.size();
|
||||
for (unsigned i = 0; i < m_size; i++) {
|
||||
m_array[i] = v[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Basic functions for creating quantified formulas.
|
||||
// The C API should be used for creating quantifiers with patterns, weights, many variables, etc.
|
||||
inline expr forall(expr const & x, expr const & b) {
|
||||
check_context(x, b);
|
||||
Z3_app vars[] = {(Z3_app) x};
|
||||
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr forall(expr const & x1, expr const & x2, expr const & b) {
|
||||
check_context(x1, b); check_context(x2, b);
|
||||
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2};
|
||||
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & b) {
|
||||
check_context(x1, b); check_context(x2, b); check_context(x3, b);
|
||||
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 };
|
||||
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) {
|
||||
check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b);
|
||||
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 };
|
||||
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr forall(expr_vector const & xs, expr const & b) {
|
||||
array<Z3_app> vars(xs);
|
||||
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr exists(expr const & x, expr const & b) {
|
||||
check_context(x, b);
|
||||
Z3_app vars[] = {(Z3_app) x};
|
||||
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr exists(expr const & x1, expr const & x2, expr const & b) {
|
||||
check_context(x1, b); check_context(x2, b);
|
||||
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2};
|
||||
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & b) {
|
||||
check_context(x1, b); check_context(x2, b); check_context(x3, b);
|
||||
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 };
|
||||
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) {
|
||||
check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b);
|
||||
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 };
|
||||
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
inline expr exists(expr_vector const & xs, expr const & b) {
|
||||
array<Z3_app> vars(xs);
|
||||
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, 0, b); b.check_error(); return expr(b.ctx(), r);
|
||||
}
|
||||
|
||||
class func_entry : public object {
|
||||
Z3_func_entry m_entry;
|
||||
void init(Z3_func_entry e) {
|
||||
|
|
|
@ -44,6 +44,21 @@ namespace Microsoft.Z3
|
|||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The following parameters can be set:
|
||||
/// - proof (Boolean) Enable proof generation
|
||||
/// - debug_ref_count (Boolean) Enable debug support for Z3_ast reference counting
|
||||
/// - trace (Boolean) Tracing support for VCC
|
||||
/// - trace_file_name (String) Trace out file for VCC traces
|
||||
/// - timeout (unsigned) default timeout (in milliseconds) used for solvers
|
||||
/// - well_sorted_check type checker
|
||||
/// - auto_config use heuristics to automatically select solver and configure it
|
||||
/// - model model generation for solvers, this parameter can be overwritten when creating a solver
|
||||
/// - model_validate validate models produced by solvers
|
||||
/// - unsat_core unsat-core generation for solvers, this parameter can be overwritten when creating a solver
|
||||
/// Note that in previous versions of Z3, this constructor was also used to set global and module parameters.
|
||||
/// For this purpose we should now use <see cref="Global.SetParameter"/>
|
||||
/// </remarks>
|
||||
public Context(Dictionary<string, string> settings)
|
||||
: base()
|
||||
{
|
||||
|
|
|
@ -27,6 +27,21 @@ public class Context extends IDisposable
|
|||
|
||||
/**
|
||||
* Constructor.
|
||||
* <remarks>
|
||||
* The following parameters can be set:
|
||||
* - proof (Boolean) Enable proof generation
|
||||
* - debug_ref_count (Boolean) Enable debug support for Z3_ast reference counting
|
||||
* - trace (Boolean) Tracing support for VCC
|
||||
* - trace_file_name (String) Trace out file for VCC traces
|
||||
* - timeout (unsigned) default timeout (in milliseconds) used for solvers
|
||||
* - well_sorted_check type checker
|
||||
* - auto_config use heuristics to automatically select solver and configure it
|
||||
* - model model generation for solvers, this parameter can be overwritten when creating a solver
|
||||
* - model_validate validate models produced by solvers
|
||||
* - unsat_core unsat-core generation for solvers, this parameter can be overwritten when creating a solver
|
||||
* Note that in previous versions of Z3, this constructor was also used to set global and
|
||||
* module parameters. For this purpose we should now use <see cref="Global.setParameter"/>
|
||||
* </remarks>
|
||||
**/
|
||||
public Context(Map<String, String> settings) throws Z3Exception
|
||||
{
|
||||
|
|
|
@ -119,13 +119,13 @@
|
|||
:pattern (?select (?select (?asElems e) a) i))))
|
||||
(assert (forall ((x Int) (f Int) (a0 Int))
|
||||
(!
|
||||
(or (<= (+ a0 (* -1 (?fClosedTime f))) 0)
|
||||
(or (<= (+ a0 (* (- 1) (?fClosedTime f))) 0)
|
||||
(not (= (?isAllocated x a0) 1))
|
||||
(= (?isAllocated (?select f x) a0) 1))
|
||||
:pattern (?isAllocated (?select f x) a0))))
|
||||
(assert (forall ((a Int) (e Int) (i Int) (a0 Int))
|
||||
(!
|
||||
(or (<= (+ a0 (* -1 (?eClosedTime e))) 0)
|
||||
(or (<= (+ a0 (* (- 1) (?eClosedTime e))) 0)
|
||||
(not (= (?isAllocated a a0) 1))
|
||||
(= (?isAllocated (?select (?select e a) i) a0) 1))
|
||||
:pattern (?isAllocated (?select (?select e a) i) a0))))
|
||||
|
@ -281,13 +281,13 @@
|
|||
:pattern (IntsAllocated h (?StructGet_ s f)))))
|
||||
(assert (forall ((x Int) (f Int) (a0 Int))
|
||||
(!
|
||||
(or (<= (+ a0 (* -1 (?fClosedTime f))) 0)
|
||||
(or (<= (+ a0 (* (- 1) (?fClosedTime f))) 0)
|
||||
(not (?isAllocated_ x a0))
|
||||
(?isAllocated_ (?select f x) a0))
|
||||
:pattern (?isAllocated_ (?select f x) a0))))
|
||||
(assert (forall ((a Int) (e Int) (i Int) (a0 Int))
|
||||
(!
|
||||
(or (<= (+ a0 (* -1 (?eClosedTime e))) 0)
|
||||
(or (<= (+ a0 (* (- 1) (?eClosedTime e))) 0)
|
||||
(not (?isAllocated_ a a0))
|
||||
(?isAllocated_ (?select (?select e a) i) a0))
|
||||
:pattern (?isAllocated_ (?select (?select e a) i) a0))))
|
||||
|
|
|
@ -25,6 +25,7 @@ void array_rewriter::updt_params(params_ref const & _p) {
|
|||
array_rewriter_params p(_p);
|
||||
m_sort_store = p.sort_store();
|
||||
m_expand_select_store = p.expand_select_store();
|
||||
m_expand_store_eq = p.expand_store_eq();
|
||||
}
|
||||
|
||||
void array_rewriter::get_param_descrs(param_descrs & r) {
|
||||
|
@ -365,3 +366,40 @@ br_status array_rewriter::mk_set_subset(expr * arg1, expr * arg2, expr_ref & res
|
|||
return BR_REWRITE3;
|
||||
}
|
||||
|
||||
br_status array_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
|
||||
if (!m_expand_store_eq) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
expr* lhs1 = lhs;
|
||||
while (m_util.is_store(lhs1)) {
|
||||
lhs1 = to_app(lhs1)->get_arg(0);
|
||||
}
|
||||
expr* rhs1 = rhs;
|
||||
while (m_util.is_store(rhs1)) {
|
||||
rhs1 = to_app(rhs1)->get_arg(0);
|
||||
}
|
||||
if (lhs1 != rhs1) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
ptr_buffer<expr> fmls, args;
|
||||
expr* e;
|
||||
expr_ref tmp1(m()), tmp2(m());
|
||||
#define MK_EQ() \
|
||||
while (m_util.is_store(e)) { \
|
||||
args.push_back(lhs); \
|
||||
args.append(to_app(e)->get_num_args()-2,to_app(e)->get_args()+1); \
|
||||
mk_select(args.size(), args.c_ptr(), tmp1); \
|
||||
args[0] = rhs; \
|
||||
mk_select(args.size(), args.c_ptr(), tmp2); \
|
||||
fmls.push_back(m().mk_eq(tmp1, tmp2)); \
|
||||
e = to_app(e)->get_arg(0); \
|
||||
args.reset(); \
|
||||
} \
|
||||
|
||||
e = lhs;
|
||||
MK_EQ();
|
||||
e = rhs;
|
||||
MK_EQ();
|
||||
result = m().mk_and(fmls.size(), fmls.c_ptr());
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
|
|
@ -31,12 +31,14 @@ class array_rewriter {
|
|||
array_util m_util;
|
||||
bool m_sort_store;
|
||||
bool m_expand_select_store;
|
||||
bool m_expand_store_eq;
|
||||
template<bool CHECK_DISEQ>
|
||||
lbool compare_args(unsigned num_args, expr * const * args1, expr * const * args2);
|
||||
public:
|
||||
array_rewriter(ast_manager & m, params_ref const & p = params_ref()):
|
||||
m_util(m) {
|
||||
updt_params(p);
|
||||
|
||||
}
|
||||
ast_manager & m() const { return m_util.get_manager(); }
|
||||
family_id get_fid() const { return m_util.get_family_id(); }
|
||||
|
@ -60,6 +62,7 @@ public:
|
|||
br_status mk_set_complement(expr * arg, expr_ref & result);
|
||||
br_status mk_set_difference(expr * arg1, expr * arg2, expr_ref & result);
|
||||
br_status mk_set_subset(expr * arg1, expr * arg2, expr_ref & result);
|
||||
br_status mk_eq_core(expr * lhs, expr * rhs, expr_ref & result);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,4 +2,5 @@ def_module_params(module_name='rewriter',
|
|||
class_name='array_rewriter_params',
|
||||
export=True,
|
||||
params=(("expand_select_store", BOOL, False, "replace a (select (store ...) ...) term by an if-then-else term"),
|
||||
("expand_store_eq", BOOL, False, "reduce (store ...) = (store ...) with a common base into selects"),
|
||||
("sort_store", BOOL, False, "sort nested stores when the indices are known to be different")))
|
||||
|
|
|
@ -62,6 +62,8 @@ struct mk_simplified_app::imp {
|
|||
st = m_dt_rw.mk_eq_core(args[0], args[1], result);
|
||||
else if (s_fid == m_f_rw.get_fid())
|
||||
st = m_f_rw.mk_eq_core(args[0], args[1], result);
|
||||
else if (s_fid == m_ar_rw.get_fid())
|
||||
st = m_ar_rw.mk_eq_core(args[0], args[1], result);
|
||||
|
||||
if (st != BR_FAILED)
|
||||
return st;
|
||||
|
|
|
@ -169,7 +169,9 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
st = m_dt_rw.mk_eq_core(args[0], args[1], result);
|
||||
else if (s_fid == m_f_rw.get_fid())
|
||||
st = m_f_rw.mk_eq_core(args[0], args[1], result);
|
||||
|
||||
else if (s_fid == m_ar_rw.get_fid())
|
||||
st = m_ar_rw.mk_eq_core(args[0], args[1], result);
|
||||
|
||||
if (st != BR_FAILED)
|
||||
return st;
|
||||
}
|
||||
|
|
328
src/muz_qe/aig_exporter.cpp
Executable file
328
src/muz_qe/aig_exporter.cpp
Executable file
|
@ -0,0 +1,328 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
aig_exporter.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Export AIG files from horn clauses
|
||||
|
||||
--*/
|
||||
|
||||
#include "aig_exporter.h"
|
||||
#include "dl_context.h"
|
||||
#include <set>
|
||||
|
||||
namespace datalog {
|
||||
|
||||
aig_exporter::aig_exporter(const rule_set& rules, context& ctx, const fact_vector *facts) :
|
||||
m_rules(rules), m_facts(facts), m(ctx.get_manager()), m_rm(ctx.get_rule_manager()),
|
||||
m_aigm(m), m_next_decl_id(1), m_next_aig_expr_id(2), m_num_and_gates(0),
|
||||
m_latch_vars(m), m_latch_varsp(m), m_ruleid_var_set(m), m_ruleid_varp_set(m)
|
||||
{
|
||||
std::set<func_decl*> predicates;
|
||||
for (rule_set::decl2rules::iterator I = m_rules.begin_grouped_rules(),
|
||||
E = m_rules.end_grouped_rules(); I != E; ++I) {
|
||||
predicates.insert(I->m_key);
|
||||
}
|
||||
|
||||
for (fact_vector::const_iterator I = facts->begin(), E = facts->end(); I != E; ++I) {
|
||||
predicates.insert(I->first);
|
||||
}
|
||||
|
||||
// reserve pred id = 0 for initalization purposes
|
||||
unsigned num_preds = (unsigned)predicates.size() + 1;
|
||||
|
||||
// poor's man round-up log2
|
||||
unsigned preds_bitsize = log2(num_preds);
|
||||
if ((1U << preds_bitsize) < num_preds)
|
||||
++preds_bitsize;
|
||||
SASSERT((1U << preds_bitsize) >= num_preds);
|
||||
|
||||
for (unsigned i = 0; i < preds_bitsize; ++i) {
|
||||
m_ruleid_var_set.push_back(m.mk_fresh_const("rule_id", m.mk_bool_sort()));
|
||||
m_ruleid_varp_set.push_back(m.mk_fresh_const("rule_id_p", m.mk_bool_sort()));
|
||||
}
|
||||
}
|
||||
|
||||
void aig_exporter::mk_latch_vars(unsigned n) {
|
||||
for (unsigned i = m_latch_vars.size(); i <= n; ++i) {
|
||||
m_latch_vars.push_back(m.mk_fresh_const("latch_var", m.mk_bool_sort()));
|
||||
m_latch_varsp.push_back(m.mk_fresh_const("latch_varp", m.mk_bool_sort()));
|
||||
}
|
||||
SASSERT(m_latch_vars.size() > n);
|
||||
}
|
||||
|
||||
expr* aig_exporter::get_latch_var(unsigned i, const expr_ref_vector& vars) {
|
||||
mk_latch_vars(i);
|
||||
return vars.get(i);
|
||||
}
|
||||
|
||||
void aig_exporter::assert_pred_id(func_decl *decl, const expr_ref_vector& vars, expr_ref_vector& exprs) {
|
||||
unsigned id = 0;
|
||||
if (decl && !m_decl_id_map.find(decl, id)) {
|
||||
id = m_next_decl_id++;
|
||||
SASSERT(id < (1U << vars.size()));
|
||||
m_decl_id_map.insert(decl, id);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < vars.size(); ++i) {
|
||||
exprs.push_back((id & (1U << i)) ? vars[i] : m.mk_not(vars[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void aig_exporter::collect_var_substs(substitution& subst, const app *h,
|
||||
const expr_ref_vector& vars, expr_ref_vector& eqs) {
|
||||
for (unsigned i = 0; i < h->get_num_args(); ++i) {
|
||||
expr *arg = h->get_arg(i);
|
||||
expr *latchvar = get_latch_var(i, vars);
|
||||
|
||||
if (is_var(arg)) {
|
||||
var *v = to_var(arg);
|
||||
expr_offset othervar;
|
||||
if (subst.find(v, 0, othervar)) {
|
||||
eqs.push_back(m.mk_eq(latchvar, othervar.get_expr()));
|
||||
} else {
|
||||
subst.insert(v, 0, expr_offset(latchvar, 0));
|
||||
}
|
||||
} else {
|
||||
eqs.push_back(m.mk_eq(latchvar, arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void aig_exporter::operator()(std::ostream& out) {
|
||||
expr_ref_vector transition_function(m), output_preds(m);
|
||||
var_ref_vector input_vars(m);
|
||||
|
||||
rule_counter& vc = m_rm.get_counter();
|
||||
expr_ref_vector exprs(m);
|
||||
substitution subst(m);
|
||||
|
||||
for (rule_set::decl2rules::iterator I = m_rules.begin_grouped_rules(),
|
||||
E = m_rules.end_grouped_rules(); I != E; ++I) {
|
||||
for (rule_vector::iterator II = I->get_value()->begin(),
|
||||
EE = I->get_value()->end(); II != EE; ++II) {
|
||||
rule *r = *II;
|
||||
unsigned numqs = r->get_positive_tail_size();
|
||||
if (numqs > 1) {
|
||||
std::cerr << "non-linear clauses not supported\n";
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (numqs != r->get_uninterpreted_tail_size()) {
|
||||
std::cerr << "negation of queries not supported\n";
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
exprs.reset();
|
||||
assert_pred_id(numqs ? r->get_tail(0)->get_decl() : 0, m_ruleid_var_set, exprs);
|
||||
assert_pred_id(r->get_head()->get_decl(), m_ruleid_varp_set, exprs);
|
||||
|
||||
subst.reset();
|
||||
subst.reserve(1, vc.get_max_rule_var(*r)+1);
|
||||
if (numqs)
|
||||
collect_var_substs(subst, r->get_tail(0), m_latch_vars, exprs);
|
||||
collect_var_substs(subst, r->get_head(), m_latch_varsp, exprs);
|
||||
|
||||
for (unsigned i = numqs; i < r->get_tail_size(); ++i) {
|
||||
expr_ref e(m);
|
||||
subst.apply(r->get_tail(i), e);
|
||||
exprs.push_back(e);
|
||||
}
|
||||
|
||||
transition_function.push_back(m.mk_and(exprs.size(), exprs.c_ptr()));
|
||||
}
|
||||
}
|
||||
|
||||
// collect table facts
|
||||
if (m_facts) {
|
||||
for (fact_vector::const_iterator I = m_facts->begin(), E = m_facts->end(); I != E; ++I) {
|
||||
exprs.reset();
|
||||
assert_pred_id(0, m_ruleid_var_set, exprs);
|
||||
assert_pred_id(I->first, m_ruleid_varp_set, exprs);
|
||||
|
||||
for (unsigned i = 0; i < I->second.size(); ++i) {
|
||||
exprs.push_back(m.mk_eq(get_latch_var(i, m_latch_varsp), I->second[i]));
|
||||
}
|
||||
|
||||
transition_function.push_back(m.mk_and(exprs.size(), exprs.c_ptr()));
|
||||
}
|
||||
}
|
||||
|
||||
expr *tr = m.mk_or(transition_function.size(), transition_function.c_ptr());
|
||||
aig_ref aig = m_aigm.mk_aig(tr);
|
||||
expr_ref aig_expr(m);
|
||||
m_aigm.to_formula(aig, aig_expr);
|
||||
|
||||
#if 0
|
||||
std::cout << mk_pp(tr, m) << "\n\n";
|
||||
std::cout << mk_pp(aig_expr, m) << "\n\n";
|
||||
#endif
|
||||
|
||||
// make rule_id vars latches
|
||||
for (unsigned i = 0; i < m_ruleid_var_set.size(); ++i) {
|
||||
m_latch_vars.push_back(m_ruleid_var_set.get(i));
|
||||
m_latch_varsp.push_back(m_ruleid_varp_set.get(i));
|
||||
}
|
||||
|
||||
// create vars for latches
|
||||
for (unsigned i = 0; i < m_latch_vars.size(); ++i) {
|
||||
mk_var(m_latch_vars.get(i));
|
||||
mk_input_var(m_latch_varsp.get(i));
|
||||
}
|
||||
|
||||
unsigned tr_id = expr_to_aig(aig_expr);
|
||||
|
||||
// create latch next state variables: (ite tr varp var)
|
||||
unsigned_vector latch_varp_ids;
|
||||
for (unsigned i = 0; i < m_latch_vars.size(); ++i) {
|
||||
unsigned in_val = mk_and(tr_id, get_var(m_latch_varsp.get(i)));
|
||||
unsigned latch_val = mk_and(neg(tr_id), get_var(m_latch_vars.get(i)));
|
||||
latch_varp_ids.push_back(mk_or(in_val, latch_val));
|
||||
}
|
||||
m_latch_varsp.reset();
|
||||
|
||||
// create output variable (true iff an output predicate is derivable)
|
||||
unsigned output_id = 0;
|
||||
{
|
||||
expr_ref_vector output(m);
|
||||
const func_decl_set& preds = m_rules.get_output_predicates();
|
||||
|
||||
for (func_decl_set::iterator I = preds.begin(), E = preds.end(); I != E; ++I) {
|
||||
exprs.reset();
|
||||
assert_pred_id(*I, m_ruleid_var_set, exprs);
|
||||
output.push_back(m.mk_and(exprs.size(), exprs.c_ptr()));
|
||||
}
|
||||
|
||||
expr *out = m.mk_or(output.size(), output.c_ptr());
|
||||
aig = m_aigm.mk_aig(out);
|
||||
m_aigm.to_formula(aig, aig_expr);
|
||||
output_id = expr_to_aig(aig_expr);
|
||||
|
||||
#if 0
|
||||
std::cout << "output formula\n";
|
||||
std::cout << mk_pp(out, m) << "\n\n";
|
||||
std::cout << mk_pp(aig_expr, m) << "\n\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
// 1) print header
|
||||
// aag var_index inputs latches outputs andgates
|
||||
out << "aag " << (m_next_aig_expr_id-1)/2 << ' ' << m_input_vars.size()
|
||||
<< ' ' << m_latch_vars.size() << " 1 " << m_num_and_gates << '\n';
|
||||
|
||||
// 2) print inputs
|
||||
for (unsigned i = 0; i < m_input_vars.size(); ++i) {
|
||||
out << m_input_vars[i] << '\n';
|
||||
}
|
||||
|
||||
// 3) print latches
|
||||
for (unsigned i = 0; i < m_latch_vars.size(); ++i) {
|
||||
out << get_var(m_latch_vars.get(i)) << ' ' << latch_varp_ids[i] << '\n';
|
||||
}
|
||||
|
||||
// 4) print outputs (just one for now)
|
||||
out << output_id << '\n';
|
||||
|
||||
// 5) print formula
|
||||
out << m_buffer.str();
|
||||
}
|
||||
|
||||
unsigned aig_exporter::expr_to_aig(const expr *e) {
|
||||
unsigned id;
|
||||
if (m_aig_expr_id_map.find(e, id))
|
||||
return id;
|
||||
|
||||
if (is_uninterp_const(e))
|
||||
return get_var(e);
|
||||
|
||||
switch (e->get_kind()) {
|
||||
case AST_APP: {
|
||||
const app *a = to_app(e);
|
||||
switch (a->get_decl_kind()) {
|
||||
case OP_OR:
|
||||
SASSERT(a->get_num_args() > 0);
|
||||
id = expr_to_aig(a->get_arg(0));
|
||||
for (unsigned i = 1; i < a->get_num_args(); ++i) {
|
||||
id = mk_or(id, expr_to_aig(a->get_arg(i)));
|
||||
}
|
||||
m_aig_expr_id_map.insert(e, id);
|
||||
return id;
|
||||
|
||||
case OP_NOT:
|
||||
return neg(expr_to_aig(a->get_arg(0)));
|
||||
|
||||
case OP_FALSE:
|
||||
return 0;
|
||||
|
||||
case OP_TRUE:
|
||||
return 1;
|
||||
}
|
||||
break;}
|
||||
|
||||
case AST_VAR:
|
||||
return get_var(e);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned aig_exporter::neg(unsigned id) const {
|
||||
return (id % 2) ? (id-1) : (id+1);
|
||||
}
|
||||
|
||||
unsigned aig_exporter::mk_and(unsigned id1, unsigned id2) {
|
||||
if (id1 > id2)
|
||||
std::swap(id1, id2);
|
||||
|
||||
std::pair<unsigned,unsigned> key(id1, id2);
|
||||
and_gates_map::const_iterator I = m_and_gates_map.find(key);
|
||||
if (I != m_and_gates_map.end())
|
||||
return I->second;
|
||||
|
||||
unsigned id = mk_expr_id();
|
||||
m_buffer << id << ' ' << id1 << ' ' << id2 << '\n';
|
||||
m_and_gates_map[key] = id;
|
||||
++m_num_and_gates;
|
||||
return id;
|
||||
}
|
||||
|
||||
unsigned aig_exporter::mk_or(unsigned id1, unsigned id2) {
|
||||
return neg(mk_and(neg(id1), neg(id2)));
|
||||
}
|
||||
|
||||
unsigned aig_exporter::get_var(const expr *e) {
|
||||
unsigned id;
|
||||
if (m_aig_expr_id_map.find(e, id))
|
||||
return id;
|
||||
return mk_input_var(e);
|
||||
}
|
||||
|
||||
unsigned aig_exporter::mk_var(const expr *e) {
|
||||
SASSERT(!m_aig_expr_id_map.contains(e));
|
||||
unsigned id = mk_expr_id();
|
||||
m_aig_expr_id_map.insert(e, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
unsigned aig_exporter::mk_input_var(const expr *e) {
|
||||
SASSERT(!m_aig_expr_id_map.contains(e));
|
||||
unsigned id = mk_expr_id();
|
||||
m_input_vars.push_back(id);
|
||||
if (e)
|
||||
m_aig_expr_id_map.insert(e, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
unsigned aig_exporter::mk_expr_id() {
|
||||
unsigned id = m_next_aig_expr_id;
|
||||
m_next_aig_expr_id += 2;
|
||||
return id;
|
||||
}
|
||||
}
|
68
src/muz_qe/aig_exporter.h
Executable file
68
src/muz_qe/aig_exporter.h
Executable file
|
@ -0,0 +1,68 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
aig_exporter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Export AIG files from horn clauses
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _AIG_EXPORTER_H_
|
||||
#define _AIG_EXPORTER_H_
|
||||
|
||||
#include "aig.h"
|
||||
#include "dl_rule_set.h"
|
||||
#include "rel_context.h"
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
|
||||
namespace datalog {
|
||||
class aig_exporter {
|
||||
public:
|
||||
aig_exporter(const rule_set& rules, context& ctx, const fact_vector *facts = 0);
|
||||
void operator()(std::ostream& out);
|
||||
|
||||
private:
|
||||
typedef obj_map<func_decl, unsigned> decl_id_map;
|
||||
typedef obj_map<const expr, unsigned> aig_expr_id_map;
|
||||
typedef std::map<std::pair<unsigned,unsigned>, unsigned> and_gates_map;
|
||||
|
||||
const rule_set& m_rules;
|
||||
const fact_vector *m_facts;
|
||||
ast_manager& m;
|
||||
rule_manager& m_rm;
|
||||
aig_manager m_aigm;
|
||||
decl_id_map m_decl_id_map;
|
||||
unsigned m_next_decl_id;
|
||||
aig_expr_id_map m_aig_expr_id_map;
|
||||
unsigned m_next_aig_expr_id;
|
||||
and_gates_map m_and_gates_map;
|
||||
unsigned m_num_and_gates;
|
||||
|
||||
expr_ref_vector m_latch_vars, m_latch_varsp;
|
||||
expr_ref_vector m_ruleid_var_set, m_ruleid_varp_set;
|
||||
unsigned_vector m_input_vars;
|
||||
|
||||
std::stringstream m_buffer;
|
||||
|
||||
void mk_latch_vars(unsigned n);
|
||||
expr* get_latch_var(unsigned i, const expr_ref_vector& vars);
|
||||
void assert_pred_id(func_decl *decl, const expr_ref_vector& vars, expr_ref_vector& exprs);
|
||||
void collect_var_substs(substitution& subst, const app *h,
|
||||
const expr_ref_vector& vars, expr_ref_vector& eqs);
|
||||
unsigned expr_to_aig(const expr *e);
|
||||
unsigned neg(unsigned id) const;
|
||||
unsigned mk_and(unsigned id1, unsigned id2);
|
||||
unsigned mk_or(unsigned id1, unsigned id2);
|
||||
unsigned get_var(const expr *e);
|
||||
unsigned mk_var(const expr *e);
|
||||
unsigned mk_input_var(const expr *e = 0);
|
||||
unsigned mk_expr_id();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -67,8 +67,10 @@ namespace datalog {
|
|||
m_solver.reset();
|
||||
m_goals.reset();
|
||||
rm.mk_query(query, m_ctx.get_rules());
|
||||
expr_ref head(m);
|
||||
head = m_ctx.get_rules().last()->get_head();
|
||||
m_ctx.apply_default_transformation();
|
||||
func_decl *head_decl = m_ctx.get_rules().get_output_predicate();
|
||||
|
||||
expr_ref head(m_ctx.get_rules().get_predicate_rules(head_decl)[0]->get_head(), m);
|
||||
ground(head);
|
||||
m_goals.push_back(to_app(head));
|
||||
return search(20, 0);
|
||||
|
@ -125,6 +127,10 @@ namespace datalog {
|
|||
m_var_subst(e, m_ground.size(), m_ground.c_ptr(), e);
|
||||
}
|
||||
|
||||
static bool rule_sort_fn(const rule *r1, const rule *r2) {
|
||||
return r1->get_uninterpreted_tail_size() < r2->get_uninterpreted_tail_size();
|
||||
}
|
||||
|
||||
lbool search(unsigned depth, unsigned index) {
|
||||
if (index == m_goals.size()) {
|
||||
return l_true;
|
||||
|
@ -135,7 +141,10 @@ namespace datalog {
|
|||
IF_VERBOSE(1, verbose_stream() << "search " << depth << " " << index << "\n";);
|
||||
unsigned num_goals = m_goals.size();
|
||||
app* head = m_goals[index].get();
|
||||
rule_vector const& rules = m_ctx.get_rules().get_predicate_rules(head->get_decl());
|
||||
|
||||
rule_vector rules(m_ctx.get_rules().get_predicate_rules(head->get_decl()));
|
||||
std::stable_sort(rules.begin(), rules.end(), rule_sort_fn);
|
||||
|
||||
lbool status = l_false;
|
||||
for (unsigned i = 0; i < rules.size(); ++i) {
|
||||
rule* r = rules[i];
|
||||
|
|
|
@ -331,6 +331,10 @@ namespace datalog {
|
|||
virtual mutator_fn * mk_filter_interpreted_fn(const base_object & t, app * condition)
|
||||
{ return 0; }
|
||||
|
||||
virtual transformer_fn * mk_filter_interpreted_and_project_fn(const base_object & t,
|
||||
app * condition, unsigned removed_col_cnt, const unsigned * removed_cols)
|
||||
{ return 0; }
|
||||
|
||||
virtual transformer_fn * mk_select_equal_and_project_fn(const base_object & t,
|
||||
const element & value, unsigned col) { return 0; }
|
||||
|
||||
|
@ -454,8 +458,8 @@ namespace datalog {
|
|||
class convenient_join_fn : public join_fn {
|
||||
signature m_result_sig;
|
||||
protected:
|
||||
const unsigned_vector m_cols1;
|
||||
const unsigned_vector m_cols2;
|
||||
unsigned_vector m_cols1;
|
||||
unsigned_vector m_cols2;
|
||||
|
||||
convenient_join_fn(const signature & o1_sig, const signature & o2_sig, unsigned col_cnt,
|
||||
const unsigned * cols1, const unsigned * cols2)
|
||||
|
@ -470,8 +474,8 @@ namespace datalog {
|
|||
class convenient_join_project_fn : public join_fn {
|
||||
signature m_result_sig;
|
||||
protected:
|
||||
const unsigned_vector m_cols1;
|
||||
const unsigned_vector m_cols2;
|
||||
unsigned_vector m_cols1;
|
||||
unsigned_vector m_cols2;
|
||||
//it is non-const because it needs to be modified in sparse_table version of the join_project operator
|
||||
unsigned_vector m_removed_cols;
|
||||
|
||||
|
@ -498,7 +502,7 @@ namespace datalog {
|
|||
|
||||
class convenient_project_fn : public convenient_transformer_fn {
|
||||
protected:
|
||||
const unsigned_vector m_removed_cols;
|
||||
unsigned_vector m_removed_cols;
|
||||
|
||||
convenient_project_fn(const signature & orig_sig, unsigned col_cnt, const unsigned * removed_cols)
|
||||
: m_removed_cols(col_cnt, removed_cols) {
|
||||
|
|
|
@ -297,6 +297,7 @@ namespace datalog {
|
|||
r->to_formula(fml);
|
||||
r2 = r;
|
||||
rm.substitute(r2, sub.size(), sub.c_ptr());
|
||||
proof_ref p(m);
|
||||
if (r0) {
|
||||
VERIFY(unifier.unify_rules(*r0.get(), 0, *r2.get()));
|
||||
expr_ref_vector sub1 = unifier.get_rule_subst(*r0.get(), true);
|
||||
|
@ -306,7 +307,10 @@ namespace datalog {
|
|||
r1->to_formula(concl);
|
||||
scoped_proof _sp(m);
|
||||
|
||||
proof* p = r->get_proof();
|
||||
p = r->get_proof();
|
||||
if (!p) {
|
||||
p = m.mk_asserted(fml);
|
||||
}
|
||||
proof* premises[2] = { pr, p };
|
||||
|
||||
positions.push_back(std::make_pair(0, 1));
|
||||
|
@ -319,13 +323,17 @@ namespace datalog {
|
|||
else {
|
||||
r2->to_formula(concl);
|
||||
scoped_proof _sp(m);
|
||||
proof* p = r->get_proof();
|
||||
p = r->get_proof();
|
||||
if (!p) {
|
||||
p = m.mk_asserted(fml);
|
||||
}
|
||||
if (sub.empty()) {
|
||||
pr = p;
|
||||
}
|
||||
else {
|
||||
substs.push_back(sub);
|
||||
pr = m.mk_hyper_resolve(1, &p, concl, positions, substs);
|
||||
proof* ps[1] = { p };
|
||||
pr = m.mk_hyper_resolve(1, ps, concl, positions, substs);
|
||||
}
|
||||
r0 = r2;
|
||||
}
|
||||
|
@ -1211,6 +1219,15 @@ namespace datalog {
|
|||
r->to_formula(fml);
|
||||
r2 = r;
|
||||
rm.substitute(r2, sub.size(), sub.c_ptr());
|
||||
proof_ref p(m);
|
||||
{
|
||||
scoped_proof _sp(m);
|
||||
p = r->get_proof();
|
||||
if (!p) {
|
||||
p = m.mk_asserted(fml);
|
||||
}
|
||||
}
|
||||
|
||||
if (r0) {
|
||||
VERIFY(unifier.unify_rules(*r0.get(), 0, *r2.get()));
|
||||
expr_ref_vector sub1 = unifier.get_rule_subst(*r0.get(), true);
|
||||
|
@ -1218,9 +1235,8 @@ namespace datalog {
|
|||
apply_subst(sub, sub2);
|
||||
unifier.apply(*r0.get(), 0, *r2.get(), r1);
|
||||
r1->to_formula(concl);
|
||||
scoped_proof _sp(m);
|
||||
|
||||
proof* p = r->get_proof();
|
||||
scoped_proof _sp(m);
|
||||
proof* premises[2] = { pr, p };
|
||||
|
||||
positions.push_back(std::make_pair(0, 1));
|
||||
|
@ -1233,13 +1249,13 @@ namespace datalog {
|
|||
else {
|
||||
r2->to_formula(concl);
|
||||
scoped_proof _sp(m);
|
||||
proof* p = r->get_proof();
|
||||
if (sub.empty()) {
|
||||
pr = p;
|
||||
}
|
||||
else {
|
||||
substs.push_back(sub);
|
||||
pr = m.mk_hyper_resolve(1, &p, concl, positions, substs);
|
||||
proof * ps[1] = { p };
|
||||
pr = m.mk_hyper_resolve(1, ps, concl, positions, substs);
|
||||
}
|
||||
r0 = r2;
|
||||
}
|
||||
|
|
|
@ -82,6 +82,34 @@ namespace datalog {
|
|||
return alloc(join_fn, *this, t1, t2, col_cnt, cols1, cols2);
|
||||
}
|
||||
|
||||
class check_table_plugin::join_project_fn : public table_join_fn {
|
||||
scoped_ptr<table_join_fn> m_tocheck;
|
||||
scoped_ptr<table_join_fn> m_checker;
|
||||
public:
|
||||
join_project_fn(check_table_plugin& p, const table_base & t1, const table_base & t2,
|
||||
unsigned col_cnt, const unsigned * cols1, const unsigned * cols2,
|
||||
unsigned removed_col_cnt, const unsigned * removed_cols) {
|
||||
m_tocheck = p.get_manager().mk_join_project_fn(tocheck(t1), tocheck(t2), col_cnt, cols1, cols2, removed_col_cnt, removed_cols);
|
||||
m_checker = p.get_manager().mk_join_project_fn(checker(t1), checker(t2), col_cnt, cols1, cols2, removed_col_cnt, removed_cols);
|
||||
}
|
||||
|
||||
virtual table_base* operator()(const table_base & t1, const table_base & t2) {
|
||||
table_base* ttocheck = (*m_tocheck)(tocheck(t1), tocheck(t2));
|
||||
table_base* tchecker = (*m_checker)(checker(t1), checker(t2));
|
||||
check_table* result = alloc(check_table, get(t1).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
table_join_fn * check_table_plugin::mk_join_project_fn(const table_base & t1, const table_base & t2,
|
||||
unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt,
|
||||
const unsigned * removed_cols) {
|
||||
if (!check_kind(t1) || !check_kind(t2)) {
|
||||
return 0;
|
||||
}
|
||||
return alloc(join_project_fn, *this, t1, t2, col_cnt, cols1, cols2, removed_col_cnt, removed_cols);
|
||||
}
|
||||
|
||||
class check_table_plugin::union_fn : public table_union_fn {
|
||||
scoped_ptr<table_union_fn> m_tocheck;
|
||||
scoped_ptr<table_union_fn> m_checker;
|
||||
|
@ -120,7 +148,6 @@ namespace datalog {
|
|||
}
|
||||
|
||||
table_base* operator()(table_base const& src) {
|
||||
IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";);
|
||||
table_base* tchecker = (*m_checker)(checker(src));
|
||||
table_base* ttocheck = (*m_tocheck)(tocheck(src));
|
||||
check_table* result = alloc(check_table, get(src).get_plugin(), tchecker->get_signature(), ttocheck, tchecker);
|
||||
|
@ -135,6 +162,31 @@ namespace datalog {
|
|||
return alloc(project_fn, *this, t, col_cnt, removed_cols);
|
||||
}
|
||||
|
||||
class check_table_plugin::select_equal_and_project_fn : public table_transformer_fn {
|
||||
scoped_ptr<table_transformer_fn> m_checker;
|
||||
scoped_ptr<table_transformer_fn> m_tocheck;
|
||||
public:
|
||||
select_equal_and_project_fn(check_table_plugin& p, const table_base & t, const table_element & value, unsigned col) {
|
||||
m_checker = p.get_manager().mk_select_equal_and_project_fn(checker(t), value, col);
|
||||
m_tocheck = p.get_manager().mk_select_equal_and_project_fn(tocheck(t), value, col);
|
||||
}
|
||||
|
||||
table_base* operator()(table_base const& src) {
|
||||
table_base* tchecker = (*m_checker)(checker(src));
|
||||
table_base* ttocheck = (*m_tocheck)(tocheck(src));
|
||||
check_table* result = alloc(check_table, get(src).get_plugin(), tchecker->get_signature(), ttocheck, tchecker);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
table_transformer_fn * check_table_plugin::mk_select_equal_and_project_fn(const table_base & t,
|
||||
const table_element & value, unsigned col) {
|
||||
if (!check_kind(t)) {
|
||||
return 0;
|
||||
}
|
||||
return alloc(select_equal_and_project_fn, *this, t, value, col);
|
||||
}
|
||||
|
||||
class check_table_plugin::rename_fn : public table_transformer_fn {
|
||||
scoped_ptr<table_transformer_fn> m_checker;
|
||||
scoped_ptr<table_transformer_fn> m_tocheck;
|
||||
|
@ -233,6 +285,33 @@ namespace datalog {
|
|||
return 0;
|
||||
}
|
||||
|
||||
class check_table_plugin::filter_interpreted_and_project_fn : public table_transformer_fn {
|
||||
scoped_ptr<table_transformer_fn> m_checker;
|
||||
scoped_ptr<table_transformer_fn> m_tocheck;
|
||||
public:
|
||||
filter_interpreted_and_project_fn(check_table_plugin& p, const table_base & t, app * condition,
|
||||
unsigned removed_col_cnt, const unsigned * removed_cols)
|
||||
{
|
||||
m_checker = p.get_manager().mk_filter_interpreted_and_project_fn(checker(t), condition, removed_col_cnt, removed_cols);
|
||||
m_tocheck = p.get_manager().mk_filter_interpreted_and_project_fn(tocheck(t), condition, removed_col_cnt, removed_cols);
|
||||
}
|
||||
|
||||
table_base* operator()(table_base const& src) {
|
||||
table_base* tchecker = (*m_checker)(checker(src));
|
||||
table_base* ttocheck = (*m_tocheck)(tocheck(src));
|
||||
check_table* result = alloc(check_table, get(src).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
table_transformer_fn * check_table_plugin::mk_filter_interpreted_and_project_fn(const table_base & t,
|
||||
app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) {
|
||||
if (check_kind(t)) {
|
||||
return alloc(filter_interpreted_and_project_fn, *this, t, condition, removed_col_cnt, removed_cols);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
class check_table_plugin::filter_by_negation_fn : public table_intersection_filter_fn {
|
||||
scoped_ptr<table_intersection_filter_fn> m_checker;
|
||||
scoped_ptr<table_intersection_filter_fn> m_tocheck;
|
||||
|
|
|
@ -35,13 +35,16 @@ namespace datalog {
|
|||
unsigned m_count;
|
||||
protected:
|
||||
class join_fn;
|
||||
class join_project_fn;
|
||||
class union_fn;
|
||||
class transformer_fn;
|
||||
class rename_fn;
|
||||
class project_fn;
|
||||
class select_equal_and_project_fn;
|
||||
class filter_equal_fn;
|
||||
class filter_identical_fn;
|
||||
class filter_interpreted_fn;
|
||||
class filter_interpreted_and_project_fn;
|
||||
class filter_by_negation_fn;
|
||||
|
||||
public:
|
||||
|
@ -54,10 +57,15 @@ namespace datalog {
|
|||
|
||||
virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2,
|
||||
unsigned col_cnt, const unsigned * cols1, const unsigned * cols2);
|
||||
virtual table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2,
|
||||
unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt,
|
||||
const unsigned * removed_cols);
|
||||
virtual table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src,
|
||||
const table_base * delta);
|
||||
virtual table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt,
|
||||
const unsigned * removed_cols);
|
||||
virtual table_transformer_fn * mk_select_equal_and_project_fn(const table_base & t,
|
||||
const table_element & value, unsigned col);
|
||||
virtual table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len,
|
||||
const unsigned * permutation_cycle);
|
||||
virtual table_mutator_fn * mk_filter_identical_fn(const table_base & t, unsigned col_cnt,
|
||||
|
@ -65,6 +73,8 @@ namespace datalog {
|
|||
virtual table_mutator_fn * mk_filter_equal_fn(const table_base & t, const table_element & value,
|
||||
unsigned col);
|
||||
virtual table_mutator_fn * mk_filter_interpreted_fn(const table_base & t, app * condition);
|
||||
virtual table_transformer_fn * mk_filter_interpreted_and_project_fn(const table_base & t,
|
||||
app * condition, unsigned removed_col_cnt, const unsigned * removed_cols);
|
||||
virtual table_intersection_filter_fn * mk_filter_by_negation_fn(
|
||||
const table_base & t,
|
||||
const table_base & negated_obj, unsigned joined_col_cnt,
|
||||
|
|
|
@ -73,6 +73,18 @@ namespace datalog {
|
|||
vars.get_cols2(), removed_cols.size(), removed_cols.c_ptr(), result));
|
||||
}
|
||||
|
||||
void compiler::make_filter_interpreted_and_project(reg_idx src, app_ref & cond,
|
||||
const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc) {
|
||||
SASSERT(!removed_cols.empty());
|
||||
relation_signature res_sig;
|
||||
relation_signature::from_project(m_reg_signatures[src], removed_cols.size(),
|
||||
removed_cols.c_ptr(), res_sig);
|
||||
result = get_fresh_register(res_sig);
|
||||
|
||||
acc.push_back(instruction::mk_filter_interpreted_and_project(src, cond,
|
||||
removed_cols.size(), removed_cols.c_ptr(), result));
|
||||
}
|
||||
|
||||
void compiler::make_select_equal_and_project(reg_idx src, const relation_element & val, unsigned col,
|
||||
reg_idx & result, instruction_block & acc) {
|
||||
relation_signature res_sig;
|
||||
|
@ -499,8 +511,7 @@ namespace datalog {
|
|||
expr * arg = a->get_arg(i);
|
||||
if(is_app(arg)) {
|
||||
app * c = to_app(arg); //argument is a constant
|
||||
SASSERT(c->get_num_args()==0);
|
||||
SASSERT(m_context.get_decl_util().is_numeral_ext(arg));
|
||||
SASSERT(m.is_value(c));
|
||||
reg_idx new_reg;
|
||||
make_select_equal_and_project(single_res, c, single_res_expr.size(), new_reg, acc);
|
||||
if(single_res!=t_reg) {
|
||||
|
@ -620,6 +631,116 @@ namespace datalog {
|
|||
}
|
||||
|
||||
// enforce interpreted tail predicates
|
||||
unsigned ft_len = r->get_tail_size(); // full tail
|
||||
ptr_vector<expr> tail;
|
||||
for (unsigned tail_index = ut_len; tail_index < ft_len; ++tail_index) {
|
||||
tail.push_back(r->get_tail(tail_index));
|
||||
}
|
||||
|
||||
if (!tail.empty()) {
|
||||
app_ref filter_cond(tail.size() == 1 ? to_app(tail.back()) : m.mk_and(tail.size(), tail.c_ptr()), m);
|
||||
ptr_vector<sort> filter_vars;
|
||||
get_free_vars(filter_cond, filter_vars);
|
||||
|
||||
// create binding
|
||||
expr_ref_vector binding(m);
|
||||
binding.resize(filter_vars.size()+1);
|
||||
|
||||
for (unsigned v = 0; v < filter_vars.size(); ++v) {
|
||||
if (!filter_vars[v])
|
||||
continue;
|
||||
|
||||
int2ints::entry * entry = var_indexes.find_core(v);
|
||||
unsigned src_col;
|
||||
if (entry) {
|
||||
src_col = entry->get_data().m_value.back();
|
||||
} else {
|
||||
// we have an unbound variable, so we add an unbound column for it
|
||||
relation_sort unbound_sort = filter_vars[v];
|
||||
|
||||
reg_idx new_reg;
|
||||
bool new_dealloc;
|
||||
make_add_unbound_column(r, 0, head_pred, filtered_res, unbound_sort, new_reg, new_dealloc, acc);
|
||||
if (dealloc)
|
||||
make_dealloc_non_void(filtered_res, acc);
|
||||
dealloc = new_dealloc;
|
||||
filtered_res = new_reg;
|
||||
|
||||
src_col = single_res_expr.size();
|
||||
single_res_expr.push_back(m.mk_var(v, unbound_sort));
|
||||
|
||||
entry = var_indexes.insert_if_not_there2(v, unsigned_vector());
|
||||
entry->get_data().m_value.push_back(src_col);
|
||||
}
|
||||
relation_sort var_sort = m_reg_signatures[filtered_res][src_col];
|
||||
binding[filter_vars.size()-v] = m.mk_var(src_col, var_sort);
|
||||
}
|
||||
|
||||
// check if there are any columns to remove
|
||||
unsigned_vector remove_columns;
|
||||
{
|
||||
unsigned_vector var_idx_to_remove;
|
||||
ptr_vector<sort> vars;
|
||||
get_free_vars(r->get_head(), vars);
|
||||
for (int2ints::iterator I = var_indexes.begin(), E = var_indexes.end();
|
||||
I != E; ++I) {
|
||||
unsigned var_idx = I->m_key;
|
||||
if (!vars.get(var_idx, 0)) {
|
||||
unsigned_vector & cols = I->m_value;
|
||||
for (unsigned i = 0; i < cols.size(); ++i) {
|
||||
remove_columns.push_back(cols[i]);
|
||||
}
|
||||
var_idx_to_remove.push_back(var_idx);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < var_idx_to_remove.size(); ++i) {
|
||||
var_indexes.remove(var_idx_to_remove[i]);
|
||||
}
|
||||
|
||||
// update column idx for after projection state
|
||||
if (!remove_columns.empty()) {
|
||||
unsigned_vector offsets;
|
||||
offsets.resize(single_res_expr.size(), 0);
|
||||
|
||||
for (unsigned i = 0; i < remove_columns.size(); ++i) {
|
||||
for (unsigned col = remove_columns[i]; col < offsets.size(); ++col) {
|
||||
++offsets[col];
|
||||
}
|
||||
}
|
||||
|
||||
for (int2ints::iterator I = var_indexes.begin(), E = var_indexes.end();
|
||||
I != E; ++I) {
|
||||
unsigned_vector & cols = I->m_value;
|
||||
for (unsigned i = 0; i < cols.size(); ++i) {
|
||||
cols[i] -= offsets[cols[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expr_ref renamed(m);
|
||||
m_context.get_var_subst()(filter_cond, binding.size(), binding.c_ptr(), renamed);
|
||||
app_ref app_renamed(to_app(renamed), m);
|
||||
if (remove_columns.empty()) {
|
||||
if (!dealloc)
|
||||
make_clone(filtered_res, filtered_res, acc);
|
||||
acc.push_back(instruction::mk_filter_interpreted(filtered_res, app_renamed));
|
||||
} else {
|
||||
reg_idx new_reg;
|
||||
std::sort(remove_columns.begin(), remove_columns.end());
|
||||
make_filter_interpreted_and_project(filtered_res, app_renamed, remove_columns, new_reg, acc);
|
||||
if (dealloc)
|
||||
make_dealloc_non_void(filtered_res, acc);
|
||||
filtered_res = new_reg;
|
||||
}
|
||||
dealloc = true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// this version is potentially better for non-symbolic tables,
|
||||
// since it constraints each unbound column at a time (reducing the
|
||||
// size of intermediate results).
|
||||
unsigned ft_len=r->get_tail_size(); //full tail
|
||||
for(unsigned tail_index=ut_len; tail_index<ft_len; tail_index++) {
|
||||
app * t = r->get_tail(tail_index);
|
||||
|
@ -687,6 +808,7 @@ namespace datalog {
|
|||
acc.push_back(instruction::mk_filter_interpreted(filtered_res, app_renamed));
|
||||
dealloc = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
//put together the columns of head relation
|
||||
|
@ -738,7 +860,7 @@ namespace datalog {
|
|||
make_dealloc_non_void(new_head_reg, acc);
|
||||
}
|
||||
|
||||
finish:
|
||||
// finish:
|
||||
m_instruction_observer.finish_rule();
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,8 @@ namespace datalog {
|
|||
instruction_block & acc);
|
||||
void make_join_project(reg_idx t1, reg_idx t2, const variable_intersection & vars,
|
||||
const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc);
|
||||
void make_filter_interpreted_and_project(reg_idx src, app_ref & cond,
|
||||
const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc);
|
||||
void make_select_equal_and_project(reg_idx src, const relation_element & val, unsigned col,
|
||||
reg_idx & result, instruction_block & acc);
|
||||
/**
|
||||
|
|
434
src/muz_qe/dl_hassel_common.cpp
Executable file
434
src/muz_qe/dl_hassel_common.cpp
Executable file
|
@ -0,0 +1,434 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_hassel_common.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "dl_hassel_common.h"
|
||||
#include "dl_context.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace datalog {
|
||||
|
||||
static void formula_to_dnf_aux(app *and, unsigned idx, std::set<expr*>& conjexpr, std::set<expr*>& toplevel, ast_manager& m) {
|
||||
if (idx == and->get_num_args()) {
|
||||
std::vector<expr*> v(conjexpr.begin(), conjexpr.end());
|
||||
toplevel.insert(m.mk_and((unsigned)v.size(), &v[0]));
|
||||
return;
|
||||
}
|
||||
|
||||
expr *e = and->get_arg(idx);
|
||||
if (is_app(e) && to_app(e)->get_decl_kind() == OP_OR) {
|
||||
app *or = to_app(e);
|
||||
// quick subsumption test: if any of the elements of the OR is already ANDed, then we skip this OR
|
||||
for (unsigned i = 0; i < or->get_num_args(); ++i) {
|
||||
if (conjexpr.count(or->get_arg(i))) {
|
||||
formula_to_dnf_aux(and, idx+1, conjexpr, toplevel, m);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < or->get_num_args(); ++i) {
|
||||
std::set<expr*> conjexpr2(conjexpr);
|
||||
conjexpr2.insert(or->get_arg(i));
|
||||
formula_to_dnf_aux(and, idx+1, conjexpr2, toplevel, m);
|
||||
}
|
||||
} else {
|
||||
conjexpr.insert(e);
|
||||
formula_to_dnf_aux(and, idx+1, conjexpr, toplevel, m);
|
||||
}
|
||||
}
|
||||
|
||||
expr_ref formula_to_dnf(expr_ref f) {
|
||||
app *a = to_app(f);
|
||||
SASSERT(a->get_decl_kind() == OP_AND);
|
||||
std::set<expr*> toplevel, conjexpr;
|
||||
formula_to_dnf_aux(a, 0, conjexpr, toplevel, f.m());
|
||||
|
||||
if (toplevel.size() > 1) {
|
||||
std::vector<expr*> v(toplevel.begin(), toplevel.end());
|
||||
return expr_ref(f.m().mk_or((unsigned)v.size(), &v[0]), f.m());
|
||||
} else {
|
||||
return expr_ref(*toplevel.begin(), f.m());
|
||||
}
|
||||
}
|
||||
|
||||
bool bit_vector::contains(const bit_vector & other) const {
|
||||
unsigned n = num_words();
|
||||
if (n == 0)
|
||||
return true;
|
||||
|
||||
for (unsigned i = 0; i < n - 1; ++i) {
|
||||
if ((m_data[i] & other.m_data[i]) != other.m_data[i])
|
||||
return false;
|
||||
}
|
||||
unsigned bit_rest = m_num_bits % 32;
|
||||
unsigned mask = (1 << bit_rest) - 1;
|
||||
if (mask == 0) mask = UINT_MAX;
|
||||
unsigned other_data = other.m_data[n-1] & mask;
|
||||
return (m_data[n-1] & other_data) == other_data;
|
||||
}
|
||||
|
||||
bool bit_vector::contains(const bit_vector & other, unsigned idx) const {
|
||||
// TODO: optimize this to avoid copy
|
||||
return slice(idx, other.size()).contains(other);
|
||||
}
|
||||
|
||||
bool bit_vector::contains_consecutive_zeros() const {
|
||||
unsigned n = num_words();
|
||||
if (n == 0)
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < n - 1; ++i) {
|
||||
if ((((m_data[i] << 1) | m_data[i]) & 0xAAAAAAAA) != 0xAAAAAAAA)
|
||||
return true;
|
||||
}
|
||||
unsigned bit_rest = m_num_bits % 32;
|
||||
unsigned mask = (1 << bit_rest) - 1;
|
||||
if (mask == 0) mask = UINT_MAX;
|
||||
mask &= 0xAAAAAAAA;
|
||||
return ((((m_data[n-1] << 1) | m_data[n-1]) & mask) != mask);
|
||||
}
|
||||
|
||||
bit_vector bit_vector::slice(unsigned idx, unsigned length) const {
|
||||
bit_vector Res(length);
|
||||
// TODO: optimize w/ memcpy when possible
|
||||
for (unsigned i = idx; i < idx + length; ++i) {
|
||||
Res.push_back(get(i));
|
||||
}
|
||||
SASSERT(Res.size() == length);
|
||||
return Res;
|
||||
}
|
||||
|
||||
void bit_vector::append(const bit_vector & other) {
|
||||
if (other.empty())
|
||||
return;
|
||||
|
||||
if ((m_num_bits % 32) == 0) {
|
||||
unsigned prev_num_bits = m_num_bits;
|
||||
resize(m_num_bits + other.m_num_bits);
|
||||
memcpy(&get_bit_word(prev_num_bits), other.m_data, other.num_words() * sizeof(unsigned));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: optimize the other cases.
|
||||
for (unsigned i = 0; i < other.m_num_bits; ++i) {
|
||||
push_back(other.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
uint64 bit_vector::to_number(unsigned idx, unsigned length) const {
|
||||
SASSERT(length <= 64);
|
||||
uint64 r = 0;
|
||||
for (unsigned i = 0; i < length; ++i) {
|
||||
r = (r << 1) | (uint64)get(idx+i);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool bit_vector::operator<(bit_vector const & other) const {
|
||||
SASSERT(m_num_bits == other.m_num_bits);
|
||||
unsigned n = num_words();
|
||||
if (n == 0)
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < n - 1; ++i) {
|
||||
if (m_data[i] > other.m_data[i])
|
||||
return false;
|
||||
if (m_data[i] < other.m_data[i])
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned bit_rest = m_num_bits % 32;
|
||||
unsigned mask = (1 << bit_rest) - 1;
|
||||
if (mask == 0) mask = UINT_MAX;
|
||||
return (m_data[n-1] & mask) < (other.m_data[n-1] & mask);
|
||||
}
|
||||
|
||||
table_information::table_information(table_plugin & p, const table_signature& sig) :
|
||||
m_column_info(sig.size()+1),
|
||||
m_bv_util(p.get_context().get_manager()),
|
||||
m_decl_util(p.get_context().get_manager()) {
|
||||
|
||||
unsigned column = 0;
|
||||
for (unsigned i = 0; i < sig.size(); ++i) {
|
||||
unsigned num_bits = uint64_log2(sig[i]);
|
||||
SASSERT(num_bits == 64 || (1ULL << num_bits) == sig[i]);
|
||||
m_column_info[i] = column;
|
||||
column += num_bits;
|
||||
}
|
||||
m_column_info[sig.size()] = column;
|
||||
}
|
||||
|
||||
void table_information::expand_column_vector(unsigned_vector& v, const table_information *other) const {
|
||||
unsigned_vector orig;
|
||||
orig.swap(v);
|
||||
|
||||
for (unsigned i = 0; i < orig.size(); ++i) {
|
||||
unsigned col, limit;
|
||||
if (orig[i] < get_num_cols()) {
|
||||
col = column_idx(orig[i]);
|
||||
limit = col + column_num_bits(orig[i]);
|
||||
} else {
|
||||
unsigned idx = orig[i] - get_num_cols();
|
||||
col = get_num_bits() + other->column_idx(idx);
|
||||
limit = col + other->column_num_bits(idx);
|
||||
}
|
||||
|
||||
for (; col < limit; ++col) {
|
||||
v.push_back(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void table_information::display(std::ostream & out) const {
|
||||
out << '<';
|
||||
for (unsigned i = 0; i < get_num_cols(); ++i) {
|
||||
if (i > 0)
|
||||
out << ", ";
|
||||
out << column_num_bits(i);
|
||||
}
|
||||
out << ">\n";
|
||||
}
|
||||
|
||||
ternary_bitvector::ternary_bitvector(unsigned size, bool full) :
|
||||
bit_vector() {
|
||||
resize(size, full);
|
||||
}
|
||||
|
||||
ternary_bitvector::ternary_bitvector(uint64 n, unsigned num_bits) :
|
||||
bit_vector(2 * num_bits) {
|
||||
append_number(n, num_bits);
|
||||
}
|
||||
|
||||
ternary_bitvector::ternary_bitvector(const table_fact& f, const table_information& t) :
|
||||
bit_vector(2 * t.get_num_bits()) {
|
||||
for (unsigned i = 0; i < f.size(); ++i) {
|
||||
SASSERT(t.column_idx(i) == size());
|
||||
append_number(f[i], t.column_num_bits(i));
|
||||
}
|
||||
SASSERT(size() == t.get_num_bits());
|
||||
}
|
||||
|
||||
void ternary_bitvector::fill1() {
|
||||
memset(m_data, 0xFF, m_capacity * sizeof(unsigned));
|
||||
}
|
||||
|
||||
unsigned ternary_bitvector::get(unsigned idx) const {
|
||||
idx *= 2;
|
||||
return (bit_vector::get(idx) << 1) | (unsigned)bit_vector::get(idx+1);
|
||||
}
|
||||
|
||||
void ternary_bitvector::set(unsigned idx, unsigned val) {
|
||||
SASSERT(val == BIT_0 || val == BIT_1 || val == BIT_x);
|
||||
idx *= 2;
|
||||
bit_vector::set(idx, (val >> 1) != 0);
|
||||
bit_vector::set(idx+1, (val & 1) != 0);
|
||||
}
|
||||
|
||||
void ternary_bitvector::push_back(unsigned val) {
|
||||
SASSERT(val == BIT_0 || val == BIT_1 || val == BIT_x);
|
||||
bit_vector::push_back((val >> 1) != 0);
|
||||
bit_vector::push_back((val & 1) != 0);
|
||||
}
|
||||
|
||||
void ternary_bitvector::append_number(uint64 n, unsigned num_bits) {
|
||||
SASSERT(num_bits <= 64);
|
||||
for (int bit = num_bits-1; bit >= 0; --bit) {
|
||||
if (n & (1ULL << bit)) {
|
||||
push_back(BIT_1);
|
||||
} else {
|
||||
push_back(BIT_0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ternary_bitvector::mk_idx_eq(unsigned idx, ternary_bitvector& val) {
|
||||
for (unsigned i = 0; i < val.size(); ++i) {
|
||||
set(idx+i, val.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
ternary_bitvector ternary_bitvector::and(const ternary_bitvector& other) const{
|
||||
ternary_bitvector result(*this);
|
||||
result &= other;
|
||||
return result;
|
||||
}
|
||||
|
||||
void ternary_bitvector::neg(union_ternary_bitvector<ternary_bitvector>& result) const {
|
||||
ternary_bitvector negated;
|
||||
negated.resize(size());
|
||||
|
||||
for (unsigned i = 0; i < size(); ++i) {
|
||||
switch (get(i)) {
|
||||
case BIT_0:
|
||||
negated.fill1();
|
||||
negated.set(i, BIT_1);
|
||||
break;
|
||||
case BIT_1:
|
||||
negated.fill1();
|
||||
negated.set(i, BIT_0);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
result.add_fact(negated);
|
||||
}
|
||||
}
|
||||
|
||||
static void join_fix_eqs(ternary_bitvector& TBV, unsigned idx, unsigned col2_offset,
|
||||
const unsigned_vector& cols1, const unsigned_vector& cols2,
|
||||
union_ternary_bitvector<ternary_bitvector>& result) {
|
||||
if (idx == cols1.size()) {
|
||||
result.add_fact(TBV);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned idx1 = cols1[idx];
|
||||
unsigned idx2 = cols2[idx] + col2_offset;
|
||||
unsigned v1 = TBV.get(idx1);
|
||||
unsigned v2 = TBV.get(idx2);
|
||||
|
||||
if (v1 == BIT_x) {
|
||||
if (v2 == BIT_x) {
|
||||
// both x: duplicate row
|
||||
ternary_bitvector TBV2(TBV);
|
||||
TBV2.set(idx1, BIT_0);
|
||||
TBV2.set(idx2, BIT_0);
|
||||
join_fix_eqs(TBV2, idx+1, col2_offset, cols1, cols2, result);
|
||||
|
||||
TBV.set(idx1, BIT_1);
|
||||
TBV.set(idx2, BIT_1);
|
||||
} else {
|
||||
TBV.set(idx1, v2);
|
||||
}
|
||||
} else if (v2 == BIT_x) {
|
||||
TBV.set(idx2, v1);
|
||||
} else if (v1 != v2) {
|
||||
// columns don't match
|
||||
return;
|
||||
}
|
||||
join_fix_eqs(TBV, idx+1, col2_offset, cols1, cols2, result);
|
||||
}
|
||||
|
||||
void ternary_bitvector::join(const ternary_bitvector& other,
|
||||
const unsigned_vector& cols1,
|
||||
const unsigned_vector& cols2,
|
||||
union_ternary_bitvector<ternary_bitvector>& result) const {
|
||||
ternary_bitvector TBV(*this);
|
||||
TBV.append(other);
|
||||
join_fix_eqs(TBV, 0, size(), cols1, cols2, result);
|
||||
}
|
||||
|
||||
bool ternary_bitvector::project(const unsigned_vector& delcols, ternary_bitvector& result) const {
|
||||
unsigned *rm_cols = delcols.c_ptr();
|
||||
|
||||
for (unsigned i = 0; i < size(); ++i) {
|
||||
if (*rm_cols == i) {
|
||||
++rm_cols;
|
||||
continue;
|
||||
}
|
||||
result.push_back(get(i));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void copy_column(ternary_bitvector& CopyTo, const ternary_bitvector& CopyFrom,
|
||||
unsigned col_dst, unsigned col_src, const table_information& src_table,
|
||||
const table_information& dst_table) {
|
||||
unsigned idx_dst = dst_table.column_idx(col_dst);
|
||||
unsigned idx_src = src_table.column_idx(col_src);
|
||||
unsigned num_bits = dst_table.column_num_bits(col_dst);
|
||||
SASSERT(num_bits == src_table.column_num_bits(col_src));
|
||||
|
||||
for (unsigned i = 0; i < num_bits; ++i) {
|
||||
CopyTo.set(idx_dst+i, CopyFrom.get(idx_src+i));
|
||||
}
|
||||
}
|
||||
|
||||
void ternary_bitvector::rename(const unsigned_vector& cyclecols,
|
||||
const unsigned_vector& out_of_cycle_cols,
|
||||
const table_information& src_table,
|
||||
const table_information& dst_table,
|
||||
ternary_bitvector& result) const {
|
||||
result.resize(dst_table.get_num_bits());
|
||||
|
||||
for (unsigned i = 1; i < cyclecols.size(); ++i) {
|
||||
copy_column(result, *this, cyclecols[i-1], cyclecols[i], src_table, dst_table);
|
||||
}
|
||||
copy_column(result, *this, cyclecols[cyclecols.size()-1], cyclecols[0], src_table, dst_table);
|
||||
|
||||
for (unsigned i = 0; i < out_of_cycle_cols.size(); ++i) {
|
||||
unsigned col = out_of_cycle_cols[i];
|
||||
copy_column(result, *this, col, col, src_table, dst_table);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned ternary_bitvector::size_in_bytes() const {
|
||||
return sizeof(*this) + m_capacity;
|
||||
}
|
||||
|
||||
void ternary_bitvector::display(std::ostream & out) const {
|
||||
for (unsigned i = 0; i < size(); ++i) {
|
||||
switch (get(i)) {
|
||||
case BIT_0:
|
||||
out << '0';
|
||||
break;
|
||||
case BIT_1:
|
||||
out << '1';
|
||||
break;
|
||||
case BIT_x:
|
||||
out << 'x';
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if Z3DEBUG
|
||||
void ternary_bitvector::expand(std::set<bit_vector> & BVs) const {
|
||||
bit_vector BV(m_num_bits);
|
||||
expand(BVs, BV, 0);
|
||||
}
|
||||
|
||||
void ternary_bitvector::expand(std::set<bit_vector> & BVs, bit_vector &BV, unsigned idx) const {
|
||||
if (idx == size()) {
|
||||
BVs.insert(BV);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (get(idx)) {
|
||||
case BIT_0:
|
||||
BV.push_back(false);
|
||||
expand(BVs, BV, idx+1);
|
||||
break;
|
||||
case BIT_1:
|
||||
BV.push_back(true);
|
||||
expand(BVs, BV, idx+1);
|
||||
break;
|
||||
case BIT_x: { // x: duplicate
|
||||
bit_vector BV2(BV);
|
||||
BV.push_back(false);
|
||||
BV2.push_back(true);
|
||||
expand(BVs, BV, idx+1);
|
||||
expand(BVs, BV2, idx+1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
1079
src/muz_qe/dl_hassel_common.h
Executable file
1079
src/muz_qe/dl_hassel_common.h
Executable file
File diff suppressed because it is too large
Load diff
219
src/muz_qe/dl_hassel_diff_table.cpp
Executable file
219
src/muz_qe/dl_hassel_diff_table.cpp
Executable file
|
@ -0,0 +1,219 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_hassel_diff_table.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "ast_printer.h"
|
||||
#include "dl_context.h"
|
||||
#include "dl_util.h"
|
||||
#include "dl_hassel_diff_table.h"
|
||||
|
||||
|
||||
namespace datalog {
|
||||
|
||||
ternary_diff_bitvector::ternary_diff_bitvector(unsigned size, bool full) :
|
||||
m_pos(size, full), m_neg(size) { }
|
||||
|
||||
ternary_diff_bitvector::ternary_diff_bitvector(uint64 n, unsigned num_bits) :
|
||||
m_pos(n, num_bits), m_neg(num_bits) { }
|
||||
|
||||
ternary_diff_bitvector::ternary_diff_bitvector(const ternary_bitvector & tbv) :
|
||||
m_pos(tbv), m_neg(tbv.size()) { }
|
||||
|
||||
bool ternary_diff_bitvector::contains(const ternary_diff_bitvector & other) const {
|
||||
return m_pos.contains(other.m_pos) && other.m_neg.contains(m_neg);
|
||||
}
|
||||
|
||||
bool ternary_diff_bitvector::is_empty() const {
|
||||
if (m_pos.is_empty())
|
||||
return true;
|
||||
|
||||
return m_neg.contains(m_pos);
|
||||
}
|
||||
|
||||
ternary_diff_bitvector ternary_diff_bitvector::and(const ternary_diff_bitvector& other) const {
|
||||
ternary_diff_bitvector result(m_pos.and(other.m_pos));
|
||||
result.m_neg.swap(m_neg.or(other.m_neg));
|
||||
return result;
|
||||
}
|
||||
|
||||
void ternary_diff_bitvector::neg(union_ternary_bitvector<ternary_diff_bitvector>& result) const {
|
||||
// not(A\B) <-> (T\A) U B
|
||||
ternary_diff_bitvector negated(size(), true);
|
||||
negated.m_neg.add_new_fact(m_pos);
|
||||
result.add_fact(negated);
|
||||
|
||||
for (union_ternary_bitvector<ternary_bitvector>::const_iterator I = m_neg.begin(),
|
||||
E = m_neg.end(); I != E; ++I) {
|
||||
result.add_fact(*I);
|
||||
}
|
||||
}
|
||||
|
||||
void ternary_diff_bitvector::subtract(const union_ternary_bitvector<ternary_diff_bitvector>& other,
|
||||
union_ternary_bitvector<ternary_diff_bitvector>& result) const {
|
||||
ternary_diff_bitvector newfact(*this);
|
||||
for (union_ternary_bitvector<ternary_diff_bitvector>::const_iterator I = other.begin(),
|
||||
E = other.end(); I != E; ++I) {
|
||||
if (!I->m_neg.empty()) {
|
||||
NOT_IMPLEMENTED_YET();
|
||||
}
|
||||
newfact.m_neg.add_fact(I->m_pos);
|
||||
}
|
||||
|
||||
if (!newfact.is_empty())
|
||||
result.add_fact(newfact);
|
||||
}
|
||||
|
||||
void ternary_diff_bitvector::join(const ternary_diff_bitvector& other,
|
||||
const unsigned_vector& cols1,
|
||||
const unsigned_vector& cols2,
|
||||
union_ternary_bitvector<ternary_diff_bitvector>& result) const {
|
||||
unsigned new_size = size() + other.size();
|
||||
ternary_diff_bitvector res(new_size);
|
||||
|
||||
res.m_pos = m_pos;
|
||||
res.m_pos.append(other.m_pos);
|
||||
|
||||
for (unsigned i = 0; i < cols1.size(); ++i) {
|
||||
unsigned idx1 = cols1[i];
|
||||
unsigned idx2 = size() + cols2[i];
|
||||
unsigned v1 = res.m_pos.get(idx1);
|
||||
unsigned v2 = res.m_pos.get(idx2);
|
||||
|
||||
if (v1 == BIT_x) {
|
||||
if (v2 == BIT_x) {
|
||||
// add to subtracted TBVs: 1xx0 and 0xx1
|
||||
{
|
||||
ternary_bitvector r(new_size, true);
|
||||
r.set(idx1, BIT_0);
|
||||
r.set(idx2, BIT_1);
|
||||
res.m_neg.add_new_fact(r);
|
||||
}
|
||||
{
|
||||
ternary_bitvector r(new_size, true);
|
||||
r.set(idx1, BIT_1);
|
||||
r.set(idx2, BIT_0);
|
||||
res.m_neg.add_new_fact(r);
|
||||
}
|
||||
} else {
|
||||
res.m_pos.set(idx1, v2);
|
||||
}
|
||||
} else if (v2 == BIT_x) {
|
||||
res.m_pos.set(idx2, v1);
|
||||
} else if (v1 != v2) {
|
||||
// columns don't match
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// handle subtracted TBVs: 1010 -> 1010xxx
|
||||
if (!m_neg.empty()) {
|
||||
ternary_bitvector padding(other.size(), true);
|
||||
for (union_ternary_bitvector<ternary_bitvector>::const_iterator I = m_neg.begin(),
|
||||
E = m_neg.end(); I != E; ++I) {
|
||||
ternary_bitvector BV(*I);
|
||||
BV.append(padding);
|
||||
res.m_neg.add_new_fact(BV);
|
||||
}
|
||||
}
|
||||
|
||||
if (!other.m_neg.empty()) {
|
||||
ternary_bitvector padding(size(), true);
|
||||
for (union_ternary_bitvector<ternary_bitvector>::const_iterator I = other.m_neg.begin(),
|
||||
E = other.m_neg.end(); I != E; ++I) {
|
||||
ternary_bitvector BV(padding);
|
||||
BV.append(*I);
|
||||
res.m_neg.add_new_fact(BV);
|
||||
}
|
||||
}
|
||||
|
||||
result.add_fact(res);
|
||||
}
|
||||
|
||||
bool ternary_diff_bitvector::project(const unsigned_vector& delcols, ternary_diff_bitvector& result) const {
|
||||
m_pos.project(delcols, result.m_pos);
|
||||
if (m_neg.empty())
|
||||
return true;
|
||||
|
||||
ternary_bitvector newneg;
|
||||
for (union_ternary_bitvector<ternary_bitvector>::const_iterator I = m_neg.begin(),
|
||||
E = m_neg.end(); I != E; ++I) {
|
||||
for (unsigned i = 0; i < delcols.size()-1; ++i) {
|
||||
unsigned idx = delcols[i];
|
||||
if (I->get(idx) != BIT_x && m_pos.get(idx) == BIT_x)
|
||||
goto skip_row;
|
||||
}
|
||||
newneg.reset();
|
||||
I->project(delcols, newneg);
|
||||
result.m_neg.add_fact(newneg);
|
||||
skip_row: ;
|
||||
}
|
||||
return !result.is_empty();
|
||||
}
|
||||
|
||||
void ternary_diff_bitvector::rename(const unsigned_vector& cyclecols,
|
||||
const unsigned_vector& out_of_cycle_cols,
|
||||
const table_information& src_table,
|
||||
const table_information& dst_table,
|
||||
ternary_diff_bitvector& result) const {
|
||||
m_pos.rename(cyclecols, out_of_cycle_cols, src_table, dst_table, result.m_pos);
|
||||
m_neg.rename(cyclecols, out_of_cycle_cols, src_table, dst_table, result.m_neg);
|
||||
}
|
||||
|
||||
unsigned ternary_diff_bitvector::get(unsigned idx) {
|
||||
return m_pos.get(idx);
|
||||
}
|
||||
|
||||
void ternary_diff_bitvector::set(unsigned idx, unsigned val) {
|
||||
m_pos.set(idx, val);
|
||||
}
|
||||
|
||||
void ternary_diff_bitvector::swap(ternary_diff_bitvector & other) {
|
||||
m_pos.swap(other.m_pos);
|
||||
m_neg.swap(other.m_neg);
|
||||
}
|
||||
|
||||
void ternary_diff_bitvector::reset() {
|
||||
m_pos.reset();
|
||||
m_neg.reset();
|
||||
}
|
||||
|
||||
void ternary_diff_bitvector::display(std::ostream & out) const {
|
||||
m_pos.display(out);
|
||||
if (!m_neg.empty()) {
|
||||
out << " \\ ";
|
||||
if (m_neg.num_disjs() > 1) out << '(';
|
||||
m_neg.display(out);
|
||||
if (m_neg.num_disjs() > 1) out << ')';
|
||||
}
|
||||
}
|
||||
|
||||
unsigned ternary_diff_bitvector::size_in_bytes() const {
|
||||
return m_pos.size_in_bytes() + m_neg.num_bytes();
|
||||
}
|
||||
|
||||
#if Z3DEBUG
|
||||
void ternary_diff_bitvector::expand(std::set<bit_vector> & BVs) const {
|
||||
m_pos.expand(BVs);
|
||||
SASSERT(!BVs.empty());
|
||||
|
||||
std::set<bit_vector> NegBVs;
|
||||
m_neg.expand(NegBVs);
|
||||
BVs.erase(NegBVs.begin(), NegBVs.end());
|
||||
}
|
||||
#endif
|
||||
|
||||
hassel_diff_table_plugin::hassel_diff_table_plugin(relation_manager & manager)
|
||||
: common_hassel_table_plugin(symbol("hassel_diff"), manager) {}
|
||||
|
||||
}
|
87
src/muz_qe/dl_hassel_diff_table.h
Executable file
87
src/muz_qe/dl_hassel_diff_table.h
Executable file
|
@ -0,0 +1,87 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_hassel_diff_table.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _DL_HASSEL_DIFF_TABLE_H_
|
||||
#define _DL_HASSEL_DIFF_TABLE_H_
|
||||
|
||||
#include "dl_hassel_common.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
class hassel_diff_table;
|
||||
|
||||
class ternary_diff_bitvector {
|
||||
// pos \ (neg0 \/ ... \/ negn)
|
||||
ternary_bitvector m_pos;
|
||||
union_ternary_bitvector<ternary_bitvector> m_neg;
|
||||
|
||||
public:
|
||||
ternary_diff_bitvector() : m_pos(), m_neg(0) {}
|
||||
ternary_diff_bitvector(unsigned size) : m_pos(size), m_neg(size) {}
|
||||
ternary_diff_bitvector(unsigned size, bool full);
|
||||
ternary_diff_bitvector(uint64 n, unsigned num_bits);
|
||||
ternary_diff_bitvector(const ternary_bitvector & tbv);
|
||||
|
||||
bool contains(const ternary_diff_bitvector & other) const;
|
||||
bool is_empty() const;
|
||||
|
||||
ternary_diff_bitvector and(const ternary_diff_bitvector& other) const;
|
||||
void neg(union_ternary_bitvector<ternary_diff_bitvector>& result) const;
|
||||
|
||||
static bool has_subtract() { return true; }
|
||||
void subtract(const union_ternary_bitvector<ternary_diff_bitvector>& other,
|
||||
union_ternary_bitvector<ternary_diff_bitvector>& result) const;
|
||||
|
||||
void join(const ternary_diff_bitvector& other, const unsigned_vector& cols1,
|
||||
const unsigned_vector& cols2, union_ternary_bitvector<ternary_diff_bitvector>& result) const;
|
||||
|
||||
bool project(const unsigned_vector& delcols, ternary_diff_bitvector& result) const;
|
||||
|
||||
void rename(const unsigned_vector& cyclecols, const unsigned_vector& out_of_cycle_cols,
|
||||
const table_information& src_table, const table_information& dst_table,
|
||||
ternary_diff_bitvector& result) const;
|
||||
|
||||
unsigned get(unsigned idx);
|
||||
void set(unsigned idx, unsigned val);
|
||||
|
||||
void swap(ternary_diff_bitvector & other);
|
||||
void reset();
|
||||
|
||||
unsigned size() const { return m_pos.size(); }
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
unsigned size_in_bytes() const;
|
||||
|
||||
#if Z3DEBUG
|
||||
void expand(std::set<bit_vector> & BVs) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef union_ternary_bitvector<ternary_diff_bitvector> union_ternary_diff_bitvector;
|
||||
|
||||
class hassel_diff_table : public common_hassel_table<union_ternary_diff_bitvector> {
|
||||
public:
|
||||
hassel_diff_table(table_plugin & p, const table_signature & sig) :
|
||||
common_hassel_table(p, sig) {}
|
||||
};
|
||||
|
||||
class hassel_diff_table_plugin : public common_hassel_table_plugin<hassel_diff_table> {
|
||||
public:
|
||||
hassel_diff_table_plugin(relation_manager & manager);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
27
src/muz_qe/dl_hassel_table.cpp
Normal file
27
src/muz_qe/dl_hassel_table.cpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_hassel_table.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "ast_printer.h"
|
||||
#include "dl_context.h"
|
||||
#include "dl_util.h"
|
||||
#include "dl_hassel_table.h"
|
||||
|
||||
|
||||
namespace datalog {
|
||||
|
||||
hassel_table_plugin::hassel_table_plugin(relation_manager & manager)
|
||||
: common_hassel_table_plugin(symbol("hassel"), manager) {}
|
||||
|
||||
}
|
39
src/muz_qe/dl_hassel_table.h
Normal file
39
src/muz_qe/dl_hassel_table.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_hassel_table.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _DL_HASSEL_TABLE_H_
|
||||
#define _DL_HASSEL_TABLE_H_
|
||||
|
||||
#include "dl_hassel_common.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
class hassel_table;
|
||||
typedef union_ternary_bitvector<ternary_bitvector> union_ternary_bitvectors;
|
||||
|
||||
class hassel_table : public common_hassel_table<union_ternary_bitvectors> {
|
||||
public:
|
||||
hassel_table(table_plugin & p, const table_signature & sig) :
|
||||
common_hassel_table(p, sig) {}
|
||||
};
|
||||
|
||||
class hassel_table_plugin : public common_hassel_table_plugin<hassel_table> {
|
||||
public:
|
||||
hassel_table_plugin(relation_manager & manager);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -526,6 +526,64 @@ namespace datalog {
|
|||
return alloc(instr_filter_interpreted, reg, condition);
|
||||
}
|
||||
|
||||
class instr_filter_interpreted_and_project : public instruction {
|
||||
reg_idx m_src;
|
||||
reg_idx m_res;
|
||||
app_ref m_cond;
|
||||
unsigned_vector m_cols;
|
||||
public:
|
||||
instr_filter_interpreted_and_project(reg_idx src, app_ref & condition,
|
||||
unsigned col_cnt, const unsigned * removed_cols, reg_idx result)
|
||||
: m_src(src), m_cond(condition), m_cols(col_cnt, removed_cols),
|
||||
m_res(result) {}
|
||||
|
||||
virtual bool perform(execution_context & ctx) {
|
||||
if (!ctx.reg(m_src)) {
|
||||
ctx.make_empty(m_res);
|
||||
return true;
|
||||
}
|
||||
|
||||
relation_transformer_fn * fn;
|
||||
relation_base & reg = *ctx.reg(m_src);
|
||||
if (!find_fn(reg, fn)) {
|
||||
fn = reg.get_manager().mk_filter_interpreted_and_project_fn(reg, m_cond, m_cols.size(), m_cols.c_ptr());
|
||||
if (!fn) {
|
||||
throw default_exception(
|
||||
"trying to perform unsupported filter_interpreted_and_project operation on a relation of kind %s",
|
||||
reg.get_plugin().get_name().bare_str());
|
||||
}
|
||||
store_fn(reg, fn);
|
||||
}
|
||||
|
||||
ctx.set_reg(m_res, (*fn)(reg));
|
||||
|
||||
if (ctx.eager_emptiness_checking() && ctx.reg(m_res)->empty()) {
|
||||
ctx.make_empty(m_res);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
|
||||
out << "filter_interpreted_and_project " << m_src << " into " << m_res;
|
||||
out << " using " << mk_pp(m_cond, m_cond.get_manager());
|
||||
out << " deleting columns ";
|
||||
print_container(m_cols, out);
|
||||
}
|
||||
|
||||
virtual void make_annotations(execution_context & ctx) {
|
||||
std::stringstream s;
|
||||
std::string a = "rel_src";
|
||||
ctx.get_register_annotation(m_src, a);
|
||||
s << "filter_interpreted_and_project " << mk_pp(m_cond, m_cond.get_manager());
|
||||
ctx.set_register_annotation(m_res, s.str());
|
||||
}
|
||||
};
|
||||
|
||||
instruction * instruction::mk_filter_interpreted_and_project(reg_idx reg, app_ref & condition,
|
||||
unsigned col_cnt, const unsigned * removed_cols, reg_idx result) {
|
||||
return alloc(instr_filter_interpreted_and_project, reg, condition, col_cnt, removed_cols, result);
|
||||
}
|
||||
|
||||
|
||||
class instr_union : public instruction {
|
||||
reg_idx m_src;
|
||||
|
@ -592,6 +650,7 @@ namespace datalog {
|
|||
}
|
||||
}
|
||||
|
||||
SASSERT(r_src.get_signature().size() == r_tgt.get_signature().size());
|
||||
TRACE("dl_verbose", r_tgt.display(tout <<"pre-union:"););
|
||||
|
||||
(*fn)(r_tgt, r_src, r_delta);
|
||||
|
|
|
@ -260,6 +260,8 @@ namespace datalog {
|
|||
static instruction * mk_filter_equal(ast_manager & m, reg_idx reg, const relation_element & value, unsigned col);
|
||||
static instruction * mk_filter_identical(reg_idx reg, unsigned col_cnt, const unsigned * identical_cols);
|
||||
static instruction * mk_filter_interpreted(reg_idx reg, app_ref & condition);
|
||||
static instruction * mk_filter_interpreted_and_project(reg_idx src, app_ref & condition,
|
||||
unsigned col_cnt, const unsigned * removed_cols, reg_idx result);
|
||||
static instruction * mk_union(reg_idx src, reg_idx tgt, reg_idx delta);
|
||||
static instruction * mk_widen(reg_idx src, reg_idx tgt, reg_idx delta);
|
||||
static instruction * mk_projection(reg_idx src, unsigned col_cnt, const unsigned * removed_cols,
|
||||
|
|
|
@ -141,13 +141,17 @@ namespace datalog {
|
|||
func_decl_ref_vector const& new_funcs() const { return m_new_funcs; }
|
||||
|
||||
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
|
||||
bool found = false;
|
||||
for (unsigned j = 0; !found && j < num; ++j) {
|
||||
found = m_util.is_mkbv(args[j]);
|
||||
}
|
||||
if (!found) {
|
||||
if (num == 0) {
|
||||
if (m_src->is_output_predicate(f))
|
||||
m_dst->set_output_predicate(f);
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < num; ++i) {
|
||||
if (!m_util.is_mkbv(args[i]))
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
//
|
||||
// f(mk_bv(args),...)
|
||||
//
|
||||
|
@ -260,7 +264,7 @@ namespace datalog {
|
|||
m_rewriter.m_cfg.set_dst(result);
|
||||
for (unsigned i = 0; !m_context.canceled() && i < sz; ++i) {
|
||||
rule * r = source.get_rule(i);
|
||||
r->to_formula(fml);
|
||||
r->to_formula(fml);
|
||||
if (blast(r, fml)) {
|
||||
proof_ref pr(m);
|
||||
if (m_context.generate_proof_trace()) {
|
||||
|
@ -275,6 +279,13 @@ namespace datalog {
|
|||
result->add_rule(r);
|
||||
}
|
||||
}
|
||||
|
||||
// copy output predicates without any rule (bit-blasting not really needed)
|
||||
const func_decl_set& decls = source.get_output_predicates();
|
||||
for (func_decl_set::iterator I = decls.begin(), E = decls.end(); I != E; ++I) {
|
||||
if (!source.contains(*I))
|
||||
result->set_output_predicate(*I);
|
||||
}
|
||||
|
||||
if (m_context.get_model_converter()) {
|
||||
filter_model_converter* fmc = alloc(filter_model_converter, m);
|
||||
|
|
|
@ -37,6 +37,7 @@ Revision History:
|
|||
#include"bool_rewriter.h"
|
||||
#include"dl_mk_backwards.h"
|
||||
#include"dl_mk_loop_counter.h"
|
||||
#include "for_each_expr.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
|
@ -47,7 +48,8 @@ namespace datalog {
|
|||
m(ctx.get_manager()),
|
||||
rm(ctx.get_rule_manager()),
|
||||
m_inner_ctx(m, ctx.get_fparams()),
|
||||
a(m) {
|
||||
a(m),
|
||||
m_pinned(m) {
|
||||
params_ref params;
|
||||
params.set_sym("default_relation", symbol("karr_relation"));
|
||||
params.set_sym("engine", symbol("datalog"));
|
||||
|
@ -201,29 +203,27 @@ namespace datalog {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mk_loop_counter lc(m_ctx);
|
||||
mk_backwards bwd(m_ctx);
|
||||
|
||||
scoped_ptr<rule_set> src_loop = lc(source);
|
||||
TRACE("dl", src_loop->display(tout << "source loop\n"););
|
||||
|
||||
// run propagation forwards, then backwards
|
||||
scoped_ptr<rule_set> src_annot = update_using_propagation(*src_loop, *src_loop);
|
||||
TRACE("dl", src_annot->display(tout << "updated using propagation\n"););
|
||||
get_invariants(*src_loop);
|
||||
|
||||
#if 0
|
||||
// figure out whether to update same rules as used for saturation.
|
||||
scoped_ptr<rule_set> rev_source = bwd(*src_annot);
|
||||
src_annot = update_using_propagation(*src_annot, *rev_source);
|
||||
#endif
|
||||
scoped_ptr<rule_set> rev_source = bwd(*src_loop);
|
||||
get_invariants(*rev_source);
|
||||
scoped_ptr<rule_set> src_annot = update_rules(*src_loop);
|
||||
rule_set* rules = lc.revert(*src_annot);
|
||||
rules->inherit_predicates(source);
|
||||
TRACE("dl", rules->display(tout););
|
||||
m_pinned.reset();
|
||||
m_fun2inv.reset();
|
||||
return rules;
|
||||
}
|
||||
|
||||
rule_set* mk_karr_invariants::update_using_propagation(rule_set const& src, rule_set const& srcref) {
|
||||
void mk_karr_invariants::get_invariants(rule_set const& src) {
|
||||
m_inner_ctx.reset();
|
||||
rel_context& rctx = m_inner_ctx.get_rel_context();
|
||||
ptr_vector<func_decl> heads;
|
||||
|
@ -232,19 +232,41 @@ namespace datalog {
|
|||
m_inner_ctx.register_predicate(*fit, false);
|
||||
}
|
||||
m_inner_ctx.ensure_opened();
|
||||
m_inner_ctx.replace_rules(srcref);
|
||||
m_inner_ctx.replace_rules(src);
|
||||
m_inner_ctx.close();
|
||||
rule_set::decl2rules::iterator dit = srcref.begin_grouped_rules();
|
||||
rule_set::decl2rules::iterator dend = srcref.end_grouped_rules();
|
||||
rule_set::decl2rules::iterator dit = src.begin_grouped_rules();
|
||||
rule_set::decl2rules::iterator dend = src.end_grouped_rules();
|
||||
for (; dit != dend; ++dit) {
|
||||
heads.push_back(dit->m_key);
|
||||
}
|
||||
m_inner_ctx.rel_query(heads.size(), heads.c_ptr());
|
||||
|
||||
rule_set* dst = alloc(rule_set, m_ctx);
|
||||
|
||||
// retrieve invariants.
|
||||
dit = src.begin_grouped_rules();
|
||||
for (; dit != dend; ++dit) {
|
||||
func_decl* p = dit->m_key;
|
||||
relation_base* rb = rctx.try_get_relation(p);
|
||||
if (rb) {
|
||||
expr_ref fml(m);
|
||||
rb->to_formula(fml);
|
||||
if (m.is_true(fml)) {
|
||||
continue;
|
||||
}
|
||||
expr* inv = 0;
|
||||
if (m_fun2inv.find(p, inv)) {
|
||||
fml = m.mk_and(inv, fml);
|
||||
}
|
||||
m_pinned.push_back(fml);
|
||||
m_fun2inv.insert(p, fml);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rule_set* mk_karr_invariants::update_rules(rule_set const& src) {
|
||||
scoped_ptr<rule_set> dst = alloc(rule_set, m_ctx);
|
||||
rule_set::iterator it = src.begin(), end = src.end();
|
||||
for (; it != end; ++it) {
|
||||
update_body(rctx, *dst, **it);
|
||||
update_body(*dst, **it);
|
||||
}
|
||||
if (m_ctx.get_model_converter()) {
|
||||
add_invariant_model_converter* kmc = alloc(add_invariant_model_converter, m);
|
||||
|
@ -252,10 +274,8 @@ namespace datalog {
|
|||
rule_set::decl2rules::iterator gend = src.end_grouped_rules();
|
||||
for (; git != gend; ++git) {
|
||||
func_decl* p = git->m_key;
|
||||
expr_ref fml(m);
|
||||
relation_base* rb = rctx.try_get_relation(p);
|
||||
if (rb) {
|
||||
rb->to_formula(fml);
|
||||
expr* fml = 0;
|
||||
if (m_fun2inv.find(p, fml)) {
|
||||
kmc->add(p, fml);
|
||||
}
|
||||
}
|
||||
|
@ -263,10 +283,10 @@ namespace datalog {
|
|||
}
|
||||
|
||||
dst->inherit_predicates(src);
|
||||
return dst;
|
||||
return dst.detach();
|
||||
}
|
||||
|
||||
void mk_karr_invariants::update_body(rel_context& rctx, rule_set& rules, rule& r) {
|
||||
void mk_karr_invariants::update_body(rule_set& rules, rule& r) {
|
||||
unsigned utsz = r.get_uninterpreted_tail_size();
|
||||
unsigned tsz = r.get_tail_size();
|
||||
app_ref_vector tail(m);
|
||||
|
@ -275,17 +295,17 @@ namespace datalog {
|
|||
tail.push_back(r.get_tail(i));
|
||||
}
|
||||
for (unsigned i = 0; i < utsz; ++i) {
|
||||
func_decl* q = r.get_decl(i);
|
||||
relation_base* rb = rctx.try_get_relation(r.get_decl(i));
|
||||
if (rb) {
|
||||
rb->to_formula(fml);
|
||||
func_decl* q = r.get_decl(i);
|
||||
expr* fml = 0;
|
||||
if (m_fun2inv.find(q, fml)) {
|
||||
expr_safe_replace rep(m);
|
||||
for (unsigned j = 0; j < q->get_arity(); ++j) {
|
||||
rep.insert(m.mk_var(j, q->get_domain(j)),
|
||||
r.get_tail(i)->get_arg(j));
|
||||
}
|
||||
rep(fml);
|
||||
tail.push_back(to_app(fml));
|
||||
expr_ref tmp(fml, m);
|
||||
rep(tmp);
|
||||
tail.push_back(to_app(tmp));
|
||||
}
|
||||
}
|
||||
rule* new_rule = &r;
|
||||
|
@ -1029,16 +1049,17 @@ namespace datalog {
|
|||
class karr_relation_plugin::filter_equal_fn : public relation_mutator_fn {
|
||||
unsigned m_col;
|
||||
rational m_value;
|
||||
bool m_valid;
|
||||
public:
|
||||
filter_equal_fn(relation_manager & m, const relation_element & value, unsigned col)
|
||||
: m_col(col) {
|
||||
arith_util arith(m.get_context().get_manager());
|
||||
VERIFY(arith.is_numeral(value, m_value));
|
||||
m_valid = arith.is_numeral(value, m_value) && m_value.is_int();
|
||||
}
|
||||
|
||||
virtual void operator()(relation_base & _r) {
|
||||
karr_relation & r = get(_r);
|
||||
if (m_value.is_int()) {
|
||||
if (m_valid) {
|
||||
r.get_ineqs();
|
||||
vector<rational> row;
|
||||
row.resize(r.get_signature().size());
|
||||
|
@ -1054,7 +1075,7 @@ namespace datalog {
|
|||
|
||||
relation_mutator_fn * karr_relation_plugin::mk_filter_equal_fn(const relation_base & r,
|
||||
const relation_element & value, unsigned col) {
|
||||
if(check_kind(r)) {
|
||||
if (check_kind(r)) {
|
||||
return alloc(filter_equal_fn, get_manager(), value, col);
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -55,8 +55,13 @@ namespace datalog {
|
|||
rule_manager& rm;
|
||||
context m_inner_ctx;
|
||||
arith_util a;
|
||||
void update_body(rel_context& rctx, rule_set& result, rule& r);
|
||||
rule_set* update_using_propagation(rule_set const& src, rule_set const& srcref);
|
||||
obj_map<func_decl, expr*> m_fun2inv;
|
||||
ast_ref_vector m_pinned;
|
||||
|
||||
void get_invariants(rule_set const& src);
|
||||
|
||||
void update_body(rule_set& result, rule& r);
|
||||
rule_set* update_rules(rule_set const& src);
|
||||
public:
|
||||
mk_karr_invariants(context & ctx, unsigned priority);
|
||||
|
||||
|
@ -89,12 +94,7 @@ namespace datalog {
|
|||
{}
|
||||
|
||||
virtual bool can_handle_signature(const relation_signature & sig) {
|
||||
for (unsigned i = 0; i < sig.size(); ++i) {
|
||||
if (a.is_int(sig[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static symbol get_name() { return symbol("karr_relation"); }
|
||||
|
|
|
@ -710,6 +710,7 @@ namespace datalog {
|
|||
void mk_slice::declare_predicates(rule_set const& src, rule_set& dst) {
|
||||
obj_map<func_decl, bit_vector>::iterator it = m_sliceable.begin(), end = m_sliceable.end();
|
||||
ptr_vector<sort> domain;
|
||||
bool has_output = false;
|
||||
func_decl* f;
|
||||
for (; it != end; ++it) {
|
||||
domain.reset();
|
||||
|
@ -731,8 +732,13 @@ namespace datalog {
|
|||
}
|
||||
else if (src.is_output_predicate(p)) {
|
||||
dst.set_output_predicate(p);
|
||||
has_output = true;
|
||||
}
|
||||
}
|
||||
// disable slicing if the output predicates don't occur in rules.
|
||||
if (!has_output) {
|
||||
m_predicates.reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool mk_slice::rule_updated(rule const& r) {
|
||||
|
|
|
@ -269,7 +269,7 @@ namespace datalog {
|
|||
unsigned_vector r1_tables_indexes;
|
||||
unsigned_vector r2_tables_indexes;
|
||||
for (unsigned i = 0; i < num_rels1; ++i) {
|
||||
if(is_tableish_relation(*r1[i])) {
|
||||
if (is_tableish_relation(*r1[i])) {
|
||||
r1_tables_indexes.push_back(i);
|
||||
continue;
|
||||
}
|
||||
|
@ -291,7 +291,7 @@ namespace datalog {
|
|||
if (!found) {
|
||||
relation_plugin & r1_plugin = get_nonsieve_plugin(*r1[i]);
|
||||
relation_base* rel2;
|
||||
if(r1_plugin.can_handle_signature(r2_sig)) {
|
||||
if (r1_plugin.can_handle_signature(r2_sig)) {
|
||||
rel2 = r1_plugin.mk_full(p, r2_sig, r1_kind);
|
||||
}
|
||||
else {
|
||||
|
@ -307,7 +307,7 @@ namespace datalog {
|
|||
}
|
||||
}
|
||||
for (unsigned i = 0; i < num_rels2; ++i) {
|
||||
if(is_tableish_relation(*r2[i])) {
|
||||
if (is_tableish_relation(*r2[i])) {
|
||||
r2_tables_indexes.push_back(i);
|
||||
continue;
|
||||
}
|
||||
|
@ -315,7 +315,7 @@ namespace datalog {
|
|||
relation_plugin & r2_plugin = get_nonsieve_plugin(*r2[i]);
|
||||
family_id r2_kind = get_nonsieve_kind(*r2[i]);
|
||||
relation_base* rel1;
|
||||
if(r2_plugin.can_handle_signature(r1_sig)) {
|
||||
if (r2_plugin.can_handle_signature(r1_sig)) {
|
||||
rel1 = r2_plugin.mk_full(p, r1_sig, r2_kind);
|
||||
}
|
||||
else {
|
||||
|
@ -331,7 +331,7 @@ namespace datalog {
|
|||
}
|
||||
}
|
||||
|
||||
if(!r1_tables_indexes.empty() && !r2_tables_indexes.empty()) {
|
||||
if (!r1_tables_indexes.empty() && !r2_tables_indexes.empty()) {
|
||||
//We may perhaps want to group the table relations by kinds so that tables of the same kind
|
||||
//get joined...
|
||||
|
||||
|
|
|
@ -720,6 +720,13 @@ namespace datalog {
|
|||
return t.get_plugin().mk_filter_interpreted_fn(t, condition);
|
||||
}
|
||||
|
||||
relation_transformer_fn * relation_manager::mk_filter_interpreted_and_project_fn(const relation_base & t,
|
||||
app * condition,
|
||||
unsigned removed_col_cnt,
|
||||
const unsigned * removed_cols) {
|
||||
return t.get_plugin().mk_filter_interpreted_and_project_fn(t, condition, removed_col_cnt, removed_cols);
|
||||
}
|
||||
|
||||
|
||||
class relation_manager::default_relation_select_equal_and_project_fn : public relation_transformer_fn {
|
||||
scoped_ptr<relation_mutator_fn> m_filter;
|
||||
|
@ -1387,6 +1394,45 @@ namespace datalog {
|
|||
}
|
||||
|
||||
|
||||
class relation_manager::default_table_filter_interpreted_and_project_fn
|
||||
: public table_transformer_fn {
|
||||
scoped_ptr<table_mutator_fn> m_filter;
|
||||
scoped_ptr<table_transformer_fn> m_project;
|
||||
app_ref m_condition;
|
||||
unsigned_vector m_removed_cols;
|
||||
public:
|
||||
default_table_filter_interpreted_and_project_fn(context & ctx, table_mutator_fn * filter,
|
||||
app * condition, unsigned removed_col_cnt, const unsigned * removed_cols)
|
||||
: m_filter(filter), m_condition(condition, ctx.get_manager()),
|
||||
m_removed_cols(removed_col_cnt, removed_cols) {}
|
||||
|
||||
virtual table_base* operator()(const table_base & tb) {
|
||||
table_base *t2 = tb.clone();
|
||||
(*m_filter)(*t2);
|
||||
if (!m_project) {
|
||||
relation_manager & rmgr = t2->get_plugin().get_manager();
|
||||
m_project = rmgr.mk_project_fn(*t2, m_removed_cols.size(), m_removed_cols.c_ptr());
|
||||
if (!m_project) {
|
||||
throw default_exception("projection does not exist");
|
||||
}
|
||||
}
|
||||
return (*m_project)(*t2);
|
||||
}
|
||||
};
|
||||
|
||||
table_transformer_fn * relation_manager::mk_filter_interpreted_and_project_fn(const table_base & t,
|
||||
app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) {
|
||||
table_transformer_fn * res = t.get_plugin().mk_filter_interpreted_and_project_fn(t, condition, removed_col_cnt, removed_cols);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
table_mutator_fn * filter = mk_filter_interpreted_fn(t, condition);
|
||||
SASSERT(filter);
|
||||
res = alloc(default_table_filter_interpreted_and_project_fn, get_context(), filter, condition, removed_col_cnt, removed_cols);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
table_intersection_filter_fn * relation_manager::mk_filter_by_intersection_fn(const table_base & t,
|
||||
const table_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols) {
|
||||
table_intersection_filter_fn * res = t.get_plugin().mk_filter_by_negation_fn(t, src, joined_col_cnt,
|
||||
|
|
|
@ -55,6 +55,7 @@ namespace datalog {
|
|||
class default_table_filter_equal_fn;
|
||||
class default_table_filter_identical_fn;
|
||||
class default_table_filter_interpreted_fn;
|
||||
class default_table_filter_interpreted_and_project_fn;
|
||||
class default_table_negation_filter_fn;
|
||||
class default_table_filter_not_equal_fn;
|
||||
class default_table_select_equal_and_project_fn;
|
||||
|
@ -350,6 +351,9 @@ namespace datalog {
|
|||
|
||||
relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition);
|
||||
|
||||
relation_transformer_fn * mk_filter_interpreted_and_project_fn(const relation_base & t, app * condition,
|
||||
unsigned removed_col_cnt, const unsigned * removed_cols);
|
||||
|
||||
/**
|
||||
\brief Operations that returns all rows of \c t for which is column \c col equal to \c value
|
||||
with the column \c col removed.
|
||||
|
@ -522,6 +526,9 @@ namespace datalog {
|
|||
|
||||
table_mutator_fn * mk_filter_interpreted_fn(const table_base & t, app * condition);
|
||||
|
||||
table_transformer_fn * mk_filter_interpreted_and_project_fn(const table_base & t, app * condition,
|
||||
unsigned removed_col_cnt, const unsigned * removed_cols);
|
||||
|
||||
/**
|
||||
\brief Operations that returns all rows of \c t for which is column \c col equal to \c value
|
||||
with the column \c col removed.
|
||||
|
|
|
@ -158,7 +158,7 @@ namespace datalog {
|
|||
inner_sig_singleton.push_back(s[i]);
|
||||
inner_columns[i] = inner.can_handle_signature(inner_sig_singleton);
|
||||
}
|
||||
#if Z3DEBUG
|
||||
#if Z3DEBUG
|
||||
//we assume that if a relation plugin can handle two sets of columns separetely,
|
||||
//it can also handle them in one relation
|
||||
relation_signature inner_sig;
|
||||
|
@ -246,7 +246,8 @@ namespace datalog {
|
|||
|
||||
relation_base * sieve_relation_plugin::mk_full(func_decl* p, const relation_signature & s) {
|
||||
relation_signature empty_sig;
|
||||
relation_base * inner = get_manager().mk_full_relation(empty_sig, p, null_family_id);
|
||||
relation_plugin& plugin = get_manager().get_appropriate_plugin(s);
|
||||
relation_base * inner = plugin.mk_full(p, empty_sig, null_family_id);
|
||||
svector<bool> inner_cols;
|
||||
inner_cols.resize(s.size(), false);
|
||||
return mk_from_inner(s, inner_cols, inner);
|
||||
|
|
|
@ -354,6 +354,21 @@ namespace datalog {
|
|||
return alloc(tr_mutator_fn, tfun);
|
||||
}
|
||||
|
||||
relation_transformer_fn * table_relation_plugin::mk_filter_interpreted_and_project_fn(const relation_base & t,
|
||||
app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) {
|
||||
if (!t.from_table())
|
||||
return 0;
|
||||
|
||||
const table_relation & tr = static_cast<const table_relation &>(t);
|
||||
table_transformer_fn * tfun = get_manager().mk_filter_interpreted_and_project_fn(tr.get_table(),
|
||||
condition, removed_col_cnt, removed_cols);
|
||||
SASSERT(tfun);
|
||||
|
||||
relation_signature sig;
|
||||
relation_signature::from_project(t.get_signature(), removed_col_cnt, removed_cols, sig);
|
||||
return alloc(tr_transformer_fn, sig, tfun);
|
||||
}
|
||||
|
||||
class table_relation_plugin::tr_intersection_filter_fn : public relation_intersection_filter_fn {
|
||||
scoped_ptr<table_intersection_filter_fn> m_tfun;
|
||||
public:
|
||||
|
|
|
@ -71,6 +71,8 @@ namespace datalog {
|
|||
virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value,
|
||||
unsigned col);
|
||||
virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition);
|
||||
virtual relation_transformer_fn * mk_filter_interpreted_and_project_fn(const relation_base & t,
|
||||
app * condition, unsigned removed_col_cnt, const unsigned * removed_cols);
|
||||
virtual relation_intersection_filter_fn * mk_filter_by_intersection_fn(const relation_base & t,
|
||||
const relation_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols);
|
||||
virtual relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t,
|
||||
|
|
|
@ -62,6 +62,7 @@ def_module_params('fixedpoint',
|
|||
('print_statistics', BOOL, False, 'print statistics'),
|
||||
('use_utvpi', BOOL, False, 'experimental use UTVPI strategy'),
|
||||
('tab_selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'),
|
||||
('dump_aig', SYMBOL, '', 'Dump clauses in AIG text format (AAG) to the given file name'),
|
||||
))
|
||||
|
||||
|
||||
|
|
|
@ -124,6 +124,15 @@ class horn_tactic : public tactic {
|
|||
|
||||
enum formula_kind { IS_RULE, IS_QUERY, IS_NONE };
|
||||
|
||||
bool is_implication(expr* f) {
|
||||
expr* e1;
|
||||
while (is_forall(f)) {
|
||||
f = to_quantifier(f)->get_expr();
|
||||
}
|
||||
while (m.is_implies(f, e1, f)) ;
|
||||
return is_predicate(f);
|
||||
}
|
||||
|
||||
formula_kind get_formula_kind(expr_ref& f) {
|
||||
expr_ref tmp(f);
|
||||
normalize(tmp);
|
||||
|
@ -149,7 +158,10 @@ class horn_tactic : public tactic {
|
|||
}
|
||||
}
|
||||
if (head) {
|
||||
// f = m.mk_implies(f, head);
|
||||
if (!is_implication(f)) {
|
||||
f = m.mk_and(body.size(), body.c_ptr());
|
||||
f = m.mk_implies(f, head);
|
||||
}
|
||||
return IS_RULE;
|
||||
}
|
||||
else {
|
||||
|
@ -200,6 +212,7 @@ class horn_tactic : public tactic {
|
|||
break;
|
||||
default:
|
||||
msg << "formula is not in Horn fragment: " << mk_pp(g->form(i), m) << "\n";
|
||||
TRACE("horn", tout << msg.str(););
|
||||
throw tactic_exception(msg.str().c_str());
|
||||
}
|
||||
}
|
||||
|
@ -230,7 +243,15 @@ class horn_tactic : public tactic {
|
|||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc) {
|
||||
|
||||
lbool is_reachable = m_ctx.query(q);
|
||||
lbool is_reachable = l_undef;
|
||||
|
||||
try {
|
||||
is_reachable = m_ctx.query(q);
|
||||
}
|
||||
catch (default_exception& ex) {
|
||||
IF_VERBOSE(1, verbose_stream() << ex.msg() << "\n";);
|
||||
throw ex;
|
||||
}
|
||||
g->inc_depth();
|
||||
|
||||
bool produce_models = g->models_enabled();
|
||||
|
|
|
@ -133,6 +133,12 @@ lbool dl_interface::query(expr * query) {
|
|||
--num_unfolds;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_ctx.get_rules().get_output_predicates().empty()) {
|
||||
m_context->set_unsat();
|
||||
return l_false;
|
||||
}
|
||||
|
||||
query_pred = m_ctx.get_rules().get_output_predicate();
|
||||
|
||||
IF_VERBOSE(2, m_ctx.display_rules(verbose_stream()););
|
||||
|
|
|
@ -18,6 +18,9 @@ Revision History:
|
|||
Extracted from dl_context
|
||||
|
||||
--*/
|
||||
|
||||
#define Z3_HASSEL_TABLE
|
||||
|
||||
#include"rel_context.h"
|
||||
#include"dl_context.h"
|
||||
#include"dl_compiler.h"
|
||||
|
@ -30,8 +33,13 @@ Revision History:
|
|||
#include"dl_mk_karr_invariants.h"
|
||||
#include"dl_finite_product_relation.h"
|
||||
#include"dl_sparse_table.h"
|
||||
#ifdef Z3_HASSEL_TABLE
|
||||
# include"dl_hassel_table.h"
|
||||
# include"dl_hassel_diff_table.h"
|
||||
#endif
|
||||
#include"dl_table.h"
|
||||
#include"dl_table_relation.h"
|
||||
#include"aig_exporter.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
|
@ -86,6 +94,10 @@ namespace datalog {
|
|||
get_rmanager().register_plugin(alloc(bitvector_table_plugin, get_rmanager()));
|
||||
get_rmanager().register_plugin(alloc(equivalence_table_plugin, get_rmanager()));
|
||||
|
||||
#ifdef Z3_HASSEL_TABLE
|
||||
get_rmanager().register_plugin(alloc(hassel_table_plugin, get_rmanager()));
|
||||
get_rmanager().register_plugin(alloc(hassel_diff_table_plugin, get_rmanager()));
|
||||
#endif
|
||||
|
||||
// register plugins for builtin relations
|
||||
|
||||
|
@ -127,6 +139,14 @@ namespace datalog {
|
|||
}
|
||||
TRACE("dl", m_context.display(tout););
|
||||
|
||||
if (m_context.get_params().dump_aig().size()) {
|
||||
const char *filename = static_cast<const char*>(m_context.get_params().dump_aig().c_ptr());
|
||||
aig_exporter aig(m_context.get_rules(), get_context(), &m_table_facts);
|
||||
std::ofstream strm(filename, std::ios_base::binary);
|
||||
aig(strm);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
compiler::compile(m_context, m_context.get_rules(), m_code, termination_code);
|
||||
|
||||
TRACE("dl", m_code.display(*this, tout); );
|
||||
|
|
|
@ -28,10 +28,9 @@ Revision History:
|
|||
namespace datalog {
|
||||
|
||||
class context;
|
||||
typedef vector<std::pair<func_decl*,relation_fact> > fact_vector;
|
||||
|
||||
class rel_context {
|
||||
typedef vector<std::pair<func_decl*,relation_fact> > fact_vector;
|
||||
|
||||
context& m_context;
|
||||
ast_manager& m;
|
||||
relation_manager m_rmanager;
|
||||
|
|
|
@ -24,6 +24,7 @@ Revision History:
|
|||
#include"statistics.h"
|
||||
#include"trace.h"
|
||||
#include"warning.h"
|
||||
#include"uint_set.h"
|
||||
|
||||
typedef int dl_var;
|
||||
|
||||
|
@ -306,14 +307,6 @@ private:
|
|||
return true;
|
||||
}
|
||||
|
||||
// Update the assignment of variable v, that is,
|
||||
// m_assignment[v] += inc
|
||||
// This method also stores the old value of v in the assignment stack.
|
||||
void acc_assignment(dl_var v, const numeral & inc) {
|
||||
TRACE("diff_logic_bug", tout << "update v: " << v << " += " << inc << " m_assignment[v] " << m_assignment[v] << "\n";);
|
||||
m_assignment_stack.push_back(assignment_trail(v, m_assignment[v]));
|
||||
m_assignment[v] += inc;
|
||||
}
|
||||
|
||||
// Restore the assignment using the information in m_assignment_stack.
|
||||
// This method is called when make_feasible fails.
|
||||
|
@ -827,6 +820,16 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// Update the assignment of variable v, that is,
|
||||
// m_assignment[v] += inc
|
||||
// This method also stores the old value of v in the assignment stack.
|
||||
void acc_assignment(dl_var v, const numeral & inc) {
|
||||
TRACE("diff_logic_bug", tout << "update v: " << v << " += " << inc << " m_assignment[v] " << m_assignment[v] << "\n";);
|
||||
m_assignment_stack.push_back(assignment_trail(v, m_assignment[v]));
|
||||
m_assignment[v] += inc;
|
||||
}
|
||||
|
||||
|
||||
struct every_var_proc {
|
||||
bool operator()(dl_var v) const {
|
||||
return true;
|
||||
|
@ -837,6 +840,36 @@ public:
|
|||
display_core(out, every_var_proc());
|
||||
}
|
||||
|
||||
void display_agl(std::ostream & out) const {
|
||||
uint_set vars;
|
||||
typename edges::const_iterator it = m_edges.begin();
|
||||
typename edges::const_iterator end = m_edges.end();
|
||||
for (; it != end; ++it) {
|
||||
edge const& e = *it;
|
||||
if (e.is_enabled()) {
|
||||
vars.insert(e.get_source());
|
||||
vars.insert(e.get_target());
|
||||
}
|
||||
}
|
||||
out << "digraph "" {\n";
|
||||
|
||||
unsigned n = m_assignment.size();
|
||||
for (unsigned v = 0; v < n; v++) {
|
||||
if (vars.contains(v)) {
|
||||
out << "\"" << v << "\" [label=\"" << v << ":" << m_assignment[v] << "\"]\n";
|
||||
}
|
||||
}
|
||||
it = m_edges.begin();
|
||||
for (; it != end; ++it) {
|
||||
edge const& e = *it;
|
||||
if (e.is_enabled()) {
|
||||
out << "\"" << e.get_source() << "\"->\"" << e.get_target() << "\"[label=\"" << e.get_weight() << "\"]\n";
|
||||
}
|
||||
}
|
||||
|
||||
out << "}\n";
|
||||
}
|
||||
|
||||
template<typename FilterAssignmentProc>
|
||||
void display_core(std::ostream & out, FilterAssignmentProc p) const {
|
||||
display_edges(out);
|
||||
|
@ -1000,6 +1033,38 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void compute_zero_succ(dl_var v, int_vector& succ) {
|
||||
unsigned n = m_assignment.size();
|
||||
m_dfs_time.reset();
|
||||
m_dfs_time.resize(n, -1);
|
||||
m_dfs_time[v] = 0;
|
||||
succ.push_back(v);
|
||||
numeral gamma;
|
||||
for (unsigned i = 0; i < succ.size(); ++i) {
|
||||
v = succ[i];
|
||||
edge_id_vector & edges = m_out_edges[v];
|
||||
typename edge_id_vector::iterator it = edges.begin();
|
||||
typename edge_id_vector::iterator end = edges.end();
|
||||
for (; it != end; ++it) {
|
||||
edge_id e_id = *it;
|
||||
edge & e = m_edges[e_id];
|
||||
if (!e.is_enabled()) {
|
||||
continue;
|
||||
}
|
||||
SASSERT(e.get_source() == v);
|
||||
set_gamma(e, gamma);
|
||||
if (gamma.is_zero()) {
|
||||
dl_var target = e.get_target();
|
||||
if (m_dfs_time[target] == -1) {
|
||||
succ.push_back(target);
|
||||
m_dfs_time[target] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
numeral get_assignment(dl_var v) const {
|
||||
return m_assignment[v];
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ namespace smt {
|
|||
class parent_trail;
|
||||
|
||||
struct GExt : public Ext {
|
||||
typedef literal explanation;
|
||||
typedef std::pair<literal,unsigned> explanation;
|
||||
};
|
||||
|
||||
class atom {
|
||||
|
@ -113,15 +113,18 @@ namespace smt {
|
|||
// a negative cycle.
|
||||
class nc_functor {
|
||||
literal_vector m_antecedents;
|
||||
unsigned_vector m_coeffs;
|
||||
theory_utvpi& m_super;
|
||||
public:
|
||||
nc_functor(theory_utvpi& s) : m_super(s) {}
|
||||
void reset() { m_antecedents.reset(); }
|
||||
void reset() { m_antecedents.reset(); m_coeffs.reset(); }
|
||||
literal_vector const& get_lits() const { return m_antecedents; }
|
||||
unsigned_vector const& get_coeffs() const { return m_coeffs; }
|
||||
|
||||
void operator()(literal const & ex) {
|
||||
if (ex != null_literal) {
|
||||
m_antecedents.push_back(ex);
|
||||
void operator()(std::pair<literal,unsigned> const & ex) {
|
||||
if (ex.first != null_literal) {
|
||||
m_antecedents.push_back(ex.first);
|
||||
m_coeffs.push_back(ex.second);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,7 +262,11 @@ namespace smt {
|
|||
|
||||
private:
|
||||
|
||||
rational mk_value(theory_var v);
|
||||
rational mk_value(theory_var v, bool is_int);
|
||||
|
||||
bool is_parity_ok(unsigned v) const;
|
||||
|
||||
void enforce_parity();
|
||||
|
||||
void validate_model();
|
||||
|
||||
|
|
|
@ -33,7 +33,17 @@ Revision History:
|
|||
|
||||
3. Solve for x^+ and x^-
|
||||
4. Check parity condition for integers (see Lahiri and Musuvathi 05)
|
||||
5. extract model for M(x) := (M(x^+)- M(x^-))/2
|
||||
This checks if x^+ and x^- are in the same component but of different
|
||||
parities.
|
||||
5. Enforce parity on variables. This checks if x^+ and x^- have different
|
||||
parities. If they have different parities, the assignment to one
|
||||
of the variables is decremented (choose the variable that is not tightly
|
||||
constrained with 0).
|
||||
The process that adjusts parities converges: Suppose we break a parity
|
||||
of a different variable y while fixing x's parity. A cyclic breaking/fixing
|
||||
of parities implies there is a strongly connected component between x, y
|
||||
and the two polarities of the variables. This contradicts the test in 4.
|
||||
6. extract model for M(x) := (M(x^+)- M(x^-))/2
|
||||
|
||||
--*/
|
||||
|
||||
|
@ -197,6 +207,15 @@ namespace smt {
|
|||
inc_conflicts();
|
||||
literal_vector const& lits = m_nc_functor.get_lits();
|
||||
context & ctx = get_context();
|
||||
IF_VERBOSE(2,
|
||||
verbose_stream() << "conflict:\n";
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
ast_manager& m = get_manager();
|
||||
expr_ref e(m);
|
||||
ctx.literal2expr(lits[i], e);
|
||||
verbose_stream() << mk_pp(e, m) << "\n";
|
||||
}
|
||||
verbose_stream() << "\n";);
|
||||
TRACE("utvpi",
|
||||
tout << "conflict: ";
|
||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||
|
@ -213,7 +232,9 @@ namespace smt {
|
|||
vector<parameter> params;
|
||||
if (get_manager().proofs_enabled()) {
|
||||
params.push_back(parameter(symbol("farkas")));
|
||||
params.resize(lits.size()+1, parameter(rational(1)));
|
||||
for (unsigned i = 0; i < m_nc_functor.get_coeffs().size(); ++i) {
|
||||
params.push_back(parameter(rational(m_nc_functor.get_coeffs()[i])));
|
||||
}
|
||||
}
|
||||
|
||||
ctx.set_conflict(
|
||||
|
@ -386,7 +407,6 @@ namespace smt {
|
|||
template<typename Ext>
|
||||
final_check_status theory_utvpi<Ext>::final_check_eh() {
|
||||
SASSERT(is_consistent());
|
||||
TRACE("utvpi", display(tout););
|
||||
if (can_propagate()) {
|
||||
propagate();
|
||||
return FC_CONTINUE;
|
||||
|
@ -413,7 +433,7 @@ namespace smt {
|
|||
unsigned sz = get_num_vars();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
enode* e = get_enode(i);
|
||||
if (a.is_int(e->get_owner())) {
|
||||
if (!a.is_int(e->get_owner())) {
|
||||
continue;
|
||||
}
|
||||
th_var v1 = to_var(i);
|
||||
|
@ -500,7 +520,7 @@ namespace smt {
|
|||
|
||||
template<typename Ext>
|
||||
theory_var theory_utvpi<Ext>::mk_term(app* n) {
|
||||
TRACE("utvpi", tout << mk_pp(n, get_manager()) << "\n";);
|
||||
TRACE("utvpi", tout << mk_pp(n, get_manager()) << "\n";);
|
||||
context& ctx = get_context();
|
||||
|
||||
bool cl = m_test.linearize(n);
|
||||
|
@ -508,7 +528,7 @@ namespace smt {
|
|||
found_non_utvpi_expr(n);
|
||||
return null_theory_var;
|
||||
}
|
||||
|
||||
|
||||
coeffs coeffs;
|
||||
rational w;
|
||||
mk_coeffs(m_test.get_linearization(), coeffs, w);
|
||||
|
@ -620,28 +640,28 @@ namespace smt {
|
|||
edge_id id = m_graph.get_num_edges();
|
||||
th_var w1 = to_var(v1), w2 = to_var(v2);
|
||||
if (terms.size() == 1 && pos1) {
|
||||
m_graph.add_edge(neg(w1), pos(w1), -weight-weight, l);
|
||||
m_graph.add_edge(neg(w1), pos(w1), -weight-weight, l);
|
||||
m_graph.add_edge(neg(w1), pos(w1), -weight-weight, std::make_pair(l,2));
|
||||
m_graph.add_edge(neg(w1), pos(w1), -weight-weight, std::make_pair(l,2));
|
||||
}
|
||||
else if (terms.size() == 1 && !pos1) {
|
||||
m_graph.add_edge(pos(w1), neg(w1), -weight-weight, l);
|
||||
m_graph.add_edge(pos(w1), neg(w1), -weight-weight, l);
|
||||
m_graph.add_edge(pos(w1), neg(w1), -weight-weight, std::make_pair(l,2));
|
||||
m_graph.add_edge(pos(w1), neg(w1), -weight-weight, std::make_pair(l,2));
|
||||
}
|
||||
else if (pos1 && pos2) {
|
||||
m_graph.add_edge(neg(w2), pos(w1), -weight, l);
|
||||
m_graph.add_edge(neg(w1), pos(w2), -weight, l);
|
||||
m_graph.add_edge(neg(w2), pos(w1), -weight, std::make_pair(l,1));
|
||||
m_graph.add_edge(neg(w1), pos(w2), -weight, std::make_pair(l,1));
|
||||
}
|
||||
else if (pos1 && !pos2) {
|
||||
m_graph.add_edge(pos(w2), pos(w1), -weight, l);
|
||||
m_graph.add_edge(neg(w1), neg(w2), -weight, l);
|
||||
m_graph.add_edge(pos(w2), pos(w1), -weight, std::make_pair(l,1));
|
||||
m_graph.add_edge(neg(w1), neg(w2), -weight, std::make_pair(l,1));
|
||||
}
|
||||
else if (!pos1 && pos2) {
|
||||
m_graph.add_edge(neg(w2), neg(w1), -weight, l);
|
||||
m_graph.add_edge(pos(w1), pos(w2), -weight, l);
|
||||
m_graph.add_edge(neg(w2), neg(w1), -weight, std::make_pair(l,1));
|
||||
m_graph.add_edge(pos(w1), pos(w2), -weight, std::make_pair(l,1));
|
||||
}
|
||||
else {
|
||||
m_graph.add_edge(pos(w1), neg(w2), -weight, l);
|
||||
m_graph.add_edge(pos(w2), neg(w1), -weight, l);
|
||||
m_graph.add_edge(pos(w1), neg(w2), -weight, std::make_pair(l,1));
|
||||
m_graph.add_edge(pos(w2), neg(w1), -weight, std::make_pair(l,1));
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
@ -656,12 +676,98 @@ namespace smt {
|
|||
return m_graph.is_feasible();
|
||||
}
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_utvpi<Ext>::is_parity_ok(unsigned i) const {
|
||||
th_var v1 = to_var(i);
|
||||
th_var v2 = neg(v1);
|
||||
rational r1 = m_graph.get_assignment(v1).get_rational();
|
||||
rational r2 = m_graph.get_assignment(v2).get_rational();
|
||||
return r1.is_even() == r2.is_even();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief adjust values for variables in the difference graph
|
||||
such that for variables of integer sort it is
|
||||
the case that x^+ - x^- is even.
|
||||
The informal justification for the procedure enforce_parity is that
|
||||
the graph does not contain a strongly connected component where
|
||||
x^+ and x+- are connected. They can be independently changed.
|
||||
Since we would like variables representing 0 (zero) map to 0,
|
||||
we selectively update the subgraph that can be updated without
|
||||
changing the value of zero (which should be 0).
|
||||
*/
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::enforce_parity() {
|
||||
unsigned_vector todo;
|
||||
|
||||
unsigned sz = get_num_vars();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
enode* e = get_enode(i);
|
||||
if (a.is_int(e->get_owner()) && !is_parity_ok(i)) {
|
||||
todo.push_back(i);
|
||||
}
|
||||
}
|
||||
if (todo.empty()) {
|
||||
return;
|
||||
}
|
||||
while (!todo.empty()) {
|
||||
unsigned i = todo.back();
|
||||
todo.pop_back();
|
||||
if (is_parity_ok(i)) {
|
||||
continue;
|
||||
}
|
||||
th_var v1 = to_var(i);
|
||||
th_var v2 = neg(v1);
|
||||
TRACE("utvpi", tout << "disparity: " << v1 << "\n";);
|
||||
int_vector zero_v;
|
||||
m_graph.compute_zero_succ(v1, zero_v);
|
||||
bool found0 = false;
|
||||
for (unsigned j = 0; !found0 && j < zero_v.size(); ++j) {
|
||||
found0 =
|
||||
(to_var(m_zero_int) == zero_v[j]) ||
|
||||
(neg(to_var(m_zero_int)) == zero_v[j]);
|
||||
}
|
||||
// variables that are tightly connected
|
||||
// to 0 should not have their values changed.
|
||||
if (found0) {
|
||||
zero_v.reset();
|
||||
m_graph.compute_zero_succ(v2, zero_v);
|
||||
}
|
||||
TRACE("utvpi",
|
||||
for (unsigned j = 0; j < zero_v.size(); ++j) {
|
||||
tout << "decrement: " << zero_v[j] << "\n";
|
||||
});
|
||||
|
||||
for (unsigned j = 0; j < zero_v.size(); ++j) {
|
||||
int v = zero_v[j];
|
||||
m_graph.acc_assignment(v, numeral(-1));
|
||||
th_var k = from_var(v);
|
||||
if (!is_parity_ok(k)) {
|
||||
TRACE("utvpi", tout << "new disparity: " << k << "\n";);
|
||||
todo.push_back(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
SASSERT(m_graph.is_feasible());
|
||||
DEBUG_CODE(
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
enode* e = get_enode(i);
|
||||
if (a.is_int(e->get_owner()) && !is_parity_ok(i)) {
|
||||
IF_VERBOSE(0, verbose_stream() << "disparities not fixed\n";);
|
||||
UNREACHABLE();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// models:
|
||||
template<typename Ext>
|
||||
void theory_utvpi<Ext>::init_model(model_generator & m) {
|
||||
m_factory = alloc(arith_factory, get_manager());
|
||||
m.register_factory(m_factory);
|
||||
// TBD: enforce strong or tight coherence?
|
||||
enforce_parity();
|
||||
compute_delta();
|
||||
DEBUG_CODE(validate_model(););
|
||||
}
|
||||
|
@ -677,7 +783,8 @@ namespace smt {
|
|||
}
|
||||
bool ok = true;
|
||||
expr* e = ctx.bool_var2expr(b);
|
||||
switch(ctx.get_assignment(b)) {
|
||||
lbool assign = ctx.get_assignment(b);
|
||||
switch(assign) {
|
||||
case l_true:
|
||||
ok = eval(e);
|
||||
break;
|
||||
|
@ -687,7 +794,23 @@ namespace smt {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
CTRACE("utvpi", !ok, tout << "validation failed: " << mk_pp(e, get_manager()) << "\n";);
|
||||
CTRACE("utvpi", !ok,
|
||||
tout << "validation failed:\n";
|
||||
tout << "Assignment: " << assign << "\n";
|
||||
m_atoms[i].display(*this, tout);
|
||||
tout << "\n";
|
||||
display(tout);
|
||||
m_graph.display_agl(tout);
|
||||
);
|
||||
if (!ok) {
|
||||
std::cout << "validation failed:\n";
|
||||
std::cout << "Assignment: " << assign << "\n";
|
||||
m_atoms[i].display(*this, std::cout);
|
||||
std::cout << "\n";
|
||||
display(std::cout);
|
||||
m_graph.display_agl(std::cout);
|
||||
|
||||
}
|
||||
// CTRACE("utvpi", ok, tout << "validation success: " << mk_pp(e, get_manager()) << "\n";);
|
||||
SASSERT(ok);
|
||||
}
|
||||
|
@ -740,7 +863,7 @@ namespace smt {
|
|||
return eval_num(e1);
|
||||
}
|
||||
if (is_uninterp_const(e)) {
|
||||
return mk_value(mk_var(e));
|
||||
return mk_value(mk_var(e), a.is_int(e));
|
||||
}
|
||||
TRACE("utvpi", tout << "expression not handled: " << mk_pp(e, get_manager()) << "\n";);
|
||||
UNREACHABLE();
|
||||
|
@ -749,23 +872,28 @@ namespace smt {
|
|||
|
||||
|
||||
template<typename Ext>
|
||||
rational theory_utvpi<Ext>::mk_value(th_var v) {
|
||||
rational theory_utvpi<Ext>::mk_value(th_var v, bool is_int) {
|
||||
SASSERT(v != null_theory_var);
|
||||
numeral val1 = m_graph.get_assignment(to_var(v));
|
||||
numeral val2 = m_graph.get_assignment(neg(to_var(v)));
|
||||
numeral val = val1 - val2;
|
||||
rational num = val.get_rational() + (m_delta * val.get_infinitesimal().to_rational());
|
||||
num = num/rational(2);
|
||||
num = floor(num);
|
||||
SASSERT(!is_int || num.is_int());
|
||||
TRACE("utvpi",
|
||||
expr* n = get_enode(v)->get_owner();
|
||||
tout << mk_pp(n, get_manager()) << " |-> (" << val1 << " - " << val2 << ")/2 = " << num << "\n";);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
model_value_proc * theory_utvpi<Ext>::mk_value(enode * n, model_generator & mg) {
|
||||
theory_var v = n->get_th_var(get_id());
|
||||
rational num = mk_value(v);
|
||||
bool is_int = a.is_int(n->get_owner());
|
||||
rational num = mk_value(v, is_int);
|
||||
TRACE("utvpi", tout << mk_pp(n->get_owner(), get_manager()) << " |-> " << num << "\n";);
|
||||
return alloc(expr_wrapper_proc, m_factory->mk_value(num, a.is_int(n->get_owner())));
|
||||
return alloc(expr_wrapper_proc, m_factory->mk_value(num, is_int));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -869,11 +869,7 @@ struct aig_manager::imp {
|
|||
|
||||
void mk_ite(aig * n) {
|
||||
aig_lit c, t, e;
|
||||
#ifdef Z3DEBUG
|
||||
bool ok =
|
||||
#endif
|
||||
m.is_ite(n, c, t, e);
|
||||
SASSERT(ok);
|
||||
VERIFY(m.is_ite(n, c, t, e));
|
||||
if (c.is_inverted()) {
|
||||
c.invert();
|
||||
std::swap(t, e);
|
||||
|
|
|
@ -70,7 +70,6 @@ public:
|
|||
void max_sharing(aig_ref & r);
|
||||
void to_formula(aig_ref const & r, expr_ref & result);
|
||||
void to_formula(aig_ref const & r, goal & result);
|
||||
void to_cnf(aig_ref const & r, goal & result);
|
||||
void display(std::ostream & out, aig_ref const & r) const;
|
||||
void display_smt2(std::ostream & out, aig_ref const & r) const;
|
||||
unsigned get_num_aigs() const;
|
||||
|
|
|
@ -30,7 +30,8 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg {
|
|||
expr_ref_vector m_out;
|
||||
fpa2bv_converter & m_conv;
|
||||
sort_ref_vector m_bindings;
|
||||
expr_ref_vector m_mappings;
|
||||
expr_ref_vector m_mappings;
|
||||
|
||||
|
||||
unsigned long long m_max_memory;
|
||||
unsigned m_max_steps;
|
||||
|
@ -166,9 +167,11 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg {
|
|||
|
||||
bool pre_visit(expr * t)
|
||||
{
|
||||
TRACE("fpa2bv", tout << "pre_visit: " << mk_ismt2_pp(t, m()) << std::endl;);
|
||||
|
||||
if (is_quantifier(t)) {
|
||||
quantifier * q = to_quantifier(t);
|
||||
TRACE("fpa2bv", tout << "pre_visit [" << q->get_id() << "]: " << mk_ismt2_pp(q->get_expr(), m()) << std::endl;);
|
||||
TRACE("fpa2bv", tout << "pre_visit quantifier [" << q->get_id() << "]: " << mk_ismt2_pp(q->get_expr(), m()) << std::endl;);
|
||||
sort_ref_vector new_bindings(m_manager);
|
||||
for (unsigned i = 0 ; i < q->get_num_decls(); i++)
|
||||
new_bindings.push_back(q->get_decl_sort(i));
|
||||
|
@ -199,17 +202,9 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg {
|
|||
unsigned ebits = m_conv.fu().get_ebits(s);
|
||||
unsigned sbits = m_conv.fu().get_sbits(s);
|
||||
name_buffer.reset();
|
||||
name_buffer << n << ".exp";
|
||||
name_buffer << n << ".bv";
|
||||
new_decl_names.push_back(symbol(name_buffer.c_str()));
|
||||
new_decl_sorts.push_back(m_conv.bu().mk_sort(ebits));
|
||||
name_buffer.reset();
|
||||
name_buffer << n << ".sig";
|
||||
new_decl_names.push_back(symbol(name_buffer.c_str()));
|
||||
new_decl_sorts.push_back(m_conv.bu().mk_sort(sbits-1));
|
||||
name_buffer.reset();
|
||||
name_buffer << n << ".sgn";
|
||||
new_decl_names.push_back(symbol(name_buffer.c_str()));
|
||||
new_decl_sorts.push_back(m_conv.bu().mk_sort(1));
|
||||
new_decl_sorts.push_back(m_conv.bu().mk_sort(sbits+ebits));
|
||||
}
|
||||
else {
|
||||
new_decl_sorts.push_back(s);
|
||||
|
@ -231,20 +226,26 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg {
|
|||
|
||||
bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr) {
|
||||
if (t->get_idx() >= m_bindings.size())
|
||||
return false;
|
||||
return false;
|
||||
unsigned inx = m_bindings.size() - t->get_idx() - 1;
|
||||
if (m_mappings[inx] == 0)
|
||||
|
||||
expr_ref new_exp(m());
|
||||
sort * s = t->get_sort();
|
||||
if (m_conv.is_float(s))
|
||||
{
|
||||
unsigned shift = 0;
|
||||
for (unsigned i = m_bindings.size() - 1; i > inx; i--)
|
||||
if (m_conv.is_float(m_bindings[i].get())) shift += 2;
|
||||
expr_ref new_var(m());
|
||||
if (m_conv.is_float(t->get_sort()))
|
||||
m_conv.mk_var(t->get_idx() + shift, t->get_sort(), new_var);
|
||||
else
|
||||
new_var = m().mk_var(t->get_idx() + shift, t->get_sort());
|
||||
m_mappings[inx] = new_var;
|
||||
unsigned ebits = m_conv.fu().get_ebits(s);
|
||||
unsigned sbits = m_conv.fu().get_sbits(s);
|
||||
new_var = m().mk_var(t->get_idx(), m_conv.bu().mk_sort(sbits+ebits));
|
||||
m_conv.mk_triple(m_conv.bu().mk_extract(sbits+ebits-1, sbits+ebits-1, new_var),
|
||||
m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var),
|
||||
m_conv.bu().mk_extract(ebits-1, 0, new_var),
|
||||
new_exp);
|
||||
}
|
||||
else
|
||||
new_exp = m().mk_var(t->get_idx(), s);
|
||||
m_mappings[inx] = new_exp;
|
||||
|
||||
result = m_mappings[inx].get();
|
||||
result_pr = 0;
|
||||
TRACE("fpa2bv", tout << "reduce_var: " << mk_ismt2_pp(t, m()) << " -> " << mk_ismt2_pp(result, m()) << std::endl;);
|
||||
|
|
|
@ -28,6 +28,7 @@ COMPILE_TIME_ASSERT(sizeof(unsigned) == 4);
|
|||
#define BV_DEFAULT_CAPACITY 2
|
||||
|
||||
class bit_vector {
|
||||
protected:
|
||||
unsigned m_num_bits;
|
||||
unsigned m_capacity; //!< in words
|
||||
unsigned * m_data;
|
||||
|
@ -64,6 +65,12 @@ public:
|
|||
m_data(0) {
|
||||
}
|
||||
|
||||
bit_vector(unsigned reserve_num_bits) :
|
||||
m_num_bits(0),
|
||||
m_capacity(num_words(reserve_num_bits)),
|
||||
m_data(alloc_svect(unsigned, m_capacity)) {
|
||||
}
|
||||
|
||||
bit_vector(bit_vector const & source):
|
||||
m_num_bits(source.m_num_bits),
|
||||
m_capacity(source.m_capacity),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue