mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 03:32:28 +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
				
			
		|  | @ -907,6 +907,7 @@ void enum_sort_example() { | |||
| } | ||||
| 
 | ||||
| void expr_vector_example() { | ||||
|     std::cout << "expr_vector example\n"; | ||||
|     context c; | ||||
|     const unsigned N = 10; | ||||
| 
 | ||||
|  | @ -928,6 +929,49 @@ void expr_vector_example() { | |||
|     std::cout << "solution\n" << m; | ||||
| } | ||||
| 
 | ||||
| void exists_expr_vector_example() { | ||||
|     std::cout << "exists expr_vector example\n"; | ||||
|     context c; | ||||
|     const unsigned N = 10; | ||||
| 
 | ||||
|     expr_vector xs(c); | ||||
|     expr x(c); | ||||
|     expr b(c); | ||||
|     b = c.bool_val(true);  | ||||
| 
 | ||||
|     for (unsigned i = 0; i < N; i++) {  | ||||
|         std::stringstream x_name;  | ||||
|         x_name << "x_" << i; | ||||
|         x = c.int_const(x_name.str().c_str()); | ||||
|         xs.push_back(x); | ||||
|         b = b && x >= 0; | ||||
|     } | ||||
| 
 | ||||
|     expr ex(c); | ||||
|     ex = exists(xs, b); | ||||
|     std::cout << ex << std::endl; | ||||
| } | ||||
| 
 | ||||
| void substitute_example() { | ||||
|     std::cout << "substitute example\n"; | ||||
|     context c; | ||||
|     expr x(c); | ||||
|     x = c.int_const("x"); | ||||
|     expr f(c); | ||||
|     f = (x == 2) || (x == 1); | ||||
|     std::cout << f << std::endl; | ||||
| 
 | ||||
|     expr two(c), three(c); | ||||
|     two   = c.int_val(2); | ||||
|     three = c.int_val(3); | ||||
|     Z3_ast from[] = { two }; | ||||
|     Z3_ast to[]   = { three }; | ||||
|     expr new_f(c); | ||||
|     new_f = to_expr(c, Z3_substitute(c, f, 1, from, to)); | ||||
|      | ||||
|     std::cout << new_f << std::endl; | ||||
| } | ||||
| 
 | ||||
| int main() { | ||||
|     try { | ||||
|         demorgan(); std::cout << "\n"; | ||||
|  | @ -959,11 +1003,13 @@ int main() { | |||
|         tactic_example9(); std::cout << "\n"; | ||||
|         tactic_qe(); std::cout << "\n"; | ||||
|         tst_visit(); std::cout << "\n"; | ||||
| 	incremental_example1(); std::cout << "\n"; | ||||
| 	incremental_example2(); std::cout << "\n"; | ||||
| 	incremental_example3(); std::cout << "\n"; | ||||
|         incremental_example1(); std::cout << "\n"; | ||||
|         incremental_example2(); std::cout << "\n"; | ||||
|         incremental_example3(); std::cout << "\n"; | ||||
|         enum_sort_example(); std::cout << "\n"; | ||||
|         expr_vector_example(); std::cout << "\n"; | ||||
|         exists_expr_vector_example(); std::cout << "\n"; | ||||
|         substitute_example(); std::cout << "\n"; | ||||
|         std::cout << "done\n"; | ||||
|     } | ||||
|     catch (exception & ex) { | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ def init_project_def(): | |||
|     add_lib('smt_tactic', ['smt'], 'smt/tactic') | ||||
|     add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls') | ||||
|     # TODO: split muz_qe into muz, qe. Perhaps, we should also consider breaking muz into muz and pdr. | ||||
|     add_lib('muz_qe', ['smt', 'sat', 'smt2parser']) | ||||
|     add_lib('muz_qe', ['smt', 'sat', 'smt2parser', 'aig_tactic']) | ||||
|     add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'muz_qe'], 'tactic/smtlogics') | ||||
|     add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv') | ||||
|     add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa', 'aig_tactic', 'muz_qe', 'sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') | ||||
|  |  | |||
|  | @ -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