From 6075ae28fcdf8ce1b1bf13ad1925711aa2adb445 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 20 Feb 2013 19:40:48 +0000 Subject: [PATCH 01/97] ML/Java: Proper use of Datatype API for List/Enum/Constructor Signed-off-by: Christoph M. Wintersteiger --- src/api/dotnet/Constructor.cs | 65 ++++++++++++----------------------- src/api/dotnet/EnumSort.cs | 46 ++++++++----------------- src/api/dotnet/ListSort.cs | 54 +++++++---------------------- src/api/java/Constructor.java | 47 ++++++++++--------------- src/api/java/EnumSort.java | 40 ++++++++++----------- src/api/java/ListSort.java | 46 +++++++++++-------------- 6 files changed, 109 insertions(+), 189 deletions(-) diff --git a/src/api/dotnet/Constructor.cs b/src/api/dotnet/Constructor.cs index 043eb3a1e..527b8bc13 100644 --- a/src/api/dotnet/Constructor.cs +++ b/src/api/dotnet/Constructor.cs @@ -34,8 +34,7 @@ namespace Microsoft.Z3 public uint NumFields { get - { - init(); + { return n; } } @@ -48,8 +47,11 @@ namespace Microsoft.Z3 get { Contract.Ensures(Contract.Result() != null); - init(); - return m_constructorDecl; + IntPtr constructor = IntPtr.Zero; + IntPtr tester = IntPtr.Zero; + IntPtr[] accessors = new IntPtr[n]; + Native.Z3_query_constructor(Context.nCtx, NativeObject, n, ref constructor, ref tester, accessors); + return new FuncDecl(Context, constructor); } } @@ -61,8 +63,11 @@ namespace Microsoft.Z3 get { Contract.Ensures(Contract.Result() != null); - init(); - return m_testerDecl; + IntPtr constructor = IntPtr.Zero; + IntPtr tester = IntPtr.Zero; + IntPtr[] accessors = new IntPtr[n]; + Native.Z3_query_constructor(Context.nCtx, NativeObject, n, ref constructor, ref tester, accessors); + return new FuncDecl(Context, tester); } } @@ -74,8 +79,14 @@ namespace Microsoft.Z3 get { Contract.Ensures(Contract.Result() != null); - init(); - return m_accessorDecls; + IntPtr constructor = IntPtr.Zero; + IntPtr tester = IntPtr.Zero; + IntPtr[] accessors = new IntPtr[n]; + Native.Z3_query_constructor(Context.nCtx, NativeObject, n, ref constructor, ref tester, accessors); + FuncDecl[] t = new FuncDecl[n]; + for (uint i = 0; i < n; i++) + t[i] = new FuncDecl(Context, accessors[i]); + return t; } } @@ -85,25 +96,11 @@ namespace Microsoft.Z3 ~Constructor() { Native.Z3_del_constructor(Context.nCtx, NativeObject); - } - - #region Object invariant - - [ContractInvariantMethod] - private void ObjectInvariant() - { - Contract.Invariant(m_testerDecl == null || m_constructorDecl != null); - Contract.Invariant(m_testerDecl == null || m_accessorDecls != null); - } - - #endregion + } #region Internal - readonly private uint n = 0; - private FuncDecl m_testerDecl = null; - private FuncDecl m_constructorDecl = null; - private FuncDecl[] m_accessorDecls = null; - + private uint n = 0; + internal Constructor(Context ctx, Symbol name, Symbol recognizer, Symbol[] fieldNames, Sort[] sorts, uint[] sortRefs) : base(ctx) @@ -129,24 +126,6 @@ namespace Microsoft.Z3 } - private void init() - { - Contract.Ensures(m_constructorDecl != null); - Contract.Ensures(m_testerDecl != null); - Contract.Ensures(m_accessorDecls != null); - - if (m_testerDecl != null) return; - IntPtr constructor = IntPtr.Zero; - IntPtr tester = IntPtr.Zero; - IntPtr[] accessors = new IntPtr[n]; - Native.Z3_query_constructor(Context.nCtx, NativeObject, n, ref constructor, ref tester, accessors); - m_constructorDecl = new FuncDecl(Context, constructor); - m_testerDecl = new FuncDecl(Context, tester); - m_accessorDecls = new FuncDecl[n]; - for (uint i = 0; i < n; i++) - m_accessorDecls[i] = new FuncDecl(Context, accessors[i]); - } - #endregion } } diff --git a/src/api/dotnet/EnumSort.cs b/src/api/dotnet/EnumSort.cs index 1a9b0536c..e62043078 100644 --- a/src/api/dotnet/EnumSort.cs +++ b/src/api/dotnet/EnumSort.cs @@ -36,8 +36,11 @@ namespace Microsoft.Z3 get { Contract.Ensures(Contract.Result() != null); - - return _constdecls; + uint n = Native.Z3_get_datatype_sort_num_constructors(Context.nCtx, NativeObject); + FuncDecl[] t = new FuncDecl[n]; + for (uint i = 0; i < n; i++) + t[i] = new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor(Context.nCtx, NativeObject, i)); + return t; } } @@ -49,8 +52,11 @@ namespace Microsoft.Z3 get { Contract.Ensures(Contract.Result() != null); - - return _consts; + FuncDecl[] cds = ConstDecls; + Expr[] t = new Expr[cds.Length]; + for (uint i = 0; i < t.Length; i++) + t[i] = Context.MkApp(cds[i]); + return t; } } @@ -62,28 +68,15 @@ namespace Microsoft.Z3 get { Contract.Ensures(Contract.Result() != null); - - return _testerdecls; + uint n = Native.Z3_get_datatype_sort_num_constructors(Context.nCtx, NativeObject); + FuncDecl[] t = new FuncDecl[n]; + for (uint i = 0; i < n; i++) + t[i] = new FuncDecl(Context, Native.Z3_get_datatype_sort_recognizer(Context.nCtx, NativeObject, i)); + return t; } } - #region Object Invariant - - [ContractInvariantMethod] - private void ObjectInvariant() - { - Contract.Invariant(this._constdecls != null); - Contract.Invariant(this._testerdecls != null); - Contract.Invariant(this._consts != null); - } - - - #endregion - #region Internal - readonly private FuncDecl[] _constdecls = null, _testerdecls = null; - readonly private Expr[] _consts = null; - internal EnumSort(Context ctx, Symbol name, Symbol[] enumNames) : base(ctx) { @@ -96,15 +89,6 @@ namespace Microsoft.Z3 IntPtr[] n_testers = new IntPtr[n]; NativeObject = Native.Z3_mk_enumeration_sort(ctx.nCtx, name.NativeObject, (uint)n, Symbol.ArrayToNative(enumNames), n_constdecls, n_testers); - _constdecls = new FuncDecl[n]; - for (uint i = 0; i < n; i++) - _constdecls[i] = new FuncDecl(ctx, n_constdecls[i]); - _testerdecls = new FuncDecl[n]; - for (uint i = 0; i < n; i++) - _testerdecls[i] = new FuncDecl(ctx, n_testers[i]); - _consts = new Expr[n]; - for (uint i = 0; i < n; i++) - _consts[i] = ctx.MkApp(_constdecls[i]); } #endregion }; diff --git a/src/api/dotnet/ListSort.cs b/src/api/dotnet/ListSort.cs index c099259a2..7dbafb385 100644 --- a/src/api/dotnet/ListSort.cs +++ b/src/api/dotnet/ListSort.cs @@ -36,7 +36,7 @@ namespace Microsoft.Z3 get { Contract.Ensures(Contract.Result() != null); - return nilDecl; + return new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor(Context.nCtx, NativeObject, 0)); } } @@ -48,7 +48,7 @@ namespace Microsoft.Z3 get { Contract.Ensures(Contract.Result() != null); - return nilConst; + return Context.MkApp(NilDecl); } } @@ -60,7 +60,7 @@ namespace Microsoft.Z3 get { Contract.Ensures(Contract.Result() != null); - return isNilDecl; + return new FuncDecl(Context, Native.Z3_get_datatype_sort_recognizer(Context.nCtx, NativeObject, 0)); } } @@ -72,7 +72,7 @@ namespace Microsoft.Z3 get { Contract.Ensures(Contract.Result() != null); - return consDecl; + return new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor(Context.nCtx, NativeObject, 1)); } } @@ -85,7 +85,7 @@ namespace Microsoft.Z3 get { Contract.Ensures(Contract.Result() != null); - return isConsDecl; + return new FuncDecl(Context, Native.Z3_get_datatype_sort_recognizer(Context.nCtx, NativeObject, 1)); } } @@ -97,7 +97,7 @@ namespace Microsoft.Z3 get { Contract.Ensures(Contract.Result() != null); - return headDecl; + return new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor_accessor(Context.nCtx, NativeObject, 1, 0)); } } @@ -109,31 +109,11 @@ namespace Microsoft.Z3 get { Contract.Ensures(Contract.Result() != null); - return tailDecl; + return new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor_accessor(Context.nCtx, NativeObject, 1, 1)); } } - #region Object Invariant - - [ContractInvariantMethod] - private void ObjectInvariant() - { - Contract.Invariant(nilConst != null); - Contract.Invariant(nilDecl != null); - Contract.Invariant(isNilDecl != null); - Contract.Invariant(consDecl != null); - Contract.Invariant(isConsDecl != null); - Contract.Invariant(headDecl != null); - Contract.Invariant(tailDecl != null); - } - - - #endregion - - #region Internal - readonly private FuncDecl nilDecl, isNilDecl, consDecl, isConsDecl, headDecl, tailDecl; - readonly private Expr nilConst; - + #region Internal internal ListSort(Context ctx, Symbol name, Sort elemSort) : base(ctx) { @@ -141,22 +121,12 @@ namespace Microsoft.Z3 Contract.Requires(name != null); Contract.Requires(elemSort != null); - IntPtr inil = IntPtr.Zero, - iisnil = IntPtr.Zero, - icons = IntPtr.Zero, - iiscons = IntPtr.Zero, - ihead = IntPtr.Zero, - itail = IntPtr.Zero; + IntPtr inil = IntPtr.Zero, iisnil = IntPtr.Zero, + icons = IntPtr.Zero, iiscons = IntPtr.Zero, + ihead = IntPtr.Zero, itail = IntPtr.Zero; NativeObject = Native.Z3_mk_list_sort(ctx.nCtx, name.NativeObject, elemSort.NativeObject, - ref inil, ref iisnil, ref icons, ref iiscons, ref ihead, ref itail); - nilDecl = new FuncDecl(ctx, inil); - isNilDecl = new FuncDecl(ctx, iisnil); - consDecl = new FuncDecl(ctx, icons); - isConsDecl = new FuncDecl(ctx, iiscons); - headDecl = new FuncDecl(ctx, ihead); - tailDecl = new FuncDecl(ctx, itail); - nilConst = ctx.MkConst(nilDecl); + ref inil, ref iisnil, ref icons, ref iiscons, ref ihead, ref itail); } #endregion }; diff --git a/src/api/java/Constructor.java b/src/api/java/Constructor.java index c12521bc5..0c53da73c 100644 --- a/src/api/java/Constructor.java +++ b/src/api/java/Constructor.java @@ -16,8 +16,7 @@ public class Constructor extends Z3Object * @throws Z3Exception **/ public int getNumFields() throws Z3Exception - { - init(); + { return n; } @@ -27,8 +26,11 @@ public class Constructor extends Z3Object **/ public FuncDecl ConstructorDecl() throws Z3Exception { - init(); - return m_constructorDecl; + Native.LongPtr constructor = new Native.LongPtr(); + Native.LongPtr tester = new Native.LongPtr(); + long[] accessors = new long[n]; + Native.queryConstructor(getContext().nCtx(), getNativeObject(), n, constructor, tester, accessors); + return new FuncDecl(getContext(), constructor.value); } /** @@ -37,8 +39,11 @@ public class Constructor extends Z3Object **/ public FuncDecl getTesterDecl() throws Z3Exception { - init(); - return m_testerDecl; + Native.LongPtr constructor = new Native.LongPtr(); + Native.LongPtr tester = new Native.LongPtr(); + long[] accessors = new long[n]; + Native.queryConstructor(getContext().nCtx(), getNativeObject(), n, constructor, tester, accessors); + return new FuncDecl(getContext(), tester.value); } /** @@ -47,8 +52,14 @@ public class Constructor extends Z3Object **/ public FuncDecl[] getAccessorDecls() throws Z3Exception { - init(); - return m_accessorDecls; + Native.LongPtr constructor = new Native.LongPtr(); + Native.LongPtr tester = new Native.LongPtr(); + long[] accessors = new long[n]; + Native.queryConstructor(getContext().nCtx(), getNativeObject(), n, constructor, tester, accessors); + FuncDecl[] t = new FuncDecl[n]; + for (int i = 0; i < n; i++) + t[i] = new FuncDecl(getContext(), accessors[i]); + return t; } /** @@ -60,9 +71,6 @@ public class Constructor extends Z3Object } private int n = 0; - private FuncDecl m_testerDecl = null; - private FuncDecl m_constructorDecl = null; - private FuncDecl[] m_accessorDecls = null; Constructor(Context ctx, Symbol name, Symbol recognizer, Symbol[] fieldNames, Sort[] sorts, int[] sortRefs) @@ -87,21 +95,4 @@ public class Constructor extends Z3Object Sort.arrayToNative(sorts), sortRefs)); } - - private void init() throws Z3Exception - { - if (m_testerDecl != null) - return; - Native.LongPtr constructor = new Native.LongPtr(); - Native.LongPtr tester = new Native.LongPtr(); - long[] accessors = new long[n]; - Native.queryConstructor(getContext().nCtx(), getNativeObject(), n, - constructor, tester, accessors); - m_constructorDecl = new FuncDecl(getContext(), constructor.value); - m_testerDecl = new FuncDecl(getContext(), tester.value); - m_accessorDecls = new FuncDecl[n]; - for (int i = 0; i < n; i++) - m_accessorDecls[i] = new FuncDecl(getContext(), accessors[i]); - } - } diff --git a/src/api/java/EnumSort.java b/src/api/java/EnumSort.java index f3cbda954..c0fb6d1d6 100644 --- a/src/api/java/EnumSort.java +++ b/src/api/java/EnumSort.java @@ -14,30 +14,39 @@ public class EnumSort extends Sort /** * The function declarations of the constants in the enumeration. **/ - public FuncDecl[] getConstDecls() + public FuncDecl[] getConstDecls() throws Z3Exception { - return _constdecls; + int n = Native.getDatatypeSortNumConstructors(getContext().nCtx(), getNativeObject()); + FuncDecl[] t = new FuncDecl[n]; + for (int i = 0; i < n; i++) + t[i] = new FuncDecl(getContext(), Native.getDatatypeSortConstructor(getContext().nCtx(), getNativeObject(), i)); + return t; } /** * The constants in the enumeration. **/ - public Expr[] getConsts() - { - return _consts; + public Expr[] getConsts() throws Z3Exception + { + FuncDecl[] cds = getConstDecls(); + Expr[] t = new Expr[cds.length]; + for (int i = 0; i < t.length; i++) + t[i] = getContext().mkApp(cds[i]); + return t; } /** * The test predicates for the constants in the enumeration. **/ - public FuncDecl[] getTesterDecls() + public FuncDecl[] getTesterDecls() throws Z3Exception { - return _testerdecls; + int n = Native.getDatatypeSortNumConstructors(getContext().nCtx(), getNativeObject()); + FuncDecl[] t = new FuncDecl[n]; + for (int i = 0; i < n; i++) + t[i] = new FuncDecl(getContext(), Native.getDatatypeSortRecognizer(getContext().nCtx(), getNativeObject(), i)); + return t; } - private FuncDecl[] _constdecls = null, _testerdecls = null; - private Expr[] _consts = null; - EnumSort(Context ctx, Symbol name, Symbol[] enumNames) throws Z3Exception { super(ctx); @@ -47,15 +56,6 @@ public class EnumSort extends Sort long[] n_testers = new long[n]; setNativeObject(Native.mkEnumerationSort(ctx.nCtx(), name.getNativeObject(), (int) n, Symbol.arrayToNative(enumNames), - n_constdecls, n_testers)); - _constdecls = new FuncDecl[n]; - for (int i = 0; i < n; i++) - _constdecls[i] = new FuncDecl(ctx, n_constdecls[i]); - _testerdecls = new FuncDecl[n]; - for (int i = 0; i < n; i++) - _testerdecls[i] = new FuncDecl(ctx, n_testers[i]); - _consts = new Expr[n]; - for (int i = 0; i < n; i++) - _consts[i] = ctx.mkApp(_constdecls[i], (Expr[])null); + n_constdecls, n_testers)); } }; diff --git a/src/api/java/ListSort.java b/src/api/java/ListSort.java index df1c51a95..af1645187 100644 --- a/src/api/java/ListSort.java +++ b/src/api/java/ListSort.java @@ -13,65 +13,68 @@ public class ListSort extends Sort { /** * The declaration of the nil function of this list sort. + * @throws Z3Exception **/ - public FuncDecl getNilDecl() + public FuncDecl getNilDecl() throws Z3Exception { - return nilDecl; + return new FuncDecl(getContext(), Native.getDatatypeSortConstructor(getContext().nCtx(), getNativeObject(), 0)); } /** * The empty list. + * @throws Z3Exception **/ - public Expr getNil() + public Expr getNil() throws Z3Exception { - return nilConst; + return getContext().mkApp(getNilDecl()); } /** * The declaration of the isNil function of this list sort. + * @throws Z3Exception **/ - public FuncDecl getIsNilDecl() + public FuncDecl getIsNilDecl() throws Z3Exception { - return isNilDecl; + return new FuncDecl(getContext(), Native.getDatatypeSortRecognizer(getContext().nCtx(), getNativeObject(), 0)); } /** * The declaration of the cons function of this list sort. + * @throws Z3Exception **/ - public FuncDecl getConsDecl() + public FuncDecl getConsDecl() throws Z3Exception { - return consDecl; + return new FuncDecl(getContext(), Native.getDatatypeSortConstructor(getContext().nCtx(), getNativeObject(), 1)); } /** * The declaration of the isCons function of this list sort. + * @throws Z3Exception * **/ - public FuncDecl getIsConsDecl() + public FuncDecl getIsConsDecl() throws Z3Exception { - return isConsDecl; + return new FuncDecl(getContext(), Native.getDatatypeSortRecognizer(getContext().nCtx(), getNativeObject(), 1)); } /** * The declaration of the head function of this list sort. + * @throws Z3Exception **/ - public FuncDecl getHeadDecl() + public FuncDecl getHeadDecl() throws Z3Exception { - return headDecl; + return new FuncDecl(getContext(), Native.getDatatypeSortConstructorAccessor(getContext().nCtx(), getNativeObject(), 1, 0)); } /** * The declaration of the tail function of this list sort. + * @throws Z3Exception **/ - public FuncDecl getTailDecl() + public FuncDecl getTailDecl() throws Z3Exception { - return tailDecl; + return new FuncDecl(getContext(), Native.getDatatypeSortConstructorAccessor(getContext().nCtx(), getNativeObject(), 1, 1)); } - private FuncDecl nilDecl, isNilDecl, consDecl, isConsDecl, headDecl, - tailDecl; - private Expr nilConst; - ListSort(Context ctx, Symbol name, Sort elemSort) throws Z3Exception { super(ctx); @@ -83,12 +86,5 @@ public class ListSort extends Sort setNativeObject(Native.mkListSort(ctx.nCtx(), name.getNativeObject(), elemSort.getNativeObject(), inil, iisnil, icons, iiscons, ihead, itail)); - nilDecl = new FuncDecl(ctx, inil.value); - isNilDecl = new FuncDecl(ctx, iisnil.value); - consDecl = new FuncDecl(ctx, icons.value); - isConsDecl = new FuncDecl(ctx, iiscons.value); - headDecl = new FuncDecl(ctx, ihead.value); - tailDecl = new FuncDecl(ctx, itail.value); - nilConst = ctx.mkConst(nilDecl); } }; From 97bf9418f7210a194e058fe298c4b5a7c3d0fe9c Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Wed, 20 Feb 2013 13:41:08 -0800 Subject: [PATCH 02/97] Add new probes for arithmetic. Check for LIA and LRA (and activate qe if applicable). Modify echo tactic to send results to the regular stream. Signed-off-by: Leonardo de Moura --- src/ast/rewriter/arith_rewriter.cpp | 8 -- src/cmd_context/echo_tactic.cpp | 4 +- src/tactic/arith/probe_arith.cpp | 128 ++++++++++++++++-- src/tactic/arith/probe_arith.h | 8 ++ src/tactic/portfolio/default_tactic.cpp | 22 ++- src/tactic/portfolio/smt_strategic_solver.cpp | 2 + src/tactic/smtlogics/quant_tactics.cpp | 7 + src/tactic/smtlogics/quant_tactics.h | 2 + 8 files changed, 147 insertions(+), 34 deletions(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 91d87cbfb..0856ab5b8 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -981,14 +981,6 @@ br_status arith_rewriter::mk_to_real_core(expr * arg, expr_ref & result) { result = m_util.mk_numeral(a, false); return BR_DONE; } -#if 0 - // The following rewriting rule is not correct. - // It is used only for making experiments. - if (m_util.is_to_int(arg)) { - result = to_app(arg)->get_arg(0); - return BR_DONE; - } -#endif // push to_real over OP_ADD, OP_MUL if (m_push_to_real) { if (m_util.is_add(arg) || m_util.is_mul(arg)) { diff --git a/src/cmd_context/echo_tactic.cpp b/src/cmd_context/echo_tactic.cpp index 10d671542..218d9c196 100644 --- a/src/cmd_context/echo_tactic.cpp +++ b/src/cmd_context/echo_tactic.cpp @@ -34,9 +34,9 @@ public: expr_dependency_ref & core) { #pragma omp critical (echo_tactic) { - m_ctx.diagnostic_stream() << m_msg; + m_ctx.regular_stream() << m_msg; if (m_newline) - m_ctx.diagnostic_stream() << std::endl; + m_ctx.regular_stream() << std::endl; } skip_tactic::operator()(in, result, mc, pc, core); } diff --git a/src/tactic/arith/probe_arith.cpp b/src/tactic/arith/probe_arith.cpp index dcb64e6d3..45fc868ac 100644 --- a/src/tactic/arith/probe_arith.cpp +++ b/src/tactic/arith/probe_arith.cpp @@ -313,23 +313,28 @@ struct is_non_nira_functor { bool m_int; bool m_real; bool m_quant; + bool m_linear; - is_non_nira_functor(ast_manager & _m, bool _int, bool _real, bool _quant):m(_m), u(m), m_int(_int), m_real(_real), m_quant(_quant) {} + is_non_nira_functor(ast_manager & _m, bool _int, bool _real, bool _quant, bool linear):m(_m), u(m), m_int(_int), m_real(_real), m_quant(_quant), m_linear(linear) {} + + void throw_found() { + throw found(); + } void operator()(var * x) { if (!m_quant) - throw found(); + throw_found(); sort * s = x->get_sort(); if (m_int && u.is_int(s)) return; if (m_real && u.is_real(s)) return; - throw found(); + throw_found(); } void operator()(quantifier *) { if (!m_quant) - throw found(); + throw_found(); } bool compatible_sort(app * n) const { @@ -344,35 +349,92 @@ struct is_non_nira_functor { void operator()(app * n) { if (!compatible_sort(n)) - throw found(); + throw_found(); family_id fid = n->get_family_id(); if (fid == m.get_basic_family_id()) return; - if (fid == u.get_family_id()) + if (fid == u.get_family_id()) { + switch (n->get_decl_kind()) { + case OP_LE: case OP_GE: case OP_LT: case OP_GT: + case OP_ADD: case OP_UMINUS: case OP_SUB: case OP_ABS: + case OP_NUM: + return; + case OP_MUL: + if (m_linear) { + if (n->get_num_args() != 2) + throw_found(); + if (!u.is_numeral(n->get_arg(0))) + throw_found(); + } + return; + case OP_IDIV: case OP_DIV: case OP_REM: case OP_MOD: + if (m_linear && !u.is_numeral(n->get_arg(1))) + throw_found(); + return; + case OP_IS_INT: + if (m_real) + throw_found(); + return; + case OP_TO_INT: + case OP_TO_REAL: + return; + case OP_POWER: + if (m_linear) + throw_found(); + return; + case OP_IRRATIONAL_ALGEBRAIC_NUM: + if (m_linear || !m_real) + throw_found(); + return; + default: + throw_found(); + } return; + } + if (is_uninterp_const(n)) return; - throw found(); + throw_found(); } }; static bool is_qfnia(goal const & g) { - is_non_nira_functor p(g.m(), true, false, false); + is_non_nira_functor p(g.m(), true, false, false, false); return !test(g, p); } static bool is_qfnra(goal const & g) { - is_non_nira_functor p(g.m(), false, true, false); + is_non_nira_functor p(g.m(), false, true, false, false); return !test(g, p); } static bool is_nia(goal const & g) { - is_non_nira_functor p(g.m(), true, false, true); + is_non_nira_functor p(g.m(), true, false, true, false); return !test(g, p); } static bool is_nra(goal const & g) { - is_non_nira_functor p(g.m(), false, true, true); + is_non_nira_functor p(g.m(), false, true, true, false); + return !test(g, p); +} + +static bool is_nira(goal const & g) { + is_non_nira_functor p(g.m(), true, true, true, false); + return !test(g, p); +} + +static bool is_lra(goal const & g) { + is_non_nira_functor p(g.m(), false, true, true, true); + return !test(g, p); +} + +static bool is_lia(goal const & g) { + is_non_nira_functor p(g.m(), true, false, true, true); + return !test(g, p); +} + +static bool is_lira(goal const & g) { + is_non_nira_functor p(g.m(), true, true, true, true); return !test(g, p); } @@ -404,6 +466,34 @@ public: } }; +class is_nira_probe : public probe { +public: + virtual result operator()(goal const & g) { + return is_nira(g); + } +}; + +class is_lia_probe : public probe { +public: + virtual result operator()(goal const & g) { + return is_lia(g); + } +}; + +class is_lra_probe : public probe { +public: + virtual result operator()(goal const & g) { + return is_lra(g); + } +}; + +class is_lira_probe : public probe { +public: + virtual result operator()(goal const & g) { + return is_lira(g); + } +}; + probe * mk_is_qfnia_probe() { return alloc(is_qfnia_probe); } @@ -419,3 +509,19 @@ probe * mk_is_nia_probe() { probe * mk_is_nra_probe() { return alloc(is_nra_probe); } + +probe * mk_is_nira_probe() { + return alloc(is_nira_probe); +} + +probe * mk_is_lia_probe() { + return alloc(is_lia_probe); +} + +probe * mk_is_lra_probe() { + return alloc(is_lra_probe); +} + +probe * mk_is_lira_probe() { + return alloc(is_lira_probe); +} diff --git a/src/tactic/arith/probe_arith.h b/src/tactic/arith/probe_arith.h index 829bcfab8..17e9efb28 100644 --- a/src/tactic/arith/probe_arith.h +++ b/src/tactic/arith/probe_arith.h @@ -49,11 +49,19 @@ probe * mk_is_qfnia_probe(); probe * mk_is_qfnra_probe(); probe * mk_is_nia_probe(); probe * mk_is_nra_probe(); +probe * mk_is_nira_probe(); +probe * mk_is_lia_probe(); +probe * mk_is_lra_probe(); +probe * mk_is_lira_probe(); /* ADD_PROBE("is-qfnia", "true if the goal is in QF_NIA (quantifier-free nonlinear integer arithmetic).", "mk_is_qfnia_probe()") ADD_PROBE("is-qfnra", "true if the goal is in QF_NRA (quantifier-free nonlinear real arithmetic).", "mk_is_qfnra_probe()") ADD_PROBE("is-nia", "true if the goal is in NIA (nonlinear integer arithmetic, formula may have quantifiers).", "mk_is_nia_probe()") ADD_PROBE("is-nra", "true if the goal is in NRA (nonlinear real arithmetic, formula may have quantifiers).", "mk_is_nra_probe()") + ADD_PROBE("is-nira", "true if the goal is in NIRA (nonlinear integer and real arithmetic, formula may have quantifiers).", "mk_is_nira_probe()") + ADD_PROBE("is-lia", "true if the goal is in LIA (linear integer arithmetic, formula may have quantifiers).", "mk_is_lia_probe()") + ADD_PROBE("is-lra", "true if the goal is in LRA (linear real arithmetic, formula may have quantifiers).", "mk_is_lra_probe()") + ADD_PROBE("is-lira", "true if the goal is in LIRA (linear integer and real arithmetic, formula may have quantifiers).", "mk_is_lira_probe()") */ #endif diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index c5687cd1a..d65ba8d35 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -26,22 +26,18 @@ Notes: #include"qfnra_tactic.h" #include"nra_tactic.h" #include"probe_arith.h" +#include"quant_tactics.h" tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { tactic * st = using_params(and_then(mk_simplify_tactic(m), - cond(mk_is_qfbv_probe(), - mk_qfbv_tactic(m), - cond(mk_is_qflia_probe(), - mk_qflia_tactic(m), - cond(mk_is_qflra_probe(), - mk_qflra_tactic(m), - cond(mk_is_qfnra_probe(), - mk_qfnra_tactic(m), - cond(mk_is_qfnia_probe(), - mk_qfnia_tactic(m), - cond(mk_is_nra_probe(), - mk_nra_tactic(m), - mk_smt_tactic()))))))), + cond(mk_is_qfbv_probe(), mk_qfbv_tactic(m), + cond(mk_is_qflia_probe(), mk_qflia_tactic(m), + cond(mk_is_qflra_probe(), mk_qflra_tactic(m), + cond(mk_is_qfnra_probe(), mk_qfnra_tactic(m), + cond(mk_is_qfnia_probe(), mk_qfnia_tactic(m), + cond(mk_is_nra_probe(), mk_nra_tactic(m), + cond(mk_is_lira_probe(), mk_lira_tactic(m, p), + mk_smt_tactic())))))))), p); return st; } diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 0e63255ca..55512f677 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -72,6 +72,8 @@ tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const return mk_uflra_tactic(m, p); else if (logic=="LRA") return mk_lra_tactic(m, p); + else if (logic=="LIA") + return mk_lia_tactic(m, p); else if (logic=="UFBV") return mk_ufbv_tactic(m, p); else if (logic=="BV") diff --git a/src/tactic/smtlogics/quant_tactics.cpp b/src/tactic/smtlogics/quant_tactics.cpp index 6b5ede813..85f53eff0 100644 --- a/src/tactic/smtlogics/quant_tactics.cpp +++ b/src/tactic/smtlogics/quant_tactics.cpp @@ -104,3 +104,10 @@ tactic * mk_lra_tactic(ast_manager & m, params_ref const & p) { return st; } +tactic * mk_lia_tactic(ast_manager & m, params_ref const & p) { + return mk_lra_tactic(m, p); +} + +tactic * mk_lira_tactic(ast_manager & m, params_ref const & p) { + return mk_lra_tactic(m, p); +} diff --git a/src/tactic/smtlogics/quant_tactics.h b/src/tactic/smtlogics/quant_tactics.h index dc8c458c4..5cf27cde4 100644 --- a/src/tactic/smtlogics/quant_tactics.h +++ b/src/tactic/smtlogics/quant_tactics.h @@ -29,5 +29,7 @@ tactic * mk_auflia_tactic(ast_manager & m, params_ref const & p); tactic * mk_auflira_tactic(ast_manager & m, params_ref const & p); tactic * mk_aufnira_tactic(ast_manager & m, params_ref const & p); tactic * mk_lra_tactic(ast_manager & m, params_ref const & p); +tactic * mk_lia_tactic(ast_manager & m, params_ref const & p); +tactic * mk_lira_tactic(ast_manager & m, params_ref const & p); #endif From 70192b66e931d7f02f4c5bc8535a7424a8d3c76a Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Wed, 20 Feb 2013 17:03:29 -0800 Subject: [PATCH 03/97] Remove dead files Signed-off-by: Leonardo de Moura --- src/ast/ast_list.h | 160 ------------------------------------------- src/shell/resource.h | 14 ---- 2 files changed, 174 deletions(-) delete mode 100644 src/ast/ast_list.h delete mode 100644 src/shell/resource.h diff --git a/src/ast/ast_list.h b/src/ast/ast_list.h deleted file mode 100644 index c02b2d66d..000000000 --- a/src/ast/ast_list.h +++ /dev/null @@ -1,160 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - ast_list.h - -Abstract: - - Quick hack to have lists of ASTs. - The lists have hash-consing. - This is a substitute for the old expr_lists implemented on top of the ASTs. - The new lists live in a different manager and do not affect the ast_manager. - -Author: - - Leonardo de Moura (leonardo) 2011-01-06. - -Revision History: - ---*/ -#ifndef _AST_LIST_H_ -#define _AST_LIST_H_ - -#include"ast.h" - -template -class ast_list_manager_tpl; - -template -class ast_list_tpl { -public: - typedef ast_list_tpl list; -private: - unsigned m_id; - unsigned m_is_nil:1; - unsigned m_ref_count:31; - AST * m_head; - list * m_tail; - - ast_list_tpl(): - m_is_nil(true), - m_ref_count(0), - m_head(0), - m_tail(0) { - } - - ast_list_tpl(AST * h, list * t): - m_is_nil(false), - m_ref_count(0), - m_head(h), - m_tail(t) { - } - - friend class ast_list_manager_tpl; - - struct hash_proc; - friend struct hash_proc; - - struct hash_proc { - unsigned operator()(ast_list_tpl * l) const { - unsigned h1 = l->m_head ? l->m_head->get_id() : 5; - unsigned h2 = l->m_tail ? l->m_tail->get_id() : 7; - return hash_u_u(h1, h2); - } - }; - - struct eq_proc; - friend struct eq_proc; - - struct eq_proc { - bool operator()(ast_list_tpl * l1, ast_list_tpl * l2) const { - return l1->m_head == l2->m_head && l1->m_tail == l2->m_tail; - } - }; - - typedef ptr_hashtable table; // for hash consing - -public: - unsigned get_id() const { return m_id; } - unsigned get_ref_count() const { return m_ref_count; } - unsigned hash() const { return m_id; } - - friend inline bool is_nil(list const * l) { return l->m_is_nil == true; } - friend inline bool is_cons(list const * l) { return !is_nil(l); } - friend inline AST * head(list const * l) { SASSERT(is_cons(l)); return l->m_head; } - friend inline list * tail(list const * l) { SASSERT(is_cons(l)); return l->m_tail; } -}; - -template -class ast_list_manager_tpl { -public: - typedef ast_list_tpl list; - typedef obj_hashtable list_set; -private: - typedef typename list::table table; - ast_manager & m_manager; - small_object_allocator m_allocator; - table m_table; - id_gen m_id_gen; - list m_nil; - -public: - ast_list_manager_tpl(ast_manager & m): - m_manager(m), - m_nil() { - m_nil.m_id = m_id_gen.mk(); - m_nil.m_ref_count = 1; - } - - void inc_ref(list * l) { - if (l != 0) { - l->m_ref_count++; - } - } - - void dec_ref(list * l) { - while (l != 0) { - SASSERT(l->m_ref_count > 0); - l->m_ref_count--; - if (l->m_ref_count > 0) - return; - SASSERT(l != &m_nil); - m_table.erase(l); - m_manager.dec_ref(l->m_head); - m_id_gen.recycle(l->m_id); - list * old_l = l; - l = l->m_tail; - m_allocator.deallocate(sizeof(list), old_l); - } - } - - list * mk_nil() { return &m_nil; } - - list * mk_cons(AST * h, list * l) { - list tmp(h, l); - list * r = 0; - if (m_table.find(&tmp, r)) - return r; - r = new (m_allocator.allocate(sizeof(list))) list(h, l); - m_manager.inc_ref(h); - inc_ref(l); - r->m_id = m_id_gen.mk(); - m_table.insert(r); - return r; - } -}; - -typedef ast_list_tpl expr_list; -typedef ast_list_manager_tpl expr_list_manager; - -typedef ast_list_tpl quantifier_list; -typedef ast_list_manager_tpl quantifier_list_manager; - -typedef obj_ref expr_list_ref; -typedef obj_ref quantifier_list_ref; -typedef ref_vector expr_list_ref_vector; -typedef ref_vector quantifier_list_ref_vector; - -#endif diff --git a/src/shell/resource.h b/src/shell/resource.h deleted file mode 100644 index dde3ba323..000000000 --- a/src/shell/resource.h +++ /dev/null @@ -1,14 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by shell.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif From 876c6a361e917891f5fb2b07f801c631068f0286 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 21 Feb 2013 16:40:10 +0000 Subject: [PATCH 04/97] Java API: build system fix for OSX Signed-off-by: Christoph M. Wintersteiger --- scripts/mk_util.py | 68 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 25686f9a7..7fb14fa7f 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -33,6 +33,7 @@ LDFLAGS=getenv("LDFLAGS", "") JAVA=getenv("JAVA", "java") JAVAC=getenv("JAVAC", "javac") JAVA_HOME=getenv("JAVA_HOME", None) +JNI_HOME=getenv("JNI_HOME", None) CXX_COMPILERS=['g++', 'clang++'] C_COMPILERS=['gcc', 'clang'] @@ -222,6 +223,7 @@ def check_java(): if r != 0: raise MKException('Failed testing Java program. Set environment variable JAVA with the path to the Java virtual machine') find_java_home() + find_jni_home() def find_jni_h(path): for root, dirs, files in os.walk(path): @@ -233,10 +235,14 @@ def find_jni_h(path): def find_java_home(): global JAVA_HOME if JAVA_HOME != None: - if is_verbose(): - print("Checking jni.h...") - if os.path.exists(os.path.join(JAVA_HOME, 'include', 'jni.h')): - return + if IS_WINDOWS: + ind = string.join(path, 'bin\java.exe') + else: + ind = string.join(path, 'bin/java') + if not os.path.exists(ind): + raise MKException("Failed to detect java at '%s'.Possible solution: set JAVA_HOME with the path to JDK." % os.path.join(path)) + else: + return if is_verbose(): print("Finding JAVA_HOME...") t = TempFile('output') @@ -252,20 +258,51 @@ def find_java_home(): m = open_pat.match(line) if m: # Remove last 3 directives from m.group(1) - print(m.group(1)) tmp = m.group(1).split(os.sep) path = string.join(tmp[:len(tmp) - 3], os.sep) - if is_verbose(): - print("Checking jni.h...") - jni_dir = find_jni_h(path) - if not jni_dir: - raise MKException("Failed to detect jni.h at '%s'.Possible solution: set JAVA_HOME with the path to JDK." % os.path.join(path, 'include')) - JAVA_HOME = os.path.split(jni_dir)[0] - if is_verbose(): - print('JAVA_HOME=%s' % JAVA_HOME) + if IS_WINDOWS: + ind = '%s%s' % (path, '\bin\java.exe') + else: + ind = '%s%s' % (path, '/bin/java') + if os.path.exists(ind): + JAVA_HOME = path + return + if IS_OSX: + path = '%s%s' % (path, '/Contents/Home/') + ind = '%s%s' % (path, 'bin/java') + if os.path.exists(ind): + JAVA_HOME = path + return + raise MKException("Failed to detect java at '%s'.Possible solution: set JAVA_HOME with the path to JDK." % os.path.join(path)) return raise MKException('Failed to find JAVA_HOME') +def find_jni_home(): + global JNI_HOME + if JNI_HOME != None: + if is_verbose(): + print("Checking jni.h...") + path = JNI_HOME + fn = os.path.join(path, 'jni.h') + print("Checking for jni.h in %s..." % JNI_HOME) + if os.path.exists(fn): + return + else: + path = '%s%s' % (JAVA_HOME, '/include/') + fn = '%s%s' % (path, 'jni.h') + print("Checking for jni.h in %s..." % path) + if os.path.exists(fn): + JNI_HOME = find_jni_h(path) + elif IS_OSX: + # Apparently Apple knows best where to put stuff... + path = '/System/Library/Frameworks/JavaVM.framework/Headers/' + fn = '%s%s' % (path, 'jni.h') + print("Checking for jni.h in %s..." % path) + if os.path.exists(fn): + JNI_HOME = find_jni_h(path) + if JNI_HOME == None: + raise MKException("Failed to detect jni.h. Possible solution: set JNI_HOME with the path to JDK.") + def is64(): return sys.maxsize >= 2**32 @@ -402,6 +439,7 @@ def display_help(exit_code): print(" JAVA Java virtual machine (only relevant if -j or --java option is provided)") print(" JAVAC Java compiler (only relevant if -j or --java option is provided)") print(" JAVA_HOME JDK installation directory (only relevant if -j or --java option is provided)") + print(" JNI_HOME JNI bindings directory (only relevant if -j or --java option is provided)") exit(exit_code) # Parse configuration option for mk_make script @@ -1086,7 +1124,7 @@ class JavaDLLComponent(Component): mk_dir(os.path.join(BUILD_DIR, 'api', 'java', 'classes')) dllfile = '%s$(SO_EXT)' % self.dll_name out.write('libz3java$(SO_EXT): libz3$(SO_EXT) %s\n' % os.path.join(self.to_src_dir, 'Native.cpp')) - t = '\t$(CXX) $(CXXFLAGS) $(CXX_OUT_FLAG)api/java/Native$(OBJ_EXT) -I"%s/include" -I"%s/include/PLATFORM" -I%s %s/Native.cpp\n' % (JAVA_HOME, JAVA_HOME, get_component('api').to_src_dir, self.to_src_dir) + t = '\t$(CXX) $(CXXFLAGS) $(CXX_OUT_FLAG)api/java/Native$(OBJ_EXT) -I"%s" -I"%s/PLATFORM" -I%s %s/Native.cpp\n' % (JNI_HOME, JNI_HOME, get_component('api').to_src_dir, self.to_src_dir) if IS_OSX: t = t.replace('PLATFORM', 'darwin') elif IS_LINUX: @@ -1388,6 +1426,7 @@ def mk_config(): print('64-bit: %s' % is64()) if is_java_enabled(): print('Java Home: %s' % JAVA_HOME) + print('JNI Home: %s' % JNI_HOME) print('Java Compiler: %s' % JAVAC) print('Java VM: %s' % JAVA) else: @@ -1492,6 +1531,7 @@ def mk_config(): print('Python version: %s' % distutils.sysconfig.get_python_version()) if is_java_enabled(): print('Java Home: %s' % JAVA_HOME) + print('JNI Home: %s' % JNI_HOME) print('Java Compiler: %s' % JAVAC) print('Java VM: %s' % JAVA) From 2c6c09301f111677c426ca4ba8cea7557344334f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 21 Feb 2013 16:46:18 +0000 Subject: [PATCH 05/97] Java API: build system bugfixes. Signed-off-by: Christoph M. Wintersteiger --- scripts/mk_util.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 7fb14fa7f..5d2fb4e17 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -236,11 +236,11 @@ def find_java_home(): global JAVA_HOME if JAVA_HOME != None: if IS_WINDOWS: - ind = string.join(path, 'bin\java.exe') + ind = '%s%s' % (JAVA_HOME, '\\bin\\java.exe') else: - ind = string.join(path, 'bin/java') + ind = '%s%s' % (JAVA_HOME, '/bin/java') if not os.path.exists(ind): - raise MKException("Failed to detect java at '%s'.Possible solution: set JAVA_HOME with the path to JDK." % os.path.join(path)) + raise MKException("Failed to detect java at '%s'.Possible solution: set JAVA_HOME with the path to JDK." % os.path.join(JAVA_HOME)) else: return if is_verbose(): @@ -261,7 +261,7 @@ def find_java_home(): tmp = m.group(1).split(os.sep) path = string.join(tmp[:len(tmp) - 3], os.sep) if IS_WINDOWS: - ind = '%s%s' % (path, '\bin\java.exe') + ind = '%s%s' % (path, '\\bin\\java.exe') else: ind = '%s%s' % (path, '/bin/java') if os.path.exists(ind): From 4922d62311c3a2a7d3c455b5a6ebc38f808854c7 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Thu, 21 Feb 2013 11:02:13 -0800 Subject: [PATCH 06/97] Fix bug reported at http://z3.codeplex.com/workitem/23 Signed-off-by: Leonardo de Moura --- RELEASE_NOTES | 2 ++ src/tactic/goal.cpp | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 13957064e..7aaaf2f8d 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -61,6 +61,8 @@ Version 4.3.2 - Fixed bugs in the C++ API (Thanks to Andrey Kupriyanov). +- Fixed bug reported at http://z3.codeplex.com/workitem/23 (Thanks to Paul Jackson). + Version 4.3.1 ============= diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index c6dad42b2..03a13aba5 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -111,19 +111,29 @@ void goal::push_back(expr * f, proof * pr, expr_dependency * d) { if (m().is_true(f)) return; if (m().is_false(f)) { + // Make sure pr and d are not deleted by the m().del(...) statements. + proof_ref saved_pr(m()); + expr_dependency_ref saved_d(m()); + saved_pr = pr; + saved_d = d; m().del(m_forms); m().del(m_proofs); m().del(m_dependencies); m_inconsistent = true; + m().push_back(m_forms, m().mk_false()); + if (proofs_enabled()) + m().push_back(m_proofs, saved_pr); + if (unsat_core_enabled()) + m().push_back(m_dependencies, saved_d); } else { SASSERT(!m_inconsistent); + m().push_back(m_forms, f); + if (proofs_enabled()) + m().push_back(m_proofs, pr); + if (unsat_core_enabled()) + m().push_back(m_dependencies, d); } - m().push_back(m_forms, f); - if (proofs_enabled()) - m().push_back(m_proofs, pr); - if (unsat_core_enabled()) - m().push_back(m_dependencies, d); } void goal::quick_process(bool save_first, expr * & f, expr_dependency * d) { From 562ae7bec53b4f0dea2bf6926a82ff377aee822c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Feb 2013 21:52:10 -0800 Subject: [PATCH 07/97] faster saturation without backwards subsumption and using SOS-style set Signed-off-by: Nikolaj Bjorner --- src/muz_qe/heap_trie.h | 283 +++++++++++++++++++++++++++--- src/muz_qe/hilbert_basis.cpp | 327 +++++++++++++++++++++++++++++++++-- src/muz_qe/hilbert_basis.h | 19 +- src/test/heap_trie.cpp | 3 +- src/test/hilbert_basis.cpp | 20 +++ 5 files changed, 607 insertions(+), 45 deletions(-) diff --git a/src/muz_qe/heap_trie.h b/src/muz_qe/heap_trie.h index 25689e930..ba7ab72f9 100644 --- a/src/muz_qe/heap_trie.h +++ b/src/muz_qe/heap_trie.h @@ -44,7 +44,7 @@ Notes: #include "small_object_allocator.h" -template +template class heap_trie { struct stats { @@ -180,6 +180,8 @@ class heap_trie { small_object_allocator m_alloc; unsigned m_num_keys; + unsigned_vector m_keys; + unsigned m_do_reshuffle; node* m_root; stats m_stats; node* m_spare_leaf; @@ -190,6 +192,7 @@ public: heap_trie(): m_alloc("heap_trie"), m_num_keys(0), + m_do_reshuffle(4), m_root(0), m_spare_leaf(0), m_spare_trie(0) @@ -202,7 +205,7 @@ public: } unsigned size() const { - return m_root->num_leaves(); + return m_root?m_root->num_leaves():0; } void reset(unsigned num_keys) { @@ -210,6 +213,10 @@ public: del_node(m_spare_leaf); del_node(m_spare_trie); m_num_keys = num_keys; + m_keys.resize(num_keys); + for (unsigned i = 0; i < num_keys; ++i) { + m_keys[i] = i; + } m_root = mk_trie(); m_spare_trie = mk_trie(); m_spare_leaf = mk_leaf(); @@ -217,7 +224,13 @@ public: void insert(Key const* keys, Value const& val) { ++m_stats.m_num_inserts; - insert(m_root, num_keys(), keys, val); + insert(m_root, num_keys(), keys, m_keys.c_ptr(), val); +#if 0 + if (m_stats.m_num_inserts == (1 << m_do_reshuffle)) { + m_do_reshuffle++; + reorder_keys(); + } +#endif } bool find_eq(Key const* keys, Value& value) { @@ -225,7 +238,7 @@ public: node* n = m_root; node* m; for (unsigned i = 0; i < num_keys(); ++i) { - if (!to_trie(n)->find(keys[i], m)) { + if (!to_trie(n)->find(get_key(keys, i), m)) { return false; } n = m; @@ -242,7 +255,7 @@ public: for (unsigned i = 0; i < num_keys(); ++i) { for (unsigned j = 0; j < todo[index].size(); ++j) { ++m_stats.m_num_find_le_nodes; - to_trie(todo[index][j])->find_le(keys[i], todo[!index]); + to_trie(todo[index][j])->find_le(get_key(keys, i), todo[!index]); } todo[index].reset(); index = !index; @@ -271,7 +284,7 @@ public: node* m; for (unsigned i = 0; i < num_keys(); ++i) { n->dec_ref(); - VERIFY (to_trie(n)->find(keys[i], m)); + VERIFY (to_trie(n)->find(get_key(keys, i), m)); n = m; } n->dec_ref(); @@ -287,14 +300,14 @@ public: st.update("heap_trie.num_find_eq", m_stats.m_num_find_eq); st.update("heap_trie.num_find_le", m_stats.m_num_find_le); st.update("heap_trie.num_find_le_nodes", m_stats.m_num_find_le_nodes); - st.update("heap_trie.num_nodes", m_root->num_nodes()); + if (m_root) st.update("heap_trie.num_nodes", m_root->num_nodes()); unsigned_vector nums; ptr_vector todo; - todo.push_back(m_root); + if (m_root) todo.push_back(m_root); while (!todo.empty()) { node* n = todo.back(); todo.pop_back(); - if (n->type() == trie_t) { + if (is_trie(n)) { trie* t = to_trie(n); unsigned sz = t->nodes().size(); if (nums.size() <= sz) { @@ -334,38 +347,252 @@ public: out << "\n"; } + class iterator { + ptr_vector m_path; + unsigned_vector m_idx; + vector m_keys; + unsigned m_count; + public: + iterator(node* n) { + if (!n) { + m_count = UINT_MAX; + } + else { + m_count = 0; + first(n); + } + } + Key const* keys() { + return m_keys.c_ptr(); + } + + Value const& value() const { + return to_leaf(m_path.back())->get_value(); + } + iterator& operator++() { fwd(); return *this; } + iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; } + bool operator==(iterator const& it) const {return m_count == it.m_count; } + bool operator!=(iterator const& it) const {return m_count != it.m_count; } + + private: + void first(node* r) { + SASSERT(r->ref_count() > 0); + while (is_trie(r)) { + trie* t = to_trie(r); + m_path.push_back(r); + unsigned sz = t->nodes().size(); + for (unsigned i = 0; i < sz; ++i) { + r = t->nodes()[i].second; + if (r->ref_count() > 0) { + m_idx.push_back(i); + m_keys.push_back(t->nodes()[i].first); + break; + } + } + } + SASSERT(is_leaf(r)); + m_path.push_back(r); + } + + void fwd() { + if (m_path.empty()) { + m_count = UINT_MAX; + return; + } + m_path.pop_back(); + while (!m_path.empty()) { + trie* t = to_trie(m_path.back()); + unsigned idx = m_idx.back(); + unsigned sz = t->nodes().size(); + m_idx.pop_back(); + m_keys.pop_back(); + for (unsigned i = idx+1; i < sz; ++i) { + node* r = t->nodes()[i].second; + if (r->ref_count() > 0) { + m_idx.push_back(i); + m_keys.push_back(t->nodes()[i].first); + first(r); + ++m_count; + return; + } + } + m_path.pop_back(); + } + m_count = UINT_MAX; + } + }; + + iterator begin() const { + return iterator(m_root); + } + + iterator end() const { + return iterator(0); + } + + private: - unsigned num_keys() const { + inline unsigned num_keys() const { return m_num_keys; } + inline Key const& get_key(Key const* keys, unsigned i) const { + return keys[m_keys[i]]; + } + + struct KeyEq { + bool operator()(Key const& k1, Key const& k2) const { + return k1 == k2; + } + }; + + + typedef hashtable key_set; + + struct key_info { + unsigned m_index; + unsigned m_index_size; + key_info(unsigned i, unsigned sz): + m_index(i), + m_index_size(sz) + {} + + bool operator<(key_info const& other) const { + return + (m_index_size < other.m_index_size) || + ((m_index_size == other.m_index_size) && + (m_index < other.m_index)); + } + }; + + void reorder_keys() { + vector weights; + weights.resize(num_keys()); + unsigned_vector depth; + ptr_vector nodes; + depth.push_back(0); + nodes.push_back(m_root); + while (!nodes.empty()) { + node* n = nodes.back(); + unsigned d = depth.back(); + nodes.pop_back(); + depth.pop_back(); + if (is_trie(n)) { + trie* t = to_trie(n); + unsigned sz = t->nodes().size(); + for (unsigned i = 0; i < sz; ++i) { + nodes.push_back(t->nodes()[i].second); + depth.push_back(d+1); + weights[d].insert(t->nodes()[i].first); + } + } + } + SASSERT(weights.size() == num_keys()); + svector infos; + unsigned sz = 0; + bool is_sorted = true; + for (unsigned i = 0; i < weights.size(); ++i) { + unsigned sz2 = weights[i].size(); + if (sz > sz2) { + is_sorted = false; + } + sz = sz2; + infos.push_back(key_info(i, sz)); + } + if (is_sorted) { + return; + } + std::sort(infos.begin(), infos.end()); + unsigned_vector sorted_keys, new_keys; + for (unsigned i = 0; i < num_keys(); ++i) { + unsigned j = infos[i].m_index; + sorted_keys.push_back(j); + new_keys.push_back(m_keys[j]); + } + // m_keys: i |-> key_index + // new_keys: i |-> new_key_index + // permutation: key_index |-> new_key_index + SASSERT(sorted_keys.size() == num_keys()); + SASSERT(new_keys.size() == num_keys()); + SASSERT(m_keys.size() == num_keys()); + iterator it = begin(); + trie* new_root = mk_trie(); + IF_VERBOSE(1, verbose_stream() << "before reshuffle: " << m_root->num_nodes() << " nodes\n";); + for (; it != end(); ++it) { + IF_VERBOSE(2, + for (unsigned i = 0; i < num_keys(); ++i) { + for (unsigned j = 0; j < num_keys(); ++j) { + if (m_keys[j] == i) { + verbose_stream() << it.keys()[j] << " "; + break; + } + } + } + verbose_stream() << " |-> " << it.value() << "\n";); + + insert(new_root, num_keys(), it.keys(), sorted_keys.c_ptr(), it.value()); + } + del_node(m_root); + m_root = new_root; + for (unsigned i = 0; i < m_keys.size(); ++i) { + m_keys[i] = new_keys[i]; + } + + IF_VERBOSE(1, verbose_stream() << "after reshuffle: " << new_root->num_nodes() << " nodes\n";); + IF_VERBOSE(2, + it = begin(); + for (; it != end(); ++it) { + for (unsigned i = 0; i < num_keys(); ++i) { + for (unsigned j = 0; j < num_keys(); ++j) { + if (m_keys[j] == i) { + verbose_stream() << it.keys()[j] << " "; + break; + } + } + } + verbose_stream() << " |-> " << it.value() << "\n"; + }); + } + bool find_le(node* n, unsigned index, Key const* keys, check_value& check) { if (index == num_keys()) { SASSERT(n->ref_count() > 0); - return check(to_leaf(n)->get_value()); + bool r = check(to_leaf(n)->get_value()); + IF_VERBOSE(1, + for (unsigned j = 0; j < index; ++j) { + verbose_stream() << " "; + } + verbose_stream() << to_leaf(n)->get_value() << (r?" hit\n":" miss\n");); + return r; } else { - Key key = keys[index]; - children_t const& nodes = to_trie(n)->nodes(); + Key const& key = get_key(keys, index); + children_t& nodes = to_trie(n)->nodes(); for (unsigned i = 0; i < nodes.size(); ++i) { ++m_stats.m_num_find_le_nodes; - if (KeyLE::le(nodes[i].first, key)) { - node* m = nodes[i].second; - if (m->ref_count() > 0 && find_le(m, index+1, keys, check)) { - return true; + node* m = nodes[i].second; + IF_VERBOSE(1, + for (unsigned j = 0; j < index; ++j) { + verbose_stream() << " "; + } + verbose_stream() << nodes[i].first << " <=? " << key << " rc:" << m->ref_count() << "\n";); + if (m->ref_count() > 0 && KeyLE::le(nodes[i].first, key) && find_le(m, index+1, keys, check)) { + if (i > 0) { + std::swap(nodes[i], nodes[0]); } + return true; } } return false; } } - void insert(node* n, unsigned num_keys, Key const* keys, Value const& val) { + void insert(node* n, unsigned num_keys, Key const* keys, unsigned const* permutation, Value const& val) { // assumption: key is not in table. for (unsigned i = 0; i < num_keys; ++i) { n->inc_ref(); - n = insert_key(to_trie(n), (i + 1 == num_keys), keys[i]); + n = insert_key(to_trie(n), (i + 1 == num_keys), keys[permutation[i]]); } n->inc_ref(); to_leaf(n)->set_value(val); @@ -400,7 +627,7 @@ private: if (!n) { return; } - if (n->type() == trie_t) { + if (is_trie(n)) { trie* t = to_trie(n); for (unsigned i = 0; i < t->nodes().size(); ++i) { del_node(t->nodes()[i].second); @@ -415,15 +642,23 @@ private: } } - trie* to_trie(node* n) const { - SASSERT(n->type() == trie_t); + static trie* to_trie(node* n) { + SASSERT(is_trie(n)); return static_cast(n); } - leaf* to_leaf(node* n) const { - SASSERT(n->type() == leaf_t); + static leaf* to_leaf(node* n) { + SASSERT(is_leaf(n)); return static_cast(n); } + + static bool is_leaf(node* n) { + return n->type() == leaf_t; + } + + static bool is_trie(node* n) { + return n->type() == trie_t; + } }; #endif diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index 7d15a1958..49bf20746 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -25,6 +25,8 @@ Revision History: template class rational_map : public map {}; +typedef int_hashtable > int_table; + class hilbert_basis::value_index1 { struct stats { @@ -36,7 +38,6 @@ class hilbert_basis::value_index1 { void reset() { memset(this, 0, sizeof(*this)); } }; - typedef int_hashtable > int_table; hilbert_basis& hb; int_table m_table; stats m_stats; @@ -167,7 +168,9 @@ class hilbert_basis::value_index2 { return hilbert_basis::is_abs_geq(n2, n1); } }; - struct checker : public heap_trie::check_value { + + typedef heap_trie ht; + struct checker : public ht::check_value { hilbert_basis* hb; offset_t m_value; offset_t* m_found; @@ -183,7 +186,7 @@ class hilbert_basis::value_index2 { } }; hilbert_basis& hb; - heap_trie m_trie; + ht m_trie; vector m_found; bool m_init; checker m_checker; @@ -483,16 +486,168 @@ public: } }; + +class hilbert_basis::vector_lt_t { + hilbert_basis& hb; +public: + vector_lt_t(hilbert_basis& hb): hb(hb) {} + bool operator()(offset_t idx1, offset_t idx2) const { + return hb.vector_lt(idx1, idx2); + } +}; + + +class hilbert_basis::passive2 { + struct lt { + passive2** p; + lt(passive2** p): p(p) {} + bool operator()(int v1, int v2) const { + return (**p)(v1, v2); + } + }; + hilbert_basis& hb; + svector const& m_sos; + unsigned_vector m_psos; + svector m_pas; + vector m_weight; + unsigned_vector m_free_list; + passive2* m_this; + lt m_lt; + heap m_heap; // binary heap over weights + + numeral sum_abs(offset_t idx) const { + numeral w(0); + unsigned nv = hb.get_num_vars(); + for (unsigned i = 0; i < nv; ++i) { + w += abs(hb.vec(idx)[i]); + } + return w; + } + +public: + passive2(hilbert_basis& hb): + hb(hb), + m_sos(hb.m_sos), + m_lt(&m_this), + m_heap(10, m_lt) + { + m_this = this; + } + + void reset() { + m_heap.reset(); + m_free_list.reset(); + m_psos.reset(); + m_pas.reset(); + m_weight.reset(); + } + + void insert(offset_t idx, unsigned offset) { + SASSERT(!m_sos.empty()); + unsigned v; + numeral w = sum_abs(idx) + sum_abs(m_sos[0]); + if (m_free_list.empty()) { + v = m_pas.size(); + m_pas.push_back(idx); + m_psos.push_back(offset); + m_weight.push_back(w); + m_heap.set_bounds(v+1); + } + else { + v = m_free_list.back(); + m_free_list.pop_back(); + m_pas[v] = idx; + m_psos[v] = offset; + m_weight[v] = w; + } + next_resolvable(v); + } + + bool empty() const { + return m_heap.empty(); + } + + unsigned pop(offset_t& sos, offset_t& pas) { + SASSERT (!empty()); + unsigned val = static_cast(m_heap.erase_min()); + unsigned psos = m_psos[val]; + sos = m_sos[psos]; + pas = m_pas[val]; + m_psos[val]++; + next_resolvable(val); + numeral old_weight = hb.vec(pas).weight(); + numeral new_weight = hb.vec(sos).weight() + old_weight; + if (new_weight.is_pos() != old_weight.is_pos()) { + psos = 0; + } + return psos; + } + + bool operator()(int v1, int v2) const { + return m_weight[v1] < m_weight[v2]; + } + + class iterator { + passive2& p; + unsigned m_idx; + void fwd() { + while (m_idx < p.m_pas.size() && + is_invalid_offset(p.m_pas[m_idx])) { + ++m_idx; + } + } + public: + iterator(passive2& p, unsigned i): p(p), m_idx(i) { fwd(); } + offset_t pas() const { return p.m_pas[m_idx]; } + offset_t sos() const { return p.m_sos[p.m_psos[m_idx]]; } + iterator& operator++() { ++m_idx; fwd(); return *this; } + iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; } + bool operator==(iterator const& it) const {return m_idx == it.m_idx; } + bool operator!=(iterator const& it) const {return m_idx != it.m_idx; } + }; + + iterator begin() { + return iterator(*this, 0); + } + + iterator end() { + return iterator(*this, m_pas.size()); + } +private: + void next_resolvable(unsigned v) { + offset_t pas = m_pas[v]; + while (m_psos[v] < m_sos.size()) { + offset_t sos = m_sos[m_psos[v]]; + if (hb.can_resolve(sos, pas)) { + m_weight[v] = sum_abs(pas) + sum_abs(sos); + m_heap.insert(v); + return; + } + ++m_psos[v]; + } + // add pas to free-list for hb if it is not in sos. + m_free_list.push_back(v); + m_psos[v] = UINT_MAX; + m_pas[v] = mk_invalid_offset(); + } +}; + + hilbert_basis::hilbert_basis(): - m_cancel(false) + m_cancel(false), + m_use_support(true), + m_use_ordered_support(true), + m_use_ordered_subsumption(true) { m_index = alloc(index, *this); m_passive = alloc(passive, *this); + m_passive2 = alloc(passive2, *this); } hilbert_basis::~hilbert_basis() { dealloc(m_index); dealloc(m_passive); + dealloc(m_passive2); } hilbert_basis::offset_t hilbert_basis::mk_invalid_offset() { @@ -510,6 +665,7 @@ void hilbert_basis::reset() { m_free_list.reset(); m_active.reset(); m_passive->reset(); + m_passive2->reset(); m_zero.reset(); m_index->reset(); m_cancel = false; @@ -621,6 +777,7 @@ lbool hilbert_basis::saturate() { init_basis(); m_current_ineq = 0; while (!m_cancel && m_current_ineq < m_ineqs.size()) { + IF_VERBOSE(1, { statistics st; collect_statistics(st); st.display(verbose_stream()); }); select_inequality(); lbool r = saturate(m_ineqs[m_current_ineq], m_iseq[m_current_ineq]); ++m_stats.m_num_saturations; @@ -635,27 +792,26 @@ lbool hilbert_basis::saturate() { return l_true; } -lbool hilbert_basis::saturate(num_vector const& ineq, bool is_eq) { +lbool hilbert_basis::saturate_orig(num_vector const& ineq, bool is_eq) { m_active.reset(); m_passive->reset(); m_zero.reset(); m_index->reset(); + int_table support; TRACE("hilbert_basis", display_ineq(tout, ineq, is_eq);); - bool has_non_negative = false; iterator it = begin(); for (; it != end(); ++it) { - values v = vec(*it); + offset_t idx = *it; + values v = vec(idx); v.weight() = get_weight(v, ineq); - add_goal(*it); - if (v.weight().is_nonneg()) { - has_non_negative = true; + add_goal(idx); + if (m_use_support) { + support.insert(idx.m_offset); } } TRACE("hilbert_basis", display(tout);); - if (!has_non_negative) { - return l_false; - } // resolve passive into active + offset_t j = alloc_vector(); while (!m_passive->empty()) { if (m_cancel) { return l_undef; @@ -667,14 +823,16 @@ lbool hilbert_basis::saturate(num_vector const& ineq, bool is_eq) { continue; } for (unsigned i = 0; !m_cancel && i < m_active.size(); ++i) { - if (can_resolve(idx, m_active[i])) { - offset_t j = alloc_vector(); + if ((!m_use_support || support.contains(m_active[i].m_offset)) && can_resolve(idx, m_active[i])) { resolve(idx, m_active[i], j); - add_goal(j); + if (add_goal(j)) { + j = alloc_vector(); + } } } m_active.push_back(idx); } + m_free_list.push_back(j); // Move positive from active and zeros to new basis. m_basis.reset(); m_basis.append(m_zero); @@ -691,7 +849,103 @@ lbool hilbert_basis::saturate(num_vector const& ineq, bool is_eq) { m_passive->reset(); m_zero.reset(); TRACE("hilbert_basis", display(tout);); - return l_true; + return m_basis.empty()?l_false:l_true; +} + +bool hilbert_basis::vector_lt(offset_t idx1, offset_t idx2) const { + values v = vec(idx1); + values w = vec(idx2); + numeral a(0), b(0); + for (unsigned i = 0; i < get_num_vars(); ++i) { + a += abs(v[i]); + b += abs(w[i]); + } + return a < b; +} + +lbool hilbert_basis::saturate(num_vector const& ineq, bool is_eq) { + m_zero.reset(); + m_index->reset(); + m_passive2->reset(); + m_sos.reset(); + TRACE("hilbert_basis", display_ineq(tout, ineq, is_eq);); + unsigned init_basis_size = 0; + for (unsigned i = 0; i < m_basis.size(); ++i) { + offset_t idx = m_basis[i]; + values v = vec(idx); + v.weight() = get_weight(v, ineq); + m_index->insert(idx, v); + if (v.weight().is_zero()) { + m_zero.push_back(idx); + } + else { + if (v.weight().is_pos()) { + m_basis[init_basis_size++] = idx; + } + m_sos.push_back(idx); + } + } + m_basis.resize(init_basis_size); + // ASSERT basis is sorted by weight. + + // initialize passive + for (unsigned i = 0; (init_basis_size > 0) && i < m_sos.size(); ++i) { + if (vec(m_sos[i]).weight().is_neg()) { + m_passive2->insert(m_sos[i], 0); + } + } + + TRACE("hilbert_basis", display(tout);); + // resolve passive into active + offset_t idx = alloc_vector(); + while (!m_cancel && !m_passive2->empty()) { + offset_t sos, pas; + TRACE("hilbert_basis", display(tout); ); + unsigned offset = m_passive2->pop(sos, pas); + SASSERT(can_resolve(sos, pas)); + resolve(sos, pas, idx); + if (is_subsumed(idx)) { + continue; + } + values v = vec(idx); + m_index->insert(idx, v); + if (v.weight().is_zero()) { + m_zero.push_back(idx); + } + else { + if (!m_use_ordered_support) { + offset = 0; + } + m_passive2->insert(idx, offset); + if (v.weight().is_pos()) { + m_basis.push_back(idx); + } + } + idx = alloc_vector(); + } + if (m_cancel) { + return l_undef; + } + + m_free_list.push_back(idx); + // remove positive values from basis if we are looking for an equality. + while (is_eq && !m_basis.empty()) { + m_free_list.push_back(m_basis.back()); + m_basis.pop_back(); + } + for (unsigned i = 0; i < init_basis_size; ++i) { + offset_t idx = m_basis[i]; + if (vec(idx).weight().is_neg()) { + m_basis[i] = m_basis.back(); + m_basis.pop_back(); + + } + } + m_basis.append(m_zero); + std::sort(m_basis.begin(), m_basis.end(), vector_lt_t(*this)); + m_zero.reset(); + TRACE("hilbert_basis", display(tout);); + return m_basis.empty()?l_false:l_true; } void hilbert_basis::get_basis_solution(unsigned i, num_vector& v, bool& is_initial) { @@ -716,11 +970,20 @@ void hilbert_basis::select_inequality() { unsigned best = m_current_ineq; unsigned non_zeros = get_num_nonzeros(m_ineqs[best]); unsigned prod = get_ineq_product(m_ineqs[best]); + //numeral diff = get_ineq_diff(m_ineqs[best]); for (unsigned j = best+1; prod != 0 && j < m_ineqs.size(); ++j) { unsigned non_zeros2 = get_num_nonzeros(m_ineqs[j]); unsigned prod2 = get_ineq_product(m_ineqs[j]); + //numeral diff2 = get_ineq_diff(m_ineqs[j]); + if (prod2 == 0) { + prod = prod2; + non_zeros = non_zeros2; + best = j; + break; + } if (non_zeros2 < non_zeros || (non_zeros2 == non_zeros && prod2 < prod)) { prod = prod2; + // diff = diff2; non_zeros = non_zeros2; best = j; } @@ -757,6 +1020,22 @@ unsigned hilbert_basis::get_ineq_product(num_vector const& ineq) { return num_pos * num_neg; } +hilbert_basis::numeral hilbert_basis::get_ineq_diff(num_vector const& ineq) { + numeral max_pos(0), min_neg(0); + iterator it = begin(); + for (; it != end(); ++it) { + values v = vec(*it); + numeral w = get_weight(v, ineq); + if (w > max_pos) { + max_pos = w; + } + else if (w < min_neg) { + min_neg = w; + } + } + return max_pos - min_neg; +} + void hilbert_basis::recycle(offset_t idx) { m_index->remove(idx, vec(idx)); m_free_list.push_back(idx); @@ -794,11 +1073,11 @@ hilbert_basis::offset_t hilbert_basis::alloc_vector() { } } -void hilbert_basis::add_goal(offset_t idx) { +bool hilbert_basis::add_goal(offset_t idx) { TRACE("hilbert_basis", display(tout, idx);); values v = vec(idx); if (is_subsumed(idx)) { - return; + return false; } m_index->insert(idx, v); if (v.weight().is_zero()) { @@ -807,6 +1086,7 @@ void hilbert_basis::add_goal(offset_t idx) { else { m_passive->insert(idx); } + return true; } bool hilbert_basis::is_subsumed(offset_t idx) { @@ -885,6 +1165,15 @@ void hilbert_basis::display(std::ostream& out) const { display(out, *it); } } + if (!m_passive2->empty()) { + passive2::iterator it = m_passive2->begin(); + passive2::iterator end = m_passive2->end(); + out << "passive:\n"; + for (; it != end; ++it) { + display(out << "sos:", it.sos()); + display(out << "pas:", it.pas()); + } + } if (!m_zero.empty()) { out << "zero:\n"; for (unsigned i = 0; i < m_zero.size(); ++i) { diff --git a/src/muz_qe/hilbert_basis.h b/src/muz_qe/hilbert_basis.h index 567d72fbc..78d4d7cec 100644 --- a/src/muz_qe/hilbert_basis.h +++ b/src/muz_qe/hilbert_basis.h @@ -36,6 +36,7 @@ private: class value_index2; class index; class passive; + class passive2; struct offset_t { unsigned m_offset; offset_t(unsigned o) : m_offset(o) {} @@ -69,13 +70,20 @@ private: svector m_basis; // vector of current basis svector m_free_list; // free list of unused storage svector m_active; // active set + svector m_sos; // set of support svector m_zero; // zeros passive* m_passive; // passive set + passive2* m_passive2; // passive set volatile bool m_cancel; stats m_stats; index* m_index; // index of generated vectors unsigned_vector m_ints; // indices that can be both positive and negative unsigned m_current_ineq; + + bool m_use_support; // parameter: (associativity) resolve only against vectors that are initially in basis. + bool m_use_ordered_support; // parameter: (commutativity) resolve in order + bool m_use_ordered_subsumption; // parameter + class iterator { hilbert_basis const& hb; unsigned m_idx; @@ -91,10 +99,12 @@ private: static offset_t mk_invalid_offset(); static bool is_invalid_offset(offset_t offs); lbool saturate(num_vector const& ineq, bool is_eq); + lbool saturate_orig(num_vector const& ineq, bool is_eq); void init_basis(); void select_inequality(); unsigned get_num_nonzeros(num_vector const& ineq); unsigned get_ineq_product(num_vector const& ineq); + numeral get_ineq_diff(num_vector const& ineq); void add_unit_vector(unsigned i, numeral const& e); unsigned get_num_vars() const; @@ -106,12 +116,15 @@ private: void recycle(offset_t idx); bool can_resolve(offset_t i, offset_t j) const; sign_t get_sign(offset_t idx) const; - void add_goal(offset_t idx); + bool add_goal(offset_t idx); offset_t alloc_vector(); void resolve(offset_t i, offset_t j, offset_t r); iterator begin() const { return iterator(*this,0); } iterator end() const { return iterator(*this, m_basis.size()); } + class vector_lt_t; + bool vector_lt(offset_t i, offset_t j) const; + values vec(offset_t offs) const; void display(std::ostream& out, offset_t o) const; @@ -125,6 +138,10 @@ public: void reset(); + void set_use_support(bool b) { m_use_support = b; } + void set_use_ordered_support(bool b) { m_use_ordered_support = b; } + void set_use_ordered_subsumption(bool b) { m_use_ordered_subsumption = b; } + // add inequality v*x >= 0 // add inequality v*x <= 0 // add equality v*x = 0 diff --git a/src/test/heap_trie.cpp b/src/test/heap_trie.cpp index ad3cd0a8d..7b57f97f2 100644 --- a/src/test/heap_trie.cpp +++ b/src/test/heap_trie.cpp @@ -4,7 +4,8 @@ struct unsigned_le { static bool le(unsigned i, unsigned j) { return i <= j; } }; -typedef heap_trie heap_trie_t; + +typedef heap_trie heap_trie_t; static void find_le(heap_trie_t& ht, unsigned num_keys, unsigned const* keys) { statistics st; diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index b02c8c90c..e2d1d337e 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -10,6 +10,9 @@ #include #include +static bool g_use_ordered_support = false; +static bool g_use_ordered_subsumption = false; +static bool g_use_support = false; class hilbert_basis_validate { ast_manager& m; @@ -241,6 +244,9 @@ static void saturate_basis(hilbert_basis& hb) { signal(SIGINT, on_ctrl_c); g_hb = &hb; g_start_time = static_cast(clock()); + hb.set_use_ordered_support(g_use_ordered_support); + hb.set_use_support(g_use_support); + hb.set_use_ordered_subsumption(g_use_ordered_subsumption); lbool is_sat = hb.saturate(); switch(is_sat) { @@ -505,6 +511,10 @@ static void tst15() { void tst_hilbert_basis() { std::cout << "hilbert basis test\n"; +// tst3(); +// return; + + g_use_ordered_support = true; if (true) { tst1(); @@ -531,4 +541,14 @@ void tst_hilbert_basis() { else { gorrila_test(0, 10, 7, 20, 11); } + + return; + std::cout << "ordered support\n"; + g_use_ordered_support = true; + tst4(); + + std::cout << "non-ordered support\n"; + g_use_ordered_support = false; + tst4(); + } From ffb1fc37dfa5ce4b9608b5e0c881f3dde113b184 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 25 Feb 2013 15:37:33 +0000 Subject: [PATCH 08/97] Java API: New JDK detection routines. Signed-off-by: Christoph M. Wintersteiger --- scripts/mk_util.py | 190 ++++++++++++++++++++++----------------------- 1 file changed, 94 insertions(+), 96 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 5d2fb4e17..c70b1d527 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -30,13 +30,12 @@ CC=getenv("CC", None) CPPFLAGS=getenv("CPPFLAGS", "") CXXFLAGS=getenv("CXXFLAGS", "") LDFLAGS=getenv("LDFLAGS", "") -JAVA=getenv("JAVA", "java") -JAVAC=getenv("JAVAC", "javac") -JAVA_HOME=getenv("JAVA_HOME", None) +JDK_HOME=getenv("JDK_HOME", None) JNI_HOME=getenv("JNI_HOME", None) CXX_COMPILERS=['g++', 'clang++'] C_COMPILERS=['gcc', 'clang'] +JAVAC=None PYTHON_PACKAGE_DIR=distutils.sysconfig.get_python_lib() BUILD_DIR='build' REV_BUILD_DIR='..' @@ -207,24 +206,6 @@ def test_openmp(cc): t.commit() return exec_compiler_cmd([cc, CPPFLAGS, 'tstomp.cpp', LDFLAGS, '-fopenmp']) == 0 -def check_java(): - t = TempFile('Hello.java') - t.add('public class Hello { public static void main(String[] args) { System.out.println("Hello, World"); }}\n') - t.commit() - if is_verbose(): - print("Testing %s..." % JAVAC) - r = exec_cmd([JAVAC, 'Hello.java']) - if r != 0: - raise MKException('Failed testing Java compiler. Set environment variable JAVAC with the path to the Java compiler') - if is_verbose(): - print("Testing %s..." % JAVA) - r = exec_cmd([JAVA, 'Hello']) - rmf('Hello.class') - if r != 0: - raise MKException('Failed testing Java program. Set environment variable JAVA with the path to the Java virtual machine') - find_java_home() - find_jni_home() - def find_jni_h(path): for root, dirs, files in os.walk(path): for f in files: @@ -232,76 +213,97 @@ def find_jni_h(path): return root return False -def find_java_home(): - global JAVA_HOME - if JAVA_HOME != None: - if IS_WINDOWS: - ind = '%s%s' % (JAVA_HOME, '\\bin\\java.exe') - else: - ind = '%s%s' % (JAVA_HOME, '/bin/java') - if not os.path.exists(ind): - raise MKException("Failed to detect java at '%s'.Possible solution: set JAVA_HOME with the path to JDK." % os.path.join(JAVA_HOME)) - else: - return - if is_verbose(): - print("Finding JAVA_HOME...") - t = TempFile('output') - null = open(os.devnull, 'wb') - try: - subprocess.call([JAVA, '-verbose'], stdout=t.fname, stderr=null) - t.commit() - except: - raise MKException('Failed to find JAVA_HOME') - open_pat = re.compile("\[Opened (.*)\]") - t = open('output', 'r') - for line in t: - m = open_pat.match(line) - if m: - # Remove last 3 directives from m.group(1) - tmp = m.group(1).split(os.sep) - path = string.join(tmp[:len(tmp) - 3], os.sep) - if IS_WINDOWS: - ind = '%s%s' % (path, '\\bin\\java.exe') - else: - ind = '%s%s' % (path, '/bin/java') - if os.path.exists(ind): - JAVA_HOME = path - return - if IS_OSX: - path = '%s%s' % (path, '/Contents/Home/') - ind = '%s%s' % (path, 'bin/java') - if os.path.exists(ind): - JAVA_HOME = path - return - raise MKException("Failed to detect java at '%s'.Possible solution: set JAVA_HOME with the path to JDK." % os.path.join(path)) - return - raise MKException('Failed to find JAVA_HOME') - -def find_jni_home(): +def check_java(): + global JDK_HOME global JNI_HOME - if JNI_HOME != None: - if is_verbose(): - print("Checking jni.h...") - path = JNI_HOME - fn = os.path.join(path, 'jni.h') - print("Checking for jni.h in %s..." % JNI_HOME) - if os.path.exists(fn): - return + global JAVAC + + if is_verbose(): + print("Finding JDK_HOME...") + + if JDK_HOME != None: + if IS_WINDOWS: + JAVAC = os.path.join(JDK_HOME, 'bin', 'javac.exe') + else: + JAVAC = os.path.join(JDK_HOME, 'bin', 'javac') + + if not os.path.exists(JAVAC): + raise MKException("Failed to detect javac at '%s/bin'; the environment variable JDK_HOME is probably set to the wrong path." % os.path.join(JDK_HOME)) else: - path = '%s%s' % (JAVA_HOME, '/include/') - fn = '%s%s' % (path, 'jni.h') - print("Checking for jni.h in %s..." % path) - if os.path.exists(fn): - JNI_HOME = find_jni_h(path) - elif IS_OSX: - # Apparently Apple knows best where to put stuff... - path = '/System/Library/Frameworks/JavaVM.framework/Headers/' - fn = '%s%s' % (path, 'jni.h') - print("Checking for jni.h in %s..." % path) - if os.path.exists(fn): - JNI_HOME = find_jni_h(path) - if JNI_HOME == None: - raise MKException("Failed to detect jni.h. Possible solution: set JNI_HOME with the path to JDK.") + # Search for javac in the path. + ind = 'javac'; + if IS_WINDOWS: + ind = ind + '.exe' + paths = os.getenv('path', None) + spaths = paths.split(os.pathsep) + for i in range(0, len(spaths)): + cmb = os.path.join(spaths[i], ind) + if os.path.exists(cmb): + JAVAC = cmb + break + + if JAVAC == None: + raise MKException('No java compiler in the path, please adjust your PATH or set JDK_HOME to the location of the JDK.') + + if is_verbose(): + print("Testing %s..." % JAVAC) + + t = TempFile('Hello.java') + t.add('public class Hello { public static void main(String[] args) { System.out.println("Hello, World"); }}\n') + t.commit() + + oo = TempFile('output') + eo = TempFile('errout') + try: + subprocess.call([JAVAC, 'Hello.java', '-verbose'], stdout=oo.fname, stderr=eo.fname) + oo.commit() + eo.commit() + except: + raise MKException('Found, but failed to run Java compiler at %s' % (JAVAC)) + + os.remove('Hello.class') + + if is_verbose(): + print("Finding jni.h...") + + if JNI_HOME != None: + if not os.path.exists(path.join(JNI_HOME, 'jni.h')): + raise MKException("Failed to detect jni.h '%s'; the environment variable JNI_HOME is probably set to the wrong path." % os.path.join(JNI_HOME)) + else: + # Search for jni.h in the library directories... + t = open('errout', 'r') + open_pat = re.compile("\[search path for class files: (.*)\]") + cdirs = [] + for line in t: + m = open_pat.match(line) + if m: + libdirs = m.group(1).split(',') + for libdir in libdirs: + q = os.path.dirname(libdir) + if cdirs.count(q) == 0: + cdirs.append(q) + + # ... plus some heuristic ones. + extra_dirs = [] + + # For the libraries, even the JDK usually uses a JRE that comes with it. To find the + # headers we have to go a little bit higher up. + for dir in cdirs: + extra_dirs.append(os.path.abspath(os.path.join(dir, '..'))) + + if IS_OSX: # Apparently Apple knows best where to put stuff... + extra_dirs.append('/System/Library/Frameworks/JavaVM.framework/Headers/') + + cdirs[len(cdirs):] = extra_dirs + + for dir in cdirs: + print dir + q = find_jni_h(dir) + if q != False: + JNI_HOME = q + + if JNI_HOME == None: + raise MKException("Failed to detect jni.h. Possible solution: set JNI_HOME with the path to JDK.") def is64(): return sys.maxsize >= 2**32 @@ -436,9 +438,7 @@ def display_help(exit_code): print(" LDFLAGS Linker flags, e.g., -L if you have libraries in a non-standard directory") print(" CPPFLAGS Preprocessor flags, e.g., -I if you have header files in a non-standard directory") print(" CXXFLAGS C++ compiler flags") - print(" JAVA Java virtual machine (only relevant if -j or --java option is provided)") - print(" JAVAC Java compiler (only relevant if -j or --java option is provided)") - print(" JAVA_HOME JDK installation directory (only relevant if -j or --java option is provided)") + print(" JDK_HOME JDK installation directory (only relevant if -j or --java option is provided)") print(" JNI_HOME JNI bindings directory (only relevant if -j or --java option is provided)") exit(exit_code) @@ -1425,10 +1425,9 @@ def mk_config(): if is_verbose(): print('64-bit: %s' % is64()) if is_java_enabled(): - print('Java Home: %s' % JAVA_HOME) + print('JDK Home: %s' % JDK_HOME) print('JNI Home: %s' % JNI_HOME) print('Java Compiler: %s' % JAVAC) - print('Java VM: %s' % JAVA) else: global CXX, CC, GMP, CPPFLAGS, CXXFLAGS, LDFLAGS ARITH = "internal" @@ -1530,10 +1529,9 @@ def mk_config(): print('gprof: enabled') print('Python version: %s' % distutils.sysconfig.get_python_version()) if is_java_enabled(): - print('Java Home: %s' % JAVA_HOME) + print('JDK Home: %s' % JDK_HOME) print('JNI Home: %s' % JNI_HOME) print('Java Compiler: %s' % JAVAC) - print('Java VM: %s' % JAVA) def mk_install(out): out.write('install:\n') From f5cdc14737b9ef3e23eb7754eee4e78637d942a6 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 25 Feb 2013 15:44:54 +0000 Subject: [PATCH 09/97] Java API: build system bugfixes Signed-off-by: Christoph M. Wintersteiger --- scripts/mk_util.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index c70b1d527..5b41eced4 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -30,7 +30,6 @@ CC=getenv("CC", None) CPPFLAGS=getenv("CPPFLAGS", "") CXXFLAGS=getenv("CXXFLAGS", "") LDFLAGS=getenv("LDFLAGS", "") -JDK_HOME=getenv("JDK_HOME", None) JNI_HOME=getenv("JNI_HOME", None) CXX_COMPILERS=['g++', 'clang++'] @@ -214,12 +213,13 @@ def find_jni_h(path): return False def check_java(): - global JDK_HOME global JNI_HOME global JAVAC + + JDK_HOME = getenv('JDK_HOME', None) # we only need to check this locally. if is_verbose(): - print("Finding JDK_HOME...") + print("Finding javac ...") if JDK_HOME != None: if IS_WINDOWS: @@ -234,13 +234,14 @@ def check_java(): ind = 'javac'; if IS_WINDOWS: ind = ind + '.exe' - paths = os.getenv('path', None) - spaths = paths.split(os.pathsep) - for i in range(0, len(spaths)): - cmb = os.path.join(spaths[i], ind) - if os.path.exists(cmb): - JAVAC = cmb - break + paths = os.getenv('PATH', None) + if paths: + spaths = paths.split(os.pathsep) + for i in range(0, len(spaths)): + cmb = os.path.join(spaths[i], ind) + if os.path.exists(cmb): + JAVAC = cmb + break if JAVAC == None: raise MKException('No java compiler in the path, please adjust your PATH or set JDK_HOME to the location of the JDK.') @@ -297,7 +298,6 @@ def check_java(): cdirs[len(cdirs):] = extra_dirs for dir in cdirs: - print dir q = find_jni_h(dir) if q != False: JNI_HOME = q @@ -1425,8 +1425,7 @@ def mk_config(): if is_verbose(): print('64-bit: %s' % is64()) if is_java_enabled(): - print('JDK Home: %s' % JDK_HOME) - print('JNI Home: %s' % JNI_HOME) + print('JNI Bindings: %s' % JNI_HOME) print('Java Compiler: %s' % JAVAC) else: global CXX, CC, GMP, CPPFLAGS, CXXFLAGS, LDFLAGS @@ -1529,8 +1528,7 @@ def mk_config(): print('gprof: enabled') print('Python version: %s' % distutils.sysconfig.get_python_version()) if is_java_enabled(): - print('JDK Home: %s' % JDK_HOME) - print('JNI Home: %s' % JNI_HOME) + print('JNI Bindings: %s' % JNI_HOME) print('Java Compiler: %s' % JAVAC) def mk_install(out): From 14f582eca5f1429d145a3794d69fa9d6c213ac2d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 25 Feb 2013 16:03:57 +0000 Subject: [PATCH 10/97] Java API: added automatic detection of jar Signed-off-by: Christoph M. Wintersteiger --- scripts/mk_util.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 5b41eced4..09aada950 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -35,6 +35,7 @@ JNI_HOME=getenv("JNI_HOME", None) CXX_COMPILERS=['g++', 'clang++'] C_COMPILERS=['gcc', 'clang'] JAVAC=None +JAR=None PYTHON_PACKAGE_DIR=distutils.sysconfig.get_python_lib() BUILD_DIR='build' REV_BUILD_DIR='..' @@ -215,6 +216,7 @@ def find_jni_h(path): def check_java(): global JNI_HOME global JAVAC + global JAR JDK_HOME = getenv('JDK_HOME', None) # we only need to check this locally. @@ -246,6 +248,17 @@ def check_java(): if JAVAC == None: raise MKException('No java compiler in the path, please adjust your PATH or set JDK_HOME to the location of the JDK.') + if is_verbose(): + print("Finding jar ...") + + if IS_WINDOWS: + JAR = os.path.join(os.path.dirname(JAVAC), 'jar.exe') + else: + JAR = os.path.join(os.path.dirname(JAVAC), 'jar') + + if not os.path.exists(JAR): + raise MKException("Failed to detect jar at '%s'; the environment variable JDK_HOME is probably set to the wrong path." % os.path.join(JDK_HOME)) + if is_verbose(): print("Testing %s..." % JAVAC) @@ -1120,6 +1133,9 @@ class JavaDLLComponent(Component): self.manifest_file = manifest_file def mk_makefile(self, out): + global JAVAC + global JAR + if is_java_enabled(): mk_dir(os.path.join(BUILD_DIR, 'api', 'java', 'classes')) dllfile = '%s$(SO_EXT)' % self.dll_name @@ -1146,6 +1162,9 @@ class JavaDLLComponent(Component): deps += '%s ' % os.path.join(self.to_src_dir, 'enumerations', jfile) out.write(deps) out.write('\n') + if IS_WINDOWS: + JAVAC = '"%s"' % JAVAC + JAR = '"%s"' % JAR t = ('\t%s %s.java -d %s\n' % (JAVAC, os.path.join(self.to_src_dir, 'enumerations', '*'), os.path.join('api', 'java', 'classes'))) out.write(t) t = ('\t%s -cp %s %s.java -d %s\n' % (JAVAC, @@ -1153,7 +1172,7 @@ class JavaDLLComponent(Component): os.path.join(self.to_src_dir, '*'), os.path.join('api', 'java', 'classes'))) out.write(t) - out.write('\tjar cfm %s.jar %s -C %s .\n' % (self.package_name, + out.write('\t%s cfm %s.jar %s -C %s .\n' % (JAR, self.package_name, os.path.join(self.to_src_dir, 'manifest'), os.path.join('api', 'java', 'classes'))) out.write('java: %s.jar\n\n' % self.package_name) From b2810592e6bbd84c521b821a47fd0f33c75f4a96 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Tue, 26 Feb 2013 08:29:01 -0800 Subject: [PATCH 11/97] Add enumeration_sort method to C++ API. Add as_expr method to goal class in C++ API. Add enum_sort_example to C++ examples/c++/example.cpp Signed-off-by: Leonardo de Moura --- examples/c++/example.cpp | 24 ++++++++++++++++++++ src/api/c++/z3++.h | 48 +++++++++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 1f127e8e4..ab5d0132c 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -883,6 +883,29 @@ void incremental_example3() { std::cout << s.check(a2) << "\n"; } +void enum_sort_example() { + std::cout << "enumeration sort example\n"; + context ctx; + const char * enum_names[] = { "a", "b", "c" }; + func_decl_vector enum_consts(ctx); + func_decl_vector enum_testers(ctx); + sort s = ctx.enumeration_sort("enumT", 3, enum_names, enum_consts, enum_testers); + // enum_consts[0] is a func_decl of arity 0. + // we convert it to an expression using the operator() + expr a = enum_consts[0](); + expr b = enum_consts[1](); + expr x = ctx.constant("x", s); + expr test = (x==a) && (x==b); + std::cout << "1: " << test << std::endl; + tactic qe(ctx, "ctx-solver-simplify"); + goal g(ctx); + g.add(test); + expr res(ctx); + apply_result result_of_elimination = qe.apply(g); + goal result_goal = result_of_elimination[0]; + std::cout << "2: " << result_goal.as_expr() << std::endl; +} + int main() { try { demorgan(); std::cout << "\n"; @@ -917,6 +940,7 @@ int main() { incremental_example1(); std::cout << "\n"; incremental_example2(); std::cout << "\n"; incremental_example3(); std::cout << "\n"; + enum_sort_example(); std::cout << "\n"; std::cout << "done\n"; } catch (exception & ex) { diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 5af4bf60b..3382b8b00 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -63,6 +63,11 @@ namespace z3 { class statistics; class apply_result; class fixedpoint; + template class ast_vector_tpl; + typedef ast_vector_tpl ast_vector; + typedef ast_vector_tpl expr_vector; + typedef ast_vector_tpl sort_vector; + typedef ast_vector_tpl func_decl_vector; inline void set_param(char const * param, char const * value) { Z3_global_param_set(param, value); } inline void set_param(char const * param, bool value) { Z3_global_param_set(param, value ? "true" : "false"); } @@ -190,7 +195,13 @@ namespace z3 { Example: Given a context \c c, c.array_sort(c.int_sort(), c.bool_sort()) is an array sort from integer to Boolean. */ sort array_sort(sort d, sort r); - + /** + \brief Return an enumeration sort: enum_names[0], ..., enum_names[n-1]. + \c cs and \c ts are output parameters. The method stores in \c cs the constants corresponding to the enumerated elements, + and in \c ts the predicates for testing if terms of the enumeration sort correspond to an enumeration. + */ + sort enumeration_sort(char const * name, unsigned n, char const * const * enum_names, func_decl_vector & cs, func_decl_vector & ts); + func_decl function(symbol const & name, unsigned arity, sort const * domain, sort const & range); func_decl function(char const * name, unsigned arity, sort const * domain, sort const & range); func_decl function(char const * name, sort const & domain, sort const & range); @@ -414,6 +425,7 @@ namespace z3 { bool is_const() const { return arity() == 0; } + expr operator()() const; expr operator()(unsigned n, expr const * args) const; expr operator()(expr const & a) const; expr operator()(int a) const; @@ -1020,11 +1032,6 @@ 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; } }; - typedef ast_vector_tpl ast_vector; - typedef ast_vector_tpl expr_vector; - typedef ast_vector_tpl sort_vector; - typedef ast_vector_tpl func_decl_vector; - class func_entry : public object { Z3_func_entry m_entry; void init(Z3_func_entry e) { @@ -1261,6 +1268,19 @@ namespace z3 { unsigned num_exprs() const { return Z3_goal_num_exprs(ctx(), m_goal); } bool is_decided_sat() const { return Z3_goal_is_decided_sat(ctx(), m_goal) != 0; } bool is_decided_unsat() const { return Z3_goal_is_decided_unsat(ctx(), m_goal) != 0; } + expr as_expr() const { + unsigned n = size(); + if (n == 0) + return ctx().bool_val(false); + else if (n == 1) + return operator[](0); + else { + array args(n); + for (unsigned i = 0; i < n; i++) + args[i] = operator[](i); + return expr(ctx(), Z3_mk_and(ctx(), n, args.ptr())); + } + } friend std::ostream & operator<<(std::ostream & out, goal const & g) { out << Z3_goal_to_string(g.ctx(), g); return out; } }; @@ -1437,6 +1457,17 @@ namespace z3 { inline sort context::real_sort() { Z3_sort s = Z3_mk_real_sort(m_ctx); check_error(); return sort(*this, s); } inline sort context::bv_sort(unsigned sz) { Z3_sort s = Z3_mk_bv_sort(m_ctx, sz); check_error(); return sort(*this, s); } inline sort context::array_sort(sort d, sort r) { Z3_sort s = Z3_mk_array_sort(m_ctx, d, r); check_error(); return sort(*this, s); } + inline sort context::enumeration_sort(char const * name, unsigned n, char const * const * enum_names, func_decl_vector & cs, func_decl_vector & ts) { + array _enum_names(n); + for (unsigned i = 0; i < n; i++) { _enum_names[i] = Z3_mk_string_symbol(*this, enum_names[i]); } + array _cs(n); + array _ts(n); + Z3_symbol _name = Z3_mk_string_symbol(*this, name); + sort s = to_sort(*this, Z3_mk_enumeration_sort(*this, _name, n, _enum_names.ptr(), _cs.ptr(), _ts.ptr())); + check_error(); + for (unsigned i = 0; i < n; i++) { cs.push_back(func_decl(*this, _cs[i])); ts.push_back(func_decl(*this, _ts[i])); } + return s; + } inline func_decl context::function(symbol const & name, unsigned arity, sort const * domain, sort const & range) { array args(arity); @@ -1538,6 +1569,11 @@ namespace z3 { return expr(ctx(), r); } + inline expr func_decl::operator()() const { + Z3_ast r = Z3_mk_app(ctx(), *this, 0, 0); + ctx().check_error(); + return expr(ctx(), r); + } inline expr func_decl::operator()(expr const & a) const { check_context(*this, a); Z3_ast args[1] = { a }; From 5fe58c2f2db10b864b21f53df1b9bbbda0d1d6a0 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 26 Feb 2013 19:13:48 +0000 Subject: [PATCH 12/97] Java API: renamed assert_(...) to add(...) .NET API: added alias Add(...) for Assert(...) Signed-off-by: Christoph M. Wintersteiger --- examples/java/JavaExample.java | 80 +++++++++++++++++----------------- src/api/dotnet/Fixedpoint.cs | 8 ++++ src/api/dotnet/Goal.cs | 8 ++++ src/api/dotnet/Solver.cs | 8 ++++ src/api/java/Fixedpoint.java | 2 +- src/api/java/Goal.java | 2 +- src/api/java/Solver.java | 2 +- 7 files changed, 67 insertions(+), 43 deletions(-) diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index c2743ece8..48395d8c2 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -197,7 +197,7 @@ class JavaExample TestFailedException { Solver s = ctx.mkSolver(); - s.assert_(f); + s.add(f); if (s.check() != sat) throw new TestFailedException(); if (sat == Status.SATISFIABLE) @@ -213,7 +213,7 @@ class JavaExample System.out.println("\nTactical solver: " + s); for (BoolExpr a : g.getFormulas()) - s.assert_(a); + s.add(a); System.out.println("Solver: " + s); if (s.check() != sat) @@ -266,8 +266,8 @@ class JavaExample p.add("mbqi", useMBQI); s.setParameters(p); for (BoolExpr a : assumptions) - s.assert_(a); - s.assert_(ctx.mkNot(f)); + s.add(a); + s.add(ctx.mkNot(f)); Status q = s.check(); switch (q) @@ -299,8 +299,8 @@ class JavaExample p.add("mbqi", useMBQI); s.setParameters(p); for (BoolExpr a : assumptions) - s.assert_(a); - s.assert_(ctx.mkNot(f)); + s.add(a); + s.add(ctx.mkNot(f)); Status q = s.check(); switch (q) @@ -326,9 +326,9 @@ class JavaExample ArithExpr yr = (ArithExpr) ctx.mkConst(ctx.mkSymbol("y"), ctx.mkRealSort()); Goal g4 = ctx.mkGoal(true, false, false); - g4.assert_(ctx.mkGt(xr, ctx.mkReal(10, 1))); - g4.assert_(ctx.mkEq(yr, ctx.mkAdd(xr, ctx.mkReal(1, 1)))); - g4.assert_(ctx.mkGt(yr, ctx.mkReal(1, 1))); + g4.add(ctx.mkGt(xr, ctx.mkReal(10, 1))); + g4.add(ctx.mkEq(yr, ctx.mkAdd(xr, ctx.mkReal(1, 1)))); + g4.add(ctx.mkGt(yr, ctx.mkReal(1, 1))); ApplyResult ar = applyTactic(ctx, ctx.mkTactic("simplify"), g4); if (ar.getNumSubgoals() == 1 @@ -345,7 +345,7 @@ class JavaExample Solver s = ctx.mkSolver(); for (BoolExpr e : ar.getSubgoals()[0].getFormulas()) - s.assert_(e); + s.add(e); Status q = s.check(); System.out.println("Solver says: " + q); System.out.println("Model: \n" + s.getModel()); @@ -367,7 +367,7 @@ class JavaExample ctx.mkBitVecSort(32)); ArrayExpr aex = (ArrayExpr) ctx.mkConst(ctx.mkSymbol("MyArray"), asort); Expr sel = ctx.mkSelect(aex, ctx.mkInt(0)); - g.assert_(ctx.mkEq(sel, ctx.mkBV(42, 32))); + g.add(ctx.mkEq(sel, ctx.mkBV(42, 32))); Symbol xs = ctx.mkSymbol("x"); IntExpr xc = (IntExpr) ctx.mkConst(xs, ctx.getIntSort()); @@ -377,11 +377,11 @@ class JavaExample Expr[] fargs = { ctx.mkConst(xs, ctx.getIntSort()) }; IntExpr fapp = (IntExpr) ctx.mkApp(fd, fargs); - g.assert_(ctx.mkEq(ctx.mkAdd(xc, fapp), ctx.mkInt(123))); + g.add(ctx.mkEq(ctx.mkAdd(xc, fapp), ctx.mkInt(123))); Solver s = ctx.mkSolver(); for (BoolExpr a : g.getFormulas()) - s.assert_(a); + s.add(a); System.out.println("Solver: " + s); Status q = s.check(); @@ -574,8 +574,8 @@ class JavaExample ctx.mkEq(X[i][j], ctx.mkInt(instance[i][j])))); Solver s = ctx.mkSolver(); - s.assert_(sudoku_c); - s.assert_(instance_c); + s.add(sudoku_c); + s.add(instance_c); if (s.check() == Status.SATISFIABLE) { @@ -798,14 +798,14 @@ class JavaExample BoolExpr nontrivial_eq = ctx.mkEq(fapp, fapp2); Goal g = ctx.mkGoal(true, false, false); - g.assert_(trivial_eq); - g.assert_(nontrivial_eq); + g.add(trivial_eq); + g.add(nontrivial_eq); System.out.println("Goal: " + g); Solver solver = ctx.mkSolver(); for (BoolExpr a : g.getFormulas()) - solver.assert_(a); + solver.add(a); if (solver.check() != Status.SATISFIABLE) throw new TestFailedException(); @@ -820,7 +820,7 @@ class JavaExample if (ar.getNumSubgoals() != 1 || !ar.getSubgoals()[0].isDecidedSat()) throw new TestFailedException(); - g.assert_(ctx.mkEq(ctx.mkNumeral(1, ctx.mkBitVecSort(32)), + g.add(ctx.mkEq(ctx.mkNumeral(1, ctx.mkBitVecSort(32)), ctx.mkNumeral(2, ctx.mkBitVecSort(32)))); ar = applyTactic(ctx, ctx.mkTactic("smt"), g); if (ar.getNumSubgoals() != 1 || !ar.getSubgoals()[0].isDecidedUnsat()) @@ -832,7 +832,7 @@ class JavaExample throw new TestFailedException(); g2 = ctx.mkGoal(true, true, false); - g2.assert_(ctx.mkFalse()); + g2.add(ctx.mkFalse()); ar = applyTactic(ctx, ctx.mkTactic("smt"), g2); if (ar.getNumSubgoals() != 1 || !ar.getSubgoals()[0].isDecidedUnsat()) throw new TestFailedException(); @@ -840,10 +840,10 @@ class JavaExample Goal g3 = ctx.mkGoal(true, true, false); Expr xc = ctx.mkConst(ctx.mkSymbol("x"), ctx.getIntSort()); Expr yc = ctx.mkConst(ctx.mkSymbol("y"), ctx.getIntSort()); - g3.assert_(ctx.mkEq(xc, ctx.mkNumeral(1, ctx.getIntSort()))); - g3.assert_(ctx.mkEq(yc, ctx.mkNumeral(2, ctx.getIntSort()))); + g3.add(ctx.mkEq(xc, ctx.mkNumeral(1, ctx.getIntSort()))); + g3.add(ctx.mkEq(yc, ctx.mkNumeral(2, ctx.getIntSort()))); BoolExpr constr = ctx.mkEq(xc, yc); - g3.assert_(constr); + g3.add(constr); ar = applyTactic(ctx, ctx.mkTactic("smt"), g3); if (ar.getNumSubgoals() != 1 || !ar.getSubgoals()[0].isDecidedUnsat()) throw new TestFailedException(); @@ -1110,13 +1110,13 @@ class JavaExample // Use a solver for QF_BV Solver s = ctx.mkSolver("QF_BV"); - s.assert_(eq); + s.add(eq); Status res = s.check(); System.out.println("solver result: " + res); // Or perhaps a tactic for QF_BV Goal g = ctx.mkGoal(true, false, false); - g.assert_(eq); + g.add(eq); Tactic t = ctx.mkTactic("qfbv"); ApplyResult ar = t.apply(g); @@ -1139,7 +1139,7 @@ class JavaExample BoolExpr q = ctx.mkEq(x, y); Goal g = ctx.mkGoal(true, false, false); - g.assert_(q); + g.add(q); Tactic t1 = ctx.mkTactic("qfbv"); Tactic t2 = ctx.mkTactic("qfbv"); @@ -1341,7 +1341,7 @@ class JavaExample /* assert x >= "big number" */ BoolExpr c1 = ctx.mkGe(x, big_number); System.out.println("assert: x >= 'big number'"); - solver.assert_(c1); + solver.add(c1); /* create a backtracking point */ System.out.println("push"); @@ -1350,7 +1350,7 @@ class JavaExample /* assert x <= 3 */ BoolExpr c2 = ctx.mkLe(x, three); System.out.println("assert: x <= 3"); - solver.assert_(c2); + solver.add(c2); /* context is inconsistent at this point */ if (solver.check() != Status.UNSATISFIABLE) @@ -1375,7 +1375,7 @@ class JavaExample /* assert y > x */ BoolExpr c3 = ctx.mkGt(y, x); System.out.println("assert: y > x"); - solver.assert_(c3); + solver.add(c3); /* the context is still consistent. */ if (solver.check() != Status.SATISFIABLE) @@ -1911,10 +1911,10 @@ class JavaExample Solver solver = ctx.mkSolver(); /* assert x < y */ - solver.assert_(ctx.mkLt(x, y)); + solver.add(ctx.mkLt(x, y)); /* assert x > 2 */ - solver.assert_(ctx.mkGt(x, two)); + solver.add(ctx.mkGt(x, two)); /* find model for the constraints above */ Model model = null; @@ -1964,9 +1964,9 @@ class JavaExample Solver solver = ctx.mkSolver(); /* assert tup1 != tup2 */ - solver.assert_(ctx.mkNot(ctx.mkEq(tup1, tup2))); + solver.add(ctx.mkNot(ctx.mkEq(tup1, tup2))); /* assert first tup1 = first tup2 */ - solver.assert_(ctx.mkEq(ctx.mkApp(first, tup1), ctx.mkApp(first, tup2))); + solver.add(ctx.mkEq(ctx.mkApp(first, tup1), ctx.mkApp(first, tup2))); /* find model for the constraints above */ Model model = null; @@ -2014,7 +2014,7 @@ class JavaExample // Assert all feasible bounds. for (int i = 0; i < num_Exprs; ++i) { - solver.assert_(ctx.mkBVULE(to_minimize[i], + solver.add(ctx.mkBVULE(to_minimize[i], ctx.mkBV(upper[i], 32))); } @@ -2050,7 +2050,7 @@ class JavaExample { last_upper = (upper[i] + lower[i]) / 2; last_index = i; - solver.assert_(ctx.mkBVULE(to_minimize[i], + solver.add(ctx.mkBVULE(to_minimize[i], ctx.mkBV(last_upper, 32))); some_work = true; break; @@ -2074,7 +2074,7 @@ class JavaExample Solver solver = ctx.mkSolver(); - solver.assert_(ctx.mkBVULE(x, ctx.mkBVAdd(y, z))); + solver.add(ctx.mkBVULE(x, ctx.mkBVAdd(y, z))); checkSmall(ctx, solver, x, y, z); } @@ -2120,10 +2120,10 @@ class JavaExample BoolExpr f3 = ctx.mkOr(ctx.mkNot(pa), ctx.mkNot(pc)); BoolExpr f4 = pd; - solver.assert_(ctx.mkOr(f1, p1)); - solver.assert_(ctx.mkOr(f2, p2)); - solver.assert_(ctx.mkOr(f3, p3)); - solver.assert_(ctx.mkOr(f4, p4)); + solver.add(ctx.mkOr(f1, p1)); + solver.add(ctx.mkOr(f2, p2)); + solver.add(ctx.mkOr(f3, p3)); + solver.add(ctx.mkOr(f4, p4)); Status result = solver.check(assumptions); if (result == Status.UNSATISFIABLE) diff --git a/src/api/dotnet/Fixedpoint.cs b/src/api/dotnet/Fixedpoint.cs index 8d13fcb43..8c6e6c4c6 100644 --- a/src/api/dotnet/Fixedpoint.cs +++ b/src/api/dotnet/Fixedpoint.cs @@ -78,6 +78,14 @@ namespace Microsoft.Z3 } } + /// + /// Alias for Assert. + /// + public void Add(params BoolExpr[] constraints) + { + Assert(constraints); + } + /// /// Register predicate as recursive relation. /// diff --git a/src/api/dotnet/Goal.cs b/src/api/dotnet/Goal.cs index e648ac80c..b108683c9 100644 --- a/src/api/dotnet/Goal.cs +++ b/src/api/dotnet/Goal.cs @@ -90,6 +90,14 @@ namespace Microsoft.Z3 } } + /// + /// Alias for Assert. + /// + public void Add(params BoolExpr[] constraints) + { + Assert(constraints); + } + /// /// Indicates whether the goal contains `false'. /// diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 8c07ef31e..274f8dc4a 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -117,6 +117,14 @@ namespace Microsoft.Z3 } } + /// + /// Alias for Assert. + /// + public void Add(params BoolExpr[] constraints) + { + Assert(constraints); + } + /// /// Assert multiple constraints into the solver, and track them (in the unsat) core /// using the Boolean constants in ps. diff --git a/src/api/java/Fixedpoint.java b/src/api/java/Fixedpoint.java index 6a8cafae2..4710368aa 100644 --- a/src/api/java/Fixedpoint.java +++ b/src/api/java/Fixedpoint.java @@ -51,7 +51,7 @@ public class Fixedpoint extends Z3Object * * @throws Z3Exception **/ - public void assert_(BoolExpr ... constraints) throws Z3Exception + public void add(BoolExpr ... constraints) throws Z3Exception { getContext().checkContextMatch(constraints); for (BoolExpr a : constraints) diff --git a/src/api/java/Goal.java b/src/api/java/Goal.java index 520a7af15..c486a57b3 100644 --- a/src/api/java/Goal.java +++ b/src/api/java/Goal.java @@ -65,7 +65,7 @@ public class Goal extends Z3Object * * @throws Z3Exception **/ - public void assert_(BoolExpr ... constraints) throws Z3Exception + public void add(BoolExpr ... constraints) throws Z3Exception { getContext().checkContextMatch(constraints); for (BoolExpr c : constraints) diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index c60d3f88c..3827de07a 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -94,7 +94,7 @@ public class Solver extends Z3Object * * @throws Z3Exception **/ - public void assert_(BoolExpr... constraints) throws Z3Exception + public void add(BoolExpr... constraints) throws Z3Exception { getContext().checkContextMatch(constraints); for (BoolExpr a : constraints) From e8140f5c1fe143bd1017b3dff1c444eea494a59c Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Tue, 26 Feb 2013 12:34:52 -0800 Subject: [PATCH 13/97] Fix compilation problems when using Visual Studio 32 bit compiler Signed-off-by: Leonardo de Moura --- src/api/c++/z3++.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 3382b8b00..43975fd04 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -251,8 +251,8 @@ namespace z3 { array(unsigned sz):m_size(sz) { m_array = new T[sz]; } ~array() { delete[] m_array; } unsigned size() const { return m_size; } - T & operator[](unsigned i) { assert(i < m_size); return m_array[i]; } - T const & operator[](unsigned i) const { assert(i < m_size); return m_array[i]; } + T & operator[](int i) { assert(0 <= i); assert(static_cast(i) < m_size); return m_array[i]; } + T const & operator[](int i) const { assert(0 <= i); assert(static_cast(i) < m_size); return m_array[i]; } T const * ptr() const { return m_array; } T * ptr() { return m_array; } }; @@ -1016,7 +1016,7 @@ namespace z3 { ~ast_vector_tpl() { Z3_ast_vector_dec_ref(ctx(), m_vector); } operator Z3_ast_vector() const { return m_vector; } unsigned size() const { return Z3_ast_vector_size(ctx(), m_vector); } - T operator[](unsigned i) const { Z3_ast r = Z3_ast_vector_get(ctx(), m_vector, i); check_error(); return cast_ast()(ctx(), r); } + T operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_ast_vector_get(ctx(), m_vector, i); check_error(); return cast_ast()(ctx(), r); } void push_back(T const & e) { Z3_ast_vector_push(ctx(), m_vector, e); check_error(); } void resize(unsigned sz) { Z3_ast_vector_resize(ctx(), m_vector, sz); check_error(); } T back() const { return operator[](size() - 1); } @@ -1112,7 +1112,10 @@ namespace z3 { func_decl get_const_decl(unsigned i) const { Z3_func_decl r = Z3_model_get_const_decl(ctx(), m_model, i); check_error(); return func_decl(ctx(), r); } func_decl get_func_decl(unsigned i) const { Z3_func_decl r = Z3_model_get_func_decl(ctx(), m_model, i); check_error(); return func_decl(ctx(), r); } unsigned size() const { return num_consts() + num_funcs(); } - func_decl operator[](unsigned i) const { return i < num_consts() ? get_const_decl(i) : get_func_decl(i - num_consts()); } + func_decl operator[](int i) const { + assert(0 <= i); + return static_cast(i) < num_consts() ? get_const_decl(i) : get_func_decl(i - num_consts()); + } expr get_const_interp(func_decl c) const { check_context(*this, c); @@ -1260,7 +1263,7 @@ namespace z3 { } void add(expr const & f) { check_context(*this, f); Z3_goal_assert(ctx(), m_goal, f); check_error(); } unsigned size() const { return Z3_goal_size(ctx(), m_goal); } - expr operator[](unsigned i) const { Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); } + expr operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); } Z3_goal_prec precision() const { return Z3_goal_precision(ctx(), m_goal); } bool inconsistent() const { return Z3_goal_inconsistent(ctx(), m_goal) != 0; } unsigned depth() const { return Z3_goal_depth(ctx(), m_goal); } @@ -1303,8 +1306,7 @@ namespace z3 { return *this; } unsigned size() const { return Z3_apply_result_get_num_subgoals(ctx(), m_apply_result); } - goal operator[](unsigned i) const { Z3_goal r = Z3_apply_result_get_subgoal(ctx(), m_apply_result, i); check_error(); return goal(ctx(), r); } - goal operator[](int i) const { assert(i >= 0); return this->operator[](static_cast(i)); } + goal operator[](int i) const { assert(0 <= i); Z3_goal r = Z3_apply_result_get_subgoal(ctx(), m_apply_result, i); check_error(); return goal(ctx(), r); } model convert_model(model const & m, unsigned i = 0) const { check_context(*this, m); Z3_model new_m = Z3_apply_result_convert_model(ctx(), m_apply_result, i, m); From 5598f334d406905fc1717a2cdbb9c9e484d19094 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Feb 2013 17:01:49 -0800 Subject: [PATCH 14/97] optimizations to Hilbert basis Signed-off-by: Nikolaj Bjorner --- src/muz_qe/hilbert_basis.cpp | 112 +++++++++++++++++++++-------------- src/muz_qe/hilbert_basis.h | 16 ++--- src/test/hilbert_basis.cpp | 2 + 3 files changed, 77 insertions(+), 53 deletions(-) diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index 49bf20746..59b513d8d 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -192,19 +192,9 @@ class hilbert_basis::value_index2 { checker m_checker; vector m_keys; -#if 1 numeral const* get_keys(values const& vs) { return vs()-1; } -#else - numeral const* get_keys(values const& vs) { - unsigned sz = m_keys.size(); - for (unsigned i = 0; i < sz; ++i) { - m_keys[sz-i-1] = vs()[i-1]; - } - return m_keys.c_ptr(); - } -#endif public: value_index2(hilbert_basis& hb): hb(hb), m_init(false) { @@ -506,7 +496,11 @@ class hilbert_basis::passive2 { } }; hilbert_basis& hb; - svector const& m_sos; + svector m_pos_sos; + svector m_neg_sos; + vector m_pos_sos_sum; + vector m_neg_sos_sum; + vector m_sum_abs; unsigned_vector m_psos; svector m_pas; vector m_weight; @@ -527,40 +521,59 @@ class hilbert_basis::passive2 { public: passive2(hilbert_basis& hb): hb(hb), - m_sos(hb.m_sos), m_lt(&m_this), m_heap(10, m_lt) { m_this = this; } + void init(svector const& I) { + for (unsigned i = 0; i < I.size(); ++i) { + numeral const& w = hb.vec(I[i]).weight(); + if (w.is_pos()) { + m_pos_sos.push_back(I[i]); + m_pos_sos_sum.push_back(sum_abs(I[i])); + } + else { + m_neg_sos.push_back(I[i]); + m_neg_sos_sum.push_back(sum_abs(I[i])); + } + } + } + void reset() { m_heap.reset(); m_free_list.reset(); m_psos.reset(); m_pas.reset(); + m_sum_abs.reset(); + m_pos_sos.reset(); + m_neg_sos.reset(); + m_pos_sos_sum.reset(); + m_neg_sos_sum.reset(); m_weight.reset(); } void insert(offset_t idx, unsigned offset) { - SASSERT(!m_sos.empty()); + SASSERT(!m_pos_sos.empty()); unsigned v; - numeral w = sum_abs(idx) + sum_abs(m_sos[0]); if (m_free_list.empty()) { v = m_pas.size(); m_pas.push_back(idx); m_psos.push_back(offset); - m_weight.push_back(w); + m_weight.push_back(numeral(0)); m_heap.set_bounds(v+1); + m_sum_abs.push_back(sum_abs(idx)); } else { v = m_free_list.back(); m_free_list.pop_back(); m_pas[v] = idx; m_psos[v] = offset; - m_weight[v] = w; + m_weight[v] = numeral(0); + m_sum_abs[v] = sum_abs(idx); } - next_resolvable(v); + next_resolvable(hb.vec(idx).weight().is_pos(), v); } bool empty() const { @@ -570,12 +583,13 @@ public: unsigned pop(offset_t& sos, offset_t& pas) { SASSERT (!empty()); unsigned val = static_cast(m_heap.erase_min()); - unsigned psos = m_psos[val]; - sos = m_sos[psos]; pas = m_pas[val]; - m_psos[val]++; - next_resolvable(val); numeral old_weight = hb.vec(pas).weight(); + bool is_positive = old_weight.is_pos(); + unsigned psos = m_psos[val]; + sos = is_positive?m_neg_sos[psos]:m_pos_sos[psos]; + m_psos[val]++; + next_resolvable(is_positive, val); numeral new_weight = hb.vec(sos).weight() + old_weight; if (new_weight.is_pos() != old_weight.is_pos()) { psos = 0; @@ -599,7 +613,7 @@ public: public: iterator(passive2& p, unsigned i): p(p), m_idx(i) { fwd(); } offset_t pas() const { return p.m_pas[m_idx]; } - offset_t sos() const { return p.m_sos[p.m_psos[m_idx]]; } + offset_t sos() const { return (p.hb.vec(pas()).weight().is_pos()?p.m_neg_sos:p.m_pos_sos)[p.m_psos[m_idx]]; } iterator& operator++() { ++m_idx; fwd(); return *this; } iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; } bool operator==(iterator const& it) const {return m_idx == it.m_idx; } @@ -614,12 +628,14 @@ public: return iterator(*this, m_pas.size()); } private: - void next_resolvable(unsigned v) { + void next_resolvable(bool is_positive, unsigned v) { offset_t pas = m_pas[v]; - while (m_psos[v] < m_sos.size()) { - offset_t sos = m_sos[m_psos[v]]; - if (hb.can_resolve(sos, pas)) { - m_weight[v] = sum_abs(pas) + sum_abs(sos); + svector const& soss = is_positive?m_neg_sos:m_pos_sos; + while (m_psos[v] < soss.size()) { + unsigned psos = m_psos[v]; + offset_t sos = soss[psos]; + if (hb.can_resolve(sos, pas, false)) { + m_weight[v] = m_sum_abs[v] + (is_positive?m_neg_sos_sum[psos]:m_pos_sos_sum[psos]); m_heap.insert(v); return; } @@ -745,7 +761,7 @@ unsigned hilbert_basis::get_num_vars() const { } hilbert_basis::values hilbert_basis::vec(offset_t offs) const { - return values(m_store.c_ptr() + (get_num_vars() + 1)*offs.m_offset); + return values(m_ineqs.size(), m_store.c_ptr() + offs.m_offset); } void hilbert_basis::init_basis() { @@ -804,6 +820,9 @@ lbool hilbert_basis::saturate_orig(num_vector const& ineq, bool is_eq) { offset_t idx = *it; values v = vec(idx); v.weight() = get_weight(v, ineq); + for (unsigned k = 0; k < m_current_ineq; ++k) { + v.weight(k) = get_weight(v, m_ineqs[k]); + } add_goal(idx); if (m_use_support) { support.insert(idx.m_offset); @@ -823,7 +842,7 @@ lbool hilbert_basis::saturate_orig(num_vector const& ineq, bool is_eq) { continue; } for (unsigned i = 0; !m_cancel && i < m_active.size(); ++i) { - if ((!m_use_support || support.contains(m_active[i].m_offset)) && can_resolve(idx, m_active[i])) { + if ((!m_use_support || support.contains(m_active[i].m_offset)) && can_resolve(idx, m_active[i], true)) { resolve(idx, m_active[i], j); if (add_goal(j)) { j = alloc_vector(); @@ -874,6 +893,9 @@ lbool hilbert_basis::saturate(num_vector const& ineq, bool is_eq) { offset_t idx = m_basis[i]; values v = vec(idx); v.weight() = get_weight(v, ineq); + for (unsigned k = 0; k < m_current_ineq; ++k) { + v.weight(k) = get_weight(v, m_ineqs[k]); + } m_index->insert(idx, v); if (v.weight().is_zero()) { m_zero.push_back(idx); @@ -886,6 +908,7 @@ lbool hilbert_basis::saturate(num_vector const& ineq, bool is_eq) { } } m_basis.resize(init_basis_size); + m_passive2->init(m_sos); // ASSERT basis is sorted by weight. // initialize passive @@ -902,7 +925,7 @@ lbool hilbert_basis::saturate(num_vector const& ineq, bool is_eq) { offset_t sos, pas; TRACE("hilbert_basis", display(tout); ); unsigned offset = m_passive2->pop(sos, pas); - SASSERT(can_resolve(sos, pas)); + SASSERT(can_resolve(sos, pas, true)); resolve(sos, pas, idx); if (is_subsumed(idx)) { continue; @@ -933,14 +956,6 @@ lbool hilbert_basis::saturate(num_vector const& ineq, bool is_eq) { m_free_list.push_back(m_basis.back()); m_basis.pop_back(); } - for (unsigned i = 0; i < init_basis_size; ++i) { - offset_t idx = m_basis[i]; - if (vec(idx).weight().is_neg()) { - m_basis[i] = m_basis.back(); - m_basis.pop_back(); - - } - } m_basis.append(m_zero); std::sort(m_basis.begin(), m_basis.end(), vector_lt_t(*this)); m_zero.reset(); @@ -1051,6 +1066,9 @@ void hilbert_basis::resolve(offset_t i, offset_t j, offset_t r) { u[k] = v[k] + w[k]; } u.weight() = v.weight() + w.weight(); + for (unsigned k = 0; k < m_current_ineq; ++k) { + u.weight(k) = v.weight(k) + w.weight(k); + } TRACE("hilbert_basis_verbose", display(tout, i); display(tout, j); @@ -1061,10 +1079,11 @@ void hilbert_basis::resolve(offset_t i, offset_t j, offset_t r) { hilbert_basis::offset_t hilbert_basis::alloc_vector() { if (m_free_list.empty()) { - unsigned num_vars = get_num_vars(); - unsigned idx = m_store.size(); - m_store.resize(idx + 1 + num_vars); - return offset_t(idx/(1+num_vars)); + unsigned sz = m_ineqs.size() + get_num_vars(); + unsigned idx = m_store.size(); + m_store.resize(idx + sz); + // std::cout << "alloc vector: " << idx << " " << sz << " " << m_store.c_ptr() + idx << " " << m_ineqs.size() << "\n"; + return offset_t(idx); } else { offset_t result = m_free_list.back(); @@ -1099,10 +1118,11 @@ bool hilbert_basis::is_subsumed(offset_t idx) { return false; } -bool hilbert_basis::can_resolve(offset_t i, offset_t j) const { - if (get_sign(i) == get_sign(j)) { +bool hilbert_basis::can_resolve(offset_t i, offset_t j, bool check_sign) const { + if (check_sign && get_sign(i) == get_sign(j)) { return false; } + SASSERT(get_sign(i) != get_sign(j)); values const& v1 = vec(i); values const& v2 = vec(j); if (v1[0].is_one() && v2[0].is_one()) { @@ -1121,7 +1141,7 @@ bool hilbert_basis::can_resolve(offset_t i, offset_t j) const { } hilbert_basis::sign_t hilbert_basis::get_sign(offset_t idx) const { - numeral val = vec(idx).weight(); + numeral const& val = vec(idx).weight(); if (val.is_pos()) { return pos; } @@ -1265,7 +1285,7 @@ bool hilbert_basis::is_subsumed(offset_t i, offset_t j) const { n >= m && (!m.is_neg() || n == m) && is_geq(v, w); for (unsigned k = 0; r && k < m_current_ineq; ++k) { - r = get_weight(vec(i), m_ineqs[k]) >= get_weight(vec(j), m_ineqs[k]); + r = v.weight(k) >= w.weight(k); } CTRACE("hilbert_basis", r, display(tout, i); diff --git a/src/muz_qe/hilbert_basis.h b/src/muz_qe/hilbert_basis.h index 78d4d7cec..bad4b1fbd 100644 --- a/src/muz_qe/hilbert_basis.h +++ b/src/muz_qe/hilbert_basis.h @@ -56,12 +56,14 @@ private: class values { numeral* m_values; public: - values(numeral* v):m_values(v) {} - numeral& weight() { return m_values[0]; } // value of a*x - numeral& operator[](unsigned i) { return m_values[i+1]; } // value of x_i - numeral const& weight() const { return m_values[0]; } // value of a*x - numeral const& operator[](unsigned i) const { return m_values[i+1]; } // value of x_i - numeral const* operator()() const { return m_values + 1; } + values(unsigned offset, numeral* v): m_values(v+offset) { } + numeral& weight() { return m_values[-1]; } // value of a*x + numeral const& weight() const { return m_values[-1]; } // value of a*x + numeral& weight(int i) { return m_values[-2-i]; } // value of b_i*x for 0 <= i < current inequality. + numeral const& weight(int i) const { return m_values[-2-i]; } // value of b_i*x + numeral& operator[](unsigned i) { return m_values[i]; } // value of x_i + numeral const& operator[](unsigned i) const { return m_values[i]; } // value of x_i + numeral const* operator()() const { return m_values; } }; vector m_ineqs; // set of asserted inequalities @@ -114,7 +116,7 @@ private: bool is_subsumed(offset_t idx); bool is_subsumed(offset_t i, offset_t j) const; void recycle(offset_t idx); - bool can_resolve(offset_t i, offset_t j) const; + bool can_resolve(offset_t i, offset_t j, bool check_sign) const; sign_t get_sign(offset_t idx) const; bool add_goal(offset_t idx); offset_t alloc_vector(); diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index e2d1d337e..69d733f68 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -521,6 +521,8 @@ void tst_hilbert_basis() { tst2(); tst3(); tst4(); + tst4(); + tst4(); tst5(); tst6(); tst7(); From 2a75f1d71e221f4984ecc2ca93c90ccf5b7f508d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Feb 2013 19:14:52 -0800 Subject: [PATCH 15/97] update logging for hilbert Signed-off-by: Nikolaj Bjorner --- src/muz_qe/heap_trie.h | 8 ++++---- src/muz_qe/hilbert_basis.cpp | 20 +++++++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/muz_qe/heap_trie.h b/src/muz_qe/heap_trie.h index e50a85505..a99861359 100644 --- a/src/muz_qe/heap_trie.h +++ b/src/muz_qe/heap_trie.h @@ -518,7 +518,7 @@ private: SASSERT(m_keys.size() == num_keys()); iterator it = begin(); trie* new_root = mk_trie(); - IF_VERBOSE(1, verbose_stream() << "before reshuffle: " << m_root->num_nodes() << " nodes\n";); + IF_VERBOSE(2, verbose_stream() << "before reshuffle: " << m_root->num_nodes() << " nodes\n";); for (; it != end(); ++it) { IF_VERBOSE(2, for (unsigned i = 0; i < num_keys(); ++i) { @@ -539,7 +539,7 @@ private: m_keys[i] = new_keys[i]; } - IF_VERBOSE(1, verbose_stream() << "after reshuffle: " << new_root->num_nodes() << " nodes\n";); + IF_VERBOSE(2, verbose_stream() << "after reshuffle: " << new_root->num_nodes() << " nodes\n";); IF_VERBOSE(2, it = begin(); for (; it != end(); ++it) { @@ -559,7 +559,7 @@ private: if (index == num_keys()) { SASSERT(n->ref_count() > 0); bool r = check(to_leaf(n)->get_value()); - IF_VERBOSE(1, + IF_VERBOSE(2, for (unsigned j = 0; j < index; ++j) { verbose_stream() << " "; } @@ -572,7 +572,7 @@ private: for (unsigned i = 0; i < nodes.size(); ++i) { ++m_stats.m_num_find_le_nodes; node* m = nodes[i].second; - IF_VERBOSE(1, + IF_VERBOSE(2, for (unsigned j = 0; j < index; ++j) { verbose_stream() << " "; } diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index 49bf20746..bc06aa15e 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -21,6 +21,7 @@ Revision History: #include "heap.h" #include "map.h" #include "heap_trie.h" +#include "stopwatch.h" template class rational_map : public map {}; @@ -777,9 +778,18 @@ lbool hilbert_basis::saturate() { init_basis(); m_current_ineq = 0; while (!m_cancel && m_current_ineq < m_ineqs.size()) { - IF_VERBOSE(1, { statistics st; collect_statistics(st); st.display(verbose_stream()); }); select_inequality(); + stopwatch sw; + sw.start(); lbool r = saturate(m_ineqs[m_current_ineq], m_iseq[m_current_ineq]); + IF_VERBOSE(1, + { statistics st; + collect_statistics(st); + st.display(verbose_stream()); + sw.stop(); + verbose_stream() << "time: " << sw.get_seconds() << "\n"; + }); + ++m_stats.m_num_saturations; if (r != l_true) { return r; @@ -933,14 +943,6 @@ lbool hilbert_basis::saturate(num_vector const& ineq, bool is_eq) { m_free_list.push_back(m_basis.back()); m_basis.pop_back(); } - for (unsigned i = 0; i < init_basis_size; ++i) { - offset_t idx = m_basis[i]; - if (vec(idx).weight().is_neg()) { - m_basis[i] = m_basis.back(); - m_basis.pop_back(); - - } - } m_basis.append(m_zero); std::sort(m_basis.begin(), m_basis.end(), vector_lt_t(*this)); m_zero.reset(); From 75eca46d93b140667bbd36fa4bb900f5ebf89e39 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Feb 2013 17:32:27 -0800 Subject: [PATCH 16/97] added Karr test Signed-off-by: Nikolaj Bjorner --- src/muz_qe/heap_trie.h | 8 +- src/muz_qe/hilbert_basis.cpp | 19 +++- src/test/heap_trie.cpp | 1 + src/test/hilbert_basis.cpp | 5 +- src/test/karr.cpp | 213 +++++++++++++++++++++++++++++++++++ src/test/main.cpp | 1 + 6 files changed, 238 insertions(+), 9 deletions(-) create mode 100644 src/test/karr.cpp diff --git a/src/muz_qe/heap_trie.h b/src/muz_qe/heap_trie.h index e50a85505..a99861359 100644 --- a/src/muz_qe/heap_trie.h +++ b/src/muz_qe/heap_trie.h @@ -518,7 +518,7 @@ private: SASSERT(m_keys.size() == num_keys()); iterator it = begin(); trie* new_root = mk_trie(); - IF_VERBOSE(1, verbose_stream() << "before reshuffle: " << m_root->num_nodes() << " nodes\n";); + IF_VERBOSE(2, verbose_stream() << "before reshuffle: " << m_root->num_nodes() << " nodes\n";); for (; it != end(); ++it) { IF_VERBOSE(2, for (unsigned i = 0; i < num_keys(); ++i) { @@ -539,7 +539,7 @@ private: m_keys[i] = new_keys[i]; } - IF_VERBOSE(1, verbose_stream() << "after reshuffle: " << new_root->num_nodes() << " nodes\n";); + IF_VERBOSE(2, verbose_stream() << "after reshuffle: " << new_root->num_nodes() << " nodes\n";); IF_VERBOSE(2, it = begin(); for (; it != end(); ++it) { @@ -559,7 +559,7 @@ private: if (index == num_keys()) { SASSERT(n->ref_count() > 0); bool r = check(to_leaf(n)->get_value()); - IF_VERBOSE(1, + IF_VERBOSE(2, for (unsigned j = 0; j < index; ++j) { verbose_stream() << " "; } @@ -572,7 +572,7 @@ private: for (unsigned i = 0; i < nodes.size(); ++i) { ++m_stats.m_num_find_le_nodes; node* m = nodes[i].second; - IF_VERBOSE(1, + IF_VERBOSE(2, for (unsigned j = 0; j < index; ++j) { verbose_stream() << " "; } diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index 59b513d8d..e7c7928a3 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -21,9 +21,8 @@ Revision History: #include "heap.h" #include "map.h" #include "heap_trie.h" +#include "stopwatch.h" -template -class rational_map : public map {}; typedef int_hashtable > int_table; @@ -263,7 +262,10 @@ class hilbert_basis::index { void reset() { memset(this, 0, sizeof(*this)); } }; - typedef rational_map value_map; + template + class numeral_map : public map {}; + + typedef numeral_map value_map; hilbert_basis& hb; value_map m_neg; value_index m_pos; @@ -793,9 +795,18 @@ lbool hilbert_basis::saturate() { init_basis(); m_current_ineq = 0; while (!m_cancel && m_current_ineq < m_ineqs.size()) { - IF_VERBOSE(1, { statistics st; collect_statistics(st); st.display(verbose_stream()); }); select_inequality(); + stopwatch sw; + sw.start(); lbool r = saturate(m_ineqs[m_current_ineq], m_iseq[m_current_ineq]); + IF_VERBOSE(1, + { statistics st; + collect_statistics(st); + st.display(verbose_stream()); + sw.stop(); + verbose_stream() << "time: " << sw.get_seconds() << "\n"; + }); + ++m_stats.m_num_saturations; if (r != l_true) { return r; diff --git a/src/test/heap_trie.cpp b/src/test/heap_trie.cpp index 7b57f97f2..dd04f7b98 100644 --- a/src/test/heap_trie.cpp +++ b/src/test/heap_trie.cpp @@ -25,6 +25,7 @@ static void find_le(heap_trie_t& ht, unsigned num_keys, unsigned const* keys) { } + void tst_heap_trie() { heap_trie_t ht; diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index 69d733f68..bd5d20f8d 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -253,7 +253,7 @@ static void saturate_basis(hilbert_basis& hb) { case l_true: std::cout << "sat\n"; hb.display(std::cout); - validate_sat(hb); + //validate_sat(hb); break; case l_false: std::cout << "unsat\n"; @@ -523,6 +523,9 @@ void tst_hilbert_basis() { tst4(); tst4(); tst4(); + tst4(); + tst4(); + tst4(); tst5(); tst6(); tst7(); diff --git a/src/test/karr.cpp b/src/test/karr.cpp new file mode 100644 index 000000000..f6e572670 --- /dev/null +++ b/src/test/karr.cpp @@ -0,0 +1,213 @@ +#include "hilbert_basis.h" + +/* + Test generation of linear congruences a la Karr. + + */ +namespace karr { + + struct matrix { + vector > A; + vector b; + + unsigned size() const { return A.size(); } + + void reset() { + A.reset(); + b.reset(); + } + + matrix& operator=(matrix const& other) { + reset(); + append(other); + return *this; + } + + void append(matrix const& other) { + A.append(other.A); + b.append(other.b); + } + + void display(std::ostream& out) { + for (unsigned i = 0; i < A.size(); ++i) { + for (unsigned j = 0; j < A[i].size(); ++j) { + out << A[i][j] << " "; + } + out << " = " << -b[i] << "\n"; + } + } + }; + + // treat src as a homogeneous matrix. + void dualizeH(matrix& dst, matrix const& src) { + hilbert_basis hb; + for (unsigned i = 0; i < src.size(); ++i) { + vector v(src.A[i]); + v.append(src.b[i]); + hb.add_eq(v, rational(0)); + } + for (unsigned i = 0; i < 1 + src.A[0].size(); ++i) { + hb.set_is_int(i); + } + lbool is_sat = hb.saturate(); + hb.display(std::cout); + SASSERT(is_sat == l_true); + dst.reset(); + unsigned basis_size = hb.get_basis_size(); + bool first_initial = true; + for (unsigned i = 0; i < basis_size; ++i) { + bool is_initial; + vector soln; + hb.get_basis_solution(i, soln, is_initial); + if (!is_initial) { + dst.b.push_back(soln.back()); + soln.pop_back(); + dst.A.push_back(soln); + } + } + } + + // treat src as an inhomegeneous matrix. + void dualizeI(matrix& dst, matrix const& src) { + hilbert_basis hb; + for (unsigned i = 0; i < src.size(); ++i) { + hb.add_eq(src.A[i], -src.b[i]); + } + for (unsigned i = 0; i < src.A[0].size(); ++i) { + hb.set_is_int(i); + } + lbool is_sat = hb.saturate(); + hb.display(std::cout); + SASSERT(is_sat == l_true); + dst.reset(); + unsigned basis_size = hb.get_basis_size(); + bool first_initial = true; + for (unsigned i = 0; i < basis_size; ++i) { + bool is_initial; + vector soln; + hb.get_basis_solution(i, soln, is_initial); + if (is_initial && first_initial) { + dst.A.push_back(soln); + dst.b.push_back(rational(1)); + first_initial = false; + } + else if (!is_initial) { + dst.A.push_back(soln); + dst.b.push_back(rational(0)); + } + } + } + + void juxtapose(matrix& dst, matrix const& M, matrix const& N) { + dst = M; + dst.append(N); + } + + void join(matrix& dst, matrix const& M, matrix const& N) { + matrix MD, ND, dstD; + dualizeI(MD, M); + dualizeI(ND, N); + juxtapose(dstD, MD, ND); + dualizeH(dst, dstD); + } + + void joinD(matrix& dst, matrix const& MD, matrix const& ND) { + matrix dstD; + juxtapose(dstD, MD, ND); + dualizeH(dst, dstD); + } + + void transition( + matrix& dst, + matrix const& src, + matrix const& Ab) { + matrix T; + // length of rows in Ab are twice as long as + // length of rows in src. + SASSERT(2*src.A[0].size() == Ab.A[0].size()); + vector zeros; + for (unsigned i = 0; i < src.A[0].size(); ++i) { + zeros.push_back(rational(0)); + } + for (unsigned i = 0; i < src.size(); ++i) { + T.A.push_back(src.A[i]); + T.A.back().append(zeros); + } + T.b.append(src.b); + T.append(Ab); + + T.display(std::cout << "T:\n"); + matrix TD; + dualizeI(TD, T); + TD.display(std::cout << "TD:\n"); + for (unsigned i = 0; i < TD.size(); ++i) { + vector v; + v.append(src.size(), TD.A[i].c_ptr() + src.size()); + dst.A.push_back(v); + dst.b.push_back(TD.b[i]); + } + dst.display(std::cout << "dst\n"); + } + + static vector V(int i, int j) { + vector v; + v.push_back(rational(i)); + v.push_back(rational(j)); + return v; + } + + static vector V(int i, int j, int k, int l) { + vector v; + v.push_back(rational(i)); + v.push_back(rational(j)); + v.push_back(rational(k)); + v.push_back(rational(l)); + return v; + } + +#define R(_x_) rational(_x_) + + + static void tst1() { + matrix Theta; + matrix Ab; + + // + Theta.A.push_back(V(1, 0)); + Theta.b.push_back(R(0)); + Theta.A.push_back(V(0, 1)); + Theta.b.push_back(R(-2)); + + Theta.display(std::cout << "Theta\n"); + + Ab.A.push_back(V(-1, 0, 1, 0)); + Ab.b.push_back(R(1)); + Ab.A.push_back(V(-1, -2, 0, 1)); + Ab.b.push_back(R(1)); + + Ab.display(std::cout << "Ab\n"); + + matrix ThetaD; + dualizeI(ThetaD, Theta); + ThetaD.display(std::cout); + + matrix t1D, e1; + transition(t1D, Theta, Ab); + joinD(e1, t1D, ThetaD); + + t1D.display(std::cout << "t1D\n"); + e1.display(std::cout << "e1\n"); + + matrix t2D, e2; + transition(t2D, e1, Ab); + joinD(e2, t2D, ThetaD); + + t2D.display(std::cout << "t2D\n"); + e2.display(std::cout << "e2\n"); + } + +}; + +void tst_karr() { + karr::tst1(); +} diff --git a/src/test/main.cpp b/src/test/main.cpp index 9dc12be1c..c48f4529e 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -209,6 +209,7 @@ int main(int argc, char ** argv) { TST(rcf); TST(hilbert_basis); TST(heap_trie); + TST(karr); } void initialize_mam() {} From 6f3850bfbcb7565043c08c6b32476d2c63b22358 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 28 Feb 2013 18:46:29 +0000 Subject: [PATCH 17/97] FPA bug and leak fixes (thanks to Gabriele Paganelli) Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 10 +- src/tactic/fpa/fpa2bv_converter.cpp | 634 ++++++++++++++++------------ src/tactic/fpa/fpa2bv_converter.h | 42 +- src/tactic/fpa/fpa2bv_rewriter.h | 4 +- src/tactic/fpa/fpa2bv_tactic.cpp | 2 +- 5 files changed, 397 insertions(+), 295 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 7f6d7f764..f2d6591dc 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -151,6 +151,10 @@ sort * float_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, paramete if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int())) { m_manager->raise_exception("expecting two integer parameters to floating point sort"); } + if (parameters[0].get_int() <= 1 || parameters[1].get_int() <= 1) + m_manager->raise_exception("floating point sorts need parameters > 1"); + if (parameters[0].get_int() > parameters[1].get_int()) + m_manager->raise_exception("floating point sorts with ebits > sbits are currently not supported"); return mk_float_sort(parameters[0].get_int(), parameters[1].get_int()); case ROUNDING_MODE_SORT: return mk_rm_sort(); @@ -349,14 +353,14 @@ func_decl * float_decl_plugin::mk_to_float(decl_kind k, unsigned num_parameters, sort * fp = mk_float_sort(domain[2]->get_parameter(0).get_int(), domain[1]->get_parameter(0).get_int()+1); symbol name("asFloat"); return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); - } + } else { // .. Otherwise we only know how to convert rationals/reals. if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int())) m_manager->raise_exception("expecting two integer parameters to asFloat"); if (arity != 2 && arity != 3) - m_manager->raise_exception("invalid number of arguments to asFloat operator"); - if (!is_rm_sort(domain[0]) || domain[1] != m_real_sort) + m_manager->raise_exception("invalid number of arguments to asFloat operator"); + if (!is_rm_sort(domain[0]) || domain[1] != m_real_sort) m_manager->raise_exception("sort mismatch"); if (arity == 2) { sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int()); diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 4afdc501f..b11e2c3ac 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -21,15 +21,15 @@ Notes: #include"fpa2bv_converter.h" -#define BVULT(X,Y,R) { expr_ref bvult_eq(m), bvult_not(m); m_simp.mk_eq(X, Y, bvult_eq); m_simp.mk_not(bvult_eq, bvult_not); m_simp.mk_and(m_bv_util.mk_ule(X,Y), bvult_not, R); } -#define BVSLT(X,Y,R) { expr_ref bvslt_eq(m), bvslt_not(m); m_simp.mk_eq(X, Y, bvslt_eq); m_simp.mk_not(bvslt_eq, bvslt_not); m_simp.mk_and(m_bv_util.mk_sle(X,Y), bvslt_not, R); } +#define BVULT(X,Y,R) { expr_ref bvult_eq(m), bvult_not(m); m_simp.mk_eq(X, Y, bvult_eq); m_simp.mk_not(bvult_eq, bvult_not); expr_ref t(m); t = m_bv_util.mk_ule(X,Y); m_simp.mk_and(t, bvult_not, R); } +#define BVSLT(X,Y,R) { expr_ref bvslt_eq(m), bvslt_not(m); m_simp.mk_eq(X, Y, bvslt_eq); m_simp.mk_not(bvslt_eq, bvslt_not); expr_ref t(m); t = m_bv_util.mk_sle(X,Y); m_simp.mk_and(t, bvslt_not, R); } fpa2bv_converter::fpa2bv_converter(ast_manager & m) : m(m), m_simp(m), m_util(m), - m_mpf_manager(m_util.fm()), - m_mpz_manager(m_mpf_manager.mpz_manager()), + m_mpf_manager(m_util.fm()), + m_mpz_manager(m_mpf_manager.mpz_manager()), m_bv_util(m), extra_assertions(m) { m_plugin = static_cast(m.get_plugin(m.mk_family_id("float"))); @@ -37,7 +37,7 @@ fpa2bv_converter::fpa2bv_converter(ast_manager & m) : fpa2bv_converter::~fpa2bv_converter() { dec_ref_map_key_values(m, m_const2bv); - dec_ref_map_key_values(m, m_rm_const2bv); + dec_ref_map_key_values(m, m_rm_const2bv); } void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { @@ -123,17 +123,23 @@ void fpa2bv_converter::mk_const(func_decl * f, expr_ref & result) { unsigned ebits = m_util.get_ebits(srt); unsigned sbits = m_util.get_sbits(srt); + expr_ref sgn(m), s(m), e(m); + sort_ref s_sgn(m), s_sig(m), s_exp(m); + s_sgn = m_bv_util.mk_sort(1); + s_sig = m_bv_util.mk_sort(sbits-1); + s_exp = m_bv_util.mk_sort(ebits); + #ifdef _DEBUG std::string p("fpa2bv"); std::string name = f->get_name().str(); - expr * sgn = m.mk_fresh_const((p + "_sgn_" + name).c_str(), m_bv_util.mk_sort(1)); - expr * s = m.mk_fresh_const((p + "_sig_" + name).c_str(), m_bv_util.mk_sort(sbits-1)); - expr * e = m.mk_fresh_const((p + "_exp_" + name).c_str(), m_bv_util.mk_sort(ebits)); + sgn = m.mk_fresh_const((p + "_sgn_" + name).c_str(), s_sgn); + s = m.mk_fresh_const((p + "_sig_" + name).c_str(), s_sig); + e = m.mk_fresh_const((p + "_exp_" + name).c_str(), s_exp); #else - expr * sgn = m.mk_fresh_const(0, m_bv_util.mk_sort(1)); - expr * s = m.mk_fresh_const(0, m_bv_util.mk_sort(sbits-1)); - expr * e = m.mk_fresh_const(0, m_bv_util.mk_sort(ebits)); + sgn = m.mk_fresh_const(0, s_sgn); + s = m.mk_fresh_const(0, s_sig); + e = m.mk_fresh_const(0, s_exp); #endif mk_triple(sgn, s, e, result); @@ -153,7 +159,7 @@ void fpa2bv_converter::mk_rm_const(func_decl * f, expr_ref & result) { result = r; } else { - SASSERT(is_rm_sort(f->get_range())); + SASSERT(is_rm_sort(f->get_range())); result = m.mk_fresh_const( #ifdef _DEBUG @@ -245,9 +251,10 @@ void fpa2bv_converter::add_core(unsigned sbits, unsigned ebits, expr_ref & rm, dbg_decouple("fpa2bv_add_exp_delta", exp_delta); // cap the delta - expr_ref cap(m); + expr_ref cap(m), cap_le_delta(m); cap = m_bv_util.mk_numeral(sbits+2, ebits); - m_simp.mk_ite(m_bv_util.mk_ule(cap, exp_delta), cap, exp_delta, exp_delta); + cap_le_delta = m_bv_util.mk_ule(cap, exp_delta); + m_simp.mk_ite(cap_le_delta, cap, exp_delta, exp_delta); dbg_decouple("fpa2bv_add_exp_delta_capped", exp_delta); @@ -270,20 +277,22 @@ void fpa2bv_converter::add_core(unsigned sbits, unsigned ebits, expr_ref & rm, SASSERT(is_well_sorted(m, shifted_d_sig)); sticky_raw = m_bv_util.mk_extract(sbits+2, 0, shifted_big); - expr_ref sticky_eq(m); - m_simp.mk_eq(sticky_raw, m_bv_util.mk_numeral(0, sbits+3), sticky_eq); - m_simp.mk_ite(sticky_eq, - m_bv_util.mk_numeral(0, sbits+3), - m_bv_util.mk_numeral(1, sbits+3), - sticky); + expr_ref sticky_eq(m), nil_sbit3(m), one_sbit3(m); + nil_sbit3 = m_bv_util.mk_numeral(0, sbits+3); + one_sbit3 = m_bv_util.mk_numeral(1, sbits+3); + m_simp.mk_eq(sticky_raw, nil_sbit3, sticky_eq); + m_simp.mk_ite(sticky_eq, nil_sbit3, one_sbit3, sticky); SASSERT(is_well_sorted(m, sticky)); - expr * or_args[2] = { shifted_d_sig.get(), sticky.get() }; + expr * or_args[2] = { shifted_d_sig, sticky }; shifted_d_sig = m_bv_util.mk_bv_or(2, or_args); SASSERT(is_well_sorted(m, shifted_d_sig)); - expr_ref eq_sgn(m), neq_sgn(m); - m_simp.mk_eq(c_sgn, d_sgn, eq_sgn); + expr_ref eq_sgn(m); + m_simp.mk_eq(c_sgn, d_sgn, eq_sgn); + + // dbg_decouple("fpa2bv_add_eq_sgn", eq_sgn); + TRACE("fpa2bv_add_core", tout << "EQ_SGN = " << mk_ismt2_pp(eq_sgn, m) << std::endl; ); // two extra bits for catching the overflow. c_sig = m_bv_util.mk_zero_extend(2, c_sig); @@ -311,19 +320,20 @@ void fpa2bv_converter::add_core(unsigned sbits, unsigned ebits, expr_ref & rm, dbg_decouple("fpa2bv_add_sign_bv", sign_bv); dbg_decouple("fpa2bv_add_n_sum", n_sum); - - family_id bvfid = m_bv_util.get_fid(); + + family_id bvfid = m_bv_util.get_fid(); expr_ref res_sgn_c1(m), res_sgn_c2(m), res_sgn_c3(m); res_sgn_c1 = m.mk_app(bvfid, OP_BAND, m_bv_util.mk_bv_not(c_sgn), d_sgn, sign_bv); res_sgn_c2 = m.mk_app(bvfid, OP_BAND, c_sgn, m_bv_util.mk_bv_not(d_sgn), m_bv_util.mk_bv_not(sign_bv)); res_sgn_c3 = m.mk_app(bvfid, OP_BAND, c_sgn, d_sgn); - expr * res_sgn_or_args[3] = { res_sgn_c1.get(), res_sgn_c2.get(), res_sgn_c3.get() }; + expr * res_sgn_or_args[3] = { res_sgn_c1, res_sgn_c2, res_sgn_c3 }; res_sgn = m_bv_util.mk_bv_or(3, res_sgn_or_args); - expr_ref res_sig_eq(m), sig_abs(m); - m_simp.mk_eq(sign_bv, m_bv_util.mk_numeral(1, 1), res_sig_eq); - m_simp.mk_ite(res_sig_eq, n_sum, sum, sig_abs); + expr_ref res_sig_eq(m), sig_abs(m), one_1(m); + one_1 = m_bv_util.mk_numeral(1, 1); + m_simp.mk_eq(sign_bv, one_1, res_sig_eq); + m_simp.mk_ite(res_sig_eq, n_sum, sum, sig_abs); dbg_decouple("fpa2bv_add_sig_abs", sig_abs); @@ -333,9 +343,9 @@ void fpa2bv_converter::add_core(unsigned sbits, unsigned ebits, expr_ref & rm, void fpa2bv_converter::mk_add(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); - - expr_ref rm(m), x(m), y(m); - rm = args[0]; + + expr_ref rm(m), x(m), y(m); + rm = args[0]; x = args[1]; y = args[2]; @@ -391,7 +401,7 @@ void fpa2bv_converter::mk_add(func_decl * f, unsigned num, expr * const * args, expr_ref rm_is_to_neg(m), v4_and(m); m_simp.mk_and(x_is_zero, y_is_zero, c4); mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg); - mk_ite(rm_is_to_neg, nzero, pzero, v4); + mk_ite(rm_is_to_neg, nzero, pzero, v4); m_simp.mk_and(x_is_neg, y_is_neg, v4_and); mk_ite(v4_and, x, v4, v4); @@ -432,8 +442,9 @@ void fpa2bv_converter::mk_add(func_decl * f, unsigned num, expr * const * args, c_sgn, c_sig, c_exp, d_sgn, d_sig, d_exp, res_sgn, res_sig, res_exp); - expr_ref is_zero_sig(m); - m_simp.mk_eq(res_sig, m_bv_util.mk_numeral(0, sbits+4), is_zero_sig); + expr_ref is_zero_sig(m), nil_sbit4(m); + nil_sbit4 = m_bv_util.mk_numeral(0, sbits+4); + m_simp.mk_eq(res_sig, nil_sbit4, is_zero_sig); SASSERT(is_well_sorted(m, is_zero_sig)); @@ -463,7 +474,7 @@ void fpa2bv_converter::mk_sub(func_decl * f, unsigned num, expr * const * args, SASSERT(num == 3); expr_ref t(m); mk_uminus(f, 1, &args[2], t); - expr * nargs[3] = { args[0], args[1], t.get() }; + expr * nargs[3] = { args[0], args[1], t }; mk_add(f, 3, nargs, result); } @@ -481,9 +492,9 @@ void fpa2bv_converter::mk_uminus(func_decl * f, unsigned num, expr * const * arg void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); - - expr_ref rm(m), x(m), y(m); - rm = args[0]; + + expr_ref rm(m), x(m), y(m); + rm = args[0]; x = args[1]; y = args[2]; @@ -589,9 +600,20 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, SASSERT(m_bv_util.get_bv_size(product) == 2*sbits); - expr_ref sticky(m); - sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(sbits-4, 0, product)); - res_sig = m_bv_util.mk_concat(m_bv_util.mk_extract(2*sbits-1, sbits-3, product), sticky); + expr_ref h_p(m), l_p(m), rbits(m); + h_p = m_bv_util.mk_extract(2*sbits-1, sbits, product); + l_p = m_bv_util.mk_extract(2*sbits-1, sbits, product); + + if (sbits >= 4) { + expr_ref sticky(m); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(sbits-4, 0, l_p)); + rbits = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits-1, sbits-3, l_p), sticky); + } + else + rbits = m_bv_util.mk_concat(l_p, m_bv_util.mk_numeral(0, 4 - m_bv_util.get_bv_size(l_p))); + + SASSERT(m_bv_util.get_bv_size(rbits) == 4); + res_sig = m_bv_util.mk_concat(h_p, rbits); round(f->get_range(), rm, res_sgn, res_sig, res_exp, v7); @@ -610,9 +632,9 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); - - expr_ref rm(m), x(m), y(m); - rm = args[0]; + + expr_ref rm(m), x(m), y(m); + rm = args[0]; x = args[1]; y = args[2]; @@ -733,9 +755,9 @@ void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, void fpa2bv_converter::mk_remainder(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); - + // Remainder is always exact, so there is no rounding mode. - expr_ref x(m), y(m); + expr_ref x(m), y(m); x = args[0]; y = args[1]; @@ -937,10 +959,10 @@ void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 4); - + // fusedma means (x * y) + z - expr_ref rm(m), x(m), y(m), z(m); - rm = args[0]; + expr_ref rm(m), x(m), y(m), z(m); + rm = args[0]; x = args[1]; y = args[2]; z = args[3]; @@ -1108,8 +1130,9 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar sig_size = m_bv_util.get_bv_size(res_sig); SASSERT(sig_size == sbits+4); - expr_ref is_zero_sig(m); - m_simp.mk_eq(res_sig, m_bv_util.mk_numeral(0, sbits+4), is_zero_sig); + expr_ref is_zero_sig(m), nil_sbits4(m); + nil_sbits4 = m_bv_util.mk_numeral(0, sbits+4); + m_simp.mk_eq(res_sig, nil_sbits4, is_zero_sig); SASSERT(is_well_sorted(m, is_zero_sig)); @@ -1142,9 +1165,9 @@ void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args, void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); - - expr_ref rm(m), x(m); - rm = args[0]; + + expr_ref rm(m), x(m); + rm = args[0]; x = args[1]; expr_ref nan(m), nzero(m), pzero(m), ninf(m), pinf(m); @@ -1175,10 +1198,10 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr * expr_ref a_sgn(m), a_sig(m), a_exp(m); unpack(x, a_sgn, a_sig, a_exp, true); - expr_ref exp_is_small(m); - m_simp.mk_eq(m_bv_util.mk_extract(ebits-1, ebits-1, a_exp), - m_bv_util.mk_numeral(1, 1), - exp_is_small); + expr_ref exp_is_small(m), exp_h(m), one_1(m); + exp_h = m_bv_util.mk_extract(ebits-1, ebits-1, a_exp); + one_1 = m_bv_util.mk_numeral(1, 1); + m_simp.mk_eq(exp_h, one_1, exp_is_small); dbg_decouple("fpa2bv_r2i_exp_is_small", exp_is_small); c3 = exp_is_small; mk_ite(x_is_pos, pzero, nzero, v3); @@ -1273,12 +1296,13 @@ void fpa2bv_converter::mk_float_lt(func_decl * f, unsigned num, expr * const * a split(x, x_sgn, x_sig, x_exp); split(y, y_sgn, y_sig, y_exp); - expr_ref c3(m), t3(m), t4(m); - - m_simp.mk_eq(x_sgn, m_bv_util.mk_numeral(1, 1), c3); + expr_ref c3(m), t3(m), t4(m), one_1(m), nil_1(m); + one_1 = m_bv_util.mk_numeral(1, 1); + nil_1 = m_bv_util.mk_numeral(0, 1); + m_simp.mk_eq(x_sgn, one_1, c3); expr_ref y_sgn_eq_0(m), y_lt_x_exp(m), y_lt_x_sig(m), y_eq_x_exp(m), y_le_x_sig_exp(m), t3_or(m); - m_simp.mk_eq(y_sgn, m_bv_util.mk_numeral(0, 1), y_sgn_eq_0); + m_simp.mk_eq(y_sgn, nil_1, y_sgn_eq_0); BVULT(y_exp, x_exp, y_lt_x_exp); BVULT(y_sig, x_sig, y_lt_x_sig); m_simp.mk_eq(y_exp, x_exp, y_eq_x_exp); @@ -1287,7 +1311,7 @@ void fpa2bv_converter::mk_float_lt(func_decl * f, unsigned num, expr * const * a m_simp.mk_ite(y_sgn_eq_0, m.mk_true(), t3_or, t3); expr_ref y_sgn_eq_1(m), x_lt_y_exp(m), x_eq_y_exp(m), x_lt_y_sig(m), x_le_y_sig_exp(m), t4_or(m); - m_simp.mk_eq(y_sgn, m_bv_util.mk_numeral(1, 1), y_sgn_eq_1); + m_simp.mk_eq(y_sgn, one_1, y_sgn_eq_1); BVULT(x_exp, y_exp, x_lt_y_exp); m_simp.mk_eq(x_exp, y_exp, x_eq_y_exp); BVULT(x_sig, y_sig, x_lt_y_sig); @@ -1418,10 +1442,11 @@ void fpa2bv_converter::mk_is_nan(expr * e, expr_ref & result) { split(e, sgn, sig, exp); // exp == 1^n , sig != 0 - expr_ref sig_is_zero(m), sig_is_not_zero(m), exp_is_top(m), top_exp(m); + expr_ref sig_is_zero(m), sig_is_not_zero(m), exp_is_top(m), top_exp(m), zero(m); mk_top_exp(m_bv_util.get_bv_size(exp), top_exp); - m_simp.mk_eq(sig, m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(sig)), sig_is_zero); + zero = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(sig)); + m_simp.mk_eq(sig, zero, sig_is_zero); m_simp.mk_not(sig_is_zero, sig_is_not_zero); m_simp.mk_eq(exp, top_exp, exp_is_top); m_simp.mk_and(exp_is_top, sig_is_not_zero, result); @@ -1430,9 +1455,10 @@ void fpa2bv_converter::mk_is_nan(expr * e, expr_ref & result) { void fpa2bv_converter::mk_is_inf(expr * e, expr_ref & result) { expr * sgn, * sig, * exp; split(e, sgn, sig, exp); - expr_ref eq1(m), eq2(m), top_exp(m); + expr_ref eq1(m), eq2(m), top_exp(m), zero(m); mk_top_exp(m_bv_util.get_bv_size(exp), top_exp); - m_simp.mk_eq(sig, m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(sig)), eq1); + zero = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(sig)); + m_simp.mk_eq(sig, zero, eq1); m_simp.mk_eq(exp, top_exp, eq2); m_simp.mk_and(eq1, eq2, result); } @@ -1455,22 +1481,27 @@ void fpa2bv_converter::mk_is_pos(expr * e, expr_ref & result) { SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_TO_FLOAT)); SASSERT(to_app(e)->get_num_args() == 3); expr * a0 = to_app(e)->get_arg(0); - m_simp.mk_eq(a0, m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(a0)), result); + expr_ref zero(m); + zero = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(a0)); + m_simp.mk_eq(a0, zero, result); } void fpa2bv_converter::mk_is_neg(expr * e, expr_ref & result) { SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_TO_FLOAT)); SASSERT(to_app(e)->get_num_args() == 3); expr * a0 = to_app(e)->get_arg(0); - m_simp.mk_eq(a0, m_bv_util.mk_numeral(1, m_bv_util.get_bv_size(a0)), result); + expr_ref one(m); + one = m_bv_util.mk_numeral(1, m_bv_util.get_bv_size(a0)); + m_simp.mk_eq(a0, one, result); } void fpa2bv_converter::mk_is_zero(expr * e, expr_ref & result) { expr * sgn, * sig, * exp; split(e, sgn, sig, exp); - expr_ref eq1(m), eq2(m), bot_exp(m); + expr_ref eq1(m), eq2(m), bot_exp(m), zero(m); mk_bot_exp(m_bv_util.get_bv_size(exp), bot_exp); - m_simp.mk_eq(sig, m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(sig)), eq1); + zero = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(sig)); + m_simp.mk_eq(sig, zero, eq1); m_simp.mk_eq(exp, bot_exp, eq2); m_simp.mk_and(eq1, eq2, result); } @@ -1478,35 +1509,40 @@ void fpa2bv_converter::mk_is_zero(expr * e, expr_ref & result) { void fpa2bv_converter::mk_is_nzero(expr * e, expr_ref & result) { expr * sgn, * sig, * exp; split(e, sgn, sig, exp); - expr_ref e_is_zero(m), eq(m); + expr_ref e_is_zero(m), eq(m), one_1(m); mk_is_zero(e, e_is_zero); - m_simp.mk_eq(sgn, m_bv_util.mk_numeral(1, 1), eq); + one_1 = m_bv_util.mk_numeral(1, 1); + m_simp.mk_eq(sgn, one_1, eq); m_simp.mk_and(eq, e_is_zero, result); } void fpa2bv_converter::mk_is_pzero(expr * e, expr_ref & result) { expr * sgn, * sig, * exp; split(e, sgn, sig, exp); - expr_ref e_is_zero(m), eq(m); + expr_ref e_is_zero(m), eq(m), nil_1(m); mk_is_zero(e, e_is_zero); - m_simp.mk_eq(sgn, m_bv_util.mk_numeral(0, 1), eq); + nil_1 = m_bv_util.mk_numeral(0, 1); + m_simp.mk_eq(sgn, nil_1, eq); m_simp.mk_and(eq, e_is_zero, result); } void fpa2bv_converter::mk_is_denormal(expr * e, expr_ref & result) { expr * sgn, * sig, * exp; split(e, sgn, sig, exp); - m_simp.mk_eq(exp, m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(exp)), result); + expr_ref zero(m); + zero = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(exp)); + m_simp.mk_eq(exp, zero, result); } void fpa2bv_converter::mk_is_normal(expr * e, expr_ref & result) { expr * sgn, * sig, * exp; split(e, sgn, sig, exp); - expr_ref is_special(m), is_denormal(m); + expr_ref is_special(m), is_denormal(m), p(m); mk_is_denormal(e, is_denormal); unsigned ebits = m_bv_util.get_bv_size(exp); - m_simp.mk_eq(exp, m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits), ebits), is_special); + p = m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits), ebits); + m_simp.mk_eq(exp, p, is_special); expr_ref or_ex(m); m_simp.mk_or(is_special, is_denormal, or_ex); @@ -1514,21 +1550,21 @@ void fpa2bv_converter::mk_is_normal(expr * e, expr_ref & result) { } void fpa2bv_converter::mk_is_rm(expr * e, BV_RM_VAL rm, expr_ref & result) { - SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == 3); + SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == 3); expr_ref rm_num(m); rm_num = m_bv_util.mk_numeral(rm, 3); - switch(rm) - { - case BV_RM_TIES_TO_AWAY: - case BV_RM_TIES_TO_EVEN: - case BV_RM_TO_NEGATIVE: - case BV_RM_TO_POSITIVE: return m_simp.mk_eq(e, rm_num, result); - case BV_RM_TO_ZERO: - default: + switch(rm) + { + case BV_RM_TIES_TO_AWAY: + case BV_RM_TIES_TO_EVEN: + case BV_RM_TO_NEGATIVE: + case BV_RM_TO_POSITIVE: return m_simp.mk_eq(e, rm_num, result); + case BV_RM_TO_ZERO: + default: rm_num = m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3); expr_ref r(m); r = m_bv_util.mk_ule(e, rm_num); return m_simp.mk_not(r, result); - } + } } void fpa2bv_converter::mk_top_exp(unsigned sz, expr_ref & result) { @@ -1546,7 +1582,7 @@ void fpa2bv_converter::mk_min_exp(unsigned ebits, expr_ref & result) { } void fpa2bv_converter::mk_max_exp(unsigned ebits, expr_ref & result) { - SASSERT(ebits > 0); + SASSERT(ebits > 0); result = m_bv_util.mk_numeral(m_mpf_manager.m_powers2.m1(ebits-1, false), ebits); } @@ -1557,9 +1593,12 @@ void fpa2bv_converter::mk_leading_zeros(expr * e, unsigned max_bits, expr_ref & if (bv_sz == 0) result = m_bv_util.mk_numeral(0, max_bits); else if (bv_sz == 1) { - expr_ref eq(m); - m_simp.mk_eq(e, m_bv_util.mk_numeral(0, 1), eq); - m_simp.mk_ite(eq, m_bv_util.mk_numeral(1, max_bits), m_bv_util.mk_numeral(0, max_bits), result); + expr_ref eq(m), nil_1(m), one_m(m), nil_m(m); + nil_1 = m_bv_util.mk_numeral(0, 1); + one_m = m_bv_util.mk_numeral(1, max_bits); + nil_m = m_bv_util.mk_numeral(0, max_bits); + m_simp.mk_eq(e, nil_1, eq); + m_simp.mk_ite(eq, one_m, nil_m, result); } else { expr_ref H(m), L(m); @@ -1573,11 +1612,13 @@ void fpa2bv_converter::mk_leading_zeros(expr * e, unsigned max_bits, expr_ref & mk_leading_zeros(H, max_bits, lzH); /* recursive! */ mk_leading_zeros(L, max_bits, lzL); - expr_ref H_is_zero(m); - m_simp.mk_eq(H, m_bv_util.mk_numeral(0, H_size), H_is_zero); + expr_ref H_is_zero(m), nil_h(m); + nil_h = m_bv_util.mk_numeral(0, H_size); + m_simp.mk_eq(H, nil_h, H_is_zero); - expr_ref sum(m); - sum = m_bv_util.mk_bv_add(m_bv_util.mk_numeral(H_size, max_bits), lzL); + expr_ref sum(m), h_m(m); + h_m = m_bv_util.mk_numeral(H_size, max_bits); + sum = m_bv_util.mk_bv_add(h_m, lzL); m_simp.mk_ite(H_is_zero, sum, lzH, result); } @@ -1634,25 +1675,40 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref mk_unbias(denormal_exp, denormal_exp); if (normalize) { - expr_ref is_sig_zero(m), shift(m), lz(m); - m_simp.mk_eq(m_bv_util.mk_numeral(0, sbits-1), sig, is_sig_zero); + expr_ref is_sig_zero(m), shift(m), lz(m), zero_s(m), zero_e(m); + zero_s = m_bv_util.mk_numeral(0, sbits-1); + zero_e = m_bv_util.mk_numeral(0, ebits); + m_simp.mk_eq(zero_s, sig, is_sig_zero); mk_leading_zeros(sig, ebits, lz); - m_simp.mk_ite(is_sig_zero, m_bv_util.mk_numeral(0, ebits), lz, shift); + m_simp.mk_ite(is_sig_zero, zero_e, lz, shift); SASSERT(is_well_sorted(m, is_sig_zero)); SASSERT(is_well_sorted(m, lz)); SASSERT(is_well_sorted(m, shift)); - if (ebits < sbits) { + SASSERT(m_bv_util.get_bv_size(shift) == ebits); + if (ebits <= sbits) { expr_ref q(m); - q = m_bv_util.mk_zero_extend(sbits-ebits, shift); + q = m_bv_util.mk_zero_extend(sbits-ebits, shift); denormal_sig = m_bv_util.mk_bv_shl(denormal_sig, q); } else { - denormal_sig = m_bv_util.mk_bv_shl(denormal_sig, shift); + // the maximum shift is `sbits', because after that the mantissa + // would be zero anyways. So we can safely cut the shift variable down, + // as long as we check the higher bits. + expr_ref sh(m), is_sh_zero(m), sl(m), zero_s(m), sbits_s(m), short_shift(m); + zero_s = m_bv_util.mk_numeral(0, sbits-1); + sbits_s = m_bv_util.mk_numeral(sbits, sbits); + sh = m_bv_util.mk_extract(ebits-1, sbits, shift); + m_simp.mk_eq(zero_s, sh, is_sh_zero); + short_shift = m_bv_util.mk_extract(sbits-1, 0, shift); + m_simp.mk_ite(is_sh_zero, short_shift, sbits_s, sl); + denormal_sig = m_bv_util.mk_bv_shl(denormal_sig, sl); } } SASSERT(is_well_sorted(m, normal_sig)); SASSERT(is_well_sorted(m, denormal_sig)); + SASSERT(is_well_sorted(m, normal_exp)); + SASSERT(is_well_sorted(m, denormal_exp)); m_simp.mk_ite(is_normal, normal_sig, denormal_sig, sig); m_simp.mk_ite(is_normal, normal_exp, denormal_exp, exp); @@ -1672,19 +1728,20 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) { - switch(f->get_decl_kind()) - { - case OP_RM_NEAREST_TIES_TO_AWAY: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_AWAY, 3); break; + switch(f->get_decl_kind()) + { + case OP_RM_NEAREST_TIES_TO_AWAY: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_AWAY, 3); break; case OP_RM_NEAREST_TIES_TO_EVEN: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3); break; case OP_RM_TOWARD_NEGATIVE: result = m_bv_util.mk_numeral(BV_RM_TO_NEGATIVE, 3); break; case OP_RM_TOWARD_POSITIVE: result = m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3); break; - case OP_RM_TOWARD_ZERO: result = m_bv_util.mk_numeral(BV_RM_TO_ZERO, 3); break; - default: UNREACHABLE(); - } + case OP_RM_TOWARD_ZERO: result = m_bv_util.mk_numeral(BV_RM_TO_ZERO, 3); break; + default: UNREACHABLE(); + } } -void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { +void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { #ifdef _DEBUG + // return; expr_ref new_e(m); new_e = m.mk_fresh_const(prefix, m.get_sort(e)); extra_assertions.push_back(m.mk_eq(new_e, e)); @@ -1701,144 +1758,158 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & dbg_decouple("fpa2bv_rnd_sig", sig); dbg_decouple("fpa2bv_rnd_exp", exp); - SASSERT(is_well_sorted(m, rm)); - SASSERT(is_well_sorted(m, sgn)); - SASSERT(is_well_sorted(m, sig)); - SASSERT(is_well_sorted(m, exp)); + SASSERT(is_well_sorted(m, rm)); + SASSERT(is_well_sorted(m, sgn)); + SASSERT(is_well_sorted(m, sig)); + SASSERT(is_well_sorted(m, exp)); - TRACE("fpa2bv_dbg", tout << "RND: " << std::endl << - "ebits = " << ebits << std::endl << - "sbits = " << sbits << std::endl << - "sgn = " << mk_ismt2_pp(sgn, m) << std::endl << - "sig = " << mk_ismt2_pp(sig, m) << std::endl << - "exp = " << mk_ismt2_pp(exp, m) << std::endl; ); + TRACE("fpa2bv_dbg", tout << "RND: " << std::endl << + "ebits = " << ebits << std::endl << + "sbits = " << sbits << std::endl << + "sgn = " << mk_ismt2_pp(sgn, m) << std::endl << + "sig = " << mk_ismt2_pp(sig, m) << std::endl << + "exp = " << mk_ismt2_pp(exp, m) << std::endl; ); - // Assumptions: sig is of the form f[-1:0] . f[1:sbits-1] [guard,round,sticky], + // Assumptions: sig is of the form f[-1:0] . f[1:sbits-1] [guard,round,sticky], // i.e., it has 2 + (sbits-1) + 3 = sbits + 4 bits, where the first one is in sgn. - // Furthermore, note that sig is an unsigned bit-vector, while exp is signed. + // Furthermore, note that sig is an unsigned bit-vector, while exp is signed. - SASSERT(ebits <= sbits); - SASSERT(m_bv_util.is_bv(rm) && m_bv_util.get_bv_size(rm) == 3); - SASSERT(m_bv_util.is_bv(sgn) && m_bv_util.get_bv_size(sgn) == 1); - SASSERT(m_bv_util.is_bv(sig) && m_bv_util.get_bv_size(sig) >= 5); - SASSERT(m_bv_util.is_bv(exp) && m_bv_util.get_bv_size(exp) >= 4); + SASSERT(ebits <= sbits); + SASSERT(m_bv_util.is_bv(rm) && m_bv_util.get_bv_size(rm) == 3); + SASSERT(m_bv_util.is_bv(sgn) && m_bv_util.get_bv_size(sgn) == 1); + SASSERT(m_bv_util.is_bv(sig) && m_bv_util.get_bv_size(sig) >= 5); + SASSERT(m_bv_util.is_bv(exp) && m_bv_util.get_bv_size(exp) >= 4); SASSERT(m_bv_util.get_bv_size(sig) == sbits+4); SASSERT(m_bv_util.get_bv_size(exp) == ebits+2); - // bool UNFen = false; + // bool UNFen = false; // bool OVFen = false; - expr_ref e_min(m), e_max(m); - mk_min_exp(ebits, e_min); - mk_max_exp(ebits, e_max); + expr_ref e_min(m), e_max(m); + mk_min_exp(ebits, e_min); + mk_max_exp(ebits, e_max); - TRACE("fpa2bv_dbg", tout << "e_min = " << mk_ismt2_pp(e_min, m) << std::endl << - "e_max = " << mk_ismt2_pp(e_max, m) << std::endl;); + TRACE("fpa2bv_dbg", tout << "e_min = " << mk_ismt2_pp(e_min, m) << std::endl << + "e_max = " << mk_ismt2_pp(e_max, m) << std::endl;); - expr_ref OVF1(m), e_top_three(m), sigm1(m), e_eq_emax_and_sigm1(m), e_eq_emax(m); - expr_ref e3(m), ne3(m), e2(m), e1(m), e21(m); - m_simp.mk_eq(m_bv_util.mk_extract(ebits+1, ebits+1, exp), m_bv_util.mk_numeral(1, 1), e3); - m_simp.mk_eq(m_bv_util.mk_extract(ebits, ebits, exp), m_bv_util.mk_numeral(1, 1), e2); - m_simp.mk_eq(m_bv_util.mk_extract(ebits-1, ebits-1, exp), m_bv_util.mk_numeral(1, 1), e1); + expr_ref OVF1(m), e_top_three(m), sigm1(m), e_eq_emax_and_sigm1(m), e_eq_emax(m); + expr_ref e3(m), ne3(m), e2(m), e1(m), e21(m), one_1(m), h_exp(m), sh_exp(m), th_exp(m); + one_1 = m_bv_util.mk_numeral(1, 1); + h_exp = m_bv_util.mk_extract(ebits+1, ebits+1, exp); + sh_exp = m_bv_util.mk_extract(ebits, ebits, exp); + th_exp = m_bv_util.mk_extract(ebits-1, ebits-1, exp); + m_simp.mk_eq(h_exp, one_1, e3); + m_simp.mk_eq(sh_exp, one_1, e2); + m_simp.mk_eq(th_exp, one_1, e1); m_simp.mk_or(e2, e1, e21); m_simp.mk_not(e3, ne3); m_simp.mk_and(ne3, e21, e_top_three); - m_simp.mk_eq(m_bv_util.mk_zero_extend(2, e_max), exp, e_eq_emax); - m_simp.mk_eq(m_bv_util.mk_extract(sbits+3, sbits+3, sig), m_bv_util.mk_numeral(1, 1), sigm1); + + expr_ref ext_emax(m), t_sig(m); + ext_emax = m_bv_util.mk_zero_extend(2, e_max); + t_sig = m_bv_util.mk_extract(sbits+3, sbits+3, sig); + m_simp.mk_eq(ext_emax, exp, e_eq_emax); + m_simp.mk_eq(t_sig, one_1, sigm1); m_simp.mk_and(e_eq_emax, sigm1, e_eq_emax_and_sigm1); m_simp.mk_or(e_top_three, e_eq_emax_and_sigm1, OVF1); dbg_decouple("fpa2bv_rnd_OVF1", OVF1); - TRACE("fpa2bv_dbg", tout << "OVF1 = " << mk_ismt2_pp(OVF1, m) << std::endl;); - SASSERT(is_well_sorted(m, OVF1)); + TRACE("fpa2bv_dbg", tout << "OVF1 = " << mk_ismt2_pp(OVF1, m) << std::endl;); + SASSERT(is_well_sorted(m, OVF1)); - expr_ref lz(m); - mk_leading_zeros(sig, ebits+2, lz); // CMW: is this always large enough? + expr_ref lz(m); + mk_leading_zeros(sig, ebits+2, lz); // CMW: is this always large enough? dbg_decouple("fpa2bv_rnd_lz", lz); - TRACE("fpa2bv_dbg", tout << "LZ = " << mk_ismt2_pp(lz, m) << std::endl;); + TRACE("fpa2bv_dbg", tout << "LZ = " << mk_ismt2_pp(lz, m) << std::endl;); - expr_ref t(m); - t = m_bv_util.mk_bv_add(exp, m_bv_util.mk_numeral(1, ebits+2)); + expr_ref t(m); + t = m_bv_util.mk_bv_add(exp, m_bv_util.mk_numeral(1, ebits+2)); t = m_bv_util.mk_bv_sub(t, lz); - t = m_bv_util.mk_bv_sub(t, m_bv_util.mk_sign_extend(2, e_min)); + t = m_bv_util.mk_bv_sub(t, m_bv_util.mk_sign_extend(2, e_min)); expr_ref TINY(m); - TINY = m_bv_util.mk_sle(t, m_bv_util.mk_numeral(-1, ebits+2)); + TINY = m_bv_util.mk_sle(t, m_bv_util.mk_numeral(-1, ebits+2)); - TRACE("fpa2bv_dbg", tout << "TINY = " << mk_ismt2_pp(TINY, m) << std::endl;); - SASSERT(is_well_sorted(m, TINY)); + TRACE("fpa2bv_dbg", tout << "TINY = " << mk_ismt2_pp(TINY, m) << std::endl;); + SASSERT(is_well_sorted(m, TINY)); dbg_decouple("fpa2bv_rnd_TINY", TINY); - expr_ref beta(m); + expr_ref beta(m); beta = m_bv_util.mk_bv_add(m_bv_util.mk_bv_sub(exp, lz), m_bv_util.mk_numeral(1, ebits+2)); - TRACE("fpa2bv_dbg", tout << "beta = " << mk_ismt2_pp(beta, m)<< std::endl; ); - SASSERT(is_well_sorted(m, beta)); + TRACE("fpa2bv_dbg", tout << "beta = " << mk_ismt2_pp(beta, m)<< std::endl; ); + SASSERT(is_well_sorted(m, beta)); dbg_decouple("fpa2bv_rnd_beta", beta); - expr_ref sigma(m), sigma_add(m); + expr_ref sigma(m), sigma_add(m); sigma_add = m_bv_util.mk_bv_add(exp, m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits-1), ebits+2)); - m_simp.mk_ite(TINY, sigma_add, lz, sigma); + m_simp.mk_ite(TINY, sigma_add, lz, sigma); dbg_decouple("fpa2bv_rnd_sigma", sigma); - TRACE("fpa2bv_dbg", tout << "Shift distance: " << mk_ismt2_pp(sigma, m) << std::endl;); + TRACE("fpa2bv_dbg", tout << "Shift distance: " << mk_ismt2_pp(sigma, m) << std::endl;); SASSERT(is_well_sorted(m, sigma)); - // Normalization shift + // Normalization shift dbg_decouple("fpa2bv_rnd_sig_before_shift", sig); - unsigned sig_size = m_bv_util.get_bv_size(sig); + unsigned sig_size = m_bv_util.get_bv_size(sig); SASSERT(sig_size == sbits+4); - unsigned sigma_size = m_bv_util.get_bv_size(sigma); + unsigned sigma_size = m_bv_util.get_bv_size(sigma); - expr_ref sigma_neg(m), sigma_cap(m), sigma_neg_capped(m), sigma_lt_zero(m), sig_ext(m), rs_sig(m), ls_sig(m), big_sh_sig(m); - sigma_neg = m_bv_util.mk_bv_neg(sigma); + expr_ref sigma_neg(m), sigma_cap(m), sigma_neg_capped(m), sigma_lt_zero(m), sig_ext(m), + rs_sig(m), ls_sig(m), big_sh_sig(m), sigma_le_cap(m); + sigma_neg = m_bv_util.mk_bv_neg(sigma); sigma_cap = m_bv_util.mk_numeral(sbits+2, sigma_size); - m_simp.mk_ite(m_bv_util.mk_sle(sigma_neg, sigma_cap), sigma_neg, sigma_cap, sigma_neg_capped); + sigma_le_cap = m_bv_util.mk_sle(sigma_neg, sigma_cap); + m_simp.mk_ite(sigma_le_cap, sigma_neg, sigma_cap, sigma_neg_capped); dbg_decouple("fpa2bv_rnd_sigma_neg", sigma_neg); dbg_decouple("fpa2bv_rnd_sigma_neg_capped", sigma_neg_capped); - sigma_lt_zero = m_bv_util.mk_sle(sigma, m_bv_util.mk_numeral(-1, sigma_size)); + sigma_lt_zero = m_bv_util.mk_sle(sigma, m_bv_util.mk_numeral(-1, sigma_size)); dbg_decouple("fpa2bv_rnd_sigma_lt_zero", sigma_lt_zero); - sig_ext = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, sig_size)); - rs_sig = m_bv_util.mk_bv_lshr(sig_ext, m_bv_util.mk_zero_extend(2*sig_size - sigma_size, sigma_neg_capped)); - ls_sig = m_bv_util.mk_bv_shl(sig_ext, m_bv_util.mk_zero_extend(2*sig_size - sigma_size, sigma)); - m_simp.mk_ite(sigma_lt_zero, rs_sig, ls_sig, big_sh_sig); + sig_ext = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, sig_size)); + rs_sig = m_bv_util.mk_bv_lshr(sig_ext, m_bv_util.mk_zero_extend(2*sig_size - sigma_size, sigma_neg_capped)); + ls_sig = m_bv_util.mk_bv_shl(sig_ext, m_bv_util.mk_zero_extend(2*sig_size - sigma_size, sigma)); + m_simp.mk_ite(sigma_lt_zero, rs_sig, ls_sig, big_sh_sig); SASSERT(m_bv_util.get_bv_size(big_sh_sig) == 2*sig_size); dbg_decouple("fpa2bv_rnd_big_sh_sig", big_sh_sig); unsigned sig_extract_low_bit = (2*sig_size-1)-(sbits+2)+1; - sig = m_bv_util.mk_extract(2*sig_size-1, sig_extract_low_bit, big_sh_sig); + sig = m_bv_util.mk_extract(2*sig_size-1, sig_extract_low_bit, big_sh_sig); SASSERT(m_bv_util.get_bv_size(sig) == sbits+2); dbg_decouple("fpa2bv_rnd_shifted_sig", sig); - expr_ref sticky(m); - sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(sig_extract_low_bit-1, 0, big_sh_sig)); - SASSERT(is_well_sorted(m, sticky)); - SASSERT(is_well_sorted(m, sig)); - - // put the sticky bit into the significand. - expr * tmp[] = { sig, m_bv_util.mk_zero_extend(sbits+1, sticky) }; - sig = m_bv_util.mk_bv_or(2, tmp); + expr_ref sticky(m); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(sig_extract_low_bit-1, 0, big_sh_sig)); + SASSERT(is_well_sorted(m, sticky)); SASSERT(is_well_sorted(m, sig)); - SASSERT(m_bv_util.get_bv_size(sig) == sbits+2); - - // CMW: The (OVF1 && OVFen) and (TINY && UNFen) cases are never taken. - m_simp.mk_ite(TINY, m_bv_util.mk_zero_extend(2, e_min), beta, exp); - SASSERT(is_well_sorted(m, exp)); - // Significand rounding + // put the sticky bit into the significand. + expr_ref ext_sticky(m); + ext_sticky = m_bv_util.mk_zero_extend(sbits+1, sticky); + expr * tmp[] = { sig, ext_sticky }; + sig = m_bv_util.mk_bv_or(2, tmp); + SASSERT(is_well_sorted(m, sig)); + SASSERT(m_bv_util.get_bv_size(sig) == sbits+2); + + // CMW: The (OVF1 && OVFen) and (TINY && UNFen) cases are never taken. + expr_ref ext_emin(m); + ext_emin = m_bv_util.mk_zero_extend(2, e_min); + m_simp.mk_ite(TINY, ext_emin, beta, exp); + SASSERT(is_well_sorted(m, exp)); + + // Significand rounding expr_ref round(m), last(m); - sticky = m_bv_util.mk_extract(0, 0, sig); // new sticky bit! - round = m_bv_util.mk_extract(1, 1, sig); + sticky = m_bv_util.mk_extract(0, 0, sig); // new sticky bit! + round = m_bv_util.mk_extract(1, 1, sig); last = m_bv_util.mk_extract(2, 2, sig); TRACE("fpa2bv_dbg", tout << "sticky = " << mk_ismt2_pp(sticky, m) << std::endl;); @@ -1847,70 +1918,76 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & dbg_decouple("fpa2bv_rnd_round", round); dbg_decouple("fpa2bv_rnd_last", last); - sig = m_bv_util.mk_extract(sbits+1, 2, sig); + sig = m_bv_util.mk_extract(sbits+1, 2, sig); - expr * last_sticky[2] = { last, sticky }; - expr * round_sticky[2] = { round, sticky }; - expr * last_or_sticky = m_bv_util.mk_bv_or(2, last_sticky); - expr * round_or_sticky = m_bv_util.mk_bv_or(2, round_sticky); - expr * round_lors[2] = { m_bv_util.mk_bv_not(round), m_bv_util.mk_bv_not(last_or_sticky) }; - expr * pos_args[2] = { sgn, m_bv_util.mk_bv_not(round_or_sticky) }; - expr * neg_args[2] = { m_bv_util.mk_bv_not(sgn), m_bv_util.mk_bv_not(round_or_sticky) }; + expr_ref last_or_sticky(m), round_or_sticky(m), not_round(m), not_lors(m), not_rors(m), not_sgn(m); + expr * last_sticky[2] = { last, sticky }; + expr * round_sticky[2] = { round, sticky }; + last_or_sticky = m_bv_util.mk_bv_or(2, last_sticky); + round_or_sticky = m_bv_util.mk_bv_or(2, round_sticky); + not_round = m_bv_util.mk_bv_not(round); + not_lors = m_bv_util.mk_bv_not(last_or_sticky); + not_rors = m_bv_util.mk_bv_not(round_or_sticky); + not_sgn = m_bv_util.mk_bv_not(sgn); + expr * round_lors[2] = { not_round, not_lors }; + expr * pos_args[2] = { sgn, not_rors }; + expr * neg_args[2] = { not_sgn, not_rors }; expr_ref inc_teven(m), inc_taway(m), inc_pos(m), inc_neg(m); - inc_teven = m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, round_lors)); - inc_taway = round; - inc_pos = m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, pos_args)); - inc_neg = m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, neg_args)); + inc_teven = m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, round_lors)); + inc_taway = round; + inc_pos = m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, pos_args)); + inc_neg = m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, neg_args)); expr_ref inc(m), inc_c2(m), inc_c3(m), inc_c4(m); - expr_ref rm_is_to_neg(m), rm_is_to_pos(m), rm_is_away(m), rm_is_even(m); + expr_ref rm_is_to_neg(m), rm_is_to_pos(m), rm_is_away(m), rm_is_even(m), nil_1(m); + nil_1 = m_bv_util.mk_numeral(0, 1); mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg); mk_is_rm(rm, BV_RM_TO_POSITIVE, rm_is_to_pos); mk_is_rm(rm, BV_RM_TIES_TO_AWAY, rm_is_away); mk_is_rm(rm, BV_RM_TIES_TO_EVEN, rm_is_even); - m_simp.mk_ite(rm_is_to_neg, inc_neg, m_bv_util.mk_numeral(0, 1), inc_c4); + m_simp.mk_ite(rm_is_to_neg, inc_neg, nil_1, inc_c4); m_simp.mk_ite(rm_is_to_pos, inc_pos, inc_c4, inc_c3); m_simp.mk_ite(rm_is_away, inc_taway, inc_c3, inc_c2); - m_simp.mk_ite(rm_is_even, inc_teven, inc_c2, inc); + m_simp.mk_ite(rm_is_even, inc_teven, inc_c2, inc); - SASSERT(m_bv_util.get_bv_size(inc) == 1 && is_well_sorted(m, inc)); + SASSERT(m_bv_util.get_bv_size(inc) == 1 && is_well_sorted(m, inc)); dbg_decouple("fpa2bv_rnd_inc", inc); - sig = m_bv_util.mk_bv_add(m_bv_util.mk_zero_extend(1, sig), - m_bv_util.mk_zero_extend(sbits, inc)); - SASSERT(is_well_sorted(m, sig)); + sig = m_bv_util.mk_bv_add(m_bv_util.mk_zero_extend(1, sig), + m_bv_util.mk_zero_extend(sbits, inc)); + SASSERT(is_well_sorted(m, sig)); dbg_decouple("fpa2bv_rnd_sig_plus_inc", sig); - // Post normalization - SASSERT(m_bv_util.get_bv_size(sig) == sbits + 1); + // Post normalization + SASSERT(m_bv_util.get_bv_size(sig) == sbits + 1); expr_ref SIGovf(m); - m_simp.mk_eq(m_bv_util.mk_extract(sbits, sbits, sig), m_bv_util.mk_numeral(1, 1), SIGovf); + t_sig = m_bv_util.mk_extract(sbits, sbits, sig); + m_simp.mk_eq(t_sig, one_1, SIGovf); SASSERT(is_well_sorted(m, SIGovf)); dbg_decouple("fpa2bv_rnd_SIGovf", SIGovf); - m_simp.mk_ite(SIGovf, - m_bv_util.mk_extract(sbits, 1, sig), - m_bv_util.mk_extract(sbits-1, 0, sig), - sig); + expr_ref hallbut1_sig(m), lallbut1_sig(m); + hallbut1_sig = m_bv_util.mk_extract(sbits, 1, sig); + lallbut1_sig = m_bv_util.mk_extract(sbits-1, 0, sig); + m_simp.mk_ite(SIGovf, hallbut1_sig, lallbut1_sig, sig); - SASSERT(m_bv_util.get_bv_size(exp) == ebits + 2); + SASSERT(m_bv_util.get_bv_size(exp) == ebits + 2); - m_simp.mk_ite(SIGovf, - m_bv_util.mk_bv_add(exp, m_bv_util.mk_numeral(1, ebits+2)), - exp, - exp); + expr_ref exp_p1(m); + exp_p1 = m_bv_util.mk_bv_add(exp, m_bv_util.mk_numeral(1, ebits+2)); + m_simp.mk_ite(SIGovf, exp_p1, exp, exp); - SASSERT(is_well_sorted(m, sig)); - SASSERT(is_well_sorted(m, exp)); + SASSERT(is_well_sorted(m, sig)); + SASSERT(is_well_sorted(m, exp)); dbg_decouple("fpa2bv_rnd_sig_postnormalized", sig); dbg_decouple("fpa2bv_rnd_exp_postnormalized", exp); - - SASSERT(m_bv_util.get_bv_size(sig) == sbits); - SASSERT(m_bv_util.get_bv_size(exp) == ebits + 2); - SASSERT(m_bv_util.get_bv_size(e_max) == ebits); + + SASSERT(m_bv_util.get_bv_size(sig) == sbits); + SASSERT(m_bv_util.get_bv_size(exp) == ebits + 2); + SASSERT(m_bv_util.get_bv_size(e_max) == ebits); - // Exponent adjustment and rounding + // Exponent adjustment and rounding expr_ref biased_exp(m); mk_bias(m_bv_util.mk_extract(ebits-1, 0, exp), biased_exp); dbg_decouple("fpa2bv_rnd_unbiased_exp", exp); @@ -1920,12 +1997,12 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & SASSERT(is_well_sorted(m, OVF1)); SASSERT(m.is_bool(OVF1)); - expr_ref preOVF2(m), OVF2(m), OVF(m); - m_simp.mk_eq(m.mk_app(m_bv_util.get_fid(), OP_BREDAND, biased_exp.get()), m_bv_util.mk_numeral(1, 1), preOVF2); + expr_ref preOVF2(m), OVF2(m), OVF(m), exp_redand(m), pem2m1(m); + exp_redand = m.mk_app(m_bv_util.get_fid(), OP_BREDAND, biased_exp.get()); + m_simp.mk_eq(exp_redand, one_1, preOVF2); m_simp.mk_and(SIGovf, preOVF2, OVF2); - m_simp.mk_ite(OVF2, m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits-2), ebits), - biased_exp, - biased_exp); + pem2m1 = m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits-2), ebits); + m_simp.mk_ite(OVF2, pem2m1, biased_exp, biased_exp); m_simp.mk_or(OVF1, OVF2, OVF); SASSERT(is_well_sorted(m, OVF2)); @@ -1950,11 +2027,11 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & m_simp.mk_eq(sgn, m_bv_util.mk_numeral(0, 1), sgn_is_zero); expr_ref max_sig(m), max_exp(m), inf_sig(m), inf_exp(m); - max_sig = m_bv_util.mk_numeral(fu().fm().m_powers2.m1(sbits-1, false), sbits-1); - max_exp = m_bv_util.mk_concat(m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits-1, false), ebits-1), + max_sig = m_bv_util.mk_numeral(fu().fm().m_powers2.m1(sbits-1, false), sbits-1); + max_exp = m_bv_util.mk_concat(m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits-1, false), ebits-1), m_bv_util.mk_numeral(0, 1)); - inf_sig = m_bv_util.mk_numeral(0, sbits-1); - inf_exp = top_exp; + inf_sig = m_bv_util.mk_numeral(0, sbits-1); + inf_exp = top_exp; dbg_decouple("fpa2bv_rnd_max_exp", max_exp); @@ -1962,15 +2039,17 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & m_simp.mk_ite(rm_zero_or_neg, max_exp, inf_exp, max_inf_exp_neg); m_simp.mk_ite(rm_zero_or_pos, max_exp, inf_exp, max_inf_exp_pos); m_simp.mk_ite(sgn_is_zero, max_inf_exp_neg, max_inf_exp_pos, ovfl_exp); - m_simp.mk_eq(m_bv_util.mk_extract(sbits-1, sbits-1, sig), m_bv_util.mk_numeral(0, 1), n_d_check); + t_sig = m_bv_util.mk_extract(sbits-1, sbits-1, sig); + m_simp.mk_eq(t_sig, nil_1, n_d_check); m_simp.mk_ite(n_d_check, bot_exp /* denormal */, biased_exp, n_d_exp); m_simp.mk_ite(OVF, ovfl_exp, n_d_exp, exp); - expr_ref max_inf_sig_neg(m), max_inf_sig_pos(m), ovfl_sig(m); + expr_ref max_inf_sig_neg(m), max_inf_sig_pos(m), ovfl_sig(m), rest_sig(m); m_simp.mk_ite(rm_zero_or_neg, max_sig, inf_sig, max_inf_sig_neg); m_simp.mk_ite(rm_zero_or_pos, max_sig, inf_sig, max_inf_sig_pos); m_simp.mk_ite(sgn_is_zero, max_inf_sig_neg, max_inf_sig_pos, ovfl_sig); - m_simp.mk_ite(OVF, ovfl_sig, m_bv_util.mk_extract(sbits-2, 0, sig), sig); + rest_sig = m_bv_util.mk_extract(sbits-2, 0, sig); + m_simp.mk_ite(OVF, ovfl_sig, rest_sig, sig); dbg_decouple("fpa2bv_rnd_sgn_final", sgn); dbg_decouple("fpa2bv_rnd_sig_final", sig); @@ -1978,26 +2057,21 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & expr_ref res_sgn(m), res_sig(m), res_exp(m); res_sgn = sgn; - res_sig = sig; - res_exp = exp; - - SASSERT(m_bv_util.get_bv_size(res_sgn) == 1); - SASSERT(is_well_sorted(m, res_sgn)); + res_sig = sig; + res_exp = exp; + + SASSERT(m_bv_util.get_bv_size(res_sgn) == 1); + SASSERT(is_well_sorted(m, res_sgn)); SASSERT(m_bv_util.get_bv_size(res_sig) == sbits-1); - SASSERT(is_well_sorted(m, res_sig)); + SASSERT(is_well_sorted(m, res_sig)); SASSERT(m_bv_util.get_bv_size(res_exp) == ebits); - SASSERT(is_well_sorted(m, res_exp)); + SASSERT(is_well_sorted(m, res_exp)); - mk_triple(res_sgn, res_sig, res_exp, result); + mk_triple(res_sgn, res_sig, res_exp, result); TRACE("fpa2bv_round", tout << "ROUND = " << mk_ismt2_pp(result, m) << std::endl; ); } - -fpa2bv_model_converter * fpa2bv_converter::mk_model_converter() { - return alloc(fpa2bv_model_converter, m, m_const2bv, m_rm_const2bv); -} - void fpa2bv_model_converter::display(std::ostream & out) { out << "(fpa2bv-model-converter"; for (obj_map::iterator it = m_const2bv.begin(); @@ -2008,7 +2082,7 @@ void fpa2bv_model_converter::display(std::ostream & out) { unsigned indent = n.size() + 4; out << mk_ismt2_pp(it->m_value, m, indent) << ")"; } - for (obj_map::iterator it = m_rm_const2bv.begin(); + for (obj_map::iterator it = m_rm_const2bv.begin(); it != m_rm_const2bv.end(); it++) { const symbol & n = it->m_key->get_name(); @@ -2024,11 +2098,23 @@ model_converter * fpa2bv_model_converter::translate(ast_translation & translator for (obj_map::iterator it = m_const2bv.begin(); it != m_const2bv.end(); it++) - res->m_const2bv.insert(translator(it->m_key), translator(it->m_value)); - for (obj_map::iterator it = m_rm_const2bv.begin(); + { + func_decl * k = translator(it->m_key); + expr * v = translator(it->m_value); + res->m_const2bv.insert(k, v); + translator.to().inc_ref(k); + translator.to().inc_ref(v); + } + for (obj_map::iterator it = m_rm_const2bv.begin(); it != m_rm_const2bv.end(); it++) - res->m_rm_const2bv.insert(translator(it->m_key), translator(it->m_value)); + { + func_decl * k = translator(it->m_key); + expr * v = translator(it->m_value); + res->m_rm_const2bv.insert(k, v); + translator.to().inc_ref(k); + translator.to().inc_ref(v); + } return res; } @@ -2098,30 +2184,30 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { mpzm.del(sig_z); } - for (obj_map::iterator it = m_rm_const2bv.begin(); + for (obj_map::iterator it = m_rm_const2bv.begin(); it != m_rm_const2bv.end(); it++) { - func_decl * var = it->m_key; + func_decl * var = it->m_key; app * a = to_app(it->m_value); SASSERT(fu.is_rm(var->get_range())); - rational val(0); - unsigned sz = 0; - if (a && bu.is_numeral(a, val, sz)) { - TRACE("fpa2bv_mc", tout << var->get_name() << " == " << val.to_string() << std::endl; ); - SASSERT(val.is_uint64()); - switch (val.get_uint64()) - { - case BV_RM_TIES_TO_AWAY: float_mdl->register_decl(var, fu.mk_round_nearest_ties_to_away()); break; - case BV_RM_TIES_TO_EVEN: float_mdl->register_decl(var, fu.mk_round_nearest_ties_to_even()); break; - case BV_RM_TO_NEGATIVE: float_mdl->register_decl(var, fu.mk_round_toward_negative()); break; - case BV_RM_TO_POSITIVE: float_mdl->register_decl(var, fu.mk_round_toward_positive()); break; - case BV_RM_TO_ZERO: - default: float_mdl->register_decl(var, fu.mk_round_toward_zero()); - } + rational val(0); + unsigned sz = 0; + if (a && bu.is_numeral(a, val, sz)) { + TRACE("fpa2bv_mc", tout << var->get_name() << " == " << val.to_string() << std::endl; ); + SASSERT(val.is_uint64()); + switch (val.get_uint64()) + { + case BV_RM_TIES_TO_AWAY: float_mdl->register_decl(var, fu.mk_round_nearest_ties_to_away()); break; + case BV_RM_TIES_TO_EVEN: float_mdl->register_decl(var, fu.mk_round_nearest_ties_to_even()); break; + case BV_RM_TO_NEGATIVE: float_mdl->register_decl(var, fu.mk_round_toward_negative()); break; + case BV_RM_TO_POSITIVE: float_mdl->register_decl(var, fu.mk_round_toward_positive()); break; + case BV_RM_TO_ZERO: + default: float_mdl->register_decl(var, fu.mk_round_toward_zero()); + } seen.insert(var); - } - } + } + } fu.fm().del(fp_val); @@ -2135,7 +2221,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { float_mdl->register_decl(c, bv_mdl->get_const_interp(c)); } - // And keep everything else +// And keep everything else sz = bv_mdl->get_num_functions(); for (unsigned i = 0; i < sz; i++) { @@ -2151,3 +2237,9 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { float_mdl->register_usort(s, u.size(), u.c_ptr()); } } + +model_converter * mk_fpa2bv_model_converter(ast_manager & m, + obj_map const & const2bv, + obj_map const & rm_const2bv) { + return alloc(fpa2bv_model_converter, m, const2bv, rm_const2bv); +} \ No newline at end of file diff --git a/src/tactic/fpa/fpa2bv_converter.h b/src/tactic/fpa/fpa2bv_converter.h index 1ee374941..6ac1d2b8b 100644 --- a/src/tactic/fpa/fpa2bv_converter.h +++ b/src/tactic/fpa/fpa2bv_converter.h @@ -35,13 +35,13 @@ class fpa2bv_converter { ast_manager & m; basic_simplifier_plugin m_simp; float_util m_util; - mpf_manager & m_mpf_manager; - unsynch_mpz_manager & m_mpz_manager; + mpf_manager & m_mpf_manager; + unsynch_mpz_manager & m_mpz_manager; bv_util m_bv_util; float_decl_plugin * m_plugin; obj_map m_const2bv; - obj_map m_rm_const2bv; + obj_map m_rm_const2bv; public: fpa2bv_converter(ast_manager & m); @@ -52,22 +52,22 @@ public: bool is_float(sort * s) { return m_util.is_float(s); } bool is_float(expr * e) { return is_app(e) && m_util.is_float(to_app(e)->get_decl()->get_range()); } bool is_float_family(func_decl * f) { return f->get_family_id() == m_util.get_family_id(); } - bool is_rm_sort(sort * s) { return m_util.is_rm(s); } + bool is_rm_sort(sort * s) { return m_util.is_rm(s); } void mk_triple(expr * sign, expr * significand, expr * exponent, expr_ref & result) { - SASSERT(m_bv_util.is_bv(sign) && m_bv_util.get_bv_size(sign) == 1); - SASSERT(m_bv_util.is_bv(significand)); - SASSERT(m_bv_util.is_bv(exponent)); + SASSERT(m_bv_util.is_bv(sign) && m_bv_util.get_bv_size(sign) == 1); + SASSERT(m_bv_util.is_bv(significand)); + SASSERT(m_bv_util.is_bv(exponent)); result = m.mk_app(m_util.get_family_id(), OP_TO_FLOAT, sign, significand, exponent); } void mk_eq(expr * a, expr * b, expr_ref & result); void mk_ite(expr * c, expr * t, expr * f, expr_ref & result); - void mk_rounding_mode(func_decl * f, expr_ref & result); + void mk_rounding_mode(func_decl * f, expr_ref & result); void mk_value(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_const(func_decl * f, expr_ref & result); - void mk_rm_const(func_decl * f, expr_ref & result); + void mk_rm_const(func_decl * f, expr_ref & result); void mk_plus_inf(func_decl * f, expr_ref & result); void mk_minus_inf(func_decl * f, expr_ref & result); @@ -102,7 +102,8 @@ public: void mk_to_float(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - fpa2bv_model_converter * mk_model_converter(); + obj_map const & const2bv() const { return m_const2bv; } + obj_map const & rm_const2bv() const { return m_rm_const2bv; } void dbg_decouple(const char * prefix, expr_ref & e); expr_ref_vector extra_assertions; @@ -122,11 +123,11 @@ protected: void mk_is_denormal(expr * e, expr_ref & result); void mk_is_normal(expr * e, expr_ref & result); - void mk_is_rm(expr * e, BV_RM_VAL rm, expr_ref & result); + void mk_is_rm(expr * e, BV_RM_VAL rm, expr_ref & result); void mk_top_exp(unsigned sz, expr_ref & result); void mk_bot_exp(unsigned sz, expr_ref & result); - void mk_min_exp(unsigned ebits, expr_ref & result); + void mk_min_exp(unsigned ebits, expr_ref & result); void mk_max_exp(unsigned ebits, expr_ref & result); void mk_leading_zeros(expr * e, unsigned max_bits, expr_ref & result); @@ -135,7 +136,7 @@ protected: void mk_unbias(expr * e, expr_ref & result); void unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp, bool normalize); - void round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & result); + void round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & result); void add_core(unsigned sbits, unsigned ebits, expr_ref & rm, expr_ref & c_sgn, expr_ref & c_sig, expr_ref & c_exp, expr_ref & d_sgn, expr_ref & d_sig, expr_ref & d_exp, @@ -146,11 +147,11 @@ protected: class fpa2bv_model_converter : public model_converter { ast_manager & m; obj_map m_const2bv; - obj_map m_rm_const2bv; + obj_map m_rm_const2bv; public: - fpa2bv_model_converter(ast_manager & m, obj_map & const2bv, - obj_map & rm_const2bv) : + fpa2bv_model_converter(ast_manager & m, obj_map const & const2bv, + obj_map const & rm_const2bv) : m(m) { // Just create a copy? for (obj_map::iterator it = const2bv.begin(); @@ -161,7 +162,7 @@ public: m.inc_ref(it->m_key); m.inc_ref(it->m_value); } - for (obj_map::iterator it = rm_const2bv.begin(); + for (obj_map::iterator it = rm_const2bv.begin(); it != rm_const2bv.end(); it++) { @@ -173,7 +174,7 @@ public: virtual ~fpa2bv_model_converter() { dec_ref_map_key_values(m, m_const2bv); - dec_ref_map_key_values(m, m_rm_const2bv); + dec_ref_map_key_values(m, m_rm_const2bv); } virtual void operator()(model_ref & md, unsigned goal_idx) { @@ -198,4 +199,9 @@ protected: void convert(model * bv_mdl, model * float_mdl); }; + +model_converter * mk_fpa2bv_model_converter(ast_manager & m, + obj_map const & const2bv, + obj_map const & rm_const2bv); + #endif diff --git a/src/tactic/fpa/fpa2bv_rewriter.h b/src/tactic/fpa/fpa2bv_rewriter.h index 94694867a..4b3525a32 100644 --- a/src/tactic/fpa/fpa2bv_rewriter.h +++ b/src/tactic/fpa/fpa2bv_rewriter.h @@ -73,7 +73,7 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { return BR_DONE; } - if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_rm_sort(f->get_range())) { + if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_rm_sort(f->get_range())) { m_conv.mk_rm_const(f, result); return BR_DONE; } @@ -102,7 +102,7 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { case OP_RM_NEAREST_TIES_TO_EVEN: case OP_RM_TOWARD_NEGATIVE: case OP_RM_TOWARD_POSITIVE: - case OP_RM_TOWARD_ZERO: m_conv.mk_rounding_mode(f, result); return BR_DONE; + case OP_RM_TOWARD_ZERO: m_conv.mk_rounding_mode(f, result); return BR_DONE; case OP_FLOAT_VALUE: m_conv.mk_value(f, num, args, result); return BR_DONE; case OP_FLOAT_PLUS_INF: m_conv.mk_plus_inf(f, result); return BR_DONE; case OP_FLOAT_MINUS_INF: m_conv.mk_minus_inf(f, result); return BR_DONE; diff --git a/src/tactic/fpa/fpa2bv_tactic.cpp b/src/tactic/fpa/fpa2bv_tactic.cpp index 79f41518e..a90ff9317 100644 --- a/src/tactic/fpa/fpa2bv_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_tactic.cpp @@ -90,7 +90,7 @@ class fpa2bv_tactic : public tactic { } if (g->models_enabled()) - mc = m_conv.mk_model_converter(); + mc = mk_fpa2bv_model_converter(m, m_conv.const2bv(), m_conv.rm_const2bv()); g->inc_depth(); result.push_back(g.get()); From 7822b86b532abdd75b7e7aad2b6383464ab8658b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 1 Mar 2013 19:06:01 +0000 Subject: [PATCH 18/97] FPA: multiple bugfixes for HWF, MPF and a bugfix for FPA2BV (many thanks to Gabriele Paganelli) Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 43 +++++++++++++------ src/util/hwf.cpp | 64 +++++++++++++++++++---------- src/util/mpf.cpp | 46 ++++++++++++--------- 3 files changed, 99 insertions(+), 54 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index b11e2c3ac..2600cb3ec 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -324,8 +324,12 @@ void fpa2bv_converter::add_core(unsigned sbits, unsigned ebits, expr_ref & rm, family_id bvfid = m_bv_util.get_fid(); expr_ref res_sgn_c1(m), res_sgn_c2(m), res_sgn_c3(m); - res_sgn_c1 = m.mk_app(bvfid, OP_BAND, m_bv_util.mk_bv_not(c_sgn), d_sgn, sign_bv); - res_sgn_c2 = m.mk_app(bvfid, OP_BAND, c_sgn, m_bv_util.mk_bv_not(d_sgn), m_bv_util.mk_bv_not(sign_bv)); + expr_ref not_c_sgn(m), not_d_sgn(m), not_sign_bv(m); + not_c_sgn = m_bv_util.mk_bv_not(c_sgn); + not_d_sgn = m_bv_util.mk_bv_not(d_sgn); + not_sign_bv = m_bv_util.mk_bv_not(sign_bv); + res_sgn_c1 = m.mk_app(bvfid, OP_BAND, not_c_sgn, d_sgn, sign_bv); + res_sgn_c2 = m.mk_app(bvfid, OP_BAND, c_sgn, not_d_sgn, not_sign_bv); res_sgn_c3 = m.mk_app(bvfid, OP_BAND, c_sgn, d_sgn); expr * res_sgn_or_args[3] = { res_sgn_c1, res_sgn_c2, res_sgn_c3 }; res_sgn = m_bv_util.mk_bv_or(3, res_sgn_or_args); @@ -398,10 +402,14 @@ void fpa2bv_converter::mk_add(func_decl * f, unsigned num, expr * const * args, m_simp.mk_and(x_is_inf, xy_is_neg, v3_and); mk_ite(v3_and, nan, y, v3); - expr_ref rm_is_to_neg(m), v4_and(m); + expr_ref rm_is_to_neg(m), signs_and(m), signs_xor(m), v4_and(m), rm_and_xor(m), neg_cond(m); m_simp.mk_and(x_is_zero, y_is_zero, c4); + m_simp.mk_and(x_is_neg, y_is_neg, signs_and); + m_simp.mk_xor(x_is_neg, y_is_neg, signs_xor); mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg); - mk_ite(rm_is_to_neg, nzero, pzero, v4); + m_simp.mk_and(rm_is_to_neg, signs_xor, rm_and_xor); + m_simp.mk_or(signs_and, rm_and_xor, neg_cond); + mk_ite(neg_cond, nzero, pzero, v4); m_simp.mk_and(x_is_neg, y_is_neg, v4_and); mk_ite(v4_and, x, v4, v4); @@ -665,8 +673,8 @@ void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, dbg_decouple("fpa2bv_div_y_is_pos", y_is_pos); dbg_decouple("fpa2bv_div_y_is_inf", y_is_inf); - expr_ref c1(m), c2(m), c3(m), c4(m), c5(m), c6(m); - expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m), v7(m); + expr_ref c1(m), c2(m), c3(m), c4(m), c5(m), c6(m), c7(m); + expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m), v7(m), v8(m); // (x is NaN) || (y is NaN) -> NaN m_simp.mk_or(x_is_nan, y_is_nan, c1); @@ -701,6 +709,11 @@ void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, mk_ite(x_is_pos, pinf, ninf, x_sgn_inf); mk_ite(x_is_zero, nan, x_sgn_inf, v6); + // (x is 0) -> result is zero with sgn = x.sgn^y.sgn + // This is a special case to avoid problems with the unpacking of zero. + c7 = x_is_zero; + mk_ite(signs_xor, nzero, pzero, v7); + // else comes the actual division. unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); @@ -738,10 +751,11 @@ void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, SASSERT(m_bv_util.get_bv_size(res_sig) == (sbits + 4)); - round(f->get_range(), rm, res_sgn, res_sig, res_exp, v7); + round(f->get_range(), rm, res_sgn, res_sig, res_exp, v8); // And finally, we tie them together. - mk_ite(c6, v6, v7, result); + mk_ite(c7, v7, v8, result); + mk_ite(c6, v6, result, result); mk_ite(c5, v5, result, result); mk_ite(c4, v4, result, result); mk_ite(c3, v3, result, result); @@ -805,7 +819,7 @@ void fpa2bv_converter::mk_remainder(func_decl * f, unsigned num, expr * const * // (x is 0) -> x c4 = x_is_zero; - v4 = x; + v4 = pzero; // (y is 0) -> NaN. c5 = y_is_zero; @@ -1674,13 +1688,15 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref denormal_exp = m_bv_util.mk_numeral(1, ebits); mk_unbias(denormal_exp, denormal_exp); + dbg_decouple("fpa2bv_unpack_denormal_exp", denormal_exp); + if (normalize) { expr_ref is_sig_zero(m), shift(m), lz(m), zero_s(m), zero_e(m); zero_s = m_bv_util.mk_numeral(0, sbits-1); zero_e = m_bv_util.mk_numeral(0, ebits); m_simp.mk_eq(zero_s, sig, is_sig_zero); mk_leading_zeros(sig, ebits, lz); - m_simp.mk_ite(is_sig_zero, zero_e, lz, shift); + m_simp.mk_ite(is_sig_zero, zero_e, lz, shift); SASSERT(is_well_sorted(m, is_sig_zero)); SASSERT(is_well_sorted(m, lz)); SASSERT(is_well_sorted(m, shift)); @@ -1688,7 +1704,7 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref if (ebits <= sbits) { expr_ref q(m); q = m_bv_util.mk_zero_extend(sbits-ebits, shift); - denormal_sig = m_bv_util.mk_bv_shl(denormal_sig, q); + denormal_sig = m_bv_util.mk_bv_shl(denormal_sig, q); } else { // the maximum shift is `sbits', because after that the mantissa @@ -1701,8 +1717,9 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref m_simp.mk_eq(zero_s, sh, is_sh_zero); short_shift = m_bv_util.mk_extract(sbits-1, 0, shift); m_simp.mk_ite(is_sh_zero, short_shift, sbits_s, sl); - denormal_sig = m_bv_util.mk_bv_shl(denormal_sig, sl); + denormal_sig = m_bv_util.mk_bv_shl(denormal_sig, sl); } + denormal_exp = m_bv_util.mk_bv_sub(denormal_exp, shift); } SASSERT(is_well_sorted(m, normal_sig)); @@ -1710,6 +1727,8 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref SASSERT(is_well_sorted(m, normal_exp)); SASSERT(is_well_sorted(m, denormal_exp)); + dbg_decouple("fpa2bv_unpack_is_normal", is_normal); + m_simp.mk_ite(is_normal, normal_sig, denormal_sig, sig); m_simp.mk_ite(is_normal, normal_exp, denormal_exp, exp); diff --git a/src/util/hwf.cpp b/src/util/hwf.cpp index 219172b34..8585e7eda 100644 --- a/src/util/hwf.cpp +++ b/src/util/hwf.cpp @@ -117,14 +117,14 @@ void hwf_manager::set(hwf & o, mpf_rounding_mode rm, char const * value) { std::string v(value); size_t e_pos = v.find('p'); if (e_pos == std::string::npos) e_pos = v.find('P'); - + std::string f, e; - + f = (e_pos != std::string::npos) ? v.substr(0, e_pos) : v; e = (e_pos != std::string::npos) ? v.substr(e_pos+1) : "0"; - + TRACE("mpf_dbg", tout << " f = " << f << " e = " << e << std::endl;); - + mpq q; m_mpq_manager.set(q, f.c_str()); @@ -132,14 +132,14 @@ void hwf_manager::set(hwf & o, mpf_rounding_mode rm, char const * value) { m_mpz_manager.set(ex, e.c_str()); set(o, rm, q, ex); - + TRACE("mpf_dbg", tout << "set: res = " << to_string(o) << std::endl;); } void hwf_manager::set(hwf & o, mpf_rounding_mode rm, mpq const & significand, mpz const & exponent) { // Assumption: this represents significand * 2^exponent. set_rounding_mode(rm); - + mpq sig; m_mpq_manager.set(sig, significand); int64 exp = m_mpz_manager.get_int64(exponent); @@ -349,7 +349,7 @@ void hwf_manager::rem(hwf const & x, hwf const & y, hwf & o) { else o.value = fmod(x.value, y.value); -// Here is an x87 alternative if the above makes problems; this may also be faster. + // Here is an x87 alternative if the above makes problems; this may also be faster. #if 0 double xv = x.value; double yv = y.value; @@ -434,7 +434,7 @@ void hwf_manager::display_smt2(std::ostream & out, hwf const & a, bool decimal) void hwf_manager::to_rational(hwf const & x, unsynch_mpq_manager & qm, mpq & o) { SASSERT(is_normal(x) || is_denormal(x) || is_zero(x)); scoped_mpz n(qm), d(qm); - + if (is_normal(x)) qm.set(n, sig(x) | 0x0010000000000000ull); else @@ -466,7 +466,7 @@ bool hwf_manager::is_neg(hwf const & x) { bool hwf_manager::is_pos(hwf const & x) { return !sgn(x) && !is_nan(x); } - + bool hwf_manager::is_nzero(hwf const & x) { return RAW(x.value) == 0x8000000000000000ull; } @@ -581,20 +581,20 @@ void hwf_manager::mk_ninf(hwf & o) { #ifdef _WINDOWS #if defined(_AMD64_) || defined(_M_IA64) - #ifdef USE_INTRINSICS - #define SETRM(RM) _MM_SET_ROUNDING_MODE(RM) - #else - #define SETRM(RM) _controlfp_s(&sse2_state, RM, _MCW_RC); - #endif +#ifdef USE_INTRINSICS +#define SETRM(RM) _MM_SET_ROUNDING_MODE(RM) #else - #ifdef USE_INTRINSICS - #define SETRM(RM) _MM_SET_ROUNDING_MODE(RM) - #else - #define SETRM(RM) __control87_2(RM, _MCW_RC, &x86_state, &sse2_state) - #endif +#define SETRM(RM) _controlfp_s(&sse2_state, RM, _MCW_RC); #endif #else - #define SETRM(RM) fesetround(RM) +#ifdef USE_INTRINSICS +#define SETRM(RM) _MM_SET_ROUNDING_MODE(RM) +#else +#define SETRM(RM) __control87_2(RM, _MCW_RC, &x86_state, &sse2_state) +#endif +#endif +#else +#define SETRM(RM) fesetround(RM) #endif unsigned hwf_manager::prev_power_of_two(hwf const & a) { @@ -608,9 +608,28 @@ unsigned hwf_manager::prev_power_of_two(hwf const & a) { void hwf_manager::set_rounding_mode(mpf_rounding_mode rm) { -#ifdef _WINDOWS +#ifdef _WINDOWS +#ifdef USE_INTRINSICS switch (rm) { - case MPF_ROUND_NEAREST_TEVEN: + case MPF_ROUND_NEAREST_TEVEN: + SETRM(_MM_ROUND_NEAREST); + break; + case MPF_ROUND_TOWARD_POSITIVE: + SETRM(_MM_ROUND_UP); + break; + case MPF_ROUND_TOWARD_NEGATIVE: + SETRM(_MM_ROUND_DOWN); + break; + case MPF_ROUND_TOWARD_ZERO: + SETRM(_MM_ROUND_TOWARD_ZERO); + break; + case MPF_ROUND_NEAREST_TAWAY: + default: + UNREACHABLE(); // Note: MPF_ROUND_NEAREST_TAWAY is not supported by the hardware! + } +#else + switch (rm) { + case MPF_ROUND_NEAREST_TEVEN: SETRM(_RC_NEAR); break; case MPF_ROUND_TOWARD_POSITIVE: @@ -626,6 +645,7 @@ void hwf_manager::set_rounding_mode(mpf_rounding_mode rm) default: UNREACHABLE(); // Note: MPF_ROUND_NEAREST_TAWAY is not supported by the hardware! } +#endif #else // OSX/Linux switch (rm) { case MPF_ROUND_NEAREST_TEVEN: diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 6c542f1af..9618ffbce 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -520,9 +520,8 @@ void mpf_manager::add_sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mp } } else if (is_zero(x) && is_zero(y)) { - if (sgn(x) && sgn_y) - set(o, x); - else if (rm == MPF_ROUND_TOWARD_NEGATIVE) + if ((x.sign && sgn_y) || + ((rm == MPF_ROUND_TOWARD_NEGATIVE) && (x.sign != sgn_y))) mk_nzero(x.ebits, x.sbits, o); else mk_pzero(x.ebits, x.sbits, o); @@ -627,29 +626,28 @@ void mpf_manager::mul(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & if (is_zero(y)) mk_nan(x.ebits, x.sbits, o); else - mk_inf(x.ebits, x.sbits, sgn(y), o); + mk_inf(x.ebits, x.sbits, y.sign, o); } else if (is_pinf(y)) { if (is_zero(x)) mk_nan(x.ebits, x.sbits, o); else - mk_inf(x.ebits, x.sbits, sgn(x), o); + mk_inf(x.ebits, x.sbits, x.sign, o); } else if (is_ninf(x)) { if (is_zero(y)) mk_nan(x.ebits, x.sbits, o); else - mk_inf(x.ebits, x.sbits, !sgn(y), o); + mk_inf(x.ebits, x.sbits, !y.sign, o); } else if (is_ninf(y)) { if (is_zero(x)) mk_nan(x.ebits, x.sbits, o); else - mk_inf(x.ebits, x.sbits, !sgn(x), o); + mk_inf(x.ebits, x.sbits, !x.sign, o); } else if (is_zero(x) || is_zero(y)) { - set(o, x); - o.sign = x.sign ^ y.sign; + mk_zero(x.ebits, x.sbits, x.sign != y.sign, o); } else { o.ebits = x.ebits; @@ -699,31 +697,35 @@ void mpf_manager::div(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & if (is_inf(y)) mk_nan(x.ebits, x.sbits, o); else - mk_inf(x.ebits, x.sbits, sgn(y), o); + mk_inf(x.ebits, x.sbits, y.sign, o); } else if (is_pinf(y)) { if (is_inf(x)) mk_nan(x.ebits, x.sbits, o); else - mk_zero(x.ebits, x.sbits, (x.sign ^ y.sign) == 1, o); + mk_zero(x.ebits, x.sbits, x.sign != y.sign, o); } else if (is_ninf(x)) { if (is_inf(y)) mk_nan(x.ebits, x.sbits, o); else - mk_inf(x.ebits, x.sbits, !sgn(y), o); + mk_inf(x.ebits, x.sbits, !y.sign, o); } else if (is_ninf(y)) { if (is_inf(x)) mk_nan(x.ebits, x.sbits, o); else - mk_zero(x.ebits, x.sbits, (x.sign ^ y.sign) == 1, o); + mk_zero(x.ebits, x.sbits, x.sign != y.sign, o); } else if (is_zero(y)) { if (is_zero(x)) mk_nan(x.ebits, x.sbits, o); else - mk_inf(x.ebits, x.sbits, sgn(x), o); + mk_inf(x.ebits, x.sbits, x.sign != y.sign, o); + } + else if (is_zero(x)) { + // Special case to avoid problems with unpacking of zeros. + mk_zero(x.ebits, x.sbits, x.sign != y.sign, o); } else { o.ebits = x.ebits; @@ -837,6 +839,10 @@ void mpf_manager::sqrt(mpf_rounding_mode rm, mpf const & x, mpf & o) { else mk_nzero(x.ebits, x.sbits, o); } + else if (is_pzero(x)) + mk_pzero(x.ebits, x.sbits, o); + else if (is_nzero(x)) + mk_nzero(x.ebits, x.sbits, o); else { o.ebits = x.ebits; o.sbits = x.sbits; @@ -933,7 +939,7 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { else if (is_inf(y)) set(o, x); else if (is_zero(x)) - set(o, x); + mk_pzero(x.ebits, x.sbits, o); else if (is_zero(y)) mk_nan(x.ebits, x.sbits, o); else { @@ -982,9 +988,9 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { void mpf_manager::maximum(mpf const & x, mpf const & y, mpf & o) { if (is_nan(x)) set(o, y); - else if (is_nan(y) || (sgn(y) && is_zero(x) && is_zero(y))) - set(o, x); - else if (gt(x, y)) + else if (is_nan(y)) + set(o, x); + else if (gt(x, y) || (is_zero(x) && is_nzero(y))) set(o, x); else set(o, y); @@ -993,9 +999,9 @@ void mpf_manager::maximum(mpf const & x, mpf const & y, mpf & o) { void mpf_manager::minimum(mpf const & x, mpf const & y, mpf & o) { if (is_nan(x)) set(o, y); - else if (is_nan(y) || (sgn(x) && is_zero(x) && is_zero(y))) + else if (is_nan(y)) set(o, x); - else if (lt(x, y)) + else if (lt(x, y) || (is_nzero(x) && is_zero(y))) set(o, x); else set(o, y); From 6c3e2e67643757811b7123e87d7dad04902689be Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Mar 2013 21:03:08 -0800 Subject: [PATCH 19/97] add default simplifications as tactic Signed-off-by: Nikolaj Bjorner --- src/muz_qe/hilbert_basis.cpp | 7 +-- src/muz_qe/horn_tactic.cpp | 85 ++++++++++++++++++++++++++++++++---- src/muz_qe/horn_tactic.h | 5 +++ 3 files changed, 86 insertions(+), 11 deletions(-) diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index c1d941c1c..e7c7928a3 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -23,8 +23,6 @@ Revision History: #include "heap_trie.h" #include "stopwatch.h" -template -class rational_map : public map {}; typedef int_hashtable > int_table; @@ -264,7 +262,10 @@ class hilbert_basis::index { void reset() { memset(this, 0, sizeof(*this)); } }; - typedef rational_map value_map; + template + class numeral_map : public map {}; + + typedef numeral_map value_map; hilbert_basis& hb; value_map m_neg; value_index m_pos; diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index 0637148d6..a8ace78aa 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -21,15 +21,18 @@ Revision History: #include"proof_converter.h" #include"horn_tactic.h" #include"dl_context.h" +#include"expr_replacer.h" class horn_tactic : public tactic { struct imp { ast_manager& m; + bool m_is_simplify; datalog::context m_ctx; smt_params m_fparams; - imp(ast_manager & m, params_ref const & p): + imp(bool is_simplify, ast_manager & m, params_ref const & p): m(m), + m_is_simplify(is_simplify), m_ctx(m, m_fparams) { updt_params(p); } @@ -180,6 +183,9 @@ class horn_tactic : public tactic { expr_ref_vector queries(m); std::stringstream msg; + m_ctx.reset(); + m_ctx.ensure_opened(); + for (unsigned i = 0; i < sz; i++) { f = g->form(i); formula_kind k = get_formula_kind(f); @@ -196,7 +202,7 @@ class horn_tactic : public tactic { } } - if (queries.size() != 1) { + if (queries.size() != 1 || m_is_simplify) { q = m.mk_fresh_const("query", m.mk_bool_sort()); register_predicate(q); for (unsigned i = 0; i < queries.size(); ++i) { @@ -208,8 +214,26 @@ class horn_tactic : public tactic { } SASSERT(queries.size() == 1); q = queries[0].get(); + if (m_is_simplify) { + simplify(q, g, result, mc, pc); + } + else { + verify(q, g, result, mc, pc); + } + } + + void verify(expr* q, + goal_ref const& g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc) { + lbool is_reachable = m_ctx.query(q); g->inc_depth(); + + bool produce_models = g->models_enabled(); + bool produce_proofs = g->proofs_enabled(); + result.push_back(g.get()); switch (is_reachable) { case l_true: { @@ -237,19 +261,60 @@ class horn_tactic : public tactic { TRACE("horn", g->display(tout);); SASSERT(g->is_well_sorted()); } + + void simplify(expr* q, + goal_ref const& g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc) { + + expr_ref fml(m); + bool produce_models = g->models_enabled(); + bool produce_proofs = g->proofs_enabled(); + + if (produce_models) { + mc = datalog::mk_skip_model_converter(); + } + if (produce_proofs) { + pc = datalog::mk_skip_proof_converter(); + } + + func_decl* query_pred = to_app(q)->get_decl(); + m_ctx.set_output_predicate(query_pred); + m_ctx.get_rules(); // flush adding rules. + m_ctx.apply_default_transformation(mc, pc); + + expr_substitution sub(m); + sub.insert(q, m.mk_false()); + scoped_ptr rep = mk_default_expr_replacer(m); + g->inc_depth(); + g->reset(); + result.push_back(g.get()); + datalog::rule_set const& rules = m_ctx.get_rules(); + datalog::rule_set::iterator it = rules.begin(), end = rules.end(); + for (; it != end; ++it) { + datalog::rule* r = *it; + r->to_formula(fml); + (*rep)(fml); + g->assert_expr(fml); + } + } + }; - + + bool m_is_simplify; params_ref m_params; statistics m_stats; imp * m_imp; public: - horn_tactic(ast_manager & m, params_ref const & p): + horn_tactic(bool is_simplify, ast_manager & m, params_ref const & p): + m_is_simplify(is_simplify), m_params(p) { - m_imp = alloc(imp, m, p); + m_imp = alloc(imp, is_simplify, m, p); } virtual tactic * translate(ast_manager & m) { - return alloc(horn_tactic, m, m_params); + return alloc(horn_tactic, m_is_simplify, m, m_params); } virtual ~horn_tactic() { @@ -293,7 +358,7 @@ public: m_imp = 0; } dealloc(d); - d = alloc(imp, m, m_params); + d = alloc(imp, m_is_simplify, m, m_params); #pragma omp critical (tactic_cancel) { m_imp = d; @@ -308,6 +373,10 @@ protected: }; tactic * mk_horn_tactic(ast_manager & m, params_ref const & p) { - return clean(alloc(horn_tactic, m, p)); + return clean(alloc(horn_tactic, false, m, p)); +} + +tactic * mk_horn_simplify_tactic(ast_manager & m, params_ref const & p) { + return clean(alloc(horn_tactic, true, m, p)); } diff --git a/src/muz_qe/horn_tactic.h b/src/muz_qe/horn_tactic.h index 7f56a77ba..f041321ea 100644 --- a/src/muz_qe/horn_tactic.h +++ b/src/muz_qe/horn_tactic.h @@ -27,4 +27,9 @@ tactic * mk_horn_tactic(ast_manager & m, params_ref const & p = params_ref()); /* ADD_TACTIC("horn", "apply tactic for horn clauses.", "mk_horn_tactic(m, p)") */ + +tactic * mk_horn_simplify_tactic(ast_manager & m, params_ref const & p = params_ref()); +/* + ADD_TACTIC("horn-simplify", "simplify horn clauses.", "mk_horn_simplify_tactic(m, p)") +*/ #endif From 352912c6b55448e348e97f9a69c27df580a65455 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Mar 2013 21:06:13 -0800 Subject: [PATCH 20/97] add default simplifications as tactic Signed-off-by: Nikolaj Bjorner --- src/muz_qe/horn_tactic.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index a8ace78aa..cd03e522e 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -287,6 +287,7 @@ class horn_tactic : public tactic { expr_substitution sub(m); sub.insert(q, m.mk_false()); scoped_ptr rep = mk_default_expr_replacer(m); + rep->set_substitution(&sub); g->inc_depth(); g->reset(); result.push_back(g.get()); From 523dc0fb36e6c52f4118641bfb1598b9f7e25229 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Mar 2013 21:24:21 -0800 Subject: [PATCH 21/97] add slicing Signed-off-by: Nikolaj Bjorner --- src/muz_qe/horn_tactic.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index cd03e522e..c22474a7c 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -22,6 +22,8 @@ Revision History: #include"horn_tactic.h" #include"dl_context.h" #include"expr_replacer.h" +#include"dl_rule_transformer.h" +#include"dl_mk_slice.h" class horn_tactic : public tactic { struct imp { @@ -30,9 +32,9 @@ class horn_tactic : public tactic { datalog::context m_ctx; smt_params m_fparams; - imp(bool is_simplify, ast_manager & m, params_ref const & p): + imp(bool t, ast_manager & m, params_ref const & p): m(m), - m_is_simplify(is_simplify), + m_is_simplify(t), m_ctx(m, m_fparams) { updt_params(p); } @@ -283,6 +285,13 @@ class horn_tactic : public tactic { m_ctx.set_output_predicate(query_pred); m_ctx.get_rules(); // flush adding rules. m_ctx.apply_default_transformation(mc, pc); + + if (m_ctx.get_params().slice()) { + datalog::rule_transformer transformer(m_ctx); + datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); + transformer.register_plugin(slice); + m_ctx.transform_rules(transformer, mc, pc); + } expr_substitution sub(m); sub.insert(q, m.mk_false()); @@ -308,10 +317,10 @@ class horn_tactic : public tactic { statistics m_stats; imp * m_imp; public: - horn_tactic(bool is_simplify, ast_manager & m, params_ref const & p): - m_is_simplify(is_simplify), + horn_tactic(bool t, ast_manager & m, params_ref const & p): + m_is_simplify(t), m_params(p) { - m_imp = alloc(imp, is_simplify, m, p); + m_imp = alloc(imp, t, m, p); } virtual tactic * translate(ast_manager & m) { From 197b2e8ddb9186693057eb6d6bc5e7e707b4f61e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Mar 2013 13:55:41 -0800 Subject: [PATCH 22/97] fix bugs reported by Arie Gurfinkel Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_context.cpp | 142 ++++++++++++++++++++++++++----------- src/muz_qe/pdr_context.h | 4 +- 2 files changed, 103 insertions(+), 43 deletions(-) diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 73bffd4e4..7df4a2b64 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -410,6 +410,15 @@ namespace pdr { add_property(result, level); } + void pred_transformer::propagate_to_infinity(unsigned invariant_level) { + expr_ref inv = get_formulas(invariant_level, false); + add_property(inv, infty_level); + // cleanup + for (unsigned i = invariant_level; i < m_levels.size(); ++i) { + m_levels[i].reset(); + } + } + lbool pred_transformer::is_reachable(model_node& n, expr_ref_vector* core, bool& uses_level) { TRACE("pdr", tout << "is-reachable: " << head()->get_name() << " level: " << n.level() << "\n"; @@ -723,26 +732,6 @@ namespace pdr { m_closed = true; } - expr_ref model_node::get_trace() const { - pred_transformer& p = pt(); - ast_manager& m = p.get_manager(); - manager& pm = p.get_pdr_manager(); - TRACE("pdr", model_smt2_pp(tout, m, get_model(), 0);); - func_decl* f = p.head(); - unsigned arity = f->get_arity(); - model_ref model = get_model_ptr(); - expr_ref_vector args(m); - expr_ref v(m); - model_evaluator mev(m); - - for (unsigned i = 0; i < arity; ++i) { - v = m.mk_const(pm.o2n(p.sig(i),0)); - expr_ref e = mev.eval(model, v); - args.push_back(e); - } - return expr_ref(m.mk_app(f, args.size(), args.c_ptr()), m); - } - static bool is_ini(datalog::rule const& r) { return r.get_uninterpreted_tail_size() == 0; } @@ -961,21 +950,80 @@ namespace pdr { return out; } - expr_ref model_search::get_trace() const { + /** + Extract trace comprising of constraints + and predicates that are satisfied from facts to the query. + The resulting trace + */ + + expr_ref model_search::get_trace(context const& ctx) const { pred_transformer& pt = get_root().pt(); ast_manager& m = pt.get_manager(); manager& pm = pt.get_pdr_manager(); - expr_ref result(m.mk_true(),m); - expr_ref_vector rules(m); - ptr_vector nodes; - nodes.push_back(m_root); - while (!nodes.empty()) { - model_node* current = nodes.back(); - nodes.pop_back(); - rules.push_back(current->get_trace()); - nodes.append(current->children()); - } - return pm.mk_and(rules); + datalog::context& dctx = ctx.get_context(); + datalog::rule_manager& rm = dctx.get_rule_manager(); + expr_ref_vector constraints(m), predicates(m); + expr_ref tmp(m); + ptr_vector children; + unsigned deltas[2]; + datalog::rule_ref rule(rm), r0(rm); + model_node* n = m_root; + datalog::var_counter& vc = rm.get_var_counter(); + substitution subst(m); + unifier unif(m); + rule = n->get_rule(); + unsigned max_var = vc.get_max_var(*rule); + predicates.push_back(rule->get_head()); + children.append(n); + bool first = true; + while (!children.empty()) { + SASSERT(children.size() == predicates.size()); + expr_ref_vector binding(m); + n = children.back(); + children.pop_back(); + n->mk_instantiate(r0, rule, binding); + + max_var = std::max(max_var, vc.get_max_var(*rule)); + subst.reset(); + subst.reserve(2, max_var+1); + deltas[0] = 0; + deltas[1] = max_var+1; + + VERIFY(unif(predicates.back(), rule->get_head(), subst)); + for (unsigned i = 0; i < constraints.size(); ++i) { + subst.apply(2, deltas, expr_offset(constraints[i].get(), 0), tmp); + dctx.get_rewriter()(tmp); + constraints[i] = tmp; + } + for (unsigned i = 0; i < predicates.size(); ++i) { + subst.apply(2, deltas, expr_offset(predicates[i].get(), 0), tmp); + predicates[i] = tmp; + } + if (!first) { + constraints.push_back(predicates.back()); + } + first = false; + predicates.pop_back(); + for (unsigned i = 0; i < rule->get_uninterpreted_tail_size(); ++i) { + subst.apply(2, deltas, expr_offset(rule->get_tail(i), 1), tmp); + predicates.push_back(tmp); + } + for (unsigned i = rule->get_uninterpreted_tail_size(); i < rule->get_tail_size(); ++i) { + subst.apply(2, deltas, expr_offset(rule->get_tail(i), 1), tmp); + dctx.get_rewriter()(tmp); + if (!m.is_true(tmp)) { + constraints.push_back(tmp); + } + } + for (unsigned i = 0; i < constraints.size(); ++i) { + max_var = std::max(vc.get_max_var(constraints[i].get()), max_var); + } + for (unsigned i = 0; i < predicates.size(); ++i) { + max_var = std::max(vc.get_max_var(predicates[i].get()), max_var); + } + children.append(n->children()); + } + return pm.mk_and(constraints); } proof_ref model_search::get_proof_trace(context const& ctx) const { @@ -1367,6 +1415,8 @@ namespace pdr { if (!m_params.validate_result()) { return; } + std::stringstream msg; + switch(m_last_result) { case l_true: { proof_ref pr = get_proof(); @@ -1374,7 +1424,8 @@ namespace pdr { expr_ref_vector side_conditions(m); bool ok = checker.check(pr, side_conditions); if (!ok) { - IF_VERBOSE(0, verbose_stream() << "proof validation failed\n";); + msg << "proof validation failed"; + throw default_exception(msg.str()); } for (unsigned i = 0; i < side_conditions.size(); ++i) { expr* cond = side_conditions[i].get(); @@ -1385,9 +1436,8 @@ namespace pdr { solver.assert_expr(tmp); lbool res = solver.check(); if (res != l_false) { - IF_VERBOSE(0, verbose_stream() << "rule validation failed\n"; - verbose_stream() << mk_pp(cond, m) << "\n"; - ); + msg << "rule validation failed when checking: " << mk_pp(cond, m); + throw default_exception(msg.str()); } } break; @@ -1430,14 +1480,15 @@ namespace pdr { names.push_back(symbol(i)); } sorts.reverse(); - tmp = m.mk_exists(sorts.size(), sorts.c_ptr(), names.c_ptr(), tmp); + if (!sorts.empty()) { + tmp = m.mk_exists(sorts.size(), sorts.c_ptr(), names.c_ptr(), tmp); + } smt::kernel solver(m, get_fparams()); solver.assert_expr(tmp); lbool res = solver.check(); if (res != l_false) { - IF_VERBOSE(0, verbose_stream() << "rule validation failed\n"; - verbose_stream() << mk_pp(tmp, m) << "\n"; - ); + msg << "rule validation failed when checking: " << mk_pp(tmp, m); + throw default_exception(msg.str()); } } } @@ -1530,6 +1581,14 @@ namespace pdr { inductive_property ex(m, mc, rs); verbose_stream() << ex.to_string(); }); + + // upgrade invariants that are known to be inductive. + decl2rel::iterator it = m_rels.begin (), end = m_rels.end (); + for (; m_inductive_lvl > 0 && it != end; ++it) { + if (it->m_value->head() != m_query_pred) { + it->m_value->propagate_to_infinity (m_inductive_lvl); + } + } validate(); return l_false; } @@ -1594,7 +1653,7 @@ namespace pdr { proof_ref pr = get_proof(); return expr_ref(pr.get(), m); } - return m_search.get_trace(); + return m_search.get_trace(*this); } expr_ref context::mk_unsat_answer() const { @@ -1939,6 +1998,7 @@ namespace pdr { } st.update("PDR num unfoldings", m_stats.m_num_nodes); st.update("PDR max depth", m_stats.m_max_depth); + st.update("PDR inductive level", m_inductive_lvl); m_pm.collect_statistics(st); for (unsigned i = 0; i < m_core_generalizers.size(); ++i) { diff --git a/src/muz_qe/pdr_context.h b/src/muz_qe/pdr_context.h index 7491327dd..32f13cdd4 100644 --- a/src/muz_qe/pdr_context.h +++ b/src/muz_qe/pdr_context.h @@ -138,6 +138,7 @@ namespace pdr { ptr_vector& get_aux_vars(datalog::rule const& r) { return m_rule2vars.find(&r); } bool propagate_to_next_level(unsigned level); + void propagate_to_infinity(unsigned level); void add_property(expr * lemma, unsigned lvl); // add property 'p' to state at level. lbool is_reachable(model_node& n, expr_ref_vector* core, bool& uses_level); @@ -223,7 +224,6 @@ namespace pdr { void set_rule(datalog::rule const* r) { m_rule = r; } datalog::rule* get_rule(); - expr_ref get_trace() const; void mk_instantiate(datalog::rule_ref& r0, datalog::rule_ref& r1, expr_ref_vector& binding); std::ostream& display(std::ostream& out, unsigned indent); @@ -253,7 +253,7 @@ namespace pdr { void set_root(model_node* n); model_node& get_root() const { return *m_root; } std::ostream& display(std::ostream& out) const; - expr_ref get_trace() const; + expr_ref get_trace(context const& ctx) const; proof_ref get_proof_trace(context const& ctx) const; void backtrack_level(bool uses_level, model_node& n); }; From e5f03f999abb3af7743163975301bbfc9f9b6d34 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 4 Mar 2013 20:21:14 +0000 Subject: [PATCH 23/97] FPA: Added conversion operator float -> float. Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 23 ++-- src/ast/rewriter/float_rewriter.cpp | 23 ++-- src/tactic/fpa/fpa2bv_converter.cpp | 169 ++++++++++++++++++++++++++-- src/util/mpf.cpp | 2 +- 4 files changed, 188 insertions(+), 29 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index f2d6591dc..62ec3a4cf 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -353,27 +353,22 @@ func_decl * float_decl_plugin::mk_to_float(decl_kind k, unsigned num_parameters, sort * fp = mk_float_sort(domain[2]->get_parameter(0).get_int(), domain[1]->get_parameter(0).get_int()+1); symbol name("asFloat"); return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); - } + } else { // .. Otherwise we only know how to convert rationals/reals. if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int())) m_manager->raise_exception("expecting two integer parameters to asFloat"); if (arity != 2 && arity != 3) m_manager->raise_exception("invalid number of arguments to asFloat operator"); - if (!is_rm_sort(domain[0]) || domain[1] != m_real_sort) + if (arity == 3 && domain[2] != m_int_sort) + m_manager->raise_exception("sort mismatch"); + if (!is_rm_sort(domain[0]) || + !(domain[1] == m_real_sort || is_sort_of(domain[1], m_family_id, FLOAT_SORT))) m_manager->raise_exception("sort mismatch"); - if (arity == 2) { - sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int()); - symbol name("asFloat"); - return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); - } - else { - if (domain[2] != m_int_sort) - m_manager->raise_exception("sort mismatch"); - sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int()); - symbol name("asFloat"); - return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); - } + + sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int()); + symbol name("asFloat"); + return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); } } diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index 482e280e3..18fea6c47 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -77,14 +77,23 @@ br_status float_rewriter::mk_to_float(func_decl * f, unsigned num_args, expr * c return BR_FAILED; rational q; - if (!m_util.au().is_numeral(args[1], q)) + mpf q_mpf; + if (m_util.au().is_numeral(args[1], q)) { + mpf v; + m_util.fm().set(v, ebits, sbits, rm, q.to_mpq()); + result = m_util.mk_value(v); + m_util.fm().del(v); + return BR_DONE; + } + else if (m_util.is_value(args[1], q_mpf)) { + mpf v; + m_util.fm().set(v, ebits, sbits, rm, q_mpf); + result = m_util.mk_value(v); + m_util.fm().del(v); + return BR_DONE; + } + else return BR_FAILED; - - mpf v; - m_util.fm().set(v, ebits, sbits, rm, q.to_mpq()); - result = m_util.mk_value(v); - m_util.fm().del(v); - return BR_DONE; } else if (num_args == 3 && m_util.is_rm(m().get_sort(args[0])) && diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 2600cb3ec..37eaa365a 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1403,23 +1403,176 @@ void fpa2bv_converter::mk_is_sign_minus(func_decl * f, unsigned num, expr * cons } void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - if (num == 3 && m_bv_util.is_bv(args[0]) && - m_bv_util.is_bv(args[1]) && m_bv_util.is_bv(args[2])) { + TRACE("fpa2bv_to_float", for (unsigned i=0; i < num; i++) + tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl; ); + + if (num == 3 && + m_bv_util.is_bv(args[0]) && + m_bv_util.is_bv(args[1]) && + m_bv_util.is_bv(args[2])) { // Theoretically, the user could have thrown in it's own triple of bit-vectors. // Just keep it here, as there will be something else that uses it. mk_triple(args[0], args[1], args[2], result); } + else if (num == 2 && is_app(args[1]) && m_util.is_float(m.get_sort(args[1]))) { + // We also support float to float conversion + expr_ref rm(m), x(m); + rm = args[0]; + x = args[1]; + + expr_ref c1(m), c2(m), c3(m), c4(m), c5(m); + expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m); + expr_ref one1(m); + + one1 = m_bv_util.mk_numeral(1, 1); + expr_ref ninf(m), pinf(m); + mk_plus_inf(f, pinf); + mk_minus_inf(f, ninf); + + // NaN -> NaN + mk_is_nan(x, c1); + mk_nan(f, v1); + + // +0 -> +0 + mk_is_pzero(x, c2); + mk_pzero(f, v2); + + // -0 -> -0 + mk_is_nzero(x, c3); + mk_nzero(f, v3); + + // +oo -> +oo + mk_is_pinf(x, c4); + v4 = pinf; + + // -oo -> -oo + mk_is_ninf(x, c5); + v5 = ninf; + + // otherwise: the actual conversion with rounding. + sort * s = f->get_range(); + expr_ref sgn(m), sig(m), exp(m); + unpack(x, sgn, sig, exp, true); + + expr_ref res_sgn(m), res_sig(m), res_exp(m); + + res_sgn = sgn; + + unsigned from_sbits = m_util.get_sbits(m.get_sort(args[1])); + unsigned from_ebits = m_util.get_ebits(m.get_sort(args[1])); + unsigned to_sbits = m_util.get_sbits(s); + unsigned to_ebits = m_util.get_ebits(s); + + SASSERT(m_bv_util.get_bv_size(sgn) == 1); + SASSERT(m_bv_util.get_bv_size(sig) == from_sbits); + SASSERT(m_bv_util.get_bv_size(exp) == from_ebits); + + if (from_sbits < (to_sbits + 3)) + // make sure that sig has at least to_sbits + 3 + res_sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, to_sbits+3-from_sbits)); + else if (from_sbits > (to_sbits + 3)) + { + // collapse the extra bits into a sticky bit. + expr_ref sticky(m), low(m), high(m); + low = m_bv_util.mk_extract(from_sbits - to_sbits - 3, 0, sig); + high = m_bv_util.mk_extract(from_sbits - 1, from_sbits - to_sbits - 2, sig); + unsigned high_sz = m_bv_util.get_bv_size(high); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, low); + res_sig = m_bv_util.mk_concat(high, sticky); + } + else + res_sig = sig; + + res_sig = m_bv_util.mk_zero_extend(1, res_sig); // extra zero in the front for the rounder. + unsigned sig_sz = m_bv_util.get_bv_size(res_sig); + SASSERT(sig_sz == to_sbits+4); + + expr_ref exponent_overflow(m); + exponent_overflow = m.mk_false(); + + if (from_ebits < (to_ebits + 2)) + res_exp = m_bv_util.mk_sign_extend(to_ebits+2-from_ebits, exp); + else if (from_ebits > (to_ebits + 2)) + { + expr_ref high(m), low(m), lows(m), high_red_or(m), high_red_and(m), or_eq(m), not_or_eq(m), and_eq(m); + expr_ref no_ovf(m), zero1(m), s_is_one(m), s_is_zero(m); + high = m_bv_util.mk_extract(from_ebits - 1, to_ebits + 2, exp); + low = m_bv_util.mk_extract(to_ebits+1, 0, exp); + lows = m_bv_util.mk_extract(to_ebits+1, to_ebits+1, low); + + high_red_or = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, high); + high_red_and = m.mk_app(m_bv_util.get_fid(), OP_BREDAND, high); + + zero1 = m_bv_util.mk_numeral(0, 1); + m_simp.mk_eq(high_red_and, one1, and_eq); + m_simp.mk_eq(high_red_or, zero1, or_eq); + m_simp.mk_eq(lows, zero1, s_is_zero); + m_simp.mk_eq(lows, one1, s_is_one); + + expr_ref c2(m); + m_simp.mk_ite(or_eq, s_is_one, m.mk_false(), c2); + m_simp.mk_ite(and_eq, s_is_zero, c2, exponent_overflow); + + // Note: Upon overflow, we _could_ try to shift the significand around... + + res_exp = low; + } + else + res_exp = exp; + + SASSERT(m_bv_util.get_bv_size(res_exp) == to_ebits+2); + + expr_ref rounded(m); + round(s, rm, res_sgn, res_sig, res_exp, rounded); + + expr_ref is_neg(m), sig_inf(m); + m_simp.mk_eq(sgn, one1, is_neg); + mk_ite(is_neg, ninf, pinf, sig_inf); + + dbg_decouple("fpa2bv_to_float_exp_ovf", exponent_overflow); + + mk_ite(exponent_overflow, sig_inf, rounded, v6); + + // And finally, we tie them together. + mk_ite(c5, v5, v6, result); + mk_ite(c4, v4, result, result); + mk_ite(c3, v3, result, result); + mk_ite(c2, v2, result, result); + mk_ite(c1, v1, result, result); + } else { + // .. other than that, we only support rationals for asFloat SASSERT(num == 2); SASSERT(m_util.is_float(f->get_range())); unsigned ebits = m_util.get_ebits(f->get_range()); - unsigned sbits = m_util.get_sbits(f->get_range()); - - SASSERT(m_util.is_rm(to_app(args[0])->get_decl()->get_range())); + unsigned sbits = m_util.get_sbits(f->get_range()); + + //SASSERT(m_bv_util.is_numeral(args[0])); + //rational tmp_rat; unsigned sz; + //m_bv_util.is_numeral(to_expr(args[0]), tmp_rat, sz); + //SASSERT(tmp_rat.is_int32()); + //SASSERT(sz == 3); + //BV_RM_VAL rm = (BV_RM_VAL) tmp_rat.get_unsigned(); + + /*mpf_rounding_mode rm; + switch(bv_rm) + { + case BV_RM_TIES_TO_AWAY: rm = MPF_ROUND_NEAREST_TAWAY; break; + case BV_RM_TIES_TO_EVEN: rm = MPF_ROUND_NEAREST_TEVEN; break; + case BV_RM_TO_NEGATIVE: rm = MPF_ROUND_TOWARD_NEGATIVE; break; + case BV_RM_TO_POSITIVE: rm = MPF_ROUND_TOWARD_POSITIVE; break; + case BV_RM_TO_ZERO: rm = MPF_ROUND_TOWARD_ZERO; break; + default: UNREACHABLE(); + }*/ + + SASSERT(m_util.au().is_numeral(args[1])); + + sort * rm_rng = to_app(args[0])->get_decl()->get_range(); + SASSERT(m_util.is_rm(rm_rng)); mpf_rounding_mode rm = static_cast(to_app(args[1])->get_decl_kind()); - + rational q; - SASSERT(m_util.au().is_numeral(args[1])); + SASSERT(m_util.au().is_numeral(args[1])); m_util.au().is_numeral(args[1], q); mpf v; @@ -1433,6 +1586,8 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a m_util.fm().del(v); } + + SASSERT(is_well_sorted(m, result)); } void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 9618ffbce..dfac97626 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -367,7 +367,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode o.ebits = ebits; o.sbits = sbits; - signed ds = sbits - x.sbits; + signed ds = sbits - x.sbits + 4; // plus rounding bits if (ds > 0) { m_mpz_manager.mul2k(o.significand, ds); From 35906889b60753ca34b931c0465607d46d3d1c88 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 5 Mar 2013 13:49:42 +0000 Subject: [PATCH 24/97] FPA: compilation bugfixes Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 37eaa365a..42fdd0a62 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1476,8 +1476,7 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a expr_ref sticky(m), low(m), high(m); low = m_bv_util.mk_extract(from_sbits - to_sbits - 3, 0, sig); high = m_bv_util.mk_extract(from_sbits - 1, from_sbits - to_sbits - 2, sig); - unsigned high_sz = m_bv_util.get_bv_size(high); - sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, low); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, low.get()); res_sig = m_bv_util.mk_concat(high, sticky); } else @@ -1494,24 +1493,24 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a res_exp = m_bv_util.mk_sign_extend(to_ebits+2-from_ebits, exp); else if (from_ebits > (to_ebits + 2)) { - expr_ref high(m), low(m), lows(m), high_red_or(m), high_red_and(m), or_eq(m), not_or_eq(m), and_eq(m); + expr_ref high(m), low(m), lows(m), high_red_or(m), high_red_and(m), h_or_eq(m), h_and_eq(m); expr_ref no_ovf(m), zero1(m), s_is_one(m), s_is_zero(m); high = m_bv_util.mk_extract(from_ebits - 1, to_ebits + 2, exp); low = m_bv_util.mk_extract(to_ebits+1, 0, exp); lows = m_bv_util.mk_extract(to_ebits+1, to_ebits+1, low); - high_red_or = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, high); - high_red_and = m.mk_app(m_bv_util.get_fid(), OP_BREDAND, high); + high_red_or = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, high.get()); + high_red_and = m.mk_app(m_bv_util.get_fid(), OP_BREDAND, high.get()); zero1 = m_bv_util.mk_numeral(0, 1); - m_simp.mk_eq(high_red_and, one1, and_eq); - m_simp.mk_eq(high_red_or, zero1, or_eq); + m_simp.mk_eq(high_red_and, one1, h_and_eq); + m_simp.mk_eq(high_red_or, zero1, h_or_eq); m_simp.mk_eq(lows, zero1, s_is_zero); m_simp.mk_eq(lows, one1, s_is_one); expr_ref c2(m); - m_simp.mk_ite(or_eq, s_is_one, m.mk_false(), c2); - m_simp.mk_ite(and_eq, s_is_zero, c2, exponent_overflow); + m_simp.mk_ite(h_or_eq, s_is_one, m.mk_false(), c2); + m_simp.mk_ite(h_and_eq, s_is_zero, c2, exponent_overflow); // Note: Upon overflow, we _could_ try to shift the significand around... @@ -2416,4 +2415,4 @@ model_converter * mk_fpa2bv_model_converter(ast_manager & m, obj_map const & const2bv, obj_map const & rm_const2bv) { return alloc(fpa2bv_model_converter, m, const2bv, rm_const2bv); -} \ No newline at end of file +} From 9a4331995e1e3b2fe779becfbb9185e3bda113c7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 5 Mar 2013 14:11:50 +0000 Subject: [PATCH 25/97] FPA: bugfix for bitblaster. Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 42fdd0a62..d7d4458f8 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1546,14 +1546,14 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); - //SASSERT(m_bv_util.is_numeral(args[0])); - //rational tmp_rat; unsigned sz; - //m_bv_util.is_numeral(to_expr(args[0]), tmp_rat, sz); - //SASSERT(tmp_rat.is_int32()); - //SASSERT(sz == 3); - //BV_RM_VAL rm = (BV_RM_VAL) tmp_rat.get_unsigned(); + SASSERT(m_bv_util.is_numeral(args[0])); + rational tmp_rat; unsigned sz; + m_bv_util.is_numeral(to_expr(args[0]), tmp_rat, sz); + SASSERT(tmp_rat.is_int32()); + SASSERT(sz == 3); + BV_RM_VAL bv_rm = (BV_RM_VAL) tmp_rat.get_unsigned(); - /*mpf_rounding_mode rm; + mpf_rounding_mode rm; switch(bv_rm) { case BV_RM_TIES_TO_AWAY: rm = MPF_ROUND_NEAREST_TAWAY; break; @@ -1562,14 +1562,10 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a case BV_RM_TO_POSITIVE: rm = MPF_ROUND_TOWARD_POSITIVE; break; case BV_RM_TO_ZERO: rm = MPF_ROUND_TOWARD_ZERO; break; default: UNREACHABLE(); - }*/ + } SASSERT(m_util.au().is_numeral(args[1])); - sort * rm_rng = to_app(args[0])->get_decl()->get_range(); - SASSERT(m_util.is_rm(rm_rng)); - mpf_rounding_mode rm = static_cast(to_app(args[1])->get_decl_kind()); - rational q; SASSERT(m_util.au().is_numeral(args[1])); m_util.au().is_numeral(args[1], q); From bdc675b1dfef87fcffeb7f3e5143128492d3bd89 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Tue, 5 Mar 2013 09:04:03 -0800 Subject: [PATCH 26/97] Fix bug reported at http://stackoverflow.com/questions/15226944/segmentation-fault-in-z3 Signed-off-by: Leonardo de Moura --- RELEASE_NOTES | 2 ++ src/ast/macros/macro_util.cpp | 15 +++++++++++---- src/model/model_v2_pp.cpp | 5 +++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 7aaaf2f8d..643c9b26f 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -63,6 +63,8 @@ Version 4.3.2 - Fixed bug reported at http://z3.codeplex.com/workitem/23 (Thanks to Paul Jackson). +- Fixed bug reported at http://stackoverflow.com/questions/15226944/segmentation-fault-in-z3 (Thanks to Tianhai Liu). + Version 4.3.1 ============= diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index e9b9c831e..bd21aa1ac 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -597,8 +597,9 @@ void hint_to_macro_head(ast_manager & m, app * head, unsigned num_decls, app_ref is_hint_head(head, vars) must also return true */ bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) { - TRACE("macro_util_hint", tout << "is_poly_hint n:\n" << mk_pp(n, m_manager) << "\nhead:\n" << mk_pp(head, m_manager) << "\nexception:\n" - << mk_pp(exception, m_manager) << "\n";); + TRACE("macro_util_hint", tout << "is_poly_hint n:\n" << mk_pp(n, m_manager) << "\nhead:\n" << mk_pp(head, m_manager) << "\nexception:\n"; + if (exception) tout << mk_pp(exception, m_manager); else tout << ""; + tout << "\n";); ptr_buffer vars; if (!is_hint_head(head, vars)) { TRACE("macro_util_hint", tout << "failed because head is not hint head\n";); @@ -792,7 +793,10 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a mk_add(args.size(), args.c_ptr(), m_manager.get_sort(arg), rest); expr_ref def(m_manager); mk_sub(rhs, rest, def); - add_arith_macro_candidate(to_app(arg), num_decls, def, atom, is_ineq, _is_poly_hint, r); + // If is_poly_hint, rhs may contain variables that do not occur in to_app(arg). + // So, we should re-check. + if (!_is_poly_hint || is_poly_hint(def, to_app(arg), 0)) + add_arith_macro_candidate(to_app(arg), num_decls, def, atom, is_ineq, _is_poly_hint, r); } else if (is_times_minus_one(arg, neg_arg) && is_app(neg_arg)) { f = to_app(neg_arg)->get_decl(); @@ -810,7 +814,10 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a mk_add(args.size(), args.c_ptr(), m_manager.get_sort(arg), rest); expr_ref def(m_manager); mk_sub(rest, rhs, def); - add_arith_macro_candidate(to_app(neg_arg), num_decls, def, atom, is_ineq, _is_poly_hint, r); + // If is_poly_hint, rhs may contain variables that do not occur in to_app(neg_arg). + // So, we should re-check. + if (!_is_poly_hint || is_poly_hint(def, to_app(neg_arg), 0)) + add_arith_macro_candidate(to_app(neg_arg), num_decls, def, atom, is_ineq, _is_poly_hint, r); } } } diff --git a/src/model/model_v2_pp.cpp b/src/model/model_v2_pp.cpp index 9073ddece..4600ccc9e 100644 --- a/src/model/model_v2_pp.cpp +++ b/src/model/model_v2_pp.cpp @@ -80,3 +80,8 @@ void model_v2_pp(std::ostream & out, model_core const & md, bool partial) { display_constants(out, md); display_functions(out, md, partial); } + +// debugging support +void pp(model_core const & md) { + model_v2_pp(std::cout, md, false); +} From e5307300de9829dfe3568224d10d05d62bdd6c86 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 6 Mar 2013 15:04:58 +0000 Subject: [PATCH 27/97] FPA: bugfixes in mul() and abs() Signed-off-by: Christoph M. Wintersteiger --- src/ast/rewriter/float_rewriter.cpp | 2 +- src/tactic/fpa/fpa2bv_converter.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index 18fea6c47..10311598b 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -227,7 +227,7 @@ br_status float_rewriter::mk_abs(expr * arg1, expr_ref & result) { return BR_DONE; } sort * s = m().get_sort(arg1); - result = m().mk_ite(m_util.mk_lt(arg1, m_util.mk_pzero(s)), + result = m().mk_ite(m_util.mk_is_sign_minus(arg1), m_util.mk_uminus(arg1), arg1); return BR_REWRITE2; diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index d7d4458f8..79f86ac46 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -610,11 +610,11 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, expr_ref h_p(m), l_p(m), rbits(m); h_p = m_bv_util.mk_extract(2*sbits-1, sbits, product); - l_p = m_bv_util.mk_extract(2*sbits-1, sbits, product); + l_p = m_bv_util.mk_extract(sbits-1, 0, product); if (sbits >= 4) { expr_ref sticky(m); - sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(sbits-4, 0, l_p)); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(sbits-4, 0, l_p)); rbits = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits-1, sbits-3, l_p), sticky); } else @@ -2094,11 +2094,11 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & expr * round_sticky[2] = { round, sticky }; last_or_sticky = m_bv_util.mk_bv_or(2, last_sticky); round_or_sticky = m_bv_util.mk_bv_or(2, round_sticky); - not_round = m_bv_util.mk_bv_not(round); + not_round = m_bv_util.mk_bv_not(round); not_lors = m_bv_util.mk_bv_not(last_or_sticky); not_rors = m_bv_util.mk_bv_not(round_or_sticky); not_sgn = m_bv_util.mk_bv_not(sgn); - expr * round_lors[2] = { not_round, not_lors }; + expr * round_lors[2] = { not_round, not_lors}; expr * pos_args[2] = { sgn, not_rors }; expr * neg_args[2] = { not_sgn, not_rors }; From f9aeeeef367ecafff815c9758e30a50e75c0d24d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Mar 2013 08:29:29 -0800 Subject: [PATCH 28/97] LRA tactic Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_context.cpp | 113 ++++++++++++++++++++----- src/muz_qe/pdr_context.h | 4 +- src/muz_qe/qe_sat_tactic.h | 2 +- src/tactic/smtlogics/quant_tactics.cpp | 8 +- 4 files changed, 99 insertions(+), 28 deletions(-) diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 73bffd4e4..348bf9154 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -723,24 +723,17 @@ namespace pdr { m_closed = true; } - expr_ref model_node::get_trace() const { + expr_ref model_node::get_trace(context const& ctx) { pred_transformer& p = pt(); ast_manager& m = p.get_manager(); - manager& pm = p.get_pdr_manager(); - TRACE("pdr", model_smt2_pp(tout, m, get_model(), 0);); - func_decl* f = p.head(); - unsigned arity = f->get_arity(); - model_ref model = get_model_ptr(); - expr_ref_vector args(m); - expr_ref v(m); - model_evaluator mev(m); - - for (unsigned i = 0; i < arity; ++i) { - v = m.mk_const(pm.o2n(p.sig(i),0)); - expr_ref e = mev.eval(model, v); - args.push_back(e); - } - return expr_ref(m.mk_app(f, args.size(), args.c_ptr()), m); + datalog::context& dctx = ctx.get_context(); + datalog::rule_manager& rm = dctx.get_rule_manager(); + datalog::rule_ref r0(rm), r1(rm); + expr_ref_vector binding(m); + expr_ref fml(m); + mk_instantiate(r0, r1, binding); + r1->to_formula(fml); + return fml; } static bool is_ini(datalog::rule const& r) { @@ -961,21 +954,95 @@ namespace pdr { return out; } - expr_ref model_search::get_trace() const { + expr_ref model_search::get_trace(context const& ctx) const { pred_transformer& pt = get_root().pt(); ast_manager& m = pt.get_manager(); manager& pm = pt.get_pdr_manager(); - expr_ref result(m.mk_true(),m); expr_ref_vector rules(m); - ptr_vector nodes; - nodes.push_back(m_root); + expr_ref_vector binding(m); + ptr_vector todo; + datalog::rule_ref r0(rm), r1(rm), r2(rm); + model_node* n = m_root; + todo.push_back(n); + while (!todo.empty()) { + n = todo.back(); + ptr_vector const& chs = n->children(); + rls.push_back(0); + for (unsigned i = 0; i < chs.size(); ++i) { + todo.push_back(chs[i]); + } + if (!chs.empty()) { + continue; + } + expr_ref fml0(m); + binding.reset(); + n->mk_instantiate(r0, r1, binding); + r0->to_formula(fml0); + datalog::rule_ref reduced_rule(rm), r3(rm); + reduced_rule = rls[0]; + // check if binding is identity. + bool binding_is_id = true; + for (unsigned i = 0; binding_is_id && i < binding.size(); ++i) { + expr* v = binding[i].get(); + binding_is_id = is_var(v) && to_var(v)->get_idx() == i; + } + if (rls.size() > 1 || !binding_is_id) { + expr_ref tmp(m); + vector substs; + svector > positions; + substs.push_back(binding); // TODO base substitution. + for (unsigned i = 1; i < rls.size(); ++i) { + datalog::rule& src = *rls[i]; + bool unified = unifier.unify_rules(*reduced_rule, 0, src); + if (!unified) { + IF_VERBOSE(0, + verbose_stream() << "Could not unify rules: "; + reduced_rule->display(dctx, verbose_stream()); + src.display(dctx, verbose_stream());); + } + expr_ref_vector sub1 = unifier.get_rule_subst(*reduced_rule, true); + TRACE("pdr", + for (unsigned k = 0; k < sub1.size(); ++k) { + tout << mk_pp(sub1[k].get(), m) << " "; + } + tout << "\n"; + ); + + for (unsigned j = 0; j < substs.size(); ++j) { + for (unsigned k = 0; k < substs[j].size(); ++k) { + var_subst(m, false)(substs[j][k].get(), sub1.size(), sub1.c_ptr(), tmp); + substs[j][k] = tmp; + } + while (substs[j].size() < sub1.size()) { + substs[j].push_back(sub1[substs[j].size()].get()); + } + } + + positions.push_back(std::make_pair(i,0)); + substs.push_back(unifier.get_rule_subst(src, false)); + VERIFY(unifier.apply(*reduced_rule.get(), 0, src, r3)); + reduced_rule = r3; + } + + expr_ref fml_concl(m); + reduced_rule->to_formula(fml_concl); + p1 = m.mk_hyper_resolve(pfs.size(), pfs.c_ptr(), fml_concl, positions, substs); + + } + cache.insert(n->state(), p1); + rules.insert(n->state(), reduced_rule); + trail.push_back(p1); + rules_trail.push_back(reduced_rule); + todo.pop_back(); + } + while (!nodes.empty()) { model_node* current = nodes.back(); nodes.pop_back(); - rules.push_back(current->get_trace()); + rules.push_back(current->get_trace(ctx)); nodes.append(current->children()); } - return pm.mk_and(rules); + return expr_ref(m.mk_and(rules.size(), rules.c_ptr()), m); } proof_ref model_search::get_proof_trace(context const& ctx) const { @@ -1594,7 +1661,7 @@ namespace pdr { proof_ref pr = get_proof(); return expr_ref(pr.get(), m); } - return m_search.get_trace(); + return m_search.get_trace(*this); } expr_ref context::mk_unsat_answer() const { diff --git a/src/muz_qe/pdr_context.h b/src/muz_qe/pdr_context.h index 7491327dd..412577fb4 100644 --- a/src/muz_qe/pdr_context.h +++ b/src/muz_qe/pdr_context.h @@ -223,7 +223,7 @@ namespace pdr { void set_rule(datalog::rule const* r) { m_rule = r; } datalog::rule* get_rule(); - expr_ref get_trace() const; + expr_ref get_trace(context const& ctx); void mk_instantiate(datalog::rule_ref& r0, datalog::rule_ref& r1, expr_ref_vector& binding); std::ostream& display(std::ostream& out, unsigned indent); @@ -253,7 +253,7 @@ namespace pdr { void set_root(model_node* n); model_node& get_root() const { return *m_root; } std::ostream& display(std::ostream& out) const; - expr_ref get_trace() const; + expr_ref get_trace(context const& ctx) const; proof_ref get_proof_trace(context const& ctx) const; void backtrack_level(bool uses_level, model_node& n); }; diff --git a/src/muz_qe/qe_sat_tactic.h b/src/muz_qe/qe_sat_tactic.h index c539216be..15228c534 100644 --- a/src/muz_qe/qe_sat_tactic.h +++ b/src/muz_qe/qe_sat_tactic.h @@ -26,7 +26,7 @@ Revision History: namespace qe { - tactic * mk_sat_tactic(ast_manager& m, params_ref const& p); + tactic * mk_sat_tactic(ast_manager& m, params_ref const& p = params_ref()); }; /* diff --git a/src/tactic/smtlogics/quant_tactics.cpp b/src/tactic/smtlogics/quant_tactics.cpp index 85f53eff0..937b0229e 100644 --- a/src/tactic/smtlogics/quant_tactics.cpp +++ b/src/tactic/smtlogics/quant_tactics.cpp @@ -22,6 +22,7 @@ Revision History: #include"solve_eqs_tactic.h" #include"elim_uncnstr_tactic.h" #include"qe_tactic.h" +#include"qe_sat_tactic.h" #include"ctx_simplify_tactic.h" #include"smt_tactic.h" @@ -98,8 +99,11 @@ tactic * mk_aufnira_tactic(ast_manager & m, params_ref const & p) { tactic * mk_lra_tactic(ast_manager & m, params_ref const & p) { tactic * st = and_then(mk_quant_preprocessor(m), - mk_qe_tactic(m), - mk_smt_tactic()); + or_else(try_for(mk_smt_tactic(), 100), + try_for(qe::mk_sat_tactic(m), 1000), + try_for(mk_smt_tactic(), 1000), + and_then(mk_qe_tactic(m), mk_smt_tactic()))); + st->updt_params(p); return st; } From 3810374cdd42b999f96bbe9b69b927baa6c437ab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Mar 2013 15:20:11 -0800 Subject: [PATCH 29/97] LRA Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_context.cpp | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 98f7920ea..30665c6e5 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -732,22 +732,6 @@ namespace pdr { m_closed = true; } -<<<<<<< HEAD - expr_ref model_node::get_trace(context const& ctx) { - pred_transformer& p = pt(); - ast_manager& m = p.get_manager(); - datalog::context& dctx = ctx.get_context(); - datalog::rule_manager& rm = dctx.get_rule_manager(); - datalog::rule_ref r0(rm), r1(rm); - expr_ref_vector binding(m); - expr_ref fml(m); - mk_instantiate(r0, r1, binding); - r1->to_formula(fml); - return fml; - } - -======= ->>>>>>> bdc675b1dfef87fcffeb7f3e5143128492d3bd89 static bool is_ini(datalog::rule const& r) { return r.get_uninterpreted_tail_size() == 0; } From ab73c20757c9f57ea708aabac264f019f1b75725 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 Mar 2013 17:53:18 -0700 Subject: [PATCH 30/97] add Karr linear invariants as transformer Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_context.cpp | 62 +-- src/muz_qe/dl_context.h | 6 +- src/muz_qe/dl_mk_array_blast.h | 2 +- src/muz_qe/dl_mk_karr_invariants.cpp | 612 +++++++++++++++++++++++++++ src/muz_qe/dl_mk_karr_invariants.h | 79 ++++ src/muz_qe/dl_rule.cpp | 9 + src/muz_qe/dl_rule.h | 1 + src/muz_qe/dl_rule_transformer.cpp | 39 +- src/muz_qe/dl_rule_transformer.h | 25 +- src/muz_qe/fixedpoint_params.pyg | 1 + src/muz_qe/hilbert_basis.cpp | 1 + src/muz_qe/pdr_context.cpp | 4 + src/muz_qe/pdr_util.cpp | 43 +- src/muz_qe/pdr_util.h | 2 + 14 files changed, 830 insertions(+), 56 deletions(-) create mode 100644 src/muz_qe/dl_mk_karr_invariants.cpp create mode 100644 src/muz_qe/dl_mk_karr_invariants.h diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 7c9d2c965..53231e7b0 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -45,6 +45,7 @@ Revision History: #include"dl_mk_partial_equiv.h" #include"dl_mk_bit_blast.h" #include"dl_mk_array_blast.h" +#include"dl_mk_karr_invariants.h" #include"datatype_decl_plugin.h" #include"expr_abstract.h" @@ -223,6 +224,7 @@ namespace datalog { m_rewriter(m), m_var_subst(m), m_rule_manager(*this), + m_transf(*this), m_trail(*this), m_pinned(m), m_vars(m), @@ -825,23 +827,23 @@ namespace datalog { } void context::transform_rules(model_converter_ref& mc, proof_converter_ref& pc) { - rule_transformer transf(*this); - transf.register_plugin(alloc(mk_filter_rules,*this)); - transf.register_plugin(alloc(mk_simple_joins,*this)); + m_transf.reset(); + m_transf.register_plugin(alloc(mk_filter_rules,*this)); + m_transf.register_plugin(alloc(mk_simple_joins,*this)); if (unbound_compressor()) { - transf.register_plugin(alloc(mk_unbound_compressor,*this)); + m_transf.register_plugin(alloc(mk_unbound_compressor,*this)); } if (similarity_compressor()) { - transf.register_plugin(alloc(mk_similarity_compressor, *this, + m_transf.register_plugin(alloc(mk_similarity_compressor, *this, similarity_compressor_threshold())); } - transf.register_plugin(alloc(datalog::mk_partial_equivalence_transformer, *this)); + m_transf.register_plugin(alloc(datalog::mk_partial_equivalence_transformer, *this)); - transform_rules(transf, mc, pc); + transform_rules(m_transf, mc, pc); } - + void context::transform_rules(rule_transformer& transf, model_converter_ref& mc, proof_converter_ref& pc) { SASSERT(m_closed); //we must finish adding rules before we start transforming them TRACE("dl", display_rules(tout);); @@ -862,32 +864,33 @@ namespace datalog { void context::apply_default_transformation(model_converter_ref& mc, proof_converter_ref& pc) { ensure_closed(); - datalog::rule_transformer transf(*this); - transf.register_plugin(alloc(datalog::mk_coi_filter, *this)); - transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this)); + m_transf.reset(); + m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this)); + m_transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this)); - transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 35005)); - transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 35000)); - transf.register_plugin(alloc(datalog::mk_coi_filter, *this, 34990)); - transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this, 34980)); + m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 35005)); + m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 35000)); + m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this, 34990)); + m_transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this, 34980)); //and another round of inlining - transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34975)); - transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34970)); - transf.register_plugin(alloc(datalog::mk_coi_filter, *this, 34960)); - transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this, 34950)); + m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34975)); + m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34970)); + m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this, 34960)); + m_transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this, 34950)); - transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34940)); - transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34930)); - transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34920)); - transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34910)); - transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34900)); - transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34890)); - transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880)); + m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34940)); + m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34930)); + m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34920)); + m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34910)); + m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34900)); + m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34890)); + m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880)); - transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); - transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); - transform_rules(transf, mc, pc); + m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); + m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); + m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 36010)); + transform_rules(m_transf, mc, pc); } void context::collect_params(param_descrs& p) { @@ -928,6 +931,7 @@ namespace datalog { void context::cancel() { m_cancel = true; + m_transf.cancel(); if (m_pdr.get()) m_pdr->cancel(); if (m_bmc.get()) m_bmc->cancel(); if (m_rel.get()) m_rel->cancel(); diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index 98380c9c8..b587daf7f 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -45,11 +45,10 @@ Revision History: #include"proof_converter.h" #include"model2expr.h" #include"smt_params.h" +#include"dl_rule_transformer.h" namespace datalog { - class rule_transformer; - enum execution_result { OK, TIMEOUT, @@ -85,6 +84,7 @@ namespace datalog { th_rewriter m_rewriter; var_subst m_var_subst; rule_manager m_rule_manager; + rule_transformer m_transf; trail_stack m_trail; ast_ref_vector m_pinned; @@ -314,7 +314,7 @@ namespace datalog { void ensure_opened(); void transform_rules(model_converter_ref& mc, proof_converter_ref& pc); - void transform_rules(rule_transformer& trans, model_converter_ref& mc, proof_converter_ref& pc); + void transform_rules(rule_transformer& transf, model_converter_ref& mc, proof_converter_ref& pc); void replace_rules(rule_set & rs); void apply_default_transformation(model_converter_ref& mc, proof_converter_ref& pc); diff --git a/src/muz_qe/dl_mk_array_blast.h b/src/muz_qe/dl_mk_array_blast.h index 1618e4fa8..c0bb39da0 100644 --- a/src/muz_qe/dl_mk_array_blast.h +++ b/src/muz_qe/dl_mk_array_blast.h @@ -49,7 +49,7 @@ namespace datalog { public: /** - \brief Create rule transformer that extracts universal quantifiers (over recursive predicates). + \brief Create rule transformer that removes array stores and selects by ackermannization. */ mk_array_blast(context & ctx, unsigned priority); diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp new file mode 100644 index 000000000..4ed959137 --- /dev/null +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -0,0 +1,612 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_karr_invariants.cpp + +Abstract: + + Extract integer linear invariants. + + The linear invariants are extracted according to Karr's method. + A short description is in + Nikolaj Bjørner, Anca Browne and Zohar Manna. Automatic Generation + of Invariants and Intermediate Assertions, in CP 95. + + The algorithm is here adapted to Horn clauses. + The idea is to maintain two data-structures for each recursive relation. + We call them R and RD + - R - set of linear congruences that are true of R. + - RD - the dual basis of of solutions for R. + + RD is updated by accumulating basis vectors for solutions + to R (the homogeneous dual of R) + R is updated from the inhomogeneous dual of RD. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-09 + +Revision History: + +--*/ + +#include"dl_mk_karr_invariants.h" + +namespace datalog { + + mk_karr_invariants::mk_karr_invariants(context & ctx, unsigned priority): + rule_transformer::plugin(priority, false), + m_ctx(ctx), + m(ctx.get_manager()), + rm(ctx.get_rule_manager()), + a(m) { + } + + mk_karr_invariants::~mk_karr_invariants() { + obj_map::iterator it = m_constraints.begin(), end = m_constraints.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + it = m_dual_constraints.begin(); + end = m_dual_constraints.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + } + + mk_karr_invariants::matrix& mk_karr_invariants::matrix::operator=(matrix const& other) { + reset(); + append(other); + return *this; + } + + void mk_karr_invariants::matrix::display(std::ostream& out) const { + for (unsigned i = 0; i < A.size(); ++i) { + for (unsigned j = 0; j < A[i].size(); ++j) { + out << A[i][j] << " "; + } + out << (eq[i]?" = ":" >= ") << -b[i] << "\n"; + } + } + + bool mk_karr_invariants::is_linear(expr* e, vector& row, rational& b, rational const& mul) { + if (!a.is_int(e)) { + return false; + } + if (is_var(e)) { + row[to_var(e)->get_idx()] += mul; + return true; + } + if (!is_app(e)) { + return false; + } + rational n; + if (a.is_numeral(e, n)) { + b += mul*n; + return true; + } + if (a.is_add(e)) { + for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { + if (!is_linear(to_app(e)->get_arg(i), row, b, mul)) { + return false; + } + } + return true; + } + expr* e1, *e2; + if (a.is_sub(e, e1, e2)) { + return is_linear(e1, row, b, mul) && is_linear(e2, row, b, -mul); + } + if (a.is_mul(e, e1, e2) && a.is_numeral(e1, n)) { + return is_linear(e2, row, b, mul*n); + } + if (a.is_mul(e, e1, e2) && a.is_numeral(e2, n)) { + return is_linear(e1, row, b, mul*n); + } + if (a.is_uminus(e, e1)) { + return is_linear(e1, row, b, -mul); + } + return false; + } + + mk_karr_invariants::matrix* mk_karr_invariants::get_constraints(func_decl* p) { + matrix* result = 0; + m_constraints.find(p, result); + return result; + } + + mk_karr_invariants::matrix& mk_karr_invariants::get_dual_constraints(func_decl* p) { + matrix* result = 0; + if (!m_dual_constraints.find(p, result)) { + result = alloc(matrix); + m_dual_constraints.insert(p, result); + } + return *result; + } + + bool mk_karr_invariants::is_eq(expr* e, var*& v, rational& n) { + expr* e1, *e2; + if (!m.is_eq(e, e1, e2)) { + return false; + } + if (!is_var(e1)) { + std::swap(e1, e2); + } + if (!is_var(e1)) { + return false; + } + v = to_var(e1); + if (!a.is_numeral(e2, n)) { + return false; + } + return true; + } + + bool mk_karr_invariants::get_transition_relation(rule const& r, matrix& M) { + unsigned num_vars = rm.get_var_counter().get_max_var(r)+1; + unsigned arity = r.get_decl()->get_arity(); + unsigned num_columns = arity + num_vars; + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + M.reset(); + + for (unsigned i = 0; i < utsz; ++i) { + matrix const* Mp = get_constraints(r.get_decl(i)); + if (!Mp) { + return false; + } + TRACE("dl", Mp->display(tout << "Intersect\n");); + intersect_matrix(r.get_tail(i), *Mp, num_columns, M); + } + + rational one(1), mone(-1); + expr* e1, *e2, *en; + var* v, *w; + rational n1, n2; + expr_ref_vector conjs(m); + for (unsigned i = utsz; i < tsz; ++i) { + conjs.push_back(r.get_tail(i)); + } + datalog::flatten_and(conjs); + + for (unsigned i = 0; i < conjs.size(); ++i) { + expr* e = conjs[i].get(); + rational b(0); + vector row; + row.resize(num_columns, rational(0)); + bool processed = true; + if (m.is_eq(e, e1, e2) && is_linear(e1, row, b, one) && is_linear(e2, row, b, mone)) { + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(true); + } + else if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(false); + } + else if ((a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b + rational(1)); + M.eq.push_back(false); + } + else if (m.is_not(e, en) && (a.is_lt(en, e2, e1) || a.is_gt(en, e1, e2)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(false); + } + else if (m.is_not(e, en) && (a.is_le(en, e2, e1) || a.is_ge(en, e1, e2)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b + rational(1)); + M.eq.push_back(false); + } + else if (m.is_or(e, e1, e2) && is_eq(e1, v, n1) && is_eq(e2, w, n2) && v == w) { + if (n1 > n2) { + std::swap(n1, n2); + } + SASSERT(n1 <= n2); + row[v->get_idx()] = rational(1); + // v - n1 >= 0 + M.A.push_back(row); + M.b.push_back(-n1); + M.eq.push_back(false); + // -v + n2 >= 0 + row[v->get_idx()] = rational(-1); + M.A.push_back(row); + M.b.push_back(n2); + M.eq.push_back(false); + } + else { + processed = false; + } + TRACE("dl", tout << (processed?"+ ":"- ") << mk_pp(e, m) << "\n";); + } + // intersect with the head predicate. + app* head = r.get_head(); + unsigned sz0 = M.A.size(); + for (unsigned i = 0; i < arity; ++i) { + rational n; + expr* arg = head->get_arg(i); + if (!a.is_int(arg)) { + // no-op + } + else if (is_var(arg)) { + vector row; + row.resize(num_columns, rational(0)); + unsigned idx = to_var(arg)->get_idx(); + row[idx] = rational(-1); + row[num_vars + i] = rational(1); + M.A.push_back(row); + M.b.push_back(rational(0)); + M.eq.push_back(true); + } + else if (a.is_numeral(arg, n)) { + vector row; + row.resize(num_columns, rational(0)); + row[num_vars + i] = rational(1); + M.A.push_back(row); + M.b.push_back(-n); + M.eq.push_back(true); + } + else { + UNREACHABLE(); + } + } + if (M.A.size() == sz0) { + return false; + } + + TRACE("dl", M.display(tout << r.get_decl()->get_name() << "\n");); + matrix MD; + dualizeI(MD, M); + M.reset(); + // project for variables in head. + for (unsigned i = 0; i < MD.size(); ++i) { + vector row; + row.append(arity, MD.A[i].c_ptr() + num_vars); + M.A.push_back(row); + M.b.push_back(MD.b[i]); + M.eq.push_back(true); + } + + return true; + } + + void mk_karr_invariants::intersect_matrix(app* p, matrix const& Mp, unsigned num_columns, matrix& M) { + for (unsigned j = 0; j < Mp.size(); ++j) { + rational b = Mp.b[j], n; + vector row; + row.resize(num_columns, rational(0)); + for (unsigned i = 0; i < p->get_num_args(); ++i) { + expr* arg = p->get_arg(i); + if (!a.is_int(arg)) { + // no-op + } + else if (is_var(arg)) { + unsigned idx = to_var(arg)->get_idx(); + row[idx] += Mp.A[j][i]; + } + else if (a.is_numeral(arg, n)) { + b += Mp.A[j][i]*n; + } + else { + UNREACHABLE(); + } + } + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(Mp.eq[j]); + } + } + + // treat src as a homogeneous matrix. + void mk_karr_invariants::dualizeH(matrix& dst, matrix const& src) { + dst.reset(); + if (src.size() == 0) { + return; + } + m_hb.reset(); + for (unsigned i = 0; i < src.size(); ++i) { + vector v(src.A[i]); + v.append(src.b[i]); + if (src.eq[i]) { + m_hb.add_eq(v, rational(0)); + } + else { + m_hb.add_ge(v, rational(0)); + } + } + for (unsigned i = 0; i < 1 + src.A[0].size(); ++i) { + m_hb.set_is_int(i); + } + lbool is_sat = m_hb.saturate(); + TRACE("dl", m_hb.display(tout);); + SASSERT(is_sat == l_true); + unsigned basis_size = m_hb.get_basis_size(); + bool first_initial = true; + for (unsigned i = 0; i < basis_size; ++i) { + bool is_initial; + vector soln; + m_hb.get_basis_solution(i, soln, is_initial); + if (!is_initial) { + dst.b.push_back(soln.back()); + dst.eq.push_back(true); + soln.pop_back(); + dst.A.push_back(soln); + } + } + } + + // treat src as an inhomegeneous matrix. + void mk_karr_invariants::dualizeI(matrix& dst, matrix const& src) { + m_hb.reset(); + for (unsigned i = 0; i < src.size(); ++i) { + if (src.eq[i]) { + m_hb.add_eq(src.A[i], -src.b[i]); + } + else { + m_hb.add_ge(src.A[i], -src.b[i]); + } + } + for (unsigned i = 0; !src.A.empty() && i < src.A[0].size(); ++i) { + m_hb.set_is_int(i); + } + lbool is_sat = m_hb.saturate(); + TRACE("dl", m_hb.display(tout);); + SASSERT(is_sat == l_true); + dst.reset(); + unsigned basis_size = m_hb.get_basis_size(); + bool first_initial = true; + for (unsigned i = 0; i < basis_size; ++i) { + bool is_initial; + vector soln; + m_hb.get_basis_solution(i, soln, is_initial); + if (is_initial && first_initial) { + dst.A.push_back(soln); + dst.b.push_back(rational(1)); + dst.eq.push_back(true); + first_initial = false; + } + else if (!is_initial) { + dst.A.push_back(soln); + dst.b.push_back(rational(0)); + dst.eq.push_back(true); + } + } + } + + void mk_karr_invariants::update_body(rule_set& rules, rule& r){ + func_decl* p = r.get_decl(); + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + app_ref_vector tail(m); + for (unsigned i = 0; i < tsz; ++i) { + tail.push_back(r.get_tail(i)); + } + for (unsigned i = 0; i < utsz; ++i) { + func_decl* q = r.get_decl(i); + matrix* N = get_constraints(q); + if (!N) { + continue; + } + expr_ref zero(m), lhs(m); + zero = a.mk_numeral(rational(0), true); + for (unsigned j = 0; j < N->size(); ++j) { + rational n; + SASSERT(N->A[j].size() == q->get_arity()); + expr_ref_vector sum(m); + for (unsigned k = 0; k < N->A[j].size(); ++k) { + n = N->A[j][k]; + if (!n.is_zero()) { + expr* arg = r.get_tail(i)->get_arg(k); + sum.push_back(a.mk_mul(a.mk_numeral(n, true), arg)); + } + } + n = N->b[j]; + if (!n.is_zero()) { + sum.push_back(a.mk_numeral(n, true)); + } + lhs = a.mk_add(sum.size(), sum.c_ptr()); + if (N->eq[j]) { + tail.push_back(m.mk_eq(lhs, zero)); + } + else { + tail.push_back(a.mk_ge(lhs, zero)); + } + } + } + rule* new_rule = &r; + if (tail.size() != tsz) { + new_rule = rm.mk(r.get_head(), tail.size(), tail.c_ptr(), 0, r.name()); + } + rules.add_rule(new_rule); + } + + class mk_karr_invariants::add_invariant_model_converter : public model_converter { + ast_manager& m; + arith_util a; + func_decl_ref_vector m_funcs; + ptr_vector m_invs; + public: + + add_invariant_model_converter(ast_manager& m): m(m), a(m), m_funcs(m) {} + + virtual ~add_invariant_model_converter() { + for (unsigned i = 0; i < m_invs.size(); ++i) { + dealloc(m_invs[i]); + } + } + + void add(func_decl* p, matrix& M) { + m_funcs.push_back(p); + m_invs.push_back(alloc(matrix, M)); + } + + virtual void operator()(model_ref & mr) { + for (unsigned i = 0; i < m_funcs.size(); ++i) { + func_decl* p = m_funcs[i].get(); + func_interp* f = mr->get_func_interp(p); + expr_ref body(m); + unsigned arity = p->get_arity(); + SASSERT(0 < arity); + if (f) { + matrix const& M = *m_invs[i]; + mk_body(M, body); + SASSERT(f->num_entries() == 0); + if (!f->is_partial()) { + body = m.mk_and(f->get_else(), body); + } + } + else { + f = alloc(func_interp, m, arity); + mr->register_decl(p, f); + body = m.mk_false(); // fragile: assume that relation was pruned by being infeasible. + } + f->set_else(body); + } + } + + virtual model_converter * translate(ast_translation & translator) { + add_invariant_model_converter* mc = alloc(add_invariant_model_converter, m); + for (unsigned i = 0; i < m_funcs.size(); ++i) { + mc->add(translator(m_funcs[i].get()), *m_invs[i]); + } + return mc; + } + + private: + void mk_body(matrix const& M, expr_ref& body) { + expr_ref_vector conj(m); + for (unsigned i = 0; i < M.size(); ++i) { + mk_body(M.A[i], M.b[i], M.eq[i], conj); + } + body = m.mk_and(conj.size(), conj.c_ptr()); + } + + void mk_body(vector const& row, rational const& b, bool is_eq, expr_ref_vector& conj) { + expr_ref_vector sum(m); + expr_ref zero(m), lhs(m); + zero = a.mk_numeral(rational(0), true); + + for (unsigned i = 0; i < row.size(); ++i) { + if (row[i].is_zero()) { + continue; + } + var* var = m.mk_var(i, a.mk_int()); + if (row[i].is_one()) { + sum.push_back(var); + } + else { + sum.push_back(a.mk_mul(a.mk_numeral(row[i], true), var)); + } + } + if (!b.is_zero()) { + sum.push_back(a.mk_numeral(b, true)); + } + lhs = a.mk_add(sum.size(), sum.c_ptr()); + if (is_eq) { + conj.push_back(m.mk_eq(lhs, zero)); + } + else { + conj.push_back(a.mk_ge(lhs, zero)); + } + } + + }; + + void mk_karr_invariants::cancel() { + rule_transformer::plugin::cancel(); + m_hb.set_cancel(true); + } + + rule_set * mk_karr_invariants::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { + if (!m_ctx.get_params().karr()) { + return 0; + } + rule_set::iterator it = source.begin(), end = source.end(); + for (; it != end; ++it) { + rule const& r = **it; + if (r.has_negation()) { + return 0; + } + } + bool change = true, non_empty = false; + while (!m_cancel && change) { + change = false; + it = source.begin(); + for (; it != end; ++it) { + rule const& r = **it; + TRACE("dl", r.display(m_ctx, tout);); + matrix MD, P; + if (!get_transition_relation(r, MD)) { + continue; + } + non_empty = true; + func_decl* p = r.get_decl(); + matrix& ND = get_dual_constraints(p); + matrix* N = get_constraints(p); + ND.append(MD); + dualizeH(P, ND); + + TRACE("dl", + MD.display(tout << "MD\n"); + P.display(tout << "P\n");); + + if (!N) { + change = true; + N = alloc(matrix, P); + m_constraints.insert(p, N); + } + else if (P.size() != N->size()) { + change = true; + *N = P; + } + } + } + + if (!non_empty) { + return 0; + } + + if (m_cancel) { + return 0; + } + + TRACE("dl", + rule_set::decl2rules::iterator git = source.begin_grouped_rules(); + rule_set::decl2rules::iterator gend = source.end_grouped_rules(); + for (; git != gend; ++git) { + func_decl* p = git->m_key; + matrix* M = get_constraints(p); + tout << p->get_name() << "\n"; + if (M) { + M->display(tout); + } + }); + + rule_set* rules = alloc(rule_set, m_ctx); + it = source.begin(); + for (; it != end; ++it) { + update_body(*rules, **it); + } + if (mc) { + add_invariant_model_converter* kmc = alloc(add_invariant_model_converter, m); + rule_set::decl2rules::iterator git = source.begin_grouped_rules(); + rule_set::decl2rules::iterator gend = source.end_grouped_rules(); + for (; git != gend; ++git) { + func_decl* p = git->m_key; + matrix* M = get_constraints(p); + if (M) { + kmc->add(p, *M); + } + } + mc = concat(mc.get(), kmc); + } + TRACE("dl", rules->display(tout);); + return rules; + } + +}; + diff --git a/src/muz_qe/dl_mk_karr_invariants.h b/src/muz_qe/dl_mk_karr_invariants.h new file mode 100644 index 000000000..3b82578a4 --- /dev/null +++ b/src/muz_qe/dl_mk_karr_invariants.h @@ -0,0 +1,79 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_karr_invariants.h + +Abstract: + + Extract integer linear invariants. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-08 + +Revision History: + +--*/ +#ifndef _DL_MK_KARR_INVARIANTS_H_ +#define _DL_MK_KARR_INVARIANTS_H_ + +#include"dl_context.h" +#include"dl_rule_set.h" +#include"dl_rule_transformer.h" +#include"arith_decl_plugin.h" +#include"hilbert_basis.h" + +namespace datalog { + + /** + \brief Rule transformer that strengthens bodies with invariants. + */ + class mk_karr_invariants : public rule_transformer::plugin { + + struct matrix { + vector > A; + vector b; + svector eq; + unsigned size() const { return A.size(); } + void reset() { A.reset(); b.reset(); eq.reset(); } + matrix& operator=(matrix const& other); + void append(matrix const& other) { A.append(other.A); b.append(other.b); eq.append(other.eq); } + void display(std::ostream& out) const; + }; + class add_invariant_model_converter; + + context& m_ctx; + ast_manager& m; + rule_manager& rm; + arith_util a; + obj_map m_constraints; + obj_map m_dual_constraints; + hilbert_basis m_hb; + + bool is_linear(expr* e, vector& row, rational& b, rational const& mul); + bool is_eq(expr* e, var*& v, rational& n); + bool get_transition_relation(rule const& r, matrix& M); + void intersect_matrix(app* p, matrix const& Mp, unsigned num_columns, matrix& M); + matrix* get_constraints(func_decl* p); + matrix& get_dual_constraints(func_decl* p); + void dualizeH(matrix& dst, matrix const& src); + void dualizeI(matrix& dst, matrix const& src); + void update_body(rule_set& rules, rule& r); + + public: + mk_karr_invariants(context & ctx, unsigned priority); + + virtual ~mk_karr_invariants(); + + virtual void cancel(); + + rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + + }; + +}; + +#endif /* _DL_MK_KARR_INVARIANTS_H_ */ + diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index d34f8a67f..3814d0b62 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -927,6 +927,15 @@ namespace datalog { return exist || univ; } + bool rule::has_negation() const { + for (unsigned i = 0; i < get_uninterpreted_tail_size(); ++i) { + if (is_neg_tail(i)) { + return true; + } + } + return false; + } + void rule::get_used_vars(used_vars& used) const { used.process(get_head()); unsigned sz = get_tail_size(); diff --git a/src/muz_qe/dl_rule.h b/src/muz_qe/dl_rule.h index a9e360344..c01b36162 100644 --- a/src/muz_qe/dl_rule.h +++ b/src/muz_qe/dl_rule.h @@ -237,6 +237,7 @@ namespace datalog { bool has_uninterpreted_non_predicates(func_decl*& f) const; void has_quantifiers(bool& existential, bool& universal) const; bool has_quantifiers() const; + bool has_negation() const; /** \brief Store in d the (direct) dependencies of the given rule. diff --git a/src/muz_qe/dl_rule_transformer.cpp b/src/muz_qe/dl_rule_transformer.cpp index 5f52e0a39..a246d9d61 100644 --- a/src/muz_qe/dl_rule_transformer.cpp +++ b/src/muz_qe/dl_rule_transformer.cpp @@ -16,40 +16,55 @@ Author: Revision History: --*/ + #include #include #include"dl_context.h" - #include"dl_rule_transformer.h" namespace datalog { rule_transformer::rule_transformer(context & ctx) - : m_context(ctx), m_rule_manager(m_context.get_rule_manager()), m_dirty(false) { + : m_context(ctx), m_rule_manager(m_context.get_rule_manager()), m_dirty(false), m_cancel(false) { } rule_transformer::~rule_transformer() { - plugin_vector::iterator it=m_plugins.begin(); - plugin_vector::iterator end=m_plugins.end(); + reset(); + } + + void rule_transformer::reset() { + plugin_vector::iterator it = m_plugins.begin(); + plugin_vector::iterator end = m_plugins.end(); for(; it!=end; ++it) { dealloc(*it); } + m_plugins.reset(); + m_dirty = false; + m_cancel = false; + } + + void rule_transformer::cancel() { + m_cancel = true; + plugin_vector::iterator it = m_plugins.begin(); + plugin_vector::iterator end = m_plugins.end(); + for(; it!=end; ++it) { + (*it)->cancel(); + } } struct rule_transformer::plugin_comparator { bool operator()(rule_transformer::plugin * p1, rule_transformer::plugin * p2) { - return p1->get_priority()>p2->get_priority(); + return p1->get_priority() > p2->get_priority(); } }; void rule_transformer::ensure_ordered() { - if (!m_dirty) { - return; + if (m_dirty) { + std::sort(m_plugins.begin(), m_plugins.end(), plugin_comparator()); + m_dirty = false; } - std::sort(m_plugins.begin(), m_plugins.end(), plugin_comparator()); - m_dirty=false; } void rule_transformer::register_plugin(plugin * p) { @@ -67,9 +82,9 @@ namespace datalog { tout<<"init:\n"; rules.display(tout); ); - plugin_vector::iterator it=m_plugins.begin(); - plugin_vector::iterator end=m_plugins.end(); - for(; it!=end; ++it) { + plugin_vector::iterator it = m_plugins.begin(); + plugin_vector::iterator end = m_plugins.end(); + for(; it!=end && !m_cancel; ++it) { plugin & p = **it; rule_set * new_rules = p(rules, mc, pc); diff --git a/src/muz_qe/dl_rule_transformer.h b/src/muz_qe/dl_rule_transformer.h index 1cc41a146..cf1a9be75 100644 --- a/src/muz_qe/dl_rule_transformer.h +++ b/src/muz_qe/dl_rule_transformer.h @@ -28,6 +28,8 @@ Revision History: namespace datalog { + class context; + class rule_transformer { public: class plugin; @@ -37,9 +39,10 @@ namespace datalog { typedef svector plugin_vector; struct plugin_comparator; - context & m_context; - rule_manager & m_rule_manager; - bool m_dirty; + context & m_context; + rule_manager & m_rule_manager; + bool m_dirty; + volatile bool m_cancel; svector m_plugins; void ensure_ordered(); @@ -47,6 +50,13 @@ namespace datalog { rule_transformer(context & ctx); ~rule_transformer(); + + /** + \brief Reset all registered transformers. + */ + void reset(); + + void cancel(); /** \brief Add a plugin for rule transformation. @@ -72,6 +82,8 @@ namespace datalog { void attach(rule_transformer & transformer) { m_transformer = &transformer; } protected: + volatile bool m_cancel; + /** \brief Create a plugin object for rule_transformer. @@ -79,7 +91,8 @@ namespace datalog { (higher priority plugins will be applied first). */ plugin(unsigned priority, bool can_destratify_negation = false) : m_priority(priority), - m_can_destratify_negation(can_destratify_negation), m_transformer(0) {} + m_can_destratify_negation(can_destratify_negation), m_transformer(0), m_cancel(false) {} + public: virtual ~plugin() {} @@ -96,8 +109,10 @@ namespace datalog { model_converter_ref& mc, proof_converter_ref& pc) = 0; + virtual void cancel() { m_cancel = true; } + /** - Removes duplicate tails. + Removes duplicate tails. */ static void remove_duplicate_tails(app_ref_vector& tail, svector& tail_neg); diff --git a/src/muz_qe/fixedpoint_params.pyg b/src/muz_qe/fixedpoint_params.pyg index c2cfadd14..7a3316c56 100644 --- a/src/muz_qe/fixedpoint_params.pyg +++ b/src/muz_qe/fixedpoint_params.pyg @@ -41,6 +41,7 @@ def_module_params('fixedpoint', ('simplify_formulas_pre', BOOL, False, "PDR: simplify derived formulas before inductive propagation"), ('simplify_formulas_post', BOOL, False, "PDR: simplify derived formulas after inductive propagation"), ('slice', BOOL, True, "PDR: simplify clause set using slicing"), + ('karr', BOOL, False, "Add linear invariants to clauses using Karr's method"), ('coalesce_rules', BOOL, False, "BMC: coalesce rules"), ('use_multicore_generalizer', BOOL, False, "PDR: extract multiple cores for blocking states"), ('use_inductive_generalizer', BOOL, True, "PDR: generalize lemmas using induction strengthening"), diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index e7c7928a3..9fbd8cc2e 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -686,6 +686,7 @@ void hilbert_basis::reset() { m_passive2->reset(); m_zero.reset(); m_index->reset(); + m_ints.reset(); m_cancel = false; } diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 30665c6e5..8bdff1800 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -1425,6 +1425,7 @@ namespace pdr { bool ok = checker.check(pr, side_conditions); if (!ok) { msg << "proof validation failed"; + IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); throw default_exception(msg.str()); } for (unsigned i = 0; i < side_conditions.size(); ++i) { @@ -1437,6 +1438,7 @@ namespace pdr { lbool res = solver.check(); if (res != l_false) { msg << "rule validation failed when checking: " << mk_pp(cond, m); + IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); throw default_exception(msg.str()); } } @@ -1488,6 +1490,7 @@ namespace pdr { lbool res = solver.check(); if (res != l_false) { msg << "rule validation failed when checking: " << mk_pp(tmp, m); + IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); throw default_exception(msg.str()); } } @@ -1595,6 +1598,7 @@ namespace pdr { catch (unknown_exception) { return l_undef; } + UNREACHABLE(); return l_undef; } diff --git a/src/muz_qe/pdr_util.cpp b/src/muz_qe/pdr_util.cpp index 1ea705e6e..237cf9415 100644 --- a/src/muz_qe/pdr_util.cpp +++ b/src/muz_qe/pdr_util.cpp @@ -32,7 +32,6 @@ Notes: #include "for_each_expr.h" #include "smt_params.h" #include "model.h" -#include "model_v2_pp.h" #include "ref_vector.h" #include "rewriter.h" #include "rewriter_def.h" @@ -42,6 +41,7 @@ Notes: #include "pdr_util.h" #include "arith_decl_plugin.h" #include "expr_replacer.h" +#include "model_smt2_pp.h" namespace pdr { @@ -510,13 +510,24 @@ namespace pdr { set_x(e); } } + + void model_evaluator::eval_exprs(expr_ref_vector& es) { + model_ref mr(m_model); + for (unsigned j = 0; j < es.size(); ++j) { + if (m_array.is_as_array(es[j].get())) { + es[j] = eval(mr, es[j].get()); + } + } + } bool model_evaluator::extract_array_func_interp(expr* a, vector& stores, expr_ref& else_case) { SASSERT(m_array.is_array(a)); + TRACE("pdr", tout << mk_pp(a, m) << "\n";); while (m_array.is_store(a)) { expr_ref_vector store(m); store.append(to_app(a)->get_num_args()-1, to_app(a)->get_args()+1); + eval_exprs(store); stores.push_back(store); a = to_app(a)->get_arg(0); } @@ -526,7 +537,7 @@ namespace pdr { return true; } - if (m_array.is_as_array(a)) { + while (m_array.is_as_array(a)) { func_decl* f = m_array.get_as_array_func_decl(to_app(a)); func_interp* g = m_model->get_func_interp(f); unsigned sz = g->num_entries(); @@ -538,20 +549,30 @@ namespace pdr { store.push_back(fe->get_result()); for (unsigned j = 0; j < store.size(); ++j) { if (!is_ground(store[j].get())) { + TRACE("pdr", tout << "could not extract array interpretation: " << mk_pp(a, m) << "\n" << mk_pp(store[j].get(), m) << "\n";); return false; } } + eval_exprs(store); stores.push_back(store); } else_case = g->get_else(); if (!else_case) { + TRACE("pdr", tout << "no else case " << mk_pp(a, m) << "\n";); return false; } if (!is_ground(else_case)) { + TRACE("pdr", tout << "non-ground else case " << mk_pp(a, m) << "\n" << mk_pp(else_case, m) << "\n";); return false; } + if (m_array.is_as_array(else_case)) { + model_ref mr(m_model); + else_case = eval(mr, else_case); + } + TRACE("pdr", tout << "else case: " << mk_pp(else_case, m) << "\n";); return true; } + TRACE("pdr", tout << "no translation: " << mk_pp(a, m) << "\n";); return false; } @@ -570,7 +591,8 @@ namespace pdr { } sort* s = m.get_sort(arg1); sort* r = get_array_range(s); - if (!r->is_infinite() && !r->is_very_big()) { + // give up evaluating finite domain/range arrays + if (!r->is_infinite() && !r->is_very_big() && !s->is_infinite() && !s->is_very_big()) { TRACE("pdr", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); set_x(e); return; @@ -591,6 +613,9 @@ namespace pdr { << mk_pp(else1, m) << " " << mk_pp(else2, m) << "\n";); set_false(e); } + else if (m_array.is_array(else1)) { + eval_array_eq(e, else1, else2); + } else { TRACE("pdr", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); set_x(e); @@ -614,18 +639,23 @@ namespace pdr { if (w1 == w2) { continue; } - else if (m.is_value(w1) && m.is_value(w2)) { + if (m.is_value(w1) && m.is_value(w2)) { TRACE("pdr", tout << "Equality evaluation: " << mk_pp(e, m) << "\n"; tout << mk_pp(s1, m) << " |-> " << mk_pp(w1, m) << "\n"; tout << mk_pp(s2, m) << " |-> " << mk_pp(w2, m) << "\n";); set_false(e); - return; + } + else if (m_array.is_array(w1)) { + eval_array_eq(e, w1, w2); + if (is_true(e)) { + continue; + } } else { TRACE("pdr", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); set_x(e); - return; } + return; } set_true(e); } @@ -869,6 +899,7 @@ namespace pdr { } if (is_x(form)) { IF_VERBOSE(0, verbose_stream() << "formula undetermined in model: " << mk_pp(form, m) << "\n";); + TRACE("pdr", model_smt2_pp(tout, m, *m_model, 0);); has_x = true; } } diff --git a/src/muz_qe/pdr_util.h b/src/muz_qe/pdr_util.h index 220e56b3c..ddbf0d122 100644 --- a/src/muz_qe/pdr_util.h +++ b/src/muz_qe/pdr_util.h @@ -104,6 +104,8 @@ namespace pdr { bool check_model(ptr_vector const & formulas); bool extract_array_func_interp(expr* a, vector& stores, expr_ref& else_case); + + void eval_exprs(expr_ref_vector& es); public: model_evaluator(ast_manager& m) : m(m), m_arith(m), m_array(m), m_refs(m) {} From 21f69c2b3abc349f1412dba74c78fecc585a1987 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 12 Mar 2013 12:27:08 +0000 Subject: [PATCH 31/97] Java API build bugfix. Thanks to Fabian Emmes for reporting this. Signed-off-by: Christoph M. Wintersteiger --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 09aada950..06120e2c4 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -281,7 +281,7 @@ def check_java(): print("Finding jni.h...") if JNI_HOME != None: - if not os.path.exists(path.join(JNI_HOME, 'jni.h')): + if not os.path.exists(os.path.join(JNI_HOME, 'jni.h')): raise MKException("Failed to detect jni.h '%s'; the environment variable JNI_HOME is probably set to the wrong path." % os.path.join(JNI_HOME)) else: # Search for jni.h in the library directories... From 39b9da71184ce12c479ed251d683a546834dbc22 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Wed, 13 Mar 2013 19:02:48 -0700 Subject: [PATCH 32/97] Fix bug in smt_model_finder, it was producing the incorrect instantiation set. Signed-off-by: Leonardo de Moura --- src/smt/smt_model_finder.cpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index e69b7a1b6..2716f6ac0 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -1924,7 +1924,8 @@ namespace smt { m_mutil.mk_add(t1, t2, r); } - bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t) const { + bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t, bool & inv) const { + inv = false; // true if invert the sign TRACE("is_var_and_ground", tout << "is_var_and_ground: " << mk_ismt2_pp(lhs, m_manager) << " " << mk_ismt2_pp(rhs, m_manager) << "\n";); if (is_var(lhs) && is_ground(rhs)) { v = to_var(lhs); @@ -1939,7 +1940,6 @@ namespace smt { return true; } else { - bool inv = false; // true if invert the sign expr_ref tmp(m_manager); if (is_var_plus_ground(lhs, inv, v, tmp) && is_ground(rhs)) { if (inv) @@ -1959,6 +1959,11 @@ namespace smt { return false; } + bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t) const { + bool inv; + return is_var_and_ground(lhs, rhs, v, t, inv); + } + bool is_x_eq_t_atom(expr * n, var * & v, expr_ref & t) const { if (!is_app(n)) return false; @@ -2011,22 +2016,28 @@ namespace smt { if (sign) { bool r = is_le_ge(atom) && is_var_and_ground(to_app(atom)->get_arg(0), to_app(atom)->get_arg(1), v, t); CTRACE("is_x_gle_t", r, tout << "is_x_gle_t: " << mk_ismt2_pp(atom, m_manager) << "\n--->\n" - << mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n";); + << mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n"; + tout << "sign: " << sign << "\n";); return r; } else { if (is_le_ge(atom)) { expr_ref tmp(m_manager); - if (is_var_and_ground(to_app(atom)->get_arg(0), to_app(atom)->get_arg(1), v, tmp)) { + bool le = is_le(atom); + bool inv = false; + if (is_var_and_ground(to_app(atom)->get_arg(0), to_app(atom)->get_arg(1), v, tmp, inv)) { + if (inv) + le = !le; sort * s = m_manager.get_sort(tmp); expr_ref one(m_manager); one = mk_one(s); - if (is_le(atom)) + if (le) mk_add(tmp, one, t); else mk_sub(tmp, one, t); TRACE("is_x_gle_t", tout << "is_x_gle_t: " << mk_ismt2_pp(atom, m_manager) << "\n--->\n" - << mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n";); + << mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n"; + tout << "sign: " << sign << "\n";); return true; } } From fed2ad2300ee49e82aa3059ec17557005f2ac022 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Tue, 5 Feb 2013 09:44:41 -0800 Subject: [PATCH 33/97] Fix nontermination bug Signed-off-by: Leonardo de Moura --- src/smt/smt_model_finder.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 2716f6ac0..f3d0ca3bb 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -1535,8 +1535,23 @@ namespace smt { n1->insert_exception(m_t); } - virtual void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) { - // do nothing... + virtual void populate_inst_sets(quantifier * q, auf_solver & slv, context * ctx) { + unsigned num_vars = q->get_num_decls(); + ast_manager & m = ctx->get_manager(); + sort * s = q->get_decl_sort(num_vars - m_var_i - 1); + if (m.is_uninterp(s)) { + // For uninterpreted sorst, we add all terms in the context. + // See Section 4.1 in the paper "Complete Quantifier Instantiation" + node * S_q_i = slv.get_uvar(q, m_var_i); + ptr_vector::const_iterator it = ctx->begin_enodes(); + ptr_vector::const_iterator end = ctx->end_enodes(); + for (; it != end; ++it) { + enode * n = *it; + if (ctx->is_relevant(n) && get_sort(n->get_owner()) == s) { + S_q_i->insert(n->get_owner(), n->get_generation()); + } + } + } } }; From b8598225bf0f261154457f76cdb318024f8a5114 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 18 Mar 2013 09:20:25 -0700 Subject: [PATCH 34/97] fix definition of bit_vector::empty() Signed-off-by: Nuno Lopes --- src/util/bit_vector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index f451ae70f..9560af7e2 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -106,7 +106,7 @@ public: } bool empty() const { - return m_num_bits != 0; + return m_num_bits == 0; } unsigned num_words() const { From d1ffeb36b0b6691f9de65cb2e9367da684734a5c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Mar 2013 21:37:44 -0700 Subject: [PATCH 35/97] fix warning messages for unused variables Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_base.cpp | 73 ++++++++-------------------- src/muz_qe/dl_mk_karr_invariants.cpp | 2 - src/muz_qe/dl_relation_manager.cpp | 15 +++--- src/muz_qe/horn_tactic.cpp | 1 - src/muz_qe/rel_context.cpp | 11 ++--- 5 files changed, 32 insertions(+), 70 deletions(-) diff --git a/src/muz_qe/dl_base.cpp b/src/muz_qe/dl_base.cpp index 89ebc7e4e..dd817754f 100644 --- a/src/muz_qe/dl_base.cpp +++ b/src/muz_qe/dl_base.cpp @@ -325,9 +325,20 @@ namespace datalog { return res; } + /** + \brief Default method for complementation. + + It assumes that the compiler creates only tables with + at most one column (0 or 1 columns). + Complementation of tables with more than one columns + is transformed into a cross product of complements and/or + difference. + + */ table_base * table_base::complement(func_decl* p, const table_element * func_columns) const { const table_signature & sig = get_signature(); SASSERT(sig.functional_columns()==0 || func_columns!=0); + SASSERT(sig.first_functional() <= 1); table_base * res = get_plugin().mk_empty(sig); @@ -335,16 +346,14 @@ namespace datalog { fact.resize(sig.first_functional()); fact.append(sig.functional_columns(), func_columns); - if(sig.first_functional()==0) { - if(empty()) { + if (sig.first_functional() == 0) { + if (empty()) { res->add_fact(fact); } return res; } - if(sig.first_functional()!=1) { //now we support only tables with one non-functional column - NOT_IMPLEMENTED_YET(); - } + VERIFY(sig.first_functional() == 1); uint64 upper_bound = get_signature()[0]; bool empty_table = empty(); @@ -356,51 +365,13 @@ namespace datalog { warning_msg(buffer.str().c_str()); } - for(table_element i=0; iadd_fact(fact); } } return res; -#if 0 - svector var_arg_indexes(arity); - var_arg_indexes.fill(0); - - svector var_arg_domain_sizes = s; - - unsigned var_cnt=var_arg_indexes.size(); - table_fact fact; - fact.resize(arity); - fact.fill(0); - unsigned depth=arity; - - while(true) { - if(depth==arity) { - SASSERT(!res->contains_fact(fact)); - if(empty_table || !contains_fact(fact)) { - res->add_fact(fact); - } - depth--; - } - else if(fact[depth]==s[depth]-1) { - val_indexes[depth]=0; - if(depth==0) { - break; - } - depth--; - } - else { - SASSERT(val_indexes[depth] soln; @@ -378,7 +377,6 @@ namespace datalog { } void mk_karr_invariants::update_body(rule_set& rules, rule& r){ - func_decl* p = r.get_decl(); unsigned utsz = r.get_uninterpreted_tail_size(); unsigned tsz = r.get_tail_size(); app_ref_vector tail(m); diff --git a/src/muz_qe/dl_relation_manager.cpp b/src/muz_qe/dl_relation_manager.cpp index 76d538b08..3407f8fbe 100644 --- a/src/muz_qe/dl_relation_manager.cpp +++ b/src/muz_qe/dl_relation_manager.cpp @@ -243,15 +243,14 @@ namespace datalog { relation_plugin & relation_manager::get_appropriate_plugin(const relation_signature & s) { relation_plugin * res = try_get_appropriate_plugin(s); - if(!res) { + if (!res) { throw default_exception("no suitable plugin found for given relation signature"); - throw 0; } return *res; } table_plugin * relation_manager::try_get_appropriate_plugin(const table_signature & t) { - if(m_favourite_table_plugin && m_favourite_table_plugin->can_handle_signature(t)) { + if (m_favourite_table_plugin && m_favourite_table_plugin->can_handle_signature(t)) { return m_favourite_table_plugin; } table_plugin_vector::iterator tpit = m_table_plugins.begin(); @@ -346,7 +345,7 @@ namespace datalog { return p->mk_empty(s); } - if(mk_empty_table_relation(s, res)) { + if (mk_empty_table_relation(s, res)) { return res; } @@ -884,10 +883,10 @@ namespace datalog { SASSERT(plugin->can_handle_signature(res_sign)); table_base * res = plugin->mk_empty(res_sign); - unsigned t1cols=t1.get_signature().size(); - unsigned t2cols=t2.get_signature().size(); - unsigned t1first_func=t1.get_signature().first_functional(); - unsigned t2first_func=t2.get_signature().first_functional(); + unsigned t1cols = t1.get_signature().size(); + unsigned t2cols = t2.get_signature().size(); + unsigned t1first_func = t1.get_signature().first_functional(); + unsigned t2first_func = t2.get_signature().first_functional(); table_base::iterator els1it = t1.begin(); table_base::iterator els1end = t1.end(); diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index c22474a7c..b588b07ba 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -233,7 +233,6 @@ class horn_tactic : public tactic { lbool is_reachable = m_ctx.query(q); g->inc_depth(); - bool produce_models = g->models_enabled(); bool produce_proofs = g->proofs_enabled(); result.push_back(g.get()); diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 1b4042ab9..00ac51e9f 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -31,9 +31,6 @@ Revision History: #include"dl_sparse_table.h" #include"dl_table.h" #include"dl_table_relation.h" -#ifndef _EXTERNAL_RELEASE -#include"dl_skip_table.h" -#endif namespace datalog { @@ -44,16 +41,16 @@ namespace datalog { m_answer(m), m_cancel(false), m_last_result_relation(0) { + + // register plugins for builtin tables + get_rmanager().register_plugin(alloc(sparse_table_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(hashtable_table_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(bitvector_table_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(equivalence_table_plugin, get_rmanager())); -#ifndef _EXTERNAL_RELEASE - get_rmanager().register_plugin(alloc(skip_table_plugin, get_rmanager())); -#endif - //register plugins for builtin relations + // register plugins for builtin relations get_rmanager().register_plugin(alloc(bound_relation_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(interval_relation_plugin, get_rmanager())); From d4d3ba104eae18e4815bb92fbf1081cbee75d186 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Mar 2013 21:41:00 -0700 Subject: [PATCH 36/97] fix compiler warning for unused variable Signed-off-by: Nikolaj Bjorner --- src/muz_qe/horn_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index b588b07ba..633aeaa81 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -169,7 +169,6 @@ class horn_tactic : public tactic { SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; tactic_report report("horn", *g); - bool produce_models = g->models_enabled(); bool produce_proofs = g->proofs_enabled(); if (produce_proofs) { @@ -233,6 +232,7 @@ class horn_tactic : public tactic { lbool is_reachable = m_ctx.query(q); g->inc_depth(); + bool produce_models = g->models_enabled(); bool produce_proofs = g->proofs_enabled(); result.push_back(g.get()); From 7e9f4e264dbd027e6060ba12834914f2dfd8b0ab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Mar 2013 21:46:42 -0700 Subject: [PATCH 37/97] working on separating horn simplificaiton Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/quant_hoist.cpp | 37 +++- src/ast/rewriter/quant_hoist.h | 8 + src/muz_qe/dl_bmc_engine.cpp | 14 +- src/muz_qe/dl_context.cpp | 14 +- src/muz_qe/dl_context.h | 14 +- src/muz_qe/dl_rule.cpp | 13 +- src/muz_qe/dl_rule.h | 8 + src/muz_qe/dl_util.cpp | 161 +----------------- src/muz_qe/dl_util.h | 76 --------- src/muz_qe/horn_tactic.cpp | 6 +- src/muz_qe/pdr_dl_interface.cpp | 34 ++-- src/muz_qe/rel_context.cpp | 12 +- src/shell/datalog_frontend.cpp | 4 +- src/smt/tactic/ctx_solver_simplify_tactic.cpp | 54 ++++-- 14 files changed, 160 insertions(+), 295 deletions(-) diff --git a/src/ast/rewriter/quant_hoist.cpp b/src/ast/rewriter/quant_hoist.cpp index b64e71866..e4275ab9c 100644 --- a/src/ast/rewriter/quant_hoist.cpp +++ b/src/ast/rewriter/quant_hoist.cpp @@ -25,7 +25,7 @@ Revision History: #include "bool_rewriter.h" #include "var_subst.h" #include "ast_pp.h" - +#include "ast_counter.h" // // Bring quantifiers of common type into prenex form. @@ -215,6 +215,37 @@ private: break; } } + + unsigned pull_quantifier(bool is_forall, expr_ref& fml, svector* names) { + unsigned index = var_counter().get_next_var(fml); + while (is_quantifier(fml) && (is_forall == to_quantifier(fml)->is_forall())) { + quantifier* q = to_quantifier(fml); + index += q->get_num_decls(); + if (names) { + names->append(q->get_num_decls(), q->get_decl_names()); + } + fml = q->get_expr(); + } + if (!has_quantifiers(fml)) { + return index; + } + app_ref_vector vars(m); + pull_quantifier(is_forall, fml, vars); + if (vars.empty()) { + return index; + } + // replace vars by de-bruijn indices + expr_safe_replace rep(m); + for (unsigned i = 0; i < vars.size(); ++i) { + app* v = vars[i].get(); + if (names) { + names->push_back(v->get_decl()->get_name()); + } + rep.insert(v, m.mk_var(index++,m.get_sort(v))); + } + rep(fml); + return index; + } }; quantifier_hoister::quantifier_hoister(ast_manager& m) { @@ -237,3 +268,7 @@ void quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, app_ref_ m_impl->pull_quantifier(is_forall, fml, vars); } +unsigned quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, svector* names) { + return m_impl->pull_quantifier(is_forall, fml, names); +} + diff --git a/src/ast/rewriter/quant_hoist.h b/src/ast/rewriter/quant_hoist.h index 878f7840d..70a79a0e2 100644 --- a/src/ast/rewriter/quant_hoist.h +++ b/src/ast/rewriter/quant_hoist.h @@ -59,6 +59,14 @@ public: The list of variables is empty if there are no top-level universal/existential quantifier. */ void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars); + + /** + \brief Pull top-most universal (is_forall true) or existential (is_forall=false) quantifier up. + Return an expression with de-Bruijn indices and the list of names that were used. + Return index of maximal variable. + */ + + unsigned pull_quantifier(bool is_forall, expr_ref& fml, svector* names); }; #endif diff --git a/src/muz_qe/dl_bmc_engine.cpp b/src/muz_qe/dl_bmc_engine.cpp index 80fcdea4a..a7c1bf7eb 100644 --- a/src/muz_qe/dl_bmc_engine.cpp +++ b/src/muz_qe/dl_bmc_engine.cpp @@ -1413,20 +1413,22 @@ namespace datalog { datalog::rule_set old_rules(m_ctx.get_rules()); datalog::rule_ref_vector query_rules(rule_manager); datalog::rule_ref query_rule(rule_manager); - rule_manager.mk_query(query, m_query_pred, query_rules, query_rule); - m_ctx.add_rules(query_rules); - expr_ref bg_assertion = m_ctx.get_background_assertion(); - model_converter_ref mc = datalog::mk_skip_model_converter(); m_pc = datalog::mk_skip_proof_converter(); + m_ctx.set_model_converter(mc); + m_ctx.set_proof_converter(m_pc); + rule_manager.mk_query(query, m_query_pred, query_rules, query_rule); + m_ctx.add_rules(query_rules); + expr_ref bg_assertion = m_ctx.get_background_assertion(); + m_ctx.set_output_predicate(m_query_pred); - m_ctx.apply_default_transformation(mc, m_pc); + m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); - m_ctx.transform_rules(transformer, mc, m_pc); + m_ctx.transform_rules(transformer); m_query_pred = slice->get_predicate(m_query_pred.get()); m_ctx.set_output_predicate(m_query_pred); } diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 53231e7b0..eb782aac8 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -474,6 +474,8 @@ namespace datalog { void context::flush_add_rules() { datalog::rule_manager& rm = get_rule_manager(); datalog::rule_ref_vector rules(rm); + rm.set_model_converter(m_mc); + rm.set_proof_converter(m_pc); for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { rm.mk_rule(m_rule_fmls[i].get(), rules, m_rule_names[i]); } @@ -826,7 +828,7 @@ namespace datalog { m_closed = false; } - void context::transform_rules(model_converter_ref& mc, proof_converter_ref& pc) { + void context::transform_rules() { m_transf.reset(); m_transf.register_plugin(alloc(mk_filter_rules,*this)); m_transf.register_plugin(alloc(mk_simple_joins,*this)); @@ -841,13 +843,13 @@ namespace datalog { } m_transf.register_plugin(alloc(datalog::mk_partial_equivalence_transformer, *this)); - transform_rules(m_transf, mc, pc); + transform_rules(m_transf); } - void context::transform_rules(rule_transformer& transf, model_converter_ref& mc, proof_converter_ref& pc) { + void context::transform_rules(rule_transformer& transf) { SASSERT(m_closed); //we must finish adding rules before we start transforming them TRACE("dl", display_rules(tout);); - if (transf(m_rule_set, mc, pc)) { + if (transf(m_rule_set, m_mc, m_pc)) { //we have already ensured the negation is stratified and transformations //should not break the stratification m_rule_set.ensure_closed(); @@ -862,7 +864,7 @@ namespace datalog { m_rule_set.add_rules(rs); } - void context::apply_default_transformation(model_converter_ref& mc, proof_converter_ref& pc) { + void context::apply_default_transformation() { ensure_closed(); m_transf.reset(); m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this)); @@ -890,7 +892,7 @@ namespace datalog { m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 36010)); - transform_rules(m_transf, mc, pc); + transform_rules(m_transf); } void context::collect_params(param_descrs& p) { diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index b587daf7f..7ca6b278c 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -85,6 +85,8 @@ namespace datalog { var_subst m_var_subst; rule_manager m_rule_manager; rule_transformer m_transf; + model_converter_ref m_mc; + proof_converter_ref m_pc; trail_stack m_trail; ast_ref_vector m_pinned; @@ -110,6 +112,8 @@ namespace datalog { DL_ENGINE m_engine; volatile bool m_cancel; + + bool is_fact(app * head) const; bool has_sort_domain(relation_sort s) const; sort_domain & get_sort_domain(relation_sort s); @@ -313,11 +317,15 @@ namespace datalog { void reopen(); void ensure_opened(); - void transform_rules(model_converter_ref& mc, proof_converter_ref& pc); - void transform_rules(rule_transformer& transf, model_converter_ref& mc, proof_converter_ref& pc); + void set_model_converter(model_converter_ref& mc) { m_mc = mc; } + void set_proof_converter(proof_converter_ref& pc) { m_pc = pc; } + + void transform_rules(); + void transform_rules(rule_transformer::plugin* plugin); + void transform_rules(rule_transformer& transf); void replace_rules(rule_set & rs); - void apply_default_transformation(model_converter_ref& mc, proof_converter_ref& pc); + void apply_default_transformation(); void collect_params(param_descrs& r); diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index 3814d0b62..0b626d72e 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -56,16 +56,16 @@ namespace datalog { void rule_manager::inc_ref(rule * r) { if (r) { - SASSERT(r->m_ref_cnt!=UINT_MAX); + SASSERT(r->m_ref_cnt != UINT_MAX); r->m_ref_cnt++; } } void rule_manager::dec_ref(rule * r) { if (r) { - SASSERT(r->m_ref_cnt>0); + SASSERT(r->m_ref_cnt > 0); r->m_ref_cnt--; - if (r->m_ref_cnt==0) { + if (r->m_ref_cnt == 0) { r->deallocate(m); } } @@ -103,8 +103,13 @@ namespace datalog { m_memoize_disj.reset(); m_refs.reset(); bind_variables(fml, true, fml1); - remove_labels(fml1); + unsigned num_rules = rules.size(); mk_rule_core(fml1, rules, name); + if (m_pc) { + // big-step proof + // m.mk_cnf_star(fml1, conj, 0, 0); + // + } } // diff --git a/src/muz_qe/dl_rule.h b/src/muz_qe/dl_rule.h index c01b36162..ebd93d090 100644 --- a/src/muz_qe/dl_rule.h +++ b/src/muz_qe/dl_rule.h @@ -24,6 +24,9 @@ Revision History: #include"dl_costs.h" #include"dl_util.h" #include"used_vars.h" +#include"proof_converter.h" +#include"model_converter.h" +#include"ast_counter.h" namespace datalog { @@ -48,12 +51,17 @@ namespace datalog { var_counter m_var_counter; obj_map m_memoize_disj; expr_ref_vector m_refs; + model_converter_ref m_mc; + proof_converter_ref m_pc; // only the context can create a rule_manager friend class context; explicit rule_manager(context& ctx); + void set_model_converter(model_converter_ref& mc) { m_mc = mc; } + void set_proof_converter(proof_converter_ref& pc) { m_pc = pc; } + /** \brief Move functions from predicate tails into the interpreted tail by introducing new variables. */ diff --git a/src/muz_qe/dl_util.cpp b/src/muz_qe/dl_util.cpp index 4a406578c..3b5ca7658 100644 --- a/src/muz_qe/dl_util.cpp +++ b/src/muz_qe/dl_util.cpp @@ -431,166 +431,6 @@ namespace datalog { } } - void counter::update(unsigned el, int delta) { - int & counter = get(el); - SASSERT(!m_stay_non_negative || counter>=0); - SASSERT(!m_stay_non_negative || static_cast(counter)>=-delta); - counter += delta; - } - - int & counter::get(unsigned el) { - return m_data.insert_if_not_there2(el, 0)->get_data().m_value; - } - - counter & counter::count(unsigned sz, const unsigned * els, int delta) { - for(unsigned i=0; im_value>0 ) { - cnt++; - } - } - return cnt; - } - - void counter::collect_positive(idx_set & acc) const { - iterator eit = begin(); - iterator eend = end(); - for(; eit!=eend; ++eit) { - if(eit->m_value>0) { acc.insert(eit->m_key); } - } - } - - bool counter::get_max_positive(unsigned & res) const { - bool found = false; - iterator eit = begin(); - iterator eend = end(); - for(; eit!=eend; ++eit) { - if( eit->m_value>0 && (!found || eit->m_key>res) ) { - found = true; - res = eit->m_key; - } - } - return found; - } - - unsigned counter::get_max_positive() const { - unsigned max_pos; - VERIFY(get_max_positive(max_pos)); - return max_pos; - } - - int counter::get_max_counter_value() const { - int res = 0; - iterator eit = begin(); - iterator eend = end(); - for (; eit!=eend; ++eit) { - if( eit->m_value>res ) { - res = eit->m_value; - } - } - return res; - } - - void var_counter::count_vars(ast_manager & m, const app * pred, int coef) { - unsigned n = pred->get_num_args(); - for (unsigned i = 0; i < n; i++) { - m_sorts.reset(); - ::get_free_vars(pred->get_arg(i), m_sorts); - for (unsigned j = 0; j < m_sorts.size(); ++j) { - if (m_sorts[j]) { - update(j, coef); - } - } - } - } - - void var_counter::count_vars(ast_manager & m, const rule * r, int coef) { - count_vars(m, r->get_head(), 1); - unsigned n = r->get_tail_size(); - for (unsigned i = 0; i < n; i++) { - count_vars(m, r->get_tail(i), coef); - } - } - - unsigned var_counter::get_max_var(bool& has_var) { - has_var = false; - unsigned max_var = 0; - while (!m_todo.empty()) { - expr* e = m_todo.back(); - unsigned scope = m_scopes.back(); - m_todo.pop_back(); - m_scopes.pop_back(); - if (m_visited.is_marked(e)) { - continue; - } - m_visited.mark(e, true); - switch(e->get_kind()) { - case AST_QUANTIFIER: { - quantifier* q = to_quantifier(e); - m_todo.push_back(q->get_expr()); - m_scopes.push_back(scope + q->get_num_decls()); - break; - } - case AST_VAR: { - if (to_var(e)->get_idx() >= scope + max_var) { - has_var = true; - max_var = to_var(e)->get_idx() - scope; - } - break; - } - case AST_APP: { - app* a = to_app(e); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - m_todo.push_back(a->get_arg(i)); - m_scopes.push_back(scope); - } - break; - } - default: - UNREACHABLE(); - break; - } - } - m_visited.reset(); - return max_var; - } - - unsigned var_counter::get_max_var(const rule & r) { - m_todo.push_back(r.get_head()); - m_scopes.push_back(0); - unsigned n = r.get_tail_size(); - bool has_var = false; - for (unsigned i = 0; i < n; i++) { - m_todo.push_back(r.get_tail(i)); - m_scopes.push_back(0); - } - return get_max_var(has_var); - } - - unsigned var_counter::get_max_var(expr* e) { - bool has_var = false; - m_todo.push_back(e); - m_scopes.push_back(0); - return get_max_var(has_var); - } - - unsigned var_counter::get_next_var(expr* e) { - bool has_var = false; - m_todo.push_back(e); - m_scopes.push_back(0); - unsigned mv = get_max_var(has_var); - if (has_var) mv++; - return mv; - } void del_rule(horn_subsume_model_converter* mc, rule& r) { if (mc) { @@ -614,6 +454,7 @@ namespace datalog { } } + void resolve_rule(replace_proof_converter* pc, rule const& r1, rule const& r2, unsigned idx, expr_ref_vector const& s1, expr_ref_vector const& s2, rule const& res) { if (!pc) return; diff --git a/src/muz_qe/dl_util.h b/src/muz_qe/dl_util.h index 69be7e9ac..4314b87f3 100644 --- a/src/muz_qe/dl_util.h +++ b/src/muz_qe/dl_util.h @@ -411,82 +411,6 @@ namespace datalog { } - class counter { - protected: - typedef u_map map_impl; - map_impl m_data; - const bool m_stay_non_negative; - public: - typedef map_impl::iterator iterator; - - counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {} - - iterator begin() const { return m_data.begin(); } - iterator end() const { return m_data.end(); } - - void update(unsigned el, int delta); - int & get(unsigned el); - /** - \brief Increase values of elements in \c els by \c delta. - - The function returns a reference to \c *this to allow for expressions like - counter().count(sz, arr).get_positive_count() - */ - counter & count(unsigned sz, const unsigned * els, int delta = 1); - counter & count(const unsigned_vector & els, int delta = 1) { - return count(els.size(), els.c_ptr(), delta); - } - - void collect_positive(idx_set & acc) const; - unsigned get_positive_count() const; - bool get_max_positive(unsigned & res) const; - unsigned get_max_positive() const; - /** - Since the default counter value of a counter is zero, the result is never negative. - */ - int get_max_counter_value() const; - }; - - class var_counter : public counter { - ptr_vector m_sorts; - expr_fast_mark1 m_visited; - ptr_vector m_todo; - unsigned_vector m_scopes; - unsigned get_max_var(bool & has_var); - - public: - var_counter(bool stay_non_negative = true) : counter(stay_non_negative) {} - void count_vars(ast_manager & m, const app * t, int coef = 1); - void count_vars(ast_manager & m, const rule * r, int coef = 1); - unsigned get_max_var(const rule& r); - unsigned get_max_var(expr* e); - unsigned get_next_var(expr* e); - }; - - class ast_counter { - typedef obj_map map_impl; - map_impl m_data; - bool m_stay_non_negative; - public: - typedef map_impl::iterator iterator; - - ast_counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {} - - iterator begin() const { return m_data.begin(); } - iterator end() const { return m_data.end(); } - - int & get(ast * el) { - return m_data.insert_if_not_there2(el, 0)->get_data().m_value; - } - void update(ast * el, int delta){ - get(el)+=delta; - SASSERT(!m_stay_non_negative || get(el)>=0); - } - - void inc(ast * el) { update(el, 1); } - void dec(ast * el) { update(el, -1); } - }; - void del_rule(horn_subsume_model_converter* mc, rule& r); void resolve_rule(replace_proof_converter* pc, rule const& r1, rule const& r2, unsigned idx, diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index c22474a7c..7596f8915 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -284,13 +284,15 @@ class horn_tactic : public tactic { func_decl* query_pred = to_app(q)->get_decl(); m_ctx.set_output_predicate(query_pred); m_ctx.get_rules(); // flush adding rules. - m_ctx.apply_default_transformation(mc, pc); + m_ctx.set_model_converter(mc); + m_ctx.set_proof_converter(pc); + m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); - m_ctx.transform_rules(transformer, mc, pc); + m_ctx.transform_rules(transformer); } expr_substitution sub(m); diff --git a/src/muz_qe/pdr_dl_interface.cpp b/src/muz_qe/pdr_dl_interface.cpp index 54a40f8b8..3498b7969 100644 --- a/src/muz_qe/pdr_dl_interface.cpp +++ b/src/muz_qe/pdr_dl_interface.cpp @@ -89,12 +89,19 @@ lbool dl_interface::query(expr * query) { func_decl_ref query_pred(m); datalog::rule_ref_vector query_rules(rule_manager); datalog::rule_ref query_rule(rule_manager); + model_converter_ref mc = datalog::mk_skip_model_converter(); + proof_converter_ref pc; + if (m_ctx.get_params().generate_proof_trace()) { + pc = datalog::mk_skip_proof_converter(); + } + m_ctx.set_model_converter(mc); + m_ctx.set_proof_converter(pc); rule_manager.mk_query(query, query_pred, query_rules, query_rule); m_ctx.add_rules(query_rules); expr_ref bg_assertion = m_ctx.get_background_assertion(); check_reset(); - + TRACE("pdr", if (!m.is_true(bg_assertion)) { tout << "axioms:\n"; @@ -105,19 +112,15 @@ lbool dl_interface::query(expr * query) { m_ctx.display_rules(tout); ); - model_converter_ref mc = datalog::mk_skip_model_converter(); - proof_converter_ref pc; - if (m_ctx.get_params().generate_proof_trace()) { - pc = datalog::mk_skip_proof_converter(); - } m_ctx.set_output_predicate(query_pred); - m_ctx.apply_default_transformation(mc, pc); + + m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); - m_ctx.transform_rules(transformer, mc, pc); + m_ctx.transform_rules(transformer); query_pred = slice->get_predicate(query_pred.get()); m_ctx.set_output_predicate(query_pred); @@ -134,22 +137,25 @@ lbool dl_interface::query(expr * query) { if (m_ctx.get_params().unfold_rules() > 0) { unsigned num_unfolds = m_ctx.get_params().unfold_rules(); - datalog::rule_transformer transformer1(m_ctx), transformer2(m_ctx); + datalog::rule_transformer transf1(m_ctx), transf2(m_ctx); + transf1.register_plugin(alloc(datalog::mk_coalesce, m_ctx)); + transf2.register_plugin(alloc(datalog::mk_unfold, m_ctx)); if (m_ctx.get_params().coalesce_rules()) { - transformer1.register_plugin(alloc(datalog::mk_coalesce, m_ctx)); - m_ctx.transform_rules(transformer1, mc, pc); + m_ctx.transform_rules(transf1); } - transformer2.register_plugin(alloc(datalog::mk_unfold, m_ctx)); while (num_unfolds > 0) { - m_ctx.transform_rules(transformer2, mc, pc); + m_ctx.transform_rules(transf2); --num_unfolds; } } // remove universal quantifiers from body. + + + datalog::mk_extract_quantifiers* extract_quantifiers = alloc(datalog::mk_extract_quantifiers, m_ctx); datalog::rule_transformer extract_q_tr(m_ctx); extract_q_tr.register_plugin(extract_quantifiers); - m_ctx.transform_rules(extract_q_tr, mc, pc); + m_ctx.transform_rules(extract_q_tr); IF_VERBOSE(2, m_ctx.display_rules(verbose_stream());); diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 1b4042ab9..bd09e67a6 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -106,9 +106,7 @@ namespace datalog { TRACE("dl", m_context.display(tout);); while (true) { - model_converter_ref mc; // Ignored in Datalog mode - proof_converter_ref pc; // Ignored in Datalog mode - m_context.transform_rules(mc, pc); + m_context.transform_rules(); compiler::compile(m_context, m_context.get_rules(), rules_code, termination_code); TRACE("dl", rules_code.display(*this, tout); ); @@ -266,14 +264,12 @@ namespace datalog { reset_negated_tables(); if (m_context.generate_explanations()) { - model_converter_ref mc; // ignored in Datalog mode - proof_converter_ref pc; // ignored in Datalog mode rule_transformer transformer(m_context); //expl_plugin is deallocated when transformer goes out of scope mk_explanations * expl_plugin = alloc(mk_explanations, m_context, m_context.explanations_on_relation_level()); transformer.register_plugin(expl_plugin); - m_context.transform_rules(transformer, mc, pc); + m_context.transform_rules(transformer); //we will retrieve the predicate with explanations instead of the original query predicate query_pred = expl_plugin->get_e_decl(query_pred); @@ -283,11 +279,9 @@ namespace datalog { } if (m_context.magic_sets_for_queries()) { - model_converter_ref mc; // Ignored in Datalog mode - proof_converter_ref pc; // Ignored in Datalog mode rule_transformer transformer(m_context); transformer.register_plugin(alloc(mk_magic_sets, m_context, qrule.get())); - m_context.transform_rules(transformer, mc, pc); + m_context.transform_rules(transformer); } lbool res = saturate(); diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index 44a9d9b66..07052609e 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -200,9 +200,7 @@ unsigned read_datalog(char const * file) { timeout = UINT_MAX; } do { - model_converter_ref mc; // ignored - proof_converter_ref pc; // ignored - ctx.transform_rules(mc, pc); + ctx.transform_rules(); datalog::compiler::compile(ctx, ctx.get_rules(), rules_code, termination_code); diff --git a/src/smt/tactic/ctx_solver_simplify_tactic.cpp b/src/smt/tactic/ctx_solver_simplify_tactic.cpp index 25c41c2a2..0092cdd38 100644 --- a/src/smt/tactic/ctx_solver_simplify_tactic.cpp +++ b/src/smt/tactic/ctx_solver_simplify_tactic.cpp @@ -92,7 +92,34 @@ protected: ptr_vector fmls; g.get_formulas(fmls); fml = m.mk_and(fmls.size(), fmls.c_ptr()); + m_solver.push(); reduce(fml); + m_solver.pop(1); + SASSERT(m_solver.get_scope_level() == 0); + TRACE("ctx_solver_simplify_tactic", + for (unsigned i = 0; i < fmls.size(); ++i) { + tout << mk_pp(fmls[i], m) << "\n"; + } + tout << "=>\n"; + tout << mk_pp(fml, m) << "\n";); + DEBUG_CODE( + { + m_solver.push(); + expr_ref fml1(m); + fml1 = m.mk_and(fmls.size(), fmls.c_ptr()); + fml1 = m.mk_iff(fml, fml1); + fml1 = m.mk_not(fml1); + m_solver.assert_expr(fml1); + lbool is_sat = m_solver.check(); + TRACE("ctx_solver_simplify_tactic", tout << "is non-equivalence sat?: " << is_sat << "\n";); + if (is_sat != l_false) { + TRACE("ctx_solver_simplify_tactic", + tout << "result is not equivalent to input\n"; + tout << mk_pp(fml1, m) << "\n";); + UNREACHABLE(); + } + m_solver.pop(1); + }); g.reset(); g.assert_expr(fml, 0, 0); IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(ctx-solver-simplify :num-steps " << m_num_steps << ")\n";); @@ -106,21 +133,22 @@ protected: svector is_checked; svector parent_ids, self_ids; expr_ref_vector fresh_vars(m), trail(m); - expr_ref res(m); + expr_ref res(m), tmp(m); obj_map > cache; unsigned id = 1; - expr* n = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); expr* n2, *fml; unsigned path_id = 0, self_pos = 0; app * a; unsigned sz; std::pair path_r; ptr_vector found; + expr* n = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); + trail.push_back(n); fml = result.get(); - m_solver.assert_expr(m.mk_not(m.mk_iff(fml, n))); + tmp = m.mk_not(m.mk_iff(fml, n)); + m_solver.assert_expr(tmp); - trail.push_back(n); todo.push_back(fml); names.push_back(n); is_checked.push_back(false); @@ -144,6 +172,7 @@ protected: goto done; } if (m.is_bool(e) && !checked && simplify_bool(n, res)) { + TRACE("ctx_solver_simplify_tactic", tout << "simplified: " << mk_pp(e, m) << " |-> " << mk_pp(res, m) << "\n";); goto done; } if (!is_app(e)) { @@ -176,7 +205,7 @@ protected: found.push_back(arg); if (path_r.first == self_pos) { - TRACE("ctx_solver_simplify_tactic", tout << "cached " << mk_pp(arg, m) << "\n";); + TRACE("ctx_solver_simplify_tactic", tout << "cached " << mk_pp(arg, m) << " |-> " << mk_pp(path_r.second, m) << "\n";); args.push_back(path_r.second); } else { @@ -188,11 +217,11 @@ protected: } else if (!n2 && !found.contains(arg)) { n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); + trail.push_back(n2); todo.push_back(arg); parent_ids.push_back(self_pos); self_ids.push_back(0); names.push_back(n2); - trail.push_back(n2); args.push_back(n2); is_checked.push_back(false); } @@ -205,7 +234,8 @@ protected: // child needs to be visited. if (n2) { m_solver.push(); - m_solver.assert_expr(m.mk_eq(res, n)); + tmp = m.mk_eq(res, n); + m_solver.assert_expr(tmp); continue; } @@ -229,7 +259,7 @@ protected: } bool simplify_bool(expr* n, expr_ref& res) { - + expr_ref tmp(m); m_solver.push(); m_solver.assert_expr(n); lbool is_sat = m_solver.check(); @@ -240,7 +270,8 @@ protected: } m_solver.push(); - m_solver.assert_expr(m.mk_not(n)); + tmp = m.mk_not(n); + m_solver.assert_expr(tmp); is_sat = m_solver.check(); m_solver.pop(1); if (is_sat == l_false) { @@ -254,7 +285,7 @@ protected: expr_ref local_simplify(app* a, expr* n, unsigned& id, unsigned index) { SASSERT(index < a->get_num_args()); SASSERT(m.is_bool(a->get_arg(index))); - expr_ref n2(m), result(m); + expr_ref n2(m), result(m), tmp(m); n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); ptr_buffer args; for (unsigned i = 0; i < a->get_num_args(); ++i) { @@ -267,7 +298,8 @@ protected: } m_mk_app(a->get_decl(), args.size(), args.c_ptr(), result); m_solver.push(); - m_solver.assert_expr(m.mk_eq(result, n)); + tmp = m.mk_eq(result, n); + m_solver.assert_expr(tmp); if (!simplify_bool(n2, result)) { result = a; } From b0787024c72f8966004df580002ca2e7de8f83b3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Mar 2013 09:47:52 -0700 Subject: [PATCH 38/97] Move ast_counter to location for common utilities. It depends on get_free_vars, so is in rewriter directory Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_compiler.cpp | 4 +- src/muz_qe/dl_mk_explanations.cpp | 4 +- src/muz_qe/dl_mk_interp_tail_simplifier.cpp | 6 +- src/muz_qe/dl_mk_karr_invariants.cpp | 2 +- src/muz_qe/dl_mk_rule_inliner.cpp | 8 +- src/muz_qe/dl_mk_similarity_compressor.cpp | 6 +- src/muz_qe/dl_mk_simple_joins.cpp | 4 +- src/muz_qe/dl_rule.cpp | 2 +- src/muz_qe/dl_rule.h | 4 +- src/muz_qe/dl_util.cpp | 150 +----------------- src/muz_qe/dl_util.h | 84 +--------- src/muz_qe/pdr_context.cpp | 6 +- src/muz_qe/pdr_quantifiers.cpp | 4 +- src/muz_qe/tab_context.cpp | 2 +- src/smt/tactic/ctx_solver_simplify_tactic.cpp | 54 +++++-- 15 files changed, 78 insertions(+), 262 deletions(-) diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index 44a449779..cc56df4b7 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -384,8 +384,8 @@ namespace datalog { void compiler::get_local_indexes_for_projection(rule * r, unsigned_vector & res) { SASSERT(r->get_positive_tail_size()==2); ast_manager & m = m_context.get_manager(); - var_counter counter; - counter.count_vars(m, r); + rule_counter counter; + counter.count_rule_vars(m, r); app * t1 = r->get_tail(0); app * t2 = r->get_tail(1); counter.count_vars(m, t1, -1); diff --git a/src/muz_qe/dl_mk_explanations.cpp b/src/muz_qe/dl_mk_explanations.cpp index b4683bdbe..464ec838e 100644 --- a/src/muz_qe/dl_mk_explanations.cpp +++ b/src/muz_qe/dl_mk_explanations.cpp @@ -708,8 +708,8 @@ namespace datalog { } rule * mk_explanations::get_e_rule(rule * r) { - var_counter ctr; - ctr.count_vars(m_manager, r); + rule_counter ctr; + ctr.count_rule_vars(m_manager, r); unsigned max_var; unsigned next_var = ctr.get_max_positive(max_var) ? (max_var+1) : 0; unsigned head_var = next_var++; diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp index d028c8751..d1b7f15dd 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp @@ -35,7 +35,7 @@ namespace datalog { // ----------------------------------- void mk_interp_tail_simplifier::rule_substitution::reset(rule * r) { - unsigned var_cnt = m_context.get_rule_manager().get_var_counter().get_max_var(*r)+1; + unsigned var_cnt = m_context.get_rule_manager().get_counter().get_max_rule_var(*r)+1; m_subst.reset(); m_subst.reserve(1, var_cnt); m_rule = r; @@ -541,8 +541,8 @@ namespace datalog { rule_ref pro_var_eq_result(m_context.get_rule_manager()); if (propagate_variable_equivalences(res, pro_var_eq_result)) { - SASSERT(var_counter().get_max_var(*r.get())==0 || - var_counter().get_max_var(*r.get()) > var_counter().get_max_var(*pro_var_eq_result.get())); + SASSERT(rule_counter().get_max_rule_var(*r.get())==0 || + rule_counter().get_max_rule_var(*r.get()) > rule_counter().get_max_rule_var(*pro_var_eq_result.get())); r = pro_var_eq_result; goto start; } diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index f690346bc..9c034c890 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -145,7 +145,7 @@ namespace datalog { } bool mk_karr_invariants::get_transition_relation(rule const& r, matrix& M) { - unsigned num_vars = rm.get_var_counter().get_max_var(r)+1; + unsigned num_vars = rm.get_counter().get_max_rule_var(r)+1; unsigned arity = r.get_decl()->get_arity(); unsigned num_columns = arity + num_vars; unsigned utsz = r.get_uninterpreted_tail_size(); diff --git a/src/muz_qe/dl_mk_rule_inliner.cpp b/src/muz_qe/dl_mk_rule_inliner.cpp index 0919e2ff0..1404c9c8c 100644 --- a/src/muz_qe/dl_mk_rule_inliner.cpp +++ b/src/muz_qe/dl_mk_rule_inliner.cpp @@ -65,8 +65,8 @@ namespace datalog { // ----------------------------------- bool rule_unifier::unify_rules(const rule& tgt, unsigned tgt_idx, const rule& src) { - var_counter& vc = m_rm.get_var_counter(); - unsigned var_cnt = std::max(vc.get_max_var(tgt), vc.get_max_var(src))+1; + rule_counter& vc = m_rm.get_counter(); + unsigned var_cnt = std::max(vc.get_max_rule_var(tgt), vc.get_max_rule_var(src))+1; m_subst.reset(); m_subst.reserve(2, var_cnt); @@ -733,7 +733,7 @@ namespace datalog { } // initialize substitution. - var_counter& vc = m_rm.get_var_counter(); + rule_counter& vc = m_rm.get_counter(); unsigned max_var = 0; for (unsigned i = 0; i < sz; ++i) { rule* r = acc[i].get(); @@ -820,7 +820,7 @@ namespace datalog { del_rule(r2, j); } - max_var = std::max(max_var, vc.get_max_var(*r.get())); + max_var = std::max(max_var, vc.get_max_rule_var(*r.get())); m_subst.reserve_vars(max_var+1); } diff --git a/src/muz_qe/dl_mk_similarity_compressor.cpp b/src/muz_qe/dl_mk_similarity_compressor.cpp index 42a5ba367..a040a623a 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.cpp +++ b/src/muz_qe/dl_mk_similarity_compressor.cpp @@ -372,10 +372,10 @@ namespace datalog { new_negs.push_back(r->is_neg_tail(i)); } - var_counter var_ctr; - var_ctr.count_vars(m_manager, r); + rule_counter ctr; + ctr.count_rule_vars(m_manager, r); unsigned max_var_idx, new_var_idx_base; - if(var_ctr.get_max_positive(max_var_idx)) { + if(ctr.get_max_positive(max_var_idx)) { new_var_idx_base = max_var_idx+1; } else { diff --git a/src/muz_qe/dl_mk_simple_joins.cpp b/src/muz_qe/dl_mk_simple_joins.cpp index 363a4f0f7..77c6c2951 100644 --- a/src/muz_qe/dl_mk_simple_joins.cpp +++ b/src/muz_qe/dl_mk_simple_joins.cpp @@ -310,8 +310,8 @@ namespace datalog { } void register_rule(rule * r) { - var_counter counter; - counter.count_vars(m, r, 1); + rule_counter counter; + counter.count_rule_vars(m, r, 1); ptr_vector & rule_content = m_rules_content.insert_if_not_there2(r, ptr_vector())->get_data().m_value; diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index 3814d0b62..de41e4774 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -705,7 +705,7 @@ namespace datalog { bool_rewriter(m).mk_and(tails_with_unbound.size(), tails_with_unbound.c_ptr(), unbound_tail); unsigned q_var_cnt = unbound_vars.num_elems(); - unsigned max_var = m_var_counter.get_max_var(*r); + unsigned max_var = m_counter.get_max_rule_var(*r); expr_ref_vector subst(m); diff --git a/src/muz_qe/dl_rule.h b/src/muz_qe/dl_rule.h index c01b36162..4afc08edb 100644 --- a/src/muz_qe/dl_rule.h +++ b/src/muz_qe/dl_rule.h @@ -45,7 +45,7 @@ namespace datalog { { ast_manager& m; context& m_ctx; - var_counter m_var_counter; + rule_counter m_counter; obj_map m_memoize_disj; expr_ref_vector m_refs; @@ -162,7 +162,7 @@ namespace datalog { static bool is_forall(ast_manager& m, expr* e, quantifier*& q); - var_counter& get_var_counter() { return m_var_counter; } + rule_counter& get_counter() { return m_counter; } }; diff --git a/src/muz_qe/dl_util.cpp b/src/muz_qe/dl_util.cpp index 4a406578c..bde03e765 100644 --- a/src/muz_qe/dl_util.cpp +++ b/src/muz_qe/dl_util.cpp @@ -431,89 +431,8 @@ namespace datalog { } } - void counter::update(unsigned el, int delta) { - int & counter = get(el); - SASSERT(!m_stay_non_negative || counter>=0); - SASSERT(!m_stay_non_negative || static_cast(counter)>=-delta); - counter += delta; - } - - int & counter::get(unsigned el) { - return m_data.insert_if_not_there2(el, 0)->get_data().m_value; - } - - counter & counter::count(unsigned sz, const unsigned * els, int delta) { - for(unsigned i=0; im_value>0 ) { - cnt++; - } - } - return cnt; - } - - void counter::collect_positive(idx_set & acc) const { - iterator eit = begin(); - iterator eend = end(); - for(; eit!=eend; ++eit) { - if(eit->m_value>0) { acc.insert(eit->m_key); } - } - } - - bool counter::get_max_positive(unsigned & res) const { - bool found = false; - iterator eit = begin(); - iterator eend = end(); - for(; eit!=eend; ++eit) { - if( eit->m_value>0 && (!found || eit->m_key>res) ) { - found = true; - res = eit->m_key; - } - } - return found; - } - - unsigned counter::get_max_positive() const { - unsigned max_pos; - VERIFY(get_max_positive(max_pos)); - return max_pos; - } - - int counter::get_max_counter_value() const { - int res = 0; - iterator eit = begin(); - iterator eend = end(); - for (; eit!=eend; ++eit) { - if( eit->m_value>res ) { - res = eit->m_value; - } - } - return res; - } - - void var_counter::count_vars(ast_manager & m, const app * pred, int coef) { - unsigned n = pred->get_num_args(); - for (unsigned i = 0; i < n; i++) { - m_sorts.reset(); - ::get_free_vars(pred->get_arg(i), m_sorts); - for (unsigned j = 0; j < m_sorts.size(); ++j) { - if (m_sorts[j]) { - update(j, coef); - } - } - } - } - - void var_counter::count_vars(ast_manager & m, const rule * r, int coef) { + + void rule_counter::count_rule_vars(ast_manager & m, const rule * r, int coef) { count_vars(m, r->get_head(), 1); unsigned n = r->get_tail_size(); for (unsigned i = 0; i < n; i++) { @@ -521,50 +440,7 @@ namespace datalog { } } - unsigned var_counter::get_max_var(bool& has_var) { - has_var = false; - unsigned max_var = 0; - while (!m_todo.empty()) { - expr* e = m_todo.back(); - unsigned scope = m_scopes.back(); - m_todo.pop_back(); - m_scopes.pop_back(); - if (m_visited.is_marked(e)) { - continue; - } - m_visited.mark(e, true); - switch(e->get_kind()) { - case AST_QUANTIFIER: { - quantifier* q = to_quantifier(e); - m_todo.push_back(q->get_expr()); - m_scopes.push_back(scope + q->get_num_decls()); - break; - } - case AST_VAR: { - if (to_var(e)->get_idx() >= scope + max_var) { - has_var = true; - max_var = to_var(e)->get_idx() - scope; - } - break; - } - case AST_APP: { - app* a = to_app(e); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - m_todo.push_back(a->get_arg(i)); - m_scopes.push_back(scope); - } - break; - } - default: - UNREACHABLE(); - break; - } - } - m_visited.reset(); - return max_var; - } - - unsigned var_counter::get_max_var(const rule & r) { + unsigned rule_counter::get_max_rule_var(const rule & r) { m_todo.push_back(r.get_head()); m_scopes.push_back(0); unsigned n = r.get_tail_size(); @@ -576,22 +452,6 @@ namespace datalog { return get_max_var(has_var); } - unsigned var_counter::get_max_var(expr* e) { - bool has_var = false; - m_todo.push_back(e); - m_scopes.push_back(0); - return get_max_var(has_var); - } - - unsigned var_counter::get_next_var(expr* e) { - bool has_var = false; - m_todo.push_back(e); - m_scopes.push_back(0); - unsigned mv = get_max_var(has_var); - if (has_var) mv++; - return mv; - } - void del_rule(horn_subsume_model_converter* mc, rule& r) { if (mc) { ast_manager& m = mc->get_manager(); @@ -678,10 +538,6 @@ namespace datalog { proof_converter* mk_skip_proof_converter() { return alloc(skip_proof_converter); } - unsigned get_max_var(const rule & r, ast_manager & m) { - var_counter ctr; - return ctr.get_max_var(r); - } void reverse_renaming(ast_manager & m, const expr_ref_vector & src, expr_ref_vector & tgt) { SASSERT(tgt.empty()); diff --git a/src/muz_qe/dl_util.h b/src/muz_qe/dl_util.h index 69be7e9ac..45d327d44 100644 --- a/src/muz_qe/dl_util.h +++ b/src/muz_qe/dl_util.h @@ -27,6 +27,7 @@ Revision History: #include"replace_proof_converter.h" #include"substitution.h" #include"fixedpoint_params.hpp" +#include"ast_counter.h" namespace datalog { @@ -411,80 +412,12 @@ namespace datalog { } - class counter { - protected: - typedef u_map map_impl; - map_impl m_data; - const bool m_stay_non_negative; + + class rule_counter : public var_counter { public: - typedef map_impl::iterator iterator; - - counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {} - - iterator begin() const { return m_data.begin(); } - iterator end() const { return m_data.end(); } - - void update(unsigned el, int delta); - int & get(unsigned el); - /** - \brief Increase values of elements in \c els by \c delta. - - The function returns a reference to \c *this to allow for expressions like - counter().count(sz, arr).get_positive_count() - */ - counter & count(unsigned sz, const unsigned * els, int delta = 1); - counter & count(const unsigned_vector & els, int delta = 1) { - return count(els.size(), els.c_ptr(), delta); - } - - void collect_positive(idx_set & acc) const; - unsigned get_positive_count() const; - bool get_max_positive(unsigned & res) const; - unsigned get_max_positive() const; - /** - Since the default counter value of a counter is zero, the result is never negative. - */ - int get_max_counter_value() const; - }; - - class var_counter : public counter { - ptr_vector m_sorts; - expr_fast_mark1 m_visited; - ptr_vector m_todo; - unsigned_vector m_scopes; - unsigned get_max_var(bool & has_var); - - public: - var_counter(bool stay_non_negative = true) : counter(stay_non_negative) {} - void count_vars(ast_manager & m, const app * t, int coef = 1); - void count_vars(ast_manager & m, const rule * r, int coef = 1); - unsigned get_max_var(const rule& r); - unsigned get_max_var(expr* e); - unsigned get_next_var(expr* e); - }; - - class ast_counter { - typedef obj_map map_impl; - map_impl m_data; - bool m_stay_non_negative; - public: - typedef map_impl::iterator iterator; - - ast_counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {} - - iterator begin() const { return m_data.begin(); } - iterator end() const { return m_data.end(); } - - int & get(ast * el) { - return m_data.insert_if_not_there2(el, 0)->get_data().m_value; - } - void update(ast * el, int delta){ - get(el)+=delta; - SASSERT(!m_stay_non_negative || get(el)>=0); - } - - void inc(ast * el) { update(el, 1); } - void dec(ast * el) { update(el, -1); } + rule_counter(bool stay_non_negative = true): var_counter(stay_non_negative) {} + void count_rule_vars(ast_manager & m, const rule * r, int coef = 1); + unsigned get_max_rule_var(const rule& r); }; void del_rule(horn_subsume_model_converter* mc, rule& r); @@ -497,11 +430,6 @@ namespace datalog { proof_converter* mk_skip_proof_converter(); - /** - Return maximal variable number, or zero is there isn't any - */ - // unsigned get_max_var(const rule & r, ast_manager & m); - void reverse_renaming(ast_manager & m, const expr_ref_vector & src, expr_ref_vector & tgt); /** diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 8bdff1800..d6718c33c 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -968,11 +968,11 @@ namespace pdr { unsigned deltas[2]; datalog::rule_ref rule(rm), r0(rm); model_node* n = m_root; - datalog::var_counter& vc = rm.get_var_counter(); + datalog::rule_counter& vc = rm.get_counter(); substitution subst(m); unifier unif(m); rule = n->get_rule(); - unsigned max_var = vc.get_max_var(*rule); + unsigned max_var = vc.get_max_rule_var(*rule); predicates.push_back(rule->get_head()); children.append(n); bool first = true; @@ -983,7 +983,7 @@ namespace pdr { children.pop_back(); n->mk_instantiate(r0, rule, binding); - max_var = std::max(max_var, vc.get_max_var(*rule)); + max_var = std::max(max_var, vc.get_max_rule_var(*rule)); subst.reset(); subst.reserve(2, max_var+1); deltas[0] = 0; diff --git a/src/muz_qe/pdr_quantifiers.cpp b/src/muz_qe/pdr_quantifiers.cpp index 5cc97893a..4a7b4b995 100644 --- a/src/muz_qe/pdr_quantifiers.cpp +++ b/src/muz_qe/pdr_quantifiers.cpp @@ -612,8 +612,8 @@ namespace pdr { datalog::rule_set::iterator it = m_rules.begin(), end = m_rules.end(); for (; it != end; ++it) { datalog::rule* r = *it; - datalog::var_counter vc(true); - unsigned max_var = vc.get_max_var(*r); + datalog::rule_counter vc(true); + unsigned max_var = vc.get_max_rule_var(*r); app_ref_vector body(m); for (unsigned i = 0; i < m_instantiations.size(); ++i) { if (r == m_instantiated_rules[i]) { diff --git a/src/muz_qe/tab_context.cpp b/src/muz_qe/tab_context.cpp index 72727bea8..681d3d4b2 100644 --- a/src/muz_qe/tab_context.cpp +++ b/src/muz_qe/tab_context.cpp @@ -317,7 +317,7 @@ namespace tb { for (unsigned i = utsz; i < tsz; ++i) { fmls.push_back(r->get_tail(i)); } - m_num_vars = 1 + r.get_manager().get_var_counter().get_max_var(*r); + m_num_vars = 1 + r.get_manager().get_counter().get_max_rule_var(*r); m_head = r->get_head(); m_predicates.reset(); for (unsigned i = 0; i < utsz; ++i) { diff --git a/src/smt/tactic/ctx_solver_simplify_tactic.cpp b/src/smt/tactic/ctx_solver_simplify_tactic.cpp index 25c41c2a2..0092cdd38 100644 --- a/src/smt/tactic/ctx_solver_simplify_tactic.cpp +++ b/src/smt/tactic/ctx_solver_simplify_tactic.cpp @@ -92,7 +92,34 @@ protected: ptr_vector fmls; g.get_formulas(fmls); fml = m.mk_and(fmls.size(), fmls.c_ptr()); + m_solver.push(); reduce(fml); + m_solver.pop(1); + SASSERT(m_solver.get_scope_level() == 0); + TRACE("ctx_solver_simplify_tactic", + for (unsigned i = 0; i < fmls.size(); ++i) { + tout << mk_pp(fmls[i], m) << "\n"; + } + tout << "=>\n"; + tout << mk_pp(fml, m) << "\n";); + DEBUG_CODE( + { + m_solver.push(); + expr_ref fml1(m); + fml1 = m.mk_and(fmls.size(), fmls.c_ptr()); + fml1 = m.mk_iff(fml, fml1); + fml1 = m.mk_not(fml1); + m_solver.assert_expr(fml1); + lbool is_sat = m_solver.check(); + TRACE("ctx_solver_simplify_tactic", tout << "is non-equivalence sat?: " << is_sat << "\n";); + if (is_sat != l_false) { + TRACE("ctx_solver_simplify_tactic", + tout << "result is not equivalent to input\n"; + tout << mk_pp(fml1, m) << "\n";); + UNREACHABLE(); + } + m_solver.pop(1); + }); g.reset(); g.assert_expr(fml, 0, 0); IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(ctx-solver-simplify :num-steps " << m_num_steps << ")\n";); @@ -106,21 +133,22 @@ protected: svector is_checked; svector parent_ids, self_ids; expr_ref_vector fresh_vars(m), trail(m); - expr_ref res(m); + expr_ref res(m), tmp(m); obj_map > cache; unsigned id = 1; - expr* n = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); expr* n2, *fml; unsigned path_id = 0, self_pos = 0; app * a; unsigned sz; std::pair path_r; ptr_vector found; + expr* n = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); + trail.push_back(n); fml = result.get(); - m_solver.assert_expr(m.mk_not(m.mk_iff(fml, n))); + tmp = m.mk_not(m.mk_iff(fml, n)); + m_solver.assert_expr(tmp); - trail.push_back(n); todo.push_back(fml); names.push_back(n); is_checked.push_back(false); @@ -144,6 +172,7 @@ protected: goto done; } if (m.is_bool(e) && !checked && simplify_bool(n, res)) { + TRACE("ctx_solver_simplify_tactic", tout << "simplified: " << mk_pp(e, m) << " |-> " << mk_pp(res, m) << "\n";); goto done; } if (!is_app(e)) { @@ -176,7 +205,7 @@ protected: found.push_back(arg); if (path_r.first == self_pos) { - TRACE("ctx_solver_simplify_tactic", tout << "cached " << mk_pp(arg, m) << "\n";); + TRACE("ctx_solver_simplify_tactic", tout << "cached " << mk_pp(arg, m) << " |-> " << mk_pp(path_r.second, m) << "\n";); args.push_back(path_r.second); } else { @@ -188,11 +217,11 @@ protected: } else if (!n2 && !found.contains(arg)) { n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); + trail.push_back(n2); todo.push_back(arg); parent_ids.push_back(self_pos); self_ids.push_back(0); names.push_back(n2); - trail.push_back(n2); args.push_back(n2); is_checked.push_back(false); } @@ -205,7 +234,8 @@ protected: // child needs to be visited. if (n2) { m_solver.push(); - m_solver.assert_expr(m.mk_eq(res, n)); + tmp = m.mk_eq(res, n); + m_solver.assert_expr(tmp); continue; } @@ -229,7 +259,7 @@ protected: } bool simplify_bool(expr* n, expr_ref& res) { - + expr_ref tmp(m); m_solver.push(); m_solver.assert_expr(n); lbool is_sat = m_solver.check(); @@ -240,7 +270,8 @@ protected: } m_solver.push(); - m_solver.assert_expr(m.mk_not(n)); + tmp = m.mk_not(n); + m_solver.assert_expr(tmp); is_sat = m_solver.check(); m_solver.pop(1); if (is_sat == l_false) { @@ -254,7 +285,7 @@ protected: expr_ref local_simplify(app* a, expr* n, unsigned& id, unsigned index) { SASSERT(index < a->get_num_args()); SASSERT(m.is_bool(a->get_arg(index))); - expr_ref n2(m), result(m); + expr_ref n2(m), result(m), tmp(m); n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); ptr_buffer args; for (unsigned i = 0; i < a->get_num_args(); ++i) { @@ -267,7 +298,8 @@ protected: } m_mk_app(a->get_decl(), args.size(), args.c_ptr(), result); m_solver.push(); - m_solver.assert_expr(m.mk_eq(result, n)); + tmp = m.mk_eq(result, n); + m_solver.assert_expr(tmp); if (!simplify_bool(n2, result)) { result = a; } From 5455704af2a320d0abaff376f4970ed02ebf1f07 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Mar 2013 15:00:23 -0700 Subject: [PATCH 39/97] move quantifier hoist routines to quant_hoist Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/ast_counter.cpp | 165 ++++++++++++++++++ src/ast/rewriter/ast_counter.h | 107 ++++++++++++ .../rewriter}/expr_safe_replace.cpp | 0 .../rewriter}/expr_safe_replace.h | 0 src/ast/rewriter/quant_hoist.cpp | 64 +++++-- src/ast/rewriter/quant_hoist.h | 8 + src/muz_qe/dl_rule.cpp | 42 +---- src/muz_qe/dl_rule.h | 2 - 8 files changed, 335 insertions(+), 53 deletions(-) create mode 100644 src/ast/rewriter/ast_counter.cpp create mode 100644 src/ast/rewriter/ast_counter.h rename src/{muz_qe => ast/rewriter}/expr_safe_replace.cpp (100%) rename src/{muz_qe => ast/rewriter}/expr_safe_replace.h (100%) diff --git a/src/ast/rewriter/ast_counter.cpp b/src/ast/rewriter/ast_counter.cpp new file mode 100644 index 000000000..c542abb60 --- /dev/null +++ b/src/ast/rewriter/ast_counter.cpp @@ -0,0 +1,165 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + ast_counter.cpp + +Abstract: + + Routines for counting features of terms, such as free variables. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-18. + +Revision History: + +--*/ + +#include "ast_counter.h" +#include "var_subst.h" + +void counter::update(unsigned el, int delta) { + int & counter = get(el); + SASSERT(!m_stay_non_negative || counter>=0); + SASSERT(!m_stay_non_negative || static_cast(counter)>=-delta); + counter += delta; +} + +int & counter::get(unsigned el) { + return m_data.insert_if_not_there2(el, 0)->get_data().m_value; +} + +counter & counter::count(unsigned sz, const unsigned * els, int delta) { + for(unsigned i=0; im_value>0 ) { + cnt++; + } + } + return cnt; +} + +void counter::collect_positive(uint_set & acc) const { + iterator eit = begin(); + iterator eend = end(); + for(; eit!=eend; ++eit) { + if(eit->m_value>0) { acc.insert(eit->m_key); } + } +} + +bool counter::get_max_positive(unsigned & res) const { + bool found = false; + iterator eit = begin(); + iterator eend = end(); + for(; eit!=eend; ++eit) { + if( eit->m_value>0 && (!found || eit->m_key>res) ) { + found = true; + res = eit->m_key; + } + } + return found; +} + +unsigned counter::get_max_positive() const { + unsigned max_pos; + VERIFY(get_max_positive(max_pos)); + return max_pos; +} + +int counter::get_max_counter_value() const { + int res = 0; + iterator eit = begin(); + iterator eend = end(); + for (; eit!=eend; ++eit) { + if( eit->m_value>res ) { + res = eit->m_value; + } + } + return res; +} + +void var_counter::count_vars(ast_manager & m, const app * pred, int coef) { + unsigned n = pred->get_num_args(); + for (unsigned i = 0; i < n; i++) { + m_sorts.reset(); + ::get_free_vars(pred->get_arg(i), m_sorts); + for (unsigned j = 0; j < m_sorts.size(); ++j) { + if (m_sorts[j]) { + update(j, coef); + } + } + } +} + + +unsigned var_counter::get_max_var(bool& has_var) { + has_var = false; + unsigned max_var = 0; + while (!m_todo.empty()) { + expr* e = m_todo.back(); + unsigned scope = m_scopes.back(); + m_todo.pop_back(); + m_scopes.pop_back(); + if (m_visited.is_marked(e)) { + continue; + } + m_visited.mark(e, true); + switch(e->get_kind()) { + case AST_QUANTIFIER: { + quantifier* q = to_quantifier(e); + m_todo.push_back(q->get_expr()); + m_scopes.push_back(scope + q->get_num_decls()); + break; + } + case AST_VAR: { + if (to_var(e)->get_idx() >= scope + max_var) { + has_var = true; + max_var = to_var(e)->get_idx() - scope; + } + break; + } + case AST_APP: { + app* a = to_app(e); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + m_todo.push_back(a->get_arg(i)); + m_scopes.push_back(scope); + } + break; + } + default: + UNREACHABLE(); + break; + } + } + m_visited.reset(); + return max_var; +} + + +unsigned var_counter::get_max_var(expr* e) { + bool has_var = false; + m_todo.push_back(e); + m_scopes.push_back(0); + return get_max_var(has_var); +} + +unsigned var_counter::get_next_var(expr* e) { + bool has_var = false; + m_todo.push_back(e); + m_scopes.push_back(0); + unsigned mv = get_max_var(has_var); + if (has_var) mv++; + return mv; +} + diff --git a/src/ast/rewriter/ast_counter.h b/src/ast/rewriter/ast_counter.h new file mode 100644 index 000000000..2a581c302 --- /dev/null +++ b/src/ast/rewriter/ast_counter.h @@ -0,0 +1,107 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + ast_counter.h + +Abstract: + + Routines for counting features of terms, such as free variables. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-18. + Krystof Hoder (t-khoder) 2010-10-10. + +Revision History: + + Hoisted from dl_util.h 2013-03-18. + +--*/ + + +#ifndef _AST_COUNTER_H_ +#define _AST_COUNTER_H_ + +#include "ast.h" +#include "map.h" +#include "uint_set.h" + +class counter { +protected: + typedef u_map map_impl; + map_impl m_data; + const bool m_stay_non_negative; +public: + typedef map_impl::iterator iterator; + + counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {} + + iterator begin() const { return m_data.begin(); } + iterator end() const { return m_data.end(); } + void update(unsigned el, int delta); + int & get(unsigned el); + + /** + \brief Increase values of elements in \c els by \c delta. + + The function returns a reference to \c *this to allow for expressions like + counter().count(sz, arr).get_positive_count() + */ + counter & count(unsigned sz, const unsigned * els, int delta = 1); + counter & count(const unsigned_vector & els, int delta = 1) { + return count(els.size(), els.c_ptr(), delta); + } + + void collect_positive(uint_set & acc) const; + unsigned get_positive_count() const; + + bool get_max_positive(unsigned & res) const; + unsigned get_max_positive() const; + + /** + Since the default counter value of a counter is zero, the result is never negative. + */ + int get_max_counter_value() const; +}; + +class var_counter : public counter { +protected: + ptr_vector m_sorts; + expr_fast_mark1 m_visited; + ptr_vector m_todo; + unsigned_vector m_scopes; + unsigned get_max_var(bool & has_var); +public: + var_counter(bool stay_non_negative = true): counter(stay_non_negative) {} + void count_vars(ast_manager & m, const app * t, int coef = 1); + unsigned get_max_var(expr* e); + unsigned get_next_var(expr* e); +}; + +class ast_counter { + typedef obj_map map_impl; + map_impl m_data; + bool m_stay_non_negative; + public: + typedef map_impl::iterator iterator; + + ast_counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {} + + iterator begin() const { return m_data.begin(); } + iterator end() const { return m_data.end(); } + + int & get(ast * el) { + return m_data.insert_if_not_there2(el, 0)->get_data().m_value; + } + void update(ast * el, int delta){ + get(el) += delta; + SASSERT(!m_stay_non_negative || get(el) >= 0); + } + + void inc(ast * el) { update(el, 1); } + void dec(ast * el) { update(el, -1); } +}; + +#endif diff --git a/src/muz_qe/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp similarity index 100% rename from src/muz_qe/expr_safe_replace.cpp rename to src/ast/rewriter/expr_safe_replace.cpp diff --git a/src/muz_qe/expr_safe_replace.h b/src/ast/rewriter/expr_safe_replace.h similarity index 100% rename from src/muz_qe/expr_safe_replace.h rename to src/ast/rewriter/expr_safe_replace.h diff --git a/src/ast/rewriter/quant_hoist.cpp b/src/ast/rewriter/quant_hoist.cpp index b64e71866..9e8db0d11 100644 --- a/src/ast/rewriter/quant_hoist.cpp +++ b/src/ast/rewriter/quant_hoist.cpp @@ -25,7 +25,8 @@ Revision History: #include "bool_rewriter.h" #include "var_subst.h" #include "ast_pp.h" - +#include "ast_counter.h" +#include "expr_safe_replace.h" // // Bring quantifiers of common type into prenex form. @@ -42,7 +43,7 @@ public: void operator()(expr* fml, app_ref_vector& vars, bool& is_fa, expr_ref& result) { quantifier_type qt = Q_none_pos; - pull_quantifiers(fml, qt, vars, result); + pull_quantifier(fml, qt, vars, result); TRACE("qe_verbose", tout << mk_pp(fml, m) << "\n"; tout << mk_pp(result, m) << "\n";); @@ -52,7 +53,7 @@ public: void pull_exists(expr* fml, app_ref_vector& vars, expr_ref& result) { quantifier_type qt = Q_exists_pos; - pull_quantifiers(fml, qt, vars, result); + pull_quantifier(fml, qt, vars, result); TRACE("qe_verbose", tout << mk_pp(fml, m) << "\n"; tout << mk_pp(result, m) << "\n";); @@ -61,7 +62,7 @@ public: void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars) { quantifier_type qt = is_forall?Q_forall_pos:Q_exists_pos; expr_ref result(m); - pull_quantifiers(fml, qt, vars, result); + pull_quantifier(fml, qt, vars, result); TRACE("qe_verbose", tout << mk_pp(fml, m) << "\n"; tout << mk_pp(result, m) << "\n";); @@ -78,7 +79,37 @@ public: expr * const * exprs = (expr* const*) (vars.c_ptr() + vars.size()- nd); instantiate(m, q, exprs, result); } - + + unsigned pull_quantifier(bool is_forall, expr_ref& fml, svector* names) { + unsigned index = var_counter().get_next_var(fml); + while (is_quantifier(fml) && (is_forall == to_quantifier(fml)->is_forall())) { + quantifier* q = to_quantifier(fml); + index += q->get_num_decls(); + if (names) { + names->append(q->get_num_decls(), q->get_decl_names()); + } + fml = q->get_expr(); + } + if (!has_quantifiers(fml)) { + return index; + } + app_ref_vector vars(m); + pull_quantifier(is_forall, fml, vars); + if (vars.empty()) { + return index; + } + // replace vars by de-bruijn indices + expr_safe_replace rep(m); + for (unsigned i = 0; i < vars.size(); ++i) { + app* v = vars[i].get(); + if (names) { + names->push_back(v->get_decl()->get_name()); + } + rep.insert(v, m.mk_var(index++,m.get_sort(v))); + } + rep(fml); + return index; + } private: @@ -143,7 +174,7 @@ private: } - void pull_quantifiers(expr* fml, quantifier_type& qt, app_ref_vector& vars, expr_ref& result) { + void pull_quantifier(expr* fml, quantifier_type& qt, app_ref_vector& vars, expr_ref& result) { if (!has_quantifiers(fml)) { result = fml; @@ -159,7 +190,7 @@ private: if (m.is_and(fml)) { num_args = a->get_num_args(); for (unsigned i = 0; i < num_args; ++i) { - pull_quantifiers(a->get_arg(i), qt, vars, tmp); + pull_quantifier(a->get_arg(i), qt, vars, tmp); args.push_back(tmp); } m_rewriter.mk_and(args.size(), args.c_ptr(), result); @@ -167,25 +198,25 @@ private: else if (m.is_or(fml)) { num_args = to_app(fml)->get_num_args(); for (unsigned i = 0; i < num_args; ++i) { - pull_quantifiers(to_app(fml)->get_arg(i), qt, vars, tmp); + pull_quantifier(to_app(fml)->get_arg(i), qt, vars, tmp); args.push_back(tmp); } m_rewriter.mk_or(args.size(), args.c_ptr(), result); } else if (m.is_not(fml)) { - pull_quantifiers(to_app(fml)->get_arg(0), negate(qt), vars, tmp); + pull_quantifier(to_app(fml)->get_arg(0), negate(qt), vars, tmp); negate(qt); result = m.mk_not(tmp); } else if (m.is_implies(fml)) { - pull_quantifiers(to_app(fml)->get_arg(0), negate(qt), vars, tmp); + pull_quantifier(to_app(fml)->get_arg(0), negate(qt), vars, tmp); negate(qt); - pull_quantifiers(to_app(fml)->get_arg(1), qt, vars, result); + pull_quantifier(to_app(fml)->get_arg(1), qt, vars, result); result = m.mk_implies(tmp, result); } else if (m.is_ite(fml)) { - pull_quantifiers(to_app(fml)->get_arg(1), qt, vars, tmp); - pull_quantifiers(to_app(fml)->get_arg(2), qt, vars, result); + pull_quantifier(to_app(fml)->get_arg(1), qt, vars, tmp); + pull_quantifier(to_app(fml)->get_arg(2), qt, vars, result); result = m.mk_ite(to_app(fml)->get_arg(0), tmp, result); } else { @@ -203,7 +234,7 @@ private: } set_quantifier_type(qt, q->is_forall()); extract_quantifier(q, vars, tmp); - pull_quantifiers(tmp, qt, vars, result); + pull_quantifier(tmp, qt, vars, result); break; } case AST_VAR: @@ -215,6 +246,8 @@ private: break; } } + + }; quantifier_hoister::quantifier_hoister(ast_manager& m) { @@ -237,3 +270,6 @@ void quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, app_ref_ m_impl->pull_quantifier(is_forall, fml, vars); } +unsigned quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, svector* names) { + return m_impl->pull_quantifier(is_forall, fml, names); +} diff --git a/src/ast/rewriter/quant_hoist.h b/src/ast/rewriter/quant_hoist.h index 878f7840d..70a79a0e2 100644 --- a/src/ast/rewriter/quant_hoist.h +++ b/src/ast/rewriter/quant_hoist.h @@ -59,6 +59,14 @@ public: The list of variables is empty if there are no top-level universal/existential quantifier. */ void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars); + + /** + \brief Pull top-most universal (is_forall true) or existential (is_forall=false) quantifier up. + Return an expression with de-Bruijn indices and the list of names that were used. + Return index of maximal variable. + */ + + unsigned pull_quantifier(bool is_forall, expr_ref& fml, svector* names); }; #endif diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index de41e4774..59a245cc4 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -107,41 +107,6 @@ namespace datalog { mk_rule_core(fml1, rules, name); } - // - // Hoist quantifier from rule (universal) or query (existential) - // - unsigned rule_manager::hoist_quantifier(bool is_forall, expr_ref& fml, svector* names) { - - unsigned index = var_counter().get_next_var(fml); - while (is_quantifier(fml) && (is_forall == to_quantifier(fml)->is_forall())) { - quantifier* q = to_quantifier(fml); - index += q->get_num_decls(); - if (names) { - names->append(q->get_num_decls(), q->get_decl_names()); - } - fml = q->get_expr(); - } - if (!has_quantifiers(fml)) { - return index; - } - app_ref_vector vars(m); - quantifier_hoister qh(m); - qh.pull_quantifier(is_forall, fml, vars); - if (vars.empty()) { - return index; - } - // replace vars by de-bruijn indices - expr_safe_replace rep(m); - for (unsigned i = 0; i < vars.size(); ++i) { - app* v = vars[i].get(); - if (names) { - names->push_back(v->get_decl()->get_name()); - } - rep.insert(v, m.mk_var(index++,m.get_sort(v))); - } - rep(fml); - return index; - } void rule_manager::mk_rule_core(expr* _fml, rule_ref_vector& rules, symbol const& name) { app_ref_vector body(m); @@ -149,7 +114,8 @@ namespace datalog { expr_ref e(m), fml(_fml, m); svector is_negated; TRACE("dl_rule", tout << mk_pp(fml, m) << "\n";); - unsigned index = hoist_quantifier(true, fml, 0); + quantifier_hoister qh(m); + unsigned index = qh.pull_quantifier(true, fml, 0); check_app(fml); head = to_app(fml); @@ -225,7 +191,8 @@ namespace datalog { // Add implicit variables. // Remove existential prefix. bind_variables(query, false, q); - hoist_quantifier(false, q, &names); + quantifier_hoister qh(m); + qh.pull_quantifier(false, q, &names); // retrieve free variables. get_free_vars(q, vars); if (vars.contains(static_cast(0))) { @@ -1115,3 +1082,4 @@ namespace datalog { }; + diff --git a/src/muz_qe/dl_rule.h b/src/muz_qe/dl_rule.h index 4afc08edb..a8c6e0314 100644 --- a/src/muz_qe/dl_rule.h +++ b/src/muz_qe/dl_rule.h @@ -81,8 +81,6 @@ namespace datalog { void mk_rule_core(expr* fml, rule_ref_vector& rules, symbol const& name); - unsigned hoist_quantifier(bool is_forall, expr_ref& fml, svector* names); - /** \brief Perform cheap quantifier elimination to reduce the number of variables in the interpreted tail. */ From babfc701a60fc1cf5c1321b77c194a041490b251 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Mar 2013 10:36:36 -0700 Subject: [PATCH 40/97] make model and proof converters a reference Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_bmc_engine.cpp | 6 ++++-- src/muz_qe/dl_context.cpp | 12 ++++++------ src/muz_qe/dl_context.h | 11 ++++++++--- src/muz_qe/horn_tactic.cpp | 6 ++++-- src/muz_qe/pdr_dl_interface.cpp | 12 +++++++----- src/muz_qe/rel_context.cpp | 12 +++--------- src/shell/datalog_frontend.cpp | 4 +--- 7 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/muz_qe/dl_bmc_engine.cpp b/src/muz_qe/dl_bmc_engine.cpp index 80fcdea4a..200338b86 100644 --- a/src/muz_qe/dl_bmc_engine.cpp +++ b/src/muz_qe/dl_bmc_engine.cpp @@ -1420,13 +1420,15 @@ namespace datalog { model_converter_ref mc = datalog::mk_skip_model_converter(); m_pc = datalog::mk_skip_proof_converter(); m_ctx.set_output_predicate(m_query_pred); - m_ctx.apply_default_transformation(mc, m_pc); + m_ctx.set_model_converter(mc); + m_ctx.set_proof_converter(m_pc); + m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); - m_ctx.transform_rules(transformer, mc, m_pc); + m_ctx.transform_rules(transformer); m_query_pred = slice->get_predicate(m_query_pred.get()); m_ctx.set_output_predicate(m_query_pred); } diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 53231e7b0..839aa93f9 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -826,7 +826,7 @@ namespace datalog { m_closed = false; } - void context::transform_rules(model_converter_ref& mc, proof_converter_ref& pc) { + void context::transform_rules() { m_transf.reset(); m_transf.register_plugin(alloc(mk_filter_rules,*this)); m_transf.register_plugin(alloc(mk_simple_joins,*this)); @@ -841,13 +841,13 @@ namespace datalog { } m_transf.register_plugin(alloc(datalog::mk_partial_equivalence_transformer, *this)); - transform_rules(m_transf, mc, pc); + transform_rules(m_transf); } - void context::transform_rules(rule_transformer& transf, model_converter_ref& mc, proof_converter_ref& pc) { + void context::transform_rules(rule_transformer& transf) { SASSERT(m_closed); //we must finish adding rules before we start transforming them TRACE("dl", display_rules(tout);); - if (transf(m_rule_set, mc, pc)) { + if (transf(m_rule_set, m_mc, m_pc)) { //we have already ensured the negation is stratified and transformations //should not break the stratification m_rule_set.ensure_closed(); @@ -862,7 +862,7 @@ namespace datalog { m_rule_set.add_rules(rs); } - void context::apply_default_transformation(model_converter_ref& mc, proof_converter_ref& pc) { + void context::apply_default_transformation() { ensure_closed(); m_transf.reset(); m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this)); @@ -890,7 +890,7 @@ namespace datalog { m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 36010)); - transform_rules(m_transf, mc, pc); + transform_rules(m_transf); } void context::collect_params(param_descrs& p) { diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index b587daf7f..f9a1f1737 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -97,6 +97,8 @@ namespace datalog { expr_ref_vector m_rule_fmls; svector m_rule_names; expr_ref_vector m_background; + model_converter_ref m_mc; + proof_converter_ref m_pc; scoped_ptr m_pdr; scoped_ptr m_bmc; @@ -313,11 +315,14 @@ namespace datalog { void reopen(); void ensure_opened(); - void transform_rules(model_converter_ref& mc, proof_converter_ref& pc); - void transform_rules(rule_transformer& transf, model_converter_ref& mc, proof_converter_ref& pc); + void set_model_converter(model_converter_ref& mc) { m_mc = mc; } + void set_proof_converter(proof_converter_ref& pc) { m_pc = pc; } + + void transform_rules(); // model_converter_ref& mc, proof_converter_ref& pc); + void transform_rules(rule_transformer& transf); // , model_converter_ref& mc, proof_converter_ref& pc); void replace_rules(rule_set & rs); - void apply_default_transformation(model_converter_ref& mc, proof_converter_ref& pc); + void apply_default_transformation(); // model_converter_ref& mc, proof_converter_ref& pc); void collect_params(param_descrs& r); diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index 633aeaa81..c87874b29 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -282,14 +282,16 @@ class horn_tactic : public tactic { func_decl* query_pred = to_app(q)->get_decl(); m_ctx.set_output_predicate(query_pred); + m_ctx.set_model_converter(mc); + m_ctx.set_proof_converter(pc); m_ctx.get_rules(); // flush adding rules. - m_ctx.apply_default_transformation(mc, pc); + m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); - m_ctx.transform_rules(transformer, mc, pc); + m_ctx.transform_rules(transformer); } expr_substitution sub(m); diff --git a/src/muz_qe/pdr_dl_interface.cpp b/src/muz_qe/pdr_dl_interface.cpp index 54a40f8b8..b55f302ed 100644 --- a/src/muz_qe/pdr_dl_interface.cpp +++ b/src/muz_qe/pdr_dl_interface.cpp @@ -111,13 +111,15 @@ lbool dl_interface::query(expr * query) { pc = datalog::mk_skip_proof_converter(); } m_ctx.set_output_predicate(query_pred); - m_ctx.apply_default_transformation(mc, pc); + m_ctx.set_model_converter(mc); + m_ctx.set_proof_converter(pc); + m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); - m_ctx.transform_rules(transformer, mc, pc); + m_ctx.transform_rules(transformer); query_pred = slice->get_predicate(query_pred.get()); m_ctx.set_output_predicate(query_pred); @@ -137,11 +139,11 @@ lbool dl_interface::query(expr * query) { datalog::rule_transformer transformer1(m_ctx), transformer2(m_ctx); if (m_ctx.get_params().coalesce_rules()) { transformer1.register_plugin(alloc(datalog::mk_coalesce, m_ctx)); - m_ctx.transform_rules(transformer1, mc, pc); + m_ctx.transform_rules(transformer1); } transformer2.register_plugin(alloc(datalog::mk_unfold, m_ctx)); while (num_unfolds > 0) { - m_ctx.transform_rules(transformer2, mc, pc); + m_ctx.transform_rules(transformer2); --num_unfolds; } } @@ -149,7 +151,7 @@ lbool dl_interface::query(expr * query) { datalog::mk_extract_quantifiers* extract_quantifiers = alloc(datalog::mk_extract_quantifiers, m_ctx); datalog::rule_transformer extract_q_tr(m_ctx); extract_q_tr.register_plugin(extract_quantifiers); - m_ctx.transform_rules(extract_q_tr, mc, pc); + m_ctx.transform_rules(extract_q_tr); IF_VERBOSE(2, m_ctx.display_rules(verbose_stream());); diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 00ac51e9f..8e22a704c 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -103,9 +103,7 @@ namespace datalog { TRACE("dl", m_context.display(tout);); while (true) { - model_converter_ref mc; // Ignored in Datalog mode - proof_converter_ref pc; // Ignored in Datalog mode - m_context.transform_rules(mc, pc); + m_context.transform_rules(); compiler::compile(m_context, m_context.get_rules(), rules_code, termination_code); TRACE("dl", rules_code.display(*this, tout); ); @@ -263,14 +261,12 @@ namespace datalog { reset_negated_tables(); if (m_context.generate_explanations()) { - model_converter_ref mc; // ignored in Datalog mode - proof_converter_ref pc; // ignored in Datalog mode rule_transformer transformer(m_context); //expl_plugin is deallocated when transformer goes out of scope mk_explanations * expl_plugin = alloc(mk_explanations, m_context, m_context.explanations_on_relation_level()); transformer.register_plugin(expl_plugin); - m_context.transform_rules(transformer, mc, pc); + m_context.transform_rules(transformer); //we will retrieve the predicate with explanations instead of the original query predicate query_pred = expl_plugin->get_e_decl(query_pred); @@ -280,11 +276,9 @@ namespace datalog { } if (m_context.magic_sets_for_queries()) { - model_converter_ref mc; // Ignored in Datalog mode - proof_converter_ref pc; // Ignored in Datalog mode rule_transformer transformer(m_context); transformer.register_plugin(alloc(mk_magic_sets, m_context, qrule.get())); - m_context.transform_rules(transformer, mc, pc); + m_context.transform_rules(transformer); } lbool res = saturate(); diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index 44a9d9b66..07052609e 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -200,9 +200,7 @@ unsigned read_datalog(char const * file) { timeout = UINT_MAX; } do { - model_converter_ref mc; // ignored - proof_converter_ref pc; // ignored - ctx.transform_rules(mc, pc); + ctx.transform_rules(); datalog::compiler::compile(ctx, ctx.get_rules(), rules_code, termination_code); From ea2b17d83b9edd5363e298dd653b01f4343c218d Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 20 Mar 2013 10:40:52 -0700 Subject: [PATCH 41/97] remove debug code Signed-off-by: Nuno Lopes --- src/muz_qe/dl_check_table.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/muz_qe/dl_check_table.cpp b/src/muz_qe/dl_check_table.cpp index d7dfbe1ae..18d5feb39 100644 --- a/src/muz_qe/dl_check_table.cpp +++ b/src/muz_qe/dl_check_table.cpp @@ -287,9 +287,6 @@ namespace datalog { bool check_table::well_formed() const { get_plugin().m_count++; - if (get_plugin().m_count == 497) { - std::cout << "here\n"; - } iterator it = m_tocheck->begin(), end = m_tocheck->end(); for (; it != end; ++it) { table_fact fact; From 39d72462516084a9c0fa1d33ec43b5e43a5d263c Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 20 Mar 2013 15:47:56 -0700 Subject: [PATCH 42/97] fix overloading of complement from base_table Signed-off-by: Nuno Lopes --- src/muz_qe/dl_check_table.cpp | 4 ++-- src/muz_qe/dl_check_table.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/muz_qe/dl_check_table.cpp b/src/muz_qe/dl_check_table.cpp index 18d5feb39..5081654b5 100644 --- a/src/muz_qe/dl_check_table.cpp +++ b/src/muz_qe/dl_check_table.cpp @@ -351,8 +351,8 @@ namespace datalog { return result; } - table_base * check_table::complement(func_decl* p) const { - check_table* result = alloc(check_table, get_plugin(), get_signature(), m_tocheck->complement(p), m_checker->complement(p)); + table_base * check_table::complement(func_decl* p, const table_element * func_columns) const { + check_table* result = alloc(check_table, get_plugin(), get_signature(), m_tocheck->complement(p, func_columns), m_checker->complement(p, func_columns)); return result; } diff --git a/src/muz_qe/dl_check_table.h b/src/muz_qe/dl_check_table.h index 6f098f8bc..7126bde66 100644 --- a/src/muz_qe/dl_check_table.h +++ b/src/muz_qe/dl_check_table.h @@ -119,7 +119,7 @@ namespace datalog { virtual void add_fact(const table_fact & f); virtual void remove_fact(const table_element* fact); virtual bool contains_fact(const table_fact & f) const; - virtual table_base * complement(func_decl* p) const; + virtual table_base * complement(func_decl* p, const table_element * func_columns = 0) const; virtual table_base * clone() const; virtual iterator begin() const { SASSERT(well_formed()); return m_tocheck->begin(); } From b2d4aa085973aee81bfa8e0edccd25066d755ce2 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Mar 2013 01:14:08 +0100 Subject: [PATCH 43/97] fix crash in qe_lite::is_var_eq Signed-off-by: unknown --- src/muz_qe/qe_lite.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/muz_qe/qe_lite.cpp b/src/muz_qe/qe_lite.cpp index 5f018895c..435768c08 100644 --- a/src/muz_qe/qe_lite.cpp +++ b/src/muz_qe/qe_lite.cpp @@ -201,9 +201,15 @@ namespace eq { return (*m_is_variable)(e); } - bool is_neg_var(ast_manager & m, expr * e) { + bool is_neg_var(ast_manager & m, expr * e, var*& v) { expr* e1; - return m.is_not(e, e1) && is_variable(e1); + if (m.is_not(e, e1) && is_variable(e1)) { + v = to_var(e1); + return true; + } + else { + return false; + } } @@ -328,18 +334,19 @@ namespace eq { bool is_var_eq(expr * e, ptr_vector& vs, expr_ref_vector & ts) { expr* lhs, *rhs; + var* v; // (= VAR t), (iff VAR t), (iff (not VAR) t), (iff t (not VAR)) cases if (m.is_eq(e, lhs, rhs) || m.is_iff(e, lhs, rhs)) { // (iff (not VAR) t) (iff t (not VAR)) cases if (!is_variable(lhs) && !is_variable(rhs) && m.is_bool(lhs)) { - if (!is_neg_var(m, lhs)) { + if (!is_neg_var(m, lhs, v)) { std::swap(lhs, rhs); } - if (!is_neg_var(m, lhs)) { + if (!is_neg_var(m, lhs, v)) { return false; } - vs.push_back(to_var(lhs)); + vs.push_back(v); ts.push_back(m.mk_not(rhs)); TRACE("qe_lite", tout << mk_pp(e, m) << "\n";); return true; @@ -378,9 +385,9 @@ namespace eq { } // VAR = false case - if (is_neg_var(m, e)) { + if (is_neg_var(m, e, v)) { ts.push_back(m.mk_false()); - vs.push_back(to_var(to_app(e)->get_arg(0))); + vs.push_back(v); TRACE("qe_lite", tout << mk_pp(e, m) << "\n";); return true; } From 54d9fb5c4b20844bb4540284abea459a0efa6dfb Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Mar 2013 01:25:22 +0100 Subject: [PATCH 44/97] Revert "fix crash in qe_lite::is_var_eq" This reverts commit b2d4aa085973aee81bfa8e0edccd25066d755ce2. --- src/muz_qe/qe_lite.cpp | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/muz_qe/qe_lite.cpp b/src/muz_qe/qe_lite.cpp index 435768c08..5f018895c 100644 --- a/src/muz_qe/qe_lite.cpp +++ b/src/muz_qe/qe_lite.cpp @@ -201,15 +201,9 @@ namespace eq { return (*m_is_variable)(e); } - bool is_neg_var(ast_manager & m, expr * e, var*& v) { + bool is_neg_var(ast_manager & m, expr * e) { expr* e1; - if (m.is_not(e, e1) && is_variable(e1)) { - v = to_var(e1); - return true; - } - else { - return false; - } + return m.is_not(e, e1) && is_variable(e1); } @@ -334,19 +328,18 @@ namespace eq { bool is_var_eq(expr * e, ptr_vector& vs, expr_ref_vector & ts) { expr* lhs, *rhs; - var* v; // (= VAR t), (iff VAR t), (iff (not VAR) t), (iff t (not VAR)) cases if (m.is_eq(e, lhs, rhs) || m.is_iff(e, lhs, rhs)) { // (iff (not VAR) t) (iff t (not VAR)) cases if (!is_variable(lhs) && !is_variable(rhs) && m.is_bool(lhs)) { - if (!is_neg_var(m, lhs, v)) { + if (!is_neg_var(m, lhs)) { std::swap(lhs, rhs); } - if (!is_neg_var(m, lhs, v)) { + if (!is_neg_var(m, lhs)) { return false; } - vs.push_back(v); + vs.push_back(to_var(lhs)); ts.push_back(m.mk_not(rhs)); TRACE("qe_lite", tout << mk_pp(e, m) << "\n";); return true; @@ -385,9 +378,9 @@ namespace eq { } // VAR = false case - if (is_neg_var(m, e, v)) { + if (is_neg_var(m, e)) { ts.push_back(m.mk_false()); - vs.push_back(v); + vs.push_back(to_var(to_app(e)->get_arg(0))); TRACE("qe_lite", tout << mk_pp(e, m) << "\n";); return true; } From c824178e7e83cdc05336ccf721f88b04772f9d4f Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 22 Mar 2013 11:50:41 -0700 Subject: [PATCH 45/97] bit_vector: fix operator==() for the case that num_bits is a multiple of 32 Signed-off-by: Nuno Lopes --- src/util/bit_vector.cpp | 3 ++- src/util/bit_vector.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index 210d230bc..2328a5849 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -116,7 +116,7 @@ void bit_vector::shift_right(unsigned k) { } } -bool bit_vector::operator==(bit_vector const & source) { +bool bit_vector::operator==(bit_vector const & source) const { if (m_num_bits != source.m_num_bits) return false; unsigned n = num_words(); @@ -129,6 +129,7 @@ bool bit_vector::operator==(bit_vector const & source) { } unsigned bit_rest = source.m_num_bits % 32; unsigned mask = (1 << bit_rest) - 1; + if (mask == 0) mask = UINT_MAX; return (m_data[i] & mask) == (source.m_data[i] & mask); } diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index 9560af7e2..2e7becee7 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -171,9 +171,9 @@ public: resize(sz, val); } - bool operator==(bit_vector const & other); + bool operator==(bit_vector const & other) const; - bool operator!=(bit_vector const & other) { return !operator==(other); } + bool operator!=(bit_vector const & other) const { return !operator==(other); } bit_vector & operator=(bit_vector const & source) { m_num_bits = source.m_num_bits; From 7e0723e42bc9aac806f6b354319a388dc49f7f66 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 22 Mar 2013 11:51:28 -0700 Subject: [PATCH 46/97] add unit test for previous commit Signed-off-by: Nuno Lopes --- src/test/bit_vector.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/test/bit_vector.cpp b/src/test/bit_vector.cpp index 2b67c3a71..7d3f96ae4 100644 --- a/src/test/bit_vector.cpp +++ b/src/test/bit_vector.cpp @@ -276,12 +276,35 @@ static void tst_bv_reset() { } } +static void tst_eq() { + bit_vector b1, b2, b3; + b1.resize(32); + b2.resize(32); + b3.resize(32); + + b1.set(3, true); + SASSERT(b1 != b2); + SASSERT(!(b1 == b2)); + SASSERT(b2 == b3); + + b3.set(3, true); + SASSERT(b1 == b3); + SASSERT(!(b1 != b3)); + + b2.set(31, true); + b3.set(31); + b3.unset(3); + SASSERT(b2 == b3); + SASSERT(!(b2 != b3)); +} + void tst_bit_vector() { tst_crash(); tst_shift(); tst_or(); tst_and(); tst_bv_reset(); + tst_eq(); return; tst2(); for (unsigned i = 0; i < 20; i++) { From 26f4d3be202606ff0189aefc103de187caf06d5d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Mar 2013 14:11:54 -0700 Subject: [PATCH 47/97] significant update to Horn routines: add module hnf to extract Horn normal form (removed from rule_manager). Associate proof objects with rules to track (all) rewrites, so that proof traces can be tracked back to original rules after transformations Signed-off-by: Nikolaj Bjorner --- src/api/z3_api.h | 2 +- src/ast/rewriter/quant_hoist.cpp | 30 +- src/ast/rewriter/quant_hoist.h | 2 +- src/muz_qe/dl_base.cpp | 2 +- src/muz_qe/dl_bmc_engine.cpp | 40 ++- src/muz_qe/dl_bmc_engine.h | 1 - src/muz_qe/dl_cmds.cpp | 4 +- src/muz_qe/dl_context.cpp | 32 +- src/muz_qe/dl_context.h | 13 +- src/muz_qe/dl_mk_array_blast.cpp | 18 +- src/muz_qe/dl_mk_array_blast.h | 3 +- src/muz_qe/dl_mk_bit_blast.cpp | 119 ++++++- src/muz_qe/dl_mk_bit_blast.h | 2 +- src/muz_qe/dl_mk_coalesce.cpp | 20 +- src/muz_qe/dl_mk_coalesce.h | 3 +- src/muz_qe/dl_mk_coi_filter.cpp | 3 +- src/muz_qe/dl_mk_coi_filter.h | 3 +- src/muz_qe/dl_mk_explanations.cpp | 4 +- src/muz_qe/dl_mk_explanations.h | 2 +- src/muz_qe/dl_mk_extract_quantifiers.cpp | 12 +- src/muz_qe/dl_mk_extract_quantifiers.h | 2 +- src/muz_qe/dl_mk_filter_rules.cpp | 6 +- src/muz_qe/dl_mk_filter_rules.h | 2 +- src/muz_qe/dl_mk_interp_tail_simplifier.cpp | 7 +- src/muz_qe/dl_mk_interp_tail_simplifier.h | 2 +- src/muz_qe/dl_mk_karr_invariants.cpp | 5 +- src/muz_qe/dl_mk_karr_invariants.h | 2 +- src/muz_qe/dl_mk_magic_sets.cpp | 4 +- src/muz_qe/dl_mk_magic_sets.h | 2 +- src/muz_qe/dl_mk_partial_equiv.cpp | 4 +- src/muz_qe/dl_mk_partial_equiv.h | 2 +- src/muz_qe/dl_mk_rule_inliner.cpp | 14 +- src/muz_qe/dl_mk_rule_inliner.h | 4 +- src/muz_qe/dl_mk_similarity_compressor.cpp | 4 +- src/muz_qe/dl_mk_similarity_compressor.h | 2 +- src/muz_qe/dl_mk_simple_joins.cpp | 9 +- src/muz_qe/dl_mk_simple_joins.h | 2 +- src/muz_qe/dl_mk_slice.cpp | 15 +- src/muz_qe/dl_mk_slice.h | 2 +- src/muz_qe/dl_mk_subsumption_checker.cpp | 13 +- src/muz_qe/dl_mk_subsumption_checker.h | 2 +- src/muz_qe/dl_mk_unbound_compressor.cpp | 5 +- src/muz_qe/dl_mk_unbound_compressor.h | 2 +- src/muz_qe/dl_mk_unfold.cpp | 15 +- src/muz_qe/dl_mk_unfold.h | 3 +- src/muz_qe/dl_rule.cpp | 333 ++++++++++---------- src/muz_qe/dl_rule.h | 45 ++- src/muz_qe/dl_rule_transformer.cpp | 4 +- src/muz_qe/dl_rule_transformer.h | 6 +- src/muz_qe/dl_util.cpp | 38 +++ src/muz_qe/dl_util.h | 3 + src/muz_qe/equiv_proof_converter.cpp | 18 +- src/muz_qe/horn_tactic.cpp | 14 +- src/muz_qe/pdr_context.cpp | 49 ++- src/muz_qe/pdr_context.h | 7 +- src/muz_qe/pdr_dl_interface.cpp | 13 +- src/muz_qe/pdr_generalizers.cpp | 6 +- src/muz_qe/qe_lite.cpp | 8 +- src/muz_qe/tab_context.cpp | 13 +- src/util/vector.h | 17 - 60 files changed, 591 insertions(+), 428 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index ea3b05e40..6d59cf650 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -701,7 +701,7 @@ typedef enum over Boolean connectives 'and' and 'or'. - - Z3_OP_PR_NFF_NEG: Proof for a (negative) NNF step. Examples: + - Z3_OP_PR_NNF_NEG: Proof for a (negative) NNF step. Examples: \nicebox{ T1: (not s_1) ~ r_1 ... diff --git a/src/ast/rewriter/quant_hoist.cpp b/src/ast/rewriter/quant_hoist.cpp index 9e8db0d11..57b693aca 100644 --- a/src/ast/rewriter/quant_hoist.cpp +++ b/src/ast/rewriter/quant_hoist.cpp @@ -80,7 +80,7 @@ public: instantiate(m, q, exprs, result); } - unsigned pull_quantifier(bool is_forall, expr_ref& fml, svector* names) { + unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector* sorts, svector* names) { unsigned index = var_counter().get_next_var(fml); while (is_quantifier(fml) && (is_forall == to_quantifier(fml)->is_forall())) { quantifier* q = to_quantifier(fml); @@ -88,6 +88,9 @@ public: if (names) { names->append(q->get_num_decls(), q->get_decl_names()); } + if (sorts) { + sorts->append(q->get_num_decls(), q->get_decl_sorts()); + } fml = q->get_expr(); } if (!has_quantifiers(fml)) { @@ -100,12 +103,29 @@ public: } // replace vars by de-bruijn indices expr_safe_replace rep(m); + svector bound_names; + ptr_vector bound_sorts; for (unsigned i = 0; i < vars.size(); ++i) { app* v = vars[i].get(); if (names) { - names->push_back(v->get_decl()->get_name()); + bound_names.push_back(v->get_decl()->get_name()); } - rep.insert(v, m.mk_var(index++,m.get_sort(v))); + if (sorts) { + bound_sorts.push_back(m.get_sort(v)); + } + rep.insert(v, m.mk_var(index++, m.get_sort(v))); + } + if (names && !bound_names.empty()) { + bound_names.reverse(); + bound_names.append(*names); + names->reset(); + names->append(bound_names); + } + if (sorts && !bound_sorts.empty()) { + bound_sorts.reverse(); + bound_sorts.append(*sorts); + sorts->reset(); + sorts->append(bound_sorts); } rep(fml); return index; @@ -270,6 +290,6 @@ void quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, app_ref_ m_impl->pull_quantifier(is_forall, fml, vars); } -unsigned quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, svector* names) { - return m_impl->pull_quantifier(is_forall, fml, names); +unsigned quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector* sorts, svector* names) { + return m_impl->pull_quantifier(is_forall, fml, sorts, names); } diff --git a/src/ast/rewriter/quant_hoist.h b/src/ast/rewriter/quant_hoist.h index 70a79a0e2..dc586d437 100644 --- a/src/ast/rewriter/quant_hoist.h +++ b/src/ast/rewriter/quant_hoist.h @@ -66,7 +66,7 @@ public: Return index of maximal variable. */ - unsigned pull_quantifier(bool is_forall, expr_ref& fml, svector* names); + unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector* sorts, svector* names); }; #endif diff --git a/src/muz_qe/dl_base.cpp b/src/muz_qe/dl_base.cpp index dd817754f..0f250d76c 100644 --- a/src/muz_qe/dl_base.cpp +++ b/src/muz_qe/dl_base.cpp @@ -233,7 +233,7 @@ namespace datalog { table_fact row; for(; it!=iend; ++it) { it->get_fact(row); - to_remove.append(row); + to_remove.push_back(row); } remove_facts(to_remove.size(), to_remove.c_ptr()); } diff --git a/src/muz_qe/dl_bmc_engine.cpp b/src/muz_qe/dl_bmc_engine.cpp index 200338b86..2961b3f54 100644 --- a/src/muz_qe/dl_bmc_engine.cpp +++ b/src/muz_qe/dl_bmc_engine.cpp @@ -307,7 +307,7 @@ namespace datalog { r1->to_formula(concl); scoped_proof _sp(m); - proof* p = m.mk_asserted(fml); + proof* p = r->get_proof(); proof* premises[2] = { pr, p }; positions.push_back(std::make_pair(0, 1)); @@ -320,7 +320,7 @@ namespace datalog { else { r2->to_formula(concl); scoped_proof _sp(m); - proof* p = m.mk_asserted(fml); + proof* p = r->get_proof(); if (sub.empty()) { pr = p; } @@ -340,7 +340,7 @@ namespace datalog { pred = r->get_decl(0); } scoped_proof _sp(m); - apply(m, b.m_pc.get(), pr); + apply(m, b.m_ctx.get_proof_converter().get(), pr); b.m_answer = pr; return l_true; } @@ -474,6 +474,9 @@ namespace datalog { } proof_ref get_proof(model_ref& md, func_decl* pred, app* prop, unsigned level) { + if (b.m_cancel) { + return proof_ref(0, m); + } TRACE("bmc", tout << "Predicate: " << pred->get_name() << "\n";); expr_ref prop_r(m), prop_v(m), fml(m), prop_body(m), tmp(m), body(m); @@ -497,7 +500,7 @@ namespace datalog { SASSERT(r); r->to_formula(fml); IF_VERBOSE(1, verbose_stream() << mk_pp(fml, m) << "\n";); - prs.push_back(m.mk_asserted(fml)); + prs.push_back(r->get_proof()); unsigned sz = r->get_uninterpreted_tail_size(); ptr_vector rule_vars; @@ -536,8 +539,9 @@ namespace datalog { model_ref md; b.m_solver.get_model(md); IF_VERBOSE(2, model_smt2_pp(verbose_stream(), m, *md, 0);); - proof_ref pr = get_proof(md, b.m_query_pred, to_app(level_query), level); - apply(m, b.m_pc.get(), pr); + proof_ref pr(m); + pr = get_proof(md, b.m_query_pred, to_app(level_query), level); + apply(m, b.m_ctx.get_proof_converter().get(), pr); b.m_answer = pr; } @@ -1034,7 +1038,7 @@ namespace datalog { var_subst vs(m, false); mk_subst(*rules[i], path, trace, sub); rules[i]->to_formula(fml); - prs.push_back(m.mk_asserted(fml)); + prs.push_back(rules[i]->get_proof()); unsigned sz = trace->get_num_args(); if (sub.empty() && sz == 0) { pr = prs[0].get(); @@ -1112,7 +1116,6 @@ namespace datalog { } void mk_answer(model_ref& md, expr_ref& trace, expr_ref& path) { - proof_ref pr(m); IF_VERBOSE(2, model_smt2_pp(verbose_stream(), m, *md, 0);); md->eval(trace, trace); md->eval(path, path); @@ -1120,7 +1123,11 @@ namespace datalog { for (unsigned i = 0; i < b.m_solver.size(); ++i) { verbose_stream() << mk_pp(b.m_solver.get_formulas()[i], m) << "\n"; }); - b.m_answer = get_proof(md, to_app(trace), to_app(path)); + scoped_proof _sp(m); + proof_ref pr(m); + pr = get_proof(md, to_app(trace), to_app(path)); + apply(m, b.m_ctx.get_proof_converter().get(), pr); + b.m_answer = pr; } }; @@ -1155,6 +1162,9 @@ namespace datalog { private: void get_model(unsigned level) { + if (b.m_cancel) { + return; + } rule_manager& rm = b.m_ctx.get_rule_manager(); expr_ref level_query = mk_level_predicate(b.m_query_pred, level); model_ref md; @@ -1212,7 +1222,7 @@ namespace datalog { r1->to_formula(concl); scoped_proof _sp(m); - proof* p = m.mk_asserted(fml); + proof* p = r->get_proof(); proof* premises[2] = { pr, p }; positions.push_back(std::make_pair(0, 1)); @@ -1225,7 +1235,7 @@ namespace datalog { else { r2->to_formula(concl); scoped_proof _sp(m); - proof* p = m.mk_asserted(fml); + proof* p = r->get_proof(); if (sub.empty()) { pr = p; } @@ -1245,7 +1255,7 @@ namespace datalog { pred = r->get_decl(0); } scoped_proof _sp(m); - apply(m, b.m_pc.get(), pr); + apply(m, b.m_ctx.get_proof_converter().get(), pr); b.m_answer = pr; } @@ -1409,6 +1419,7 @@ namespace datalog { m_ctx.ensure_opened(); m_rules.reset(); + datalog::rule_manager& rule_manager = m_ctx.get_rule_manager(); datalog::rule_set old_rules(m_ctx.get_rules()); datalog::rule_ref_vector query_rules(rule_manager); @@ -1417,11 +1428,8 @@ namespace datalog { m_ctx.add_rules(query_rules); expr_ref bg_assertion = m_ctx.get_background_assertion(); - model_converter_ref mc = datalog::mk_skip_model_converter(); - m_pc = datalog::mk_skip_proof_converter(); + m_ctx.set_output_predicate(m_query_pred); - m_ctx.set_model_converter(mc); - m_ctx.set_proof_converter(m_pc); m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { diff --git a/src/muz_qe/dl_bmc_engine.h b/src/muz_qe/dl_bmc_engine.h index 06901a160..5911f5f72 100644 --- a/src/muz_qe/dl_bmc_engine.h +++ b/src/muz_qe/dl_bmc_engine.h @@ -39,7 +39,6 @@ namespace datalog { func_decl_ref m_query_pred; expr_ref m_answer; volatile bool m_cancel; - proof_converter_ref m_pc; void checkpoint(); diff --git a/src/muz_qe/dl_cmds.cpp b/src/muz_qe/dl_cmds.cpp index c88e7346e..d49a8a671 100644 --- a/src/muz_qe/dl_cmds.cpp +++ b/src/muz_qe/dl_cmds.cpp @@ -262,8 +262,10 @@ public: case datalog::OK: break; + default: - UNREACHABLE(); + // exception was raised. + break; } break; } diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 839aa93f9..7d9fe8d7e 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -231,6 +231,7 @@ namespace datalog { m_rule_set(*this), m_rule_fmls(m), m_background(m), + m_mc(0), m_closed(false), m_saturation_was_run(false), m_last_answer(m), @@ -474,8 +475,11 @@ namespace datalog { void context::flush_add_rules() { datalog::rule_manager& rm = get_rule_manager(); datalog::rule_ref_vector rules(rm); + scoped_proof_mode _scp(m, generate_proof_trace()?PGM_FINE:PGM_DISABLED); for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { - rm.mk_rule(m_rule_fmls[i].get(), rules, m_rule_names[i]); + expr* fml = m_rule_fmls[i].get(); + proof* p = generate_proof_trace()?m.mk_asserted(fml):0; + rm.mk_rule(fml, p, rules, m_rule_names[i]); } add_rules(rules); m_rule_fmls.reset(); @@ -489,7 +493,11 @@ namespace datalog { void context::update_rule(expr* rl, symbol const& name) { datalog::rule_manager& rm = get_rule_manager(); datalog::rule_ref_vector rules(rm); - rm.mk_rule(rl, rules, name); + proof* p = 0; + if (generate_proof_trace()) { + p = m.mk_asserted(rl); + } + rm.mk_rule(rl, p, rules, name); if (rules.size() != 1) { std::stringstream strm; strm << "Rule " << name << " has a non-trivial body. It cannot be modified"; @@ -683,7 +691,7 @@ namespace datalog { todo.push_back(e2); } else if (is_quantifier(e)) { - todo.append(to_quantifier(e)->get_expr()); + todo.push_back(to_quantifier(e)->get_expr()); } else if ((m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) && m.is_true(e1)) { @@ -737,6 +745,9 @@ namespace datalog { UNREACHABLE(); break; } + if (generate_proof_trace() && !r->get_proof()) { + m_rule_manager.mk_rule_asserted_proof(*r.get()); + } } void context::add_rule(rule_ref& r) { @@ -847,7 +858,7 @@ namespace datalog { void context::transform_rules(rule_transformer& transf) { SASSERT(m_closed); //we must finish adding rules before we start transforming them TRACE("dl", display_rules(tout);); - if (transf(m_rule_set, m_mc, m_pc)) { + if (transf(m_rule_set, m_mc)) { //we have already ensured the negation is stratified and transformations //should not break the stratification m_rule_set.ensure_closed(); @@ -887,9 +898,9 @@ namespace datalog { m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34890)); m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880)); - m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); - m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); - m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 36010)); + m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 34870)); + m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 34860)); + m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 34850)); transform_rules(m_transf); } @@ -1035,6 +1046,8 @@ namespace datalog { } void context::new_query() { + m_mc = mk_skip_model_converter(); + flush_add_rules(); m_last_status = OK; m_last_answer = 0; @@ -1146,6 +1159,7 @@ namespace datalog { switch(get_engine()) { case DATALOG_ENGINE: return false; + case PDR_ENGINE: case QPDR_ENGINE: ensure_pdr(); m_pdr->display_certificate(out); @@ -1239,7 +1253,7 @@ namespace datalog { ptr_vector sorts; get_free_vars(m_rule_fmls[i].get(), sorts); if (!sorts.empty()) { - rm.mk_rule(m_rule_fmls[i].get(), rule_refs, m_rule_names[i]); + rm.mk_rule(m_rule_fmls[i].get(), 0, rule_refs, m_rule_names[i]); m_rule_fmls[i] = m_rule_fmls.back(); m_rule_names[i] = m_rule_names.back(); m_rule_fmls.pop_back(); @@ -1256,7 +1270,7 @@ namespace datalog { } for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { rules.push_back(m_rule_fmls[i].get()); - names.push_back(m_rule_names[i]); + names.push_back(m_rule_names[i]); } } diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index f9a1f1737..778cccc0c 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -42,7 +42,6 @@ Revision History: #include"params.h" #include"trail.h" #include"model_converter.h" -#include"proof_converter.h" #include"model2expr.h" #include"smt_params.h" #include"dl_rule_transformer.h" @@ -142,6 +141,7 @@ namespace datalog { var_subst & get_var_subst() { return m_var_subst; } dl_decl_util & get_decl_util() { return m_decl_util; } + bool generate_proof_trace() const { return m_params.generate_proof_trace(); } bool output_profile() const { return m_params.output_profile(); } bool fix_unbound_vars() const { return m_params.fix_unbound_vars(); } symbol default_table() const { return m_params.default_table(); } @@ -315,14 +315,15 @@ namespace datalog { void reopen(); void ensure_opened(); - void set_model_converter(model_converter_ref& mc) { m_mc = mc; } - void set_proof_converter(proof_converter_ref& pc) { m_pc = pc; } + model_converter_ref& get_model_converter() { return m_mc; } + proof_converter_ref& get_proof_converter() { return m_pc; } + void add_proof_converter(proof_converter* pc) { m_pc = concat(m_pc.get(), pc); } - void transform_rules(); // model_converter_ref& mc, proof_converter_ref& pc); - void transform_rules(rule_transformer& transf); // , model_converter_ref& mc, proof_converter_ref& pc); + void transform_rules(); + void transform_rules(rule_transformer& transf); void replace_rules(rule_set & rs); - void apply_default_transformation(); // model_converter_ref& mc, proof_converter_ref& pc); + void apply_default_transformation(); void collect_params(param_descrs& r); diff --git a/src/muz_qe/dl_mk_array_blast.cpp b/src/muz_qe/dl_mk_array_blast.cpp index b22fdf7ef..537b0b5ac 100644 --- a/src/muz_qe/dl_mk_array_blast.cpp +++ b/src/muz_qe/dl_mk_array_blast.cpp @@ -197,25 +197,18 @@ namespace datalog { } fml2 = m.mk_implies(body, head); - rm.mk_rule(fml2, new_rules, r.name()); + proof_ref p(m); + rm.mk_rule(fml2, p, new_rules, r.name()); SASSERT(new_rules.size() == 1); TRACE("dl", new_rules[0]->display(m_ctx, tout << "new rule\n");); rules.add_rule(new_rules[0].get()); - if (m_pc) { - new_rules[0]->to_formula(fml2); - m_pc->insert(fml1, fml2); - } + rm.mk_rule_rewrite_proof(r, *new_rules[0].get()); return true; } - rule_set * mk_array_blast::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - ref epc; - if (pc) { - epc = alloc(equiv_proof_converter, m); - } - m_pc = epc.get(); + rule_set * mk_array_blast::operator()(rule_set const & source, model_converter_ref& mc) { rule_set* rules = alloc(rule_set, m_ctx); rule_set::iterator it = source.begin(), end = source.end(); @@ -227,9 +220,6 @@ namespace datalog { dealloc(rules); rules = 0; } - if (pc) { - pc = concat(pc.get(), epc.get()); - } return rules; } diff --git a/src/muz_qe/dl_mk_array_blast.h b/src/muz_qe/dl_mk_array_blast.h index c0bb39da0..94eb64601 100644 --- a/src/muz_qe/dl_mk_array_blast.h +++ b/src/muz_qe/dl_mk_array_blast.h @@ -37,7 +37,6 @@ namespace datalog { rule_manager& rm; params_ref m_params; th_rewriter m_rewriter; - equiv_proof_converter* m_pc; typedef obj_map defs_t; @@ -55,7 +54,7 @@ namespace datalog { virtual ~mk_array_blast(); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index 1fa93a0ca..1e984f254 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -21,7 +21,8 @@ Revision History: #include "bit_blaster_rewriter.h" #include "rewriter_def.h" #include "ast_pp.h" - +#include "expr_safe_replace.h" +#include "filter_model_converter.h" namespace datalog { @@ -35,6 +36,73 @@ namespace datalog { // P(bv(x,y)) :- P_bv(x,y) // Query + // this model converter should be composed with a filter converter + // that gets rid of the new functions. + class bit_blast_model_converter : public model_converter { + ast_manager& m; + bv_util m_bv; + func_decl_ref_vector m_old_funcs; + func_decl_ref_vector m_new_funcs; + public: + bit_blast_model_converter(ast_manager& m): + m(m), + m_bv(m), + m_old_funcs(m), + m_new_funcs(m) {} + + void insert(func_decl* old_f, func_decl* new_f) { + m_old_funcs.push_back(old_f); + m_new_funcs.push_back(new_f); + } + + virtual model_converter * translate(ast_translation & translator) { + return alloc(bit_blast_model_converter, m); + } + + virtual void operator()(model_ref & model) { + for (unsigned i = 0; i < m_new_funcs.size(); ++i) { + func_decl* p = m_new_funcs[i].get(); + func_decl* q = m_old_funcs[i].get(); + func_interp* f = model->get_func_interp(p); + expr_ref body(m); + unsigned arity_p = p->get_arity(); + unsigned arity_q = q->get_arity(); + SASSERT(0 < arity_p); + model->register_decl(p, f); + func_interp* g = alloc(func_interp, m, arity_q); + + if (f) { + body = f->get_interp(); + SASSERT(!f->is_partial()); + SASSERT(body); + } + else { + body = m.mk_false(); + } + unsigned idx = 0; + expr_ref arg(m), proj(m); + expr_safe_replace sub(m); + for (unsigned j = 0; j < arity_q; ++j) { + sort* s = q->get_domain(j); + arg = m.mk_var(j, s); + if (m_bv.is_bv_sort(s)) { + expr* args[1] = { arg }; + unsigned sz = m_bv.get_bv_size(s); + for (unsigned k = 0; k < sz; ++k) { + proj = m.mk_app(m_bv.get_family_id(), OP_BIT2BOOL, 1, args); + sub.insert(m.mk_var(idx++, m.mk_bool_sort()), proj); + } + } + else { + sub.insert(m.mk_var(idx++, s), arg); + } + } + sub(body); + g->set_else(body); + model->register_decl(q, g); + } + } + }; class expand_mkbv_cfg : public default_rewriter_cfg { @@ -43,7 +111,8 @@ namespace datalog { ast_manager& m; bv_util m_util; expr_ref_vector m_args, m_f_vars, m_g_vars; - func_decl_ref_vector m_pinned; + func_decl_ref_vector m_old_funcs; + func_decl_ref_vector m_new_funcs; obj_map m_pred2blast; @@ -57,10 +126,14 @@ namespace datalog { m_args(m), m_f_vars(m), m_g_vars(m), - m_pinned(m) + m_old_funcs(m), + m_new_funcs(m) {} ~expand_mkbv_cfg() {} + + func_decl_ref_vector const& old_funcs() const { return m_old_funcs; } + 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) { rule_manager& rm = m_context.get_rule_manager(); @@ -105,13 +178,18 @@ namespace datalog { domain.push_back(m.get_sort(m_args[i].get())); } g = m_context.mk_fresh_head_predicate(f->get_name(), symbol("bv"), m_args.size(), domain.c_ptr(), f); - m_pinned.push_back(g); + m_old_funcs.push_back(f); + m_new_funcs.push_back(g); m_pred2blast.insert(f, g); // Create rule f(mk_mkbv(args)) :- g(args) fml = m.mk_implies(m.mk_app(g, m_g_vars.size(), m_g_vars.c_ptr()), m.mk_app(f, m_f_vars.size(), m_f_vars.c_ptr())); - rm.mk_rule(fml, m_rules, g->get_name()); + proof_ref pr(m); + if (m_context.generate_proof_trace()) { + pr = m.mk_asserted(fml); // or a def? + } + rm.mk_rule(fml, pr, m_rules, g->get_name()); } result = m.mk_app(g, m_args.size(), m_args.c_ptr()); result_pr = 0; @@ -170,14 +248,11 @@ namespace datalog { m_blaster.updt_params(m_params); } - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - // TODO mc, pc + rule_set * operator()(rule_set const & source, model_converter_ref& mc) { + // TODO pc if (!m_context.get_params().bit_blast()) { return 0; } - if (m_context.get_engine() != PDR_ENGINE) { - return 0; - } rule_manager& rm = m_context.get_rule_manager(); unsigned sz = source.get_num_rules(); expr_ref fml(m); @@ -185,9 +260,13 @@ namespace datalog { rule_set * result = alloc(rule_set, m_context); for (unsigned i = 0; i < sz; ++i) { rule * r = source.get_rule(i); - r->to_formula(fml); + r->to_formula(fml); if (blast(fml)) { - rm.mk_rule(fml, m_rules, r->name()); + proof_ref pr(m); + if (m_context.generate_proof_trace()) { + pr = m.mk_asserted(fml); // loses original proof of r. + } + rm.mk_rule(fml, pr, m_rules, r->name()); } else { m_rules.push_back(r); @@ -197,6 +276,18 @@ namespace datalog { for (unsigned i = 0; i < m_rules.size(); ++i) { result->add_rule(m_rules.get(i)); } + + if (mc) { + filter_model_converter* fmc = alloc(filter_model_converter, m); + bit_blast_model_converter* bvmc = alloc(bit_blast_model_converter, m); + func_decl_ref_vector const& old_funcs = m_rewriter.m_cfg.old_funcs(); + func_decl_ref_vector const& new_funcs = m_rewriter.m_cfg.new_funcs(); + for (unsigned i = 0; i < old_funcs.size(); ++i) { + fmc->insert(new_funcs[i]); + bvmc->insert(old_funcs[i], new_funcs[i]); + } + mc = concat(mc.get(), concat(bvmc, fmc)); + } return result; } @@ -210,8 +301,8 @@ namespace datalog { dealloc(m_impl); } - rule_set * mk_bit_blast::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - return (*m_impl)(source, mc, pc); + rule_set * mk_bit_blast::operator()(rule_set const & source, model_converter_ref& mc) { + return (*m_impl)(source, mc); } }; diff --git a/src/muz_qe/dl_mk_bit_blast.h b/src/muz_qe/dl_mk_bit_blast.h index e16c2058b..3a6de75e3 100644 --- a/src/muz_qe/dl_mk_bit_blast.h +++ b/src/muz_qe/dl_mk_bit_blast.h @@ -44,7 +44,7 @@ namespace datalog { mk_bit_blast(context & ctx, unsigned priority = 35000); ~mk_bit_blast(); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_coalesce.cpp b/src/muz_qe/dl_mk_coalesce.cpp index 222881bc4..de5388312 100644 --- a/src/muz_qe/dl_mk_coalesce.cpp +++ b/src/muz_qe/dl_mk_coalesce.cpp @@ -133,7 +133,7 @@ namespace datalog { tail.push_back(to_app(fml)); is_neg.push_back(false); res = rm.mk(head, tail.size(), tail.c_ptr(), is_neg.c_ptr(), tgt->name()); - if (m_pc) { + if (m_ctx.generate_proof_trace()) { src.to_formula(fml1); tgt->to_formula(fml2); res->to_formula(fml); @@ -142,12 +142,13 @@ namespace datalog { sort* domain[3] = { ps, ps, m.mk_bool_sort() }; func_decl* merge = m.mk_func_decl(symbol("merge-clauses"), 3, domain, ps); // TBD: ad-hoc proof rule expr* args[3] = { m.mk_asserted(fml1), m.mk_asserted(fml2), fml }; - m_pc->insert(m.mk_app(merge, 3, args)); + // ...m_pc->insert(m.mk_app(merge, 3, args)); #else svector > pos; vector substs; - proof* p = m.mk_asserted(fml1); - m_pc->insert(m.mk_hyper_resolve(1, &p, fml, pos, substs)); + proof* p = src.get_proof(); + p = m.mk_hyper_resolve(1, &p, fml, pos, substs); + res->set_proof(m, p); #endif } tgt = res; @@ -170,13 +171,7 @@ namespace datalog { return true; } - rule_set * mk_coalesce::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - m_pc = 0; - ref rpc; - if (pc) { - rpc = alloc(replace_proof_converter, m); - m_pc = rpc.get(); - } + rule_set * mk_coalesce::operator()(rule_set const & source, model_converter_ref& mc) { rule_set* rules = alloc(rule_set, m_ctx); rule_set::decl2rules::iterator it = source.begin_grouped_rules(), end = source.end_grouped_rules(); for (; it != end; ++it) { @@ -195,9 +190,6 @@ namespace datalog { rules->add_rule(r1.get()); } } - if (pc) { - pc = concat(pc.get(), rpc.get()); - } return rules; } diff --git a/src/muz_qe/dl_mk_coalesce.h b/src/muz_qe/dl_mk_coalesce.h index 4259d31fe..ab0b74479 100644 --- a/src/muz_qe/dl_mk_coalesce.h +++ b/src/muz_qe/dl_mk_coalesce.h @@ -37,7 +37,6 @@ namespace datalog { rule_manager& rm; expr_ref_vector m_sub1, m_sub2; unsigned m_idx; - replace_proof_converter* m_pc; void mk_pred(app_ref& pred, app* p1, app* p2); @@ -53,7 +52,7 @@ namespace datalog { */ mk_coalesce(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_coi_filter.cpp b/src/muz_qe/dl_mk_coi_filter.cpp index 04d654120..915dd4306 100644 --- a/src/muz_qe/dl_mk_coi_filter.cpp +++ b/src/muz_qe/dl_mk_coi_filter.cpp @@ -35,8 +35,7 @@ namespace datalog { rule_set * mk_coi_filter::operator()( rule_set const & source, - model_converter_ref& mc, - proof_converter_ref& pc) + model_converter_ref& mc) { if (source.get_num_rules()==0) { return 0; diff --git a/src/muz_qe/dl_mk_coi_filter.h b/src/muz_qe/dl_mk_coi_filter.h index b8fb37964..2191048d3 100644 --- a/src/muz_qe/dl_mk_coi_filter.h +++ b/src/muz_qe/dl_mk_coi_filter.h @@ -40,8 +40,7 @@ namespace datalog { rule_set * operator()(rule_set const & source, - model_converter_ref& mc, - proof_converter_ref& pc); + model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_explanations.cpp b/src/muz_qe/dl_mk_explanations.cpp index 464ec838e..af5b1d97a 100644 --- a/src/muz_qe/dl_mk_explanations.cpp +++ b/src/muz_qe/dl_mk_explanations.cpp @@ -875,8 +875,8 @@ namespace datalog { } } - rule_set * mk_explanations::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - SASSERT(!mc && !pc); + rule_set * mk_explanations::operator()(rule_set const & source, model_converter_ref& mc) { + SASSERT(!mc); if(source.get_num_rules()==0) { return 0; } diff --git a/src/muz_qe/dl_mk_explanations.h b/src/muz_qe/dl_mk_explanations.h index 36fb1a3a1..40606f8df 100644 --- a/src/muz_qe/dl_mk_explanations.h +++ b/src/muz_qe/dl_mk_explanations.h @@ -82,7 +82,7 @@ namespace datalog { return get_union_decl(m_context); } - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); static expr* get_explanation(relation_base const& r); }; diff --git a/src/muz_qe/dl_mk_extract_quantifiers.cpp b/src/muz_qe/dl_mk_extract_quantifiers.cpp index 35f7485d5..a3d5cc2ab 100644 --- a/src/muz_qe/dl_mk_extract_quantifiers.cpp +++ b/src/muz_qe/dl_mk_extract_quantifiers.cpp @@ -168,7 +168,15 @@ namespace datalog { fml = m.mk_implies(m.mk_and(fmls.size(), fmls.c_ptr()), r.get_head()); TRACE("dl", tout << "new rule\n" << mk_pp(fml, m) << "\n";); rule_ref_vector rules(rm); - rm.mk_rule(fml, rules, r.name()); + proof_ref pr(m); + if (m_ctx.generate_proof_trace()) { + scoped_proof _scp(m); + expr_ref fml1(m); + r.to_formula(fml1); + pr = m.mk_rewrite(fml1, fml); + pr = m.mk_modus_ponens(r.get_proof(), pr); + } + rm.mk_rule(fml, pr, rules, r.name()); for (unsigned i = 0; i < rules.size(); ++i) { new_rules.add_rule(rules[i].get()); m_quantifiers.insert(rules[i].get(), alloc(quantifier_ref_vector, qs)); @@ -347,7 +355,7 @@ namespace datalog { m_quantifiers.reset(); } - rule_set * mk_extract_quantifiers::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { + rule_set * mk_extract_quantifiers::operator()(rule_set const & source, model_converter_ref& mc) { reset(); rule_set::iterator it = source.begin(), end = source.end(); for (; !m_has_quantifiers && it != end; ++it) { diff --git a/src/muz_qe/dl_mk_extract_quantifiers.h b/src/muz_qe/dl_mk_extract_quantifiers.h index b32dbc32d..7d2f7b149 100644 --- a/src/muz_qe/dl_mk_extract_quantifiers.h +++ b/src/muz_qe/dl_mk_extract_quantifiers.h @@ -77,7 +77,7 @@ namespace datalog { void set_query(func_decl* q); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); bool has_quantifiers() { return m_has_quantifiers; } diff --git a/src/muz_qe/dl_mk_filter_rules.cpp b/src/muz_qe/dl_mk_filter_rules.cpp index 4f01a3651..46fde4bc2 100644 --- a/src/muz_qe/dl_mk_filter_rules.cpp +++ b/src/muz_qe/dl_mk_filter_rules.cpp @@ -90,6 +90,7 @@ namespace datalog { rule * filter_rule = m_context.get_rule_manager().mk(filter_head, 1, &filter_tail, (const bool *)0); filter_rule->set_accounting_parent_object(m_context, m_current); m_result->add_rule(filter_rule); + m_context.get_rule_manager().mk_rule_asserted_proof(*filter_rule); } else { dealloc(key); @@ -135,12 +136,13 @@ namespace datalog { } new_is_negated.push_back(r->is_neg_tail(i)); } - if(rule_modified) { + if (rule_modified) { remove_duplicate_tails(new_tail, new_is_negated); SASSERT(new_tail.size() == new_is_negated.size()); rule * new_rule = m_context.get_rule_manager().mk(new_head, new_tail.size(), new_tail.c_ptr(), new_is_negated.c_ptr()); new_rule->set_accounting_parent_object(m_context, m_current); m_result->add_rule(new_rule); + m_context.get_rule_manager().mk_rule_rewrite_proof(*r, *new_rule); m_modified = true; } else { @@ -148,7 +150,7 @@ namespace datalog { } } - rule_set * mk_filter_rules::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { + rule_set * mk_filter_rules::operator()(rule_set const & source, model_converter_ref& mc) { // TODO mc, pc m_tail2filter.reset(); m_result = alloc(rule_set, m_context); diff --git a/src/muz_qe/dl_mk_filter_rules.h b/src/muz_qe/dl_mk_filter_rules.h index cd1d10997..daa72e36f 100644 --- a/src/muz_qe/dl_mk_filter_rules.h +++ b/src/muz_qe/dl_mk_filter_rules.h @@ -72,7 +72,7 @@ namespace datalog { /** \brief Return a new rule set where only filter rules contain atoms with repeated variables and/or values. */ - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp index d1b7f15dd..a48b7b32f 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp @@ -554,11 +554,13 @@ namespace datalog { bool mk_interp_tail_simplifier::transform_rules(const rule_set & orig, rule_set & tgt) { bool modified = false; + rule_manager& rm = m_context.get_rule_manager(); rule_set::iterator rit = orig.begin(); rule_set::iterator rend = orig.end(); for (; rit!=rend; ++rit) { - rule_ref new_rule(m_context.get_rule_manager()); + rule_ref new_rule(rm); if (transform_rule(*rit, new_rule)) { + rm.mk_rule_rewrite_proof(**rit, *new_rule.get()); bool is_modified = *rit != new_rule; modified |= is_modified; tgt.add_rule(new_rule); @@ -570,8 +572,7 @@ namespace datalog { return modified; } - rule_set * mk_interp_tail_simplifier::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - // TODO mc, pc + rule_set * mk_interp_tail_simplifier::operator()(rule_set const & source, model_converter_ref& mc) { if (source.get_num_rules() == 0) { return 0; } diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.h b/src/muz_qe/dl_mk_interp_tail_simplifier.h index 5e4fd8fbc..4cb14914a 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.h +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.h @@ -93,7 +93,7 @@ namespace datalog { */ bool transform_rule(rule * r, rule_ref& res); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 9c034c890..18b152589 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -310,7 +310,7 @@ namespace datalog { m_hb.reset(); for (unsigned i = 0; i < src.size(); ++i) { vector v(src.A[i]); - v.append(src.b[i]); + v.push_back(src.b[i]); if (src.eq[i]) { m_hb.add_eq(v, rational(0)); } @@ -420,6 +420,7 @@ namespace datalog { new_rule = rm.mk(r.get_head(), tail.size(), tail.c_ptr(), 0, r.name()); } rules.add_rule(new_rule); + rm.mk_rule_rewrite_proof(r, *new_rule); // should be weakening rule. } class mk_karr_invariants::add_invariant_model_converter : public model_converter { @@ -519,7 +520,7 @@ namespace datalog { m_hb.set_cancel(true); } - rule_set * mk_karr_invariants::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { + rule_set * mk_karr_invariants::operator()(rule_set const & source, model_converter_ref& mc) { if (!m_ctx.get_params().karr()) { return 0; } diff --git a/src/muz_qe/dl_mk_karr_invariants.h b/src/muz_qe/dl_mk_karr_invariants.h index 3b82578a4..7cd26d495 100644 --- a/src/muz_qe/dl_mk_karr_invariants.h +++ b/src/muz_qe/dl_mk_karr_invariants.h @@ -69,7 +69,7 @@ namespace datalog { virtual void cancel(); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; diff --git a/src/muz_qe/dl_mk_magic_sets.cpp b/src/muz_qe/dl_mk_magic_sets.cpp index 373a90969..990040ab8 100644 --- a/src/muz_qe/dl_mk_magic_sets.cpp +++ b/src/muz_qe/dl_mk_magic_sets.cpp @@ -317,8 +317,8 @@ namespace datalog { m_rules.push_back(r); } - rule_set * mk_magic_sets::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - SASSERT(!mc && !pc); + rule_set * mk_magic_sets::operator()(rule_set const & source, model_converter_ref& mc) { + SASSERT(!mc); unsigned init_rule_cnt = source.get_num_rules(); { func_decl_set intentional; diff --git a/src/muz_qe/dl_mk_magic_sets.h b/src/muz_qe/dl_mk_magic_sets.h index f98ad55a3..3f50e6713 100644 --- a/src/muz_qe/dl_mk_magic_sets.h +++ b/src/muz_qe/dl_mk_magic_sets.h @@ -121,7 +121,7 @@ namespace datalog { */ mk_magic_sets(context & ctx, rule * goal_rule); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_partial_equiv.cpp b/src/muz_qe/dl_mk_partial_equiv.cpp index 367a15743..b55f5294e 100644 --- a/src/muz_qe/dl_mk_partial_equiv.cpp +++ b/src/muz_qe/dl_mk_partial_equiv.cpp @@ -86,8 +86,8 @@ namespace datalog { } - rule_set * mk_partial_equivalence_transformer::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - // TODO mc, pc + rule_set * mk_partial_equivalence_transformer::operator()(rule_set const & source, model_converter_ref& mc) { + // TODO mc if (source.get_num_rules() == 0) { return 0; diff --git a/src/muz_qe/dl_mk_partial_equiv.h b/src/muz_qe/dl_mk_partial_equiv.h index 8fef4aea9..c44d59e8c 100644 --- a/src/muz_qe/dl_mk_partial_equiv.h +++ b/src/muz_qe/dl_mk_partial_equiv.h @@ -35,7 +35,7 @@ namespace datalog { m(ctx.get_manager()), m_context(ctx) {} - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); private: diff --git a/src/muz_qe/dl_mk_rule_inliner.cpp b/src/muz_qe/dl_mk_rule_inliner.cpp index 1404c9c8c..047ed768f 100644 --- a/src/muz_qe/dl_mk_rule_inliner.cpp +++ b/src/muz_qe/dl_mk_rule_inliner.cpp @@ -181,10 +181,10 @@ namespace datalog { } if (m_unifier.apply(tgt, tail_index, src, res)) { - if (m_pc) { + if (m_context.generate_proof_trace()) { expr_ref_vector s1 = m_unifier.get_rule_subst(tgt, true); expr_ref_vector s2 = m_unifier.get_rule_subst(src, false); - datalog::resolve_rule(m_pc, tgt, src, tail_index, s1, s2, *res.get()); + datalog::resolve_rule(tgt, src, tail_index, s1, s2, *res.get()); } return true; } @@ -837,11 +837,10 @@ namespace datalog { return done_something; } - rule_set * mk_rule_inliner::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { + rule_set * mk_rule_inliner::operator()(rule_set const & source, model_converter_ref& mc) { bool something_done = false; ref hsmc; - ref hpc; if (source.get_num_rules() == 0) { return 0; @@ -858,11 +857,7 @@ namespace datalog { if (mc) { hsmc = alloc(horn_subsume_model_converter, m); } - if (pc) { - hpc = alloc(replace_proof_converter, m); - } m_mc = hsmc.get(); - m_pc = hpc.get(); scoped_ptr res = alloc(rule_set, m_context); @@ -889,9 +884,6 @@ namespace datalog { if (mc) { mc = concat(mc.get(), hsmc.get()); } - if (pc) { - pc = concat(pc.get(), hpc.get()); - } } return res.detach(); diff --git a/src/muz_qe/dl_mk_rule_inliner.h b/src/muz_qe/dl_mk_rule_inliner.h index 6d5448cd6..a58b3b473 100644 --- a/src/muz_qe/dl_mk_rule_inliner.h +++ b/src/muz_qe/dl_mk_rule_inliner.h @@ -114,7 +114,6 @@ namespace datalog { ast_counter m_tail_pred_ctr; rule_set m_inlined_rules; horn_subsume_model_converter* m_mc; - replace_proof_converter* m_pc; //used in try_to_inline_rule and do_eager_inlining @@ -188,7 +187,6 @@ namespace datalog { m_pinned(m_rm), m_inlined_rules(m_context), m_mc(0), - m_pc(0), m_unifier(ctx), m_head_index(m), m_tail_index(m), @@ -198,7 +196,7 @@ namespace datalog { {} virtual ~mk_rule_inliner() { } - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_similarity_compressor.cpp b/src/muz_qe/dl_mk_similarity_compressor.cpp index a040a623a..dfd0a4d81 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.cpp +++ b/src/muz_qe/dl_mk_similarity_compressor.cpp @@ -500,8 +500,8 @@ namespace datalog { } } - rule_set * mk_similarity_compressor::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - // TODO mc, pc + rule_set * mk_similarity_compressor::operator()(rule_set const & source, model_converter_ref& mc) { + // TODO mc m_modified = false; unsigned init_rule_cnt = source.get_num_rules(); SASSERT(m_rules.empty()); diff --git a/src/muz_qe/dl_mk_similarity_compressor.h b/src/muz_qe/dl_mk_similarity_compressor.h index ad4a5e246..d1ded01e7 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.h +++ b/src/muz_qe/dl_mk_similarity_compressor.h @@ -69,7 +69,7 @@ namespace datalog { public: mk_similarity_compressor(context & ctx, unsigned threshold_count); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_simple_joins.cpp b/src/muz_qe/dl_mk_simple_joins.cpp index 77c6c2951..f19e34fec 100644 --- a/src/muz_qe/dl_mk_simple_joins.cpp +++ b/src/muz_qe/dl_mk_simple_joins.cpp @@ -706,19 +706,20 @@ namespace datalog { negs.c_ptr()); new_rule->set_accounting_parent_object(m_context, orig_r); - + m_context.get_rule_manager().mk_rule_rewrite_proof(*orig_r, *new_rule); result->add_rule(new_rule); } - while(!m_introduced_rules.empty()) { + while (!m_introduced_rules.empty()) { result->add_rule(m_introduced_rules.back()); + m_context.get_rule_manager().mk_rule_asserted_proof(*m_introduced_rules.back()); m_introduced_rules.pop_back(); } return result; } }; - rule_set * mk_simple_joins::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - // TODO mc, pc + rule_set * mk_simple_joins::operator()(rule_set const & source, model_converter_ref& mc) { + // TODO mc rule_set rs_aux_copy(m_context); rs_aux_copy.add_rules(source); if(!rs_aux_copy.is_closed()) { diff --git a/src/muz_qe/dl_mk_simple_joins.h b/src/muz_qe/dl_mk_simple_joins.h index 5431c4117..df8d3f55c 100644 --- a/src/muz_qe/dl_mk_simple_joins.h +++ b/src/muz_qe/dl_mk_simple_joins.h @@ -53,7 +53,7 @@ namespace datalog { public: mk_simple_joins(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_slice.cpp b/src/muz_qe/dl_mk_slice.cpp index 84b732280..0adab78ce 100644 --- a/src/muz_qe/dl_mk_slice.cpp +++ b/src/muz_qe/dl_mk_slice.cpp @@ -164,10 +164,8 @@ namespace datalog { TRACE("dl", tout << "does not have fact\n" << mk_pp(fact, m) << "\n";); return false; } - expr_ref fml(m); proof_ref new_p(m); - r->to_formula(fml); - new_p = m.mk_asserted(fml); + new_p = r->get_proof(); m_pinned_exprs.push_back(new_p); m_todo.pop_back(); m_new_proof.insert(p, new_p); @@ -784,6 +782,9 @@ namespace datalog { rm.fix_unbound_vars(new_rule, false); TRACE("dl", r.display(m_ctx, tout << "replacing:\n"); new_rule->display(m_ctx, tout << "by:\n");); + if (m_ctx.generate_proof_trace()) { + rm.mk_rule_asserted_proof(*new_rule.get()); + } } else { new_rule = &r; @@ -801,7 +802,7 @@ namespace datalog { } } - rule_set * mk_slice::operator()(rule_set const & src, model_converter_ref& mc, proof_converter_ref& pc) { + rule_set * mk_slice::operator()(rule_set const & src, model_converter_ref& mc) { for (unsigned i = 0; i < src.get_num_rules(); ++i) { if (src.get_rule(i)->has_quantifiers()) { return 0; @@ -809,8 +810,8 @@ namespace datalog { } ref spc; ref smc; - if (pc) { - spc = alloc(slice_proof_converter, m_ctx); + if (m_ctx.generate_proof_trace()) { + spc = alloc(slice_proof_converter, m_ctx); } if (mc) { smc = alloc(slice_model_converter, *this, m); @@ -834,7 +835,7 @@ namespace datalog { m_mc->add_sliceable(it->m_key, it->m_value); } } - pc = concat(pc.get(), spc.get()); + m_ctx.add_proof_converter(spc.get()); mc = concat(mc.get(), smc.get()); return result; } diff --git a/src/muz_qe/dl_mk_slice.h b/src/muz_qe/dl_mk_slice.h index 26a8175f2..4290ee4b9 100644 --- a/src/muz_qe/dl_mk_slice.h +++ b/src/muz_qe/dl_mk_slice.h @@ -102,7 +102,7 @@ namespace datalog { virtual ~mk_slice() { } - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); func_decl* get_predicate(func_decl* p) { func_decl* q = p; m_predicates.find(p, q); return q; } diff --git a/src/muz_qe/dl_mk_subsumption_checker.cpp b/src/muz_qe/dl_mk_subsumption_checker.cpp index 19c28c036..2f0d56475 100644 --- a/src/muz_qe/dl_mk_subsumption_checker.cpp +++ b/src/muz_qe/dl_mk_subsumption_checker.cpp @@ -166,7 +166,8 @@ namespace datalog { res = m_context.get_rule_manager().mk(head, tail.size(), tail.c_ptr(), tail_neg.c_ptr()); res->set_accounting_parent_object(m_context, r); m_context.get_rule_manager().fix_unbound_vars(res, true); - + m_context.get_rule_manager().mk_rule_rewrite_proof(*r, *res.get()); + return true; } @@ -208,10 +209,10 @@ namespace datalog { continue; } rule * defining_rule; - TRUSTME(m_total_relation_defining_rules.find(head_pred, defining_rule)); - if(defining_rule) { + VERIFY(m_total_relation_defining_rules.find(head_pred, defining_rule)); + if (defining_rule) { rule_ref totality_rule(m_context.get_rule_manager()); - TRUSTME(transform_rule(defining_rule, subs_index, totality_rule)); + VERIFY(transform_rule(defining_rule, subs_index, totality_rule)); if(defining_rule!=totality_rule) { modified = true; } @@ -331,8 +332,8 @@ namespace datalog { } } - rule_set * mk_subsumption_checker::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - // TODO mc, pc + rule_set * mk_subsumption_checker::operator()(rule_set const & source, model_converter_ref& mc) { + // TODO mc m_have_new_total_rule = false; collect_ground_unconditional_rule_heads(source); diff --git a/src/muz_qe/dl_mk_subsumption_checker.h b/src/muz_qe/dl_mk_subsumption_checker.h index ce33e7574..a95f08c5d 100644 --- a/src/muz_qe/dl_mk_subsumption_checker.h +++ b/src/muz_qe/dl_mk_subsumption_checker.h @@ -84,7 +84,7 @@ namespace datalog { reset_dealloc_values(m_ground_unconditional_rule_heads); } - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_unbound_compressor.cpp b/src/muz_qe/dl_mk_unbound_compressor.cpp index e3db82759..54b6f4ebe 100644 --- a/src/muz_qe/dl_mk_unbound_compressor.cpp +++ b/src/muz_qe/dl_mk_unbound_compressor.cpp @@ -238,6 +238,7 @@ namespace datalog { unsigned new_rule_index = m_rules.size(); m_rules.push_back(new_rule); + m_context.get_rule_manager().mk_rule_rewrite_proof(*r, *new_rule.get()); m_head_occurrence_ctr.inc(new_rule->get_head()->get_decl()); @@ -333,8 +334,8 @@ namespace datalog { } } - rule_set * mk_unbound_compressor::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - // TODO mc, pc + rule_set * mk_unbound_compressor::operator()(rule_set const & source, model_converter_ref& mc) { + // TODO mc m_modified = false; m_context.get_rel_context().get_rmanager().collect_non_empty_predicates(m_non_empty_rels); diff --git a/src/muz_qe/dl_mk_unbound_compressor.h b/src/muz_qe/dl_mk_unbound_compressor.h index 0e13bad75..256be180d 100644 --- a/src/muz_qe/dl_mk_unbound_compressor.h +++ b/src/muz_qe/dl_mk_unbound_compressor.h @@ -82,7 +82,7 @@ namespace datalog { public: mk_unbound_compressor(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_unfold.cpp b/src/muz_qe/dl_mk_unfold.cpp index d26a0a290..7af82110a 100644 --- a/src/muz_qe/dl_mk_unfold.cpp +++ b/src/muz_qe/dl_mk_unfold.cpp @@ -42,29 +42,20 @@ namespace datalog { if (m_unify.unify_rules(r, tail_idx, r2) && m_unify.apply(r, tail_idx, r2, new_rule)) { expr_ref_vector s1 = m_unify.get_rule_subst(r, true); - expr_ref_vector s2 = m_unify.get_rule_subst(r2, false); - resolve_rule(m_pc, r, r2, tail_idx, s1, s2, *new_rule.get()); + expr_ref_vector s2 = m_unify.get_rule_subst(r2, false); + resolve_rule(r, r2, tail_idx, s1, s2, *new_rule.get()); expand_tail(*new_rule.get(), tail_idx+r2.get_uninterpreted_tail_size(), src, dst); } } } } - rule_set * mk_unfold::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - m_pc = 0; - ref rpc; - if (pc) { - rpc = alloc(replace_proof_converter, m); - m_pc = rpc.get(); - } + rule_set * mk_unfold::operator()(rule_set const & source, model_converter_ref& mc) { rule_set* rules = alloc(rule_set, m_ctx); rule_set::iterator it = source.begin(), end = source.end(); for (; it != end; ++it) { expand_tail(**it, 0, source, *rules); } - if (pc) { - pc = concat(pc.get(), rpc.get()); - } return rules; } diff --git a/src/muz_qe/dl_mk_unfold.h b/src/muz_qe/dl_mk_unfold.h index 3d20686a7..90aefa86e 100644 --- a/src/muz_qe/dl_mk_unfold.h +++ b/src/muz_qe/dl_mk_unfold.h @@ -35,7 +35,6 @@ namespace datalog { ast_manager& m; rule_manager& rm; rule_unifier m_unify; - replace_proof_converter* m_pc; void expand_tail(rule& r, unsigned tail_idx, rule_set const& src, rule_set& dst); @@ -45,7 +44,7 @@ namespace datalog { */ mk_unfold(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index 59a245cc4..1896e7e64 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -42,13 +42,13 @@ Revision History: #include"bool_rewriter.h" #include"qe_lite.h" #include"expr_safe_replace.h" +#include"hnf.h" namespace datalog { rule_manager::rule_manager(context& ctx) : m(ctx.get_manager()), - m_ctx(ctx), - m_refs(ctx.get_manager()) {} + m_ctx(ctx) {} bool rule_manager::is_predicate(func_decl * f) const { return m_ctx.is_predicate(f); @@ -89,72 +89,32 @@ namespace datalog { } }; - void rule_manager::remove_labels(expr_ref& fml) { + void rule_manager::remove_labels(expr_ref& fml, proof_ref& pr) { expr_ref tmp(m); remove_label_cfg r_cfg(m); rewriter_tpl rwr(m, false, r_cfg); rwr(fml, tmp); + if (pr && fml != tmp) { + + pr = m.mk_modus_ponens(pr, m.mk_rewrite(fml, tmp)); + } fml = tmp; } - void rule_manager::mk_rule(expr* fml, rule_ref_vector& rules, symbol const& name) { + void rule_manager::mk_rule(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name) { + scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED); + proof_ref pr(p, m); expr_ref fml1(m); - m_memoize_disj.reset(); - m_refs.reset(); bind_variables(fml, true, fml1); - remove_labels(fml1); - mk_rule_core(fml1, rules, name); + if (fml1 != fml && pr) { + pr = m.mk_asserted(fml1); + } + remove_labels(fml1, pr); + mk_rule_core_new(fml1, pr, rules, name); } - - void rule_manager::mk_rule_core(expr* _fml, rule_ref_vector& rules, symbol const& name) { - app_ref_vector body(m); - app_ref head(m); - expr_ref e(m), fml(_fml, m); - svector is_negated; - TRACE("dl_rule", tout << mk_pp(fml, m) << "\n";); - quantifier_hoister qh(m); - unsigned index = qh.pull_quantifier(true, fml, 0); - check_app(fml); - head = to_app(fml); - - while (m.is_implies(head)) { - e = head->get_arg(0); - th_rewriter th_rwr(m); - th_rwr(e); - body.push_back(ensure_app(e)); - e = to_app(head)->get_arg(1); - check_app(e); - head = to_app(e.get()); - } - symbol head_name = (name == symbol::null)?head->get_decl()->get_name():name; - flatten_body(body); - if (body.size() == 1 && m.is_or(body[0].get()) && contains_predicate(body[0].get())) { - app* _or = to_app(body[0].get()); - for (unsigned i = 0; i < _or->get_num_args(); ++i) { - e = m.mk_implies(_or->get_arg(i), head); - mk_rule_core(e, rules, head_name); - } - return; - } - - eliminate_disjunctions(body, rules, head_name); - eliminate_quantifier_body(body, rules, head_name); - hoist_compound(index, head, body); - unsigned sz = body.size(); - for (unsigned i = 0; i < sz; ++i) { - app_ref b(body[i].get(), m); - hoist_compound(index, b, body); - body[i] = b; - } - TRACE("dl_rule", - tout << mk_pp(head, m) << " :- "; - for (unsigned i = 0; i < body.size(); ++i) { - tout << mk_pp(body[i].get(), m) << " "; - } - tout << "\n";); - + void rule_manager::mk_negations(app_ref_vector& body, svector& is_negated) { for (unsigned i = 0; i < body.size(); ++i) { expr* e = body[i].get(), *e1; if (m.is_not(e, e1) && is_predicate(e1)) { @@ -165,23 +125,105 @@ namespace datalog { else { is_negated.push_back(false); } - } - check_valid_rule(head, body.size(), body.c_ptr()); + } + } - rules.push_back(mk(head.get(), body.size(), body.c_ptr(), is_negated.c_ptr(), name)); - - if (m_ctx.fix_unbound_vars()) { - unsigned rule_cnt = rules.size(); - for (unsigned i=0; i is_negated; + unsigned index = extract_horn(fml, body, head); + hoist_compound_predicates(index, head, body); + TRACE("dl_rule", + tout << mk_pp(head, m) << " :- "; + for (unsigned i = 0; i < body.size(); ++i) { + tout << mk_pp(body[i].get(), m) << " "; + } + tout << "\n";); + + + mk_negations(body, is_negated); + check_valid_rule(head, body.size(), body.c_ptr()); + + rule_ref r(*this); + r = mk(head.get(), body.size(), body.c_ptr(), is_negated.c_ptr(), name); + + expr_ref fml1(m); + if (p) { + r->to_formula(fml1); + if (fml1 == fml) { + // no-op. + } + else if (is_quantifier(fml1)) { + p = m.mk_modus_ponens(p, m.mk_symmetry(m.mk_der(to_quantifier(fml1), fml))); + } + else { + p = m.mk_modus_ponens(p, m.mk_rewrite(fml, fml1)); + } + } + + if (m_ctx.fix_unbound_vars()) { + fix_unbound_vars(r, true); + } + + if (p) { + expr_ref fml2(m); + r->to_formula(fml2); + if (fml1 != fml2) { + p = m.mk_modus_ponens(p, m.mk_rewrite(fml1, fml2)); + } + r->set_proof(m, p); + } + rules.push_back(r); + } + + unsigned rule_manager::extract_horn(expr* fml, app_ref_vector& body, app_ref& head) { + expr* e1, *e2; + unsigned index = m_counter.get_next_var(fml); + if (::is_forall(fml)) { + index += to_quantifier(fml)->get_num_decls(); + fml = to_quantifier(fml)->get_expr(); + } + if (m.is_implies(fml, e1, e2)) { + expr_ref_vector es(m); + head = ensure_app(e2); + datalog::flatten_and(e1, es); + for (unsigned i = 0; i < es.size(); ++i) { + body.push_back(ensure_app(es[i].get())); + } + } + else { + head = ensure_app(fml); + } + return index; + } + + void rule_manager::hoist_compound_predicates(unsigned index, app_ref& head, app_ref_vector& body) { + unsigned sz = body.size(); + hoist_compound(index, head, body); + for (unsigned i = 0; i < sz; ++i) { + app_ref b(body[i].get(), m); + hoist_compound(index, b, body); + body[i] = b; + } + } + + void rule_manager::mk_query(expr* query, func_decl_ref& qpred, rule_ref_vector& query_rules, rule_ref& query_rule) { ptr_vector vars; svector names; @@ -192,7 +234,7 @@ namespace datalog { // Remove existential prefix. bind_variables(query, false, q); quantifier_hoister qh(m); - qh.pull_quantifier(false, q, &names); + qh.pull_quantifier(false, q, 0, &names); // retrieve free variables. get_free_vars(q, vars); if (vars.contains(static_cast(0))) { @@ -250,7 +292,12 @@ namespace datalog { rule_expr = m.mk_forall(vars.size(), vars.c_ptr(), names.c_ptr(), impl); } - mk_rule(rule_expr, query_rules); + scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED); + proof_ref pr(m); + if (m_ctx.generate_proof_trace()) { + pr = m.mk_asserted(rule_expr); + } + mk_rule(rule_expr, pr, query_rules); SASSERT(query_rules.size() >= 1); query_rule = query_rules.back(); } @@ -330,73 +377,6 @@ namespace datalog { return false; } - void rule_manager::eliminate_disjunctions(app_ref_vector::element_ref& body, rule_ref_vector& rules, symbol const& name) { - - app* b = body.get(); - expr* e1; - bool negate_args = false; - bool is_disj = false; - unsigned num_disj = 0; - expr* const* disjs = 0; - if (!contains_predicate(b)) { - return; - } - TRACE("dl_rule", tout << mk_ismt2_pp(b, m) << "\n";); - if (m.is_or(b)) { - is_disj = true; - negate_args = false; - num_disj = b->get_num_args(); - disjs = b->get_args(); - } - if (m.is_not(b, e1) && m.is_and(e1)) { - is_disj = true; - negate_args = true; - num_disj = to_app(e1)->get_num_args(); - disjs = to_app(e1)->get_args(); - } - if (is_disj) { - ptr_vector sorts0, sorts1; - get_free_vars(b, sorts0); - expr_ref_vector args(m); - for (unsigned i = 0; i < sorts0.size(); ++i) { - if (sorts0[i]) { - args.push_back(m.mk_var(i,sorts0[i])); - sorts1.push_back(sorts0[i]); - } - } - app* old_head = 0; - if (m_memoize_disj.find(b, old_head)) { - body = old_head; - } - else { - app_ref head(m); - func_decl_ref f(m); - f = m.mk_fresh_func_decl(name.str().c_str(),"", sorts1.size(), sorts1.c_ptr(), m.mk_bool_sort()); - m_ctx.register_predicate(f); - head = m.mk_app(f, args.size(), args.c_ptr()); - - for (unsigned i = 0; i < num_disj; ++i) { - expr_ref fml(m); - expr* e = disjs[i]; - if (negate_args) e = m.mk_not(e); - fml = m.mk_implies(e,head); - mk_rule_core(fml, rules, name); - } - m_memoize_disj.insert(b, head); - m_refs.push_back(b); - m_refs.push_back(head); - // update the body to be the newly introduced head relation - body = head; - } - } - } - - void rule_manager::eliminate_disjunctions(app_ref_vector& body, rule_ref_vector& rules, symbol const& name) { - for (unsigned i = 0; i < body.size(); ++i) { - app_ref_vector::element_ref t = body[i]; - eliminate_disjunctions(t, rules, name); - } - } bool rule_manager::is_forall(ast_manager& m, expr* e, quantifier*& q) { expr* e1, *e2; @@ -415,40 +395,6 @@ namespace datalog { return false; } - void rule_manager::eliminate_quantifier_body(app_ref_vector::element_ref& body, rule_ref_vector& rules, symbol const& name) { - quantifier* q; - if (is_forall(m, body.get(), q) && contains_predicate(q)) { - expr* e = q->get_expr(); - if (!is_predicate(e)) { - ptr_vector sorts0, sorts1; - get_free_vars(e, sorts0); - expr_ref_vector args(m); - for (unsigned i = 0; i < sorts0.size(); ++i) { - if (sorts0[i]) { - args.push_back(m.mk_var(i,sorts0[i])); - sorts1.push_back(sorts0[i]); - } - } - app_ref head(m), fml(m); - func_decl_ref f(m); - f = m.mk_fresh_func_decl(name.str().c_str(),"", sorts1.size(), sorts1.c_ptr(), m.mk_bool_sort()); - m_ctx.register_predicate(f); - head = m.mk_app(f, args.size(), args.c_ptr()); - fml = m.mk_implies(e, head); - mk_rule_core(fml, rules, name); - // update the body to be the newly introduced head relation - body = m.mk_eq(m.mk_true(), m.update_quantifier(q, head)); - } - } - } - - void rule_manager::eliminate_quantifier_body(app_ref_vector& body, rule_ref_vector& rules, symbol const& name) { - for (unsigned i = 0; i < body.size(); ++i) { - app_ref_vector::element_ref t = body[i]; - eliminate_quantifier_body(t, rules, name); - } - } - app_ref rule_manager::ensure_app(expr* e) { SASSERT(m.is_bool(e)); @@ -476,6 +422,7 @@ namespace datalog { r->m_head = head; r->m_name = name; r->m_tail_size = n; + r->m_proof = 0; m.inc_ref(r->m_head); app * * uninterp_tail = r->m_tail; //grows upwards @@ -533,6 +480,11 @@ namespace datalog { if (normalize) { r->norm_vars(*this); } + DEBUG_CODE(ptr_vector sorts; + ::get_free_vars(head, sorts); + for (unsigned i = 0; i < n; ++i) { + ::get_free_vars(tail[i], sorts); + }); return r; } @@ -754,6 +706,27 @@ namespace datalog { r->set_accounting_parent_object(m_ctx, old_r); } + void rule_manager::mk_rule_rewrite_proof(rule& old_rule, rule& new_rule) { + if (&old_rule != &new_rule && + !new_rule.get_proof() && + old_rule.get_proof()) { + expr_ref fml(m); + new_rule.to_formula(fml); + scoped_proof _sc(m); + proof* p = m.mk_rewrite(m.get_fact(old_rule.get_proof()), fml); + new_rule.set_proof(m, m.mk_modus_ponens(old_rule.get_proof(), p)); + } + } + + void rule_manager::mk_rule_asserted_proof(rule& r) { + if (m_ctx.generate_proof_trace()) { + scoped_proof _scp(m); + expr_ref fml(m); + r.to_formula(fml); + r.set_proof(m, m.mk_asserted(fml)); + } + } + void rule_manager::substitute(rule_ref& r, unsigned sz, expr*const* es) { expr_ref tmp(m); app_ref new_head(m); @@ -812,10 +785,23 @@ namespace datalog { for (unsigned i = 0; i < n; i++) { m.dec_ref(get_tail(i)); } + if (m_proof) { + m.dec_ref(m_proof); + } this->~rule(); m.get_allocator().deallocate(get_obj_size(n), this); } + void rule::set_proof(ast_manager& m, proof* p) { + if (p) { + m.inc_ref(p); + } + if (m_proof) { + m.dec_ref(m_proof); + } + m_proof = p; + } + bool rule::is_in_tail(const func_decl * p, bool only_positive) const { unsigned len = only_positive ? get_positive_tail_size() : get_uninterpreted_tail_size(); for (unsigned i = 0; i < len; i++) { @@ -993,6 +979,9 @@ namespace datalog { out << '}'; } out << '\n'; + if (m_proof) { + out << mk_pp(m_proof, m) << '\n'; + } } void rule::to_formula(expr_ref& fml) const { diff --git a/src/muz_qe/dl_rule.h b/src/muz_qe/dl_rule.h index a8c6e0314..5b1338b22 100644 --- a/src/muz_qe/dl_rule.h +++ b/src/muz_qe/dl_rule.h @@ -43,11 +43,9 @@ namespace datalog { */ class rule_manager { - ast_manager& m; - context& m_ctx; - rule_counter m_counter; - obj_map m_memoize_disj; - expr_ref_vector m_refs; + ast_manager& m; + context& m_ctx; + rule_counter m_counter; // only the context can create a rule_manager friend class context; @@ -57,19 +55,13 @@ namespace datalog { /** \brief Move functions from predicate tails into the interpreted tail by introducing new variables. */ + void hoist_compound_predicates(unsigned num_bound, app_ref& head, app_ref_vector& body); + void hoist_compound(unsigned& num_bound, app_ref& fml, app_ref_vector& body); void flatten_body(app_ref_vector& body); - void remove_labels(expr_ref& fml); - - void eliminate_disjunctions(app_ref_vector::element_ref& body, rule_ref_vector& rules, symbol const& name); - - void eliminate_disjunctions(app_ref_vector& body, rule_ref_vector& rules, symbol const& name); - - void eliminate_quantifier_body(app_ref_vector::element_ref& body, rule_ref_vector& rules, symbol const& name); - - void eliminate_quantifier_body(app_ref_vector& body, rule_ref_vector& rules, symbol const& name); + void remove_labels(expr_ref& fml, proof_ref& pr); app_ref ensure_app(expr* e); @@ -81,6 +73,16 @@ namespace datalog { void mk_rule_core(expr* fml, rule_ref_vector& rules, symbol const& name); + void mk_negations(app_ref_vector& body, svector& is_negated); + + void mk_rule_core_new(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name); + + void mk_rule_core2(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name); + + static expr_ref mk_implies(app_ref_vector const& body, expr* head); + + unsigned extract_horn(expr* fml, app_ref_vector& body, app_ref& head); + /** \brief Perform cheap quantifier elimination to reduce the number of variables in the interpreted tail. */ @@ -99,7 +101,7 @@ namespace datalog { The formula is of the form (forall (...) (forall (...) (=> (and ...) head))) */ - void mk_rule(expr* fml, rule_ref_vector& rules, symbol const& name = symbol::null); + void mk_rule(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name = symbol::null); /** \brief Create a Datalog query from an expression. @@ -129,7 +131,15 @@ namespace datalog { /** make sure there are not non-quantified variables that occur only in interpreted predicates */ void fix_unbound_vars(rule_ref& r, bool try_quantifier_elimination); + /** + \brief add proof that new rule is obtained by rewriting old rule. + */ + void mk_rule_rewrite_proof(rule& old_rule, rule& new_rule); + /** + \brief tag rule as asserted. + */ + void mk_rule_asserted_proof(rule& r); /** \brief apply substitution to variables of rule. @@ -168,6 +178,7 @@ namespace datalog { friend class rule_manager; app * m_head; + proof* m_proof; unsigned m_tail_size:20; // unsigned m_reserve:12; unsigned m_ref_cnt; @@ -199,6 +210,10 @@ namespace datalog { void get_used_vars(used_vars& uv) const; public: + + proof * get_proof() const { return m_proof; } + + void set_proof(ast_manager& m, proof* p); app * get_head() const { return m_head; } diff --git a/src/muz_qe/dl_rule_transformer.cpp b/src/muz_qe/dl_rule_transformer.cpp index a246d9d61..5ecbf2b45 100644 --- a/src/muz_qe/dl_rule_transformer.cpp +++ b/src/muz_qe/dl_rule_transformer.cpp @@ -73,7 +73,7 @@ namespace datalog { m_dirty=true; } - bool rule_transformer::operator()(rule_set & rules, model_converter_ref& mc, proof_converter_ref& pc) { + bool rule_transformer::operator()(rule_set & rules, model_converter_ref& mc) { ensure_ordered(); bool modified = false; @@ -87,7 +87,7 @@ namespace datalog { for(; it!=end && !m_cancel; ++it) { plugin & p = **it; - rule_set * new_rules = p(rules, mc, pc); + rule_set * new_rules = p(rules, mc); if (!new_rules) { continue; } diff --git a/src/muz_qe/dl_rule_transformer.h b/src/muz_qe/dl_rule_transformer.h index cf1a9be75..3b2140caf 100644 --- a/src/muz_qe/dl_rule_transformer.h +++ b/src/muz_qe/dl_rule_transformer.h @@ -24,7 +24,6 @@ Revision History: #include"dl_rule.h" #include"dl_rule_set.h" #include"model_converter.h" -#include"proof_converter.h" namespace datalog { @@ -69,7 +68,7 @@ namespace datalog { \brief Transform the rule set using the registered transformation plugins. If the rule set has changed, return true; otherwise return false. */ - bool operator()(rule_set & rules, model_converter_ref& mc, proof_converter_ref& pc); + bool operator()(rule_set & rules, model_converter_ref& mc); }; class rule_transformer::plugin { @@ -106,8 +105,7 @@ namespace datalog { The caller takes ownership of the returned \c rule_set object. */ virtual rule_set * operator()(rule_set const & source, - model_converter_ref& mc, - proof_converter_ref& pc) = 0; + model_converter_ref& mc) = 0; virtual void cancel() { m_cancel = true; } diff --git a/src/muz_qe/dl_util.cpp b/src/muz_qe/dl_util.cpp index bde03e765..28634d30e 100644 --- a/src/muz_qe/dl_util.cpp +++ b/src/muz_qe/dl_util.cpp @@ -511,6 +511,44 @@ namespace datalog { pc->insert(pr); } + void resolve_rule(rule const& r1, rule const& r2, unsigned idx, + expr_ref_vector const& s1, expr_ref_vector const& s2, rule& res) { + if (!r1.get_proof()) { + return; + } + SASSERT(r2.get_proof()); + ast_manager& m = s1.get_manager(); + expr_ref fml(m); + res.to_formula(fml); + vector substs; + svector > positions; + substs.push_back(s1); + substs.push_back(s2); + + scoped_proof _sc(m); + proof_ref pr(m); + proof_ref_vector premises(m); + premises.push_back(r1.get_proof()); + premises.push_back(r2.get_proof()); + positions.push_back(std::make_pair(idx+1, 0)); + + TRACE("dl", + tout << premises[0]->get_id() << " " << mk_pp(premises[0].get(), m) << "\n"; + for (unsigned i = 0; i < s1.size(); ++i) { + tout << mk_pp(s1[i], m) << " "; + } + tout << "\n"; + tout << premises[1]->get_id() << " " << mk_pp(premises[1].get(), m) << "\n"; + for (unsigned i = 0; i < s2.size(); ++i) { + tout << mk_pp(s2[i], m) << " "; + } + tout << "\n"; + ); + + pr = m.mk_hyper_resolve(2, premises.c_ptr(), fml, positions, substs); + res.set_proof(m, pr); + } + class skip_model_converter : public model_converter { public: skip_model_converter() {} diff --git a/src/muz_qe/dl_util.h b/src/muz_qe/dl_util.h index 45d327d44..e53e6c998 100644 --- a/src/muz_qe/dl_util.h +++ b/src/muz_qe/dl_util.h @@ -425,6 +425,9 @@ namespace datalog { void resolve_rule(replace_proof_converter* pc, rule const& r1, rule const& r2, unsigned idx, expr_ref_vector const& s1, expr_ref_vector const& s2, rule const& res); + void resolve_rule(rule const& r1, rule const& r2, unsigned idx, + expr_ref_vector const& s1, expr_ref_vector const& s2, rule& res); + model_converter* mk_skip_model_converter(); proof_converter* mk_skip_proof_converter(); diff --git a/src/muz_qe/equiv_proof_converter.cpp b/src/muz_qe/equiv_proof_converter.cpp index 53db01900..98ea88044 100644 --- a/src/muz_qe/equiv_proof_converter.cpp +++ b/src/muz_qe/equiv_proof_converter.cpp @@ -22,12 +22,14 @@ Revision History: #include "dl_util.h" void equiv_proof_converter::insert(expr* fml1, expr* fml2) { - datalog::scoped_proof _sp(m); - proof_ref p1(m), p2(m), p3(m); - p1 = m.mk_asserted(fml1); - p2 = m.mk_rewrite(fml1, fml2); - p3 = m.mk_modus_ponens(p1, p2); - TRACE("proof_converter", tout << mk_pp(p3.get(), m) << "\n";); - SASSERT(m.has_fact(p3)); - m_replace.insert(p3); + if (fml1 != fml2) { + datalog::scoped_proof _sp(m); + proof_ref p1(m), p2(m), p3(m); + p1 = m.mk_asserted(fml1); + p2 = m.mk_rewrite(fml1, fml2); + p3 = m.mk_modus_ponens(p1, p2); + TRACE("proof_converter", tout << mk_pp(p3.get(), m) << "\n";); + SASSERT(m.has_fact(p3)); + m_replace.insert(p3); + } } diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index c87874b29..02c41c091 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -113,8 +113,8 @@ class horn_tactic : public tactic { todo.append(to_app(a)->get_num_args(), to_app(a)->get_args()); } else if (m.is_ite(a)) { - todo.append(to_app(a)->get_arg(1)); - todo.append(to_app(a)->get_arg(2)); + todo.push_back(to_app(a)->get_arg(1)); + todo.push_back(to_app(a)->get_arg(2)); } else if (is_predicate(a)) { register_predicate(a); @@ -270,20 +270,10 @@ class horn_tactic : public tactic { proof_converter_ref & pc) { expr_ref fml(m); - bool produce_models = g->models_enabled(); - bool produce_proofs = g->proofs_enabled(); - if (produce_models) { - mc = datalog::mk_skip_model_converter(); - } - if (produce_proofs) { - pc = datalog::mk_skip_proof_converter(); - } func_decl* query_pred = to_app(q)->get_decl(); m_ctx.set_output_predicate(query_pred); - m_ctx.set_model_converter(mc); - m_ctx.set_proof_converter(pc); m_ctx.get_rules(); // flush adding rules. m_ctx.apply_default_transformation(); diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index d6718c33c..d4027d73d 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -950,16 +950,45 @@ namespace pdr { return out; } + /** + \brief Ensure that all nodes in the tree have associated models. + get_trace and get_proof_trace rely on models to extract rules. + */ + void model_search::update_models() { + obj_map models; + ptr_vector todo; + todo.push_back(m_root); + while (!todo.empty()) { + model_node* n = todo.back(); + if (n->get_model_ptr()) { + models.insert(n->state(), n->get_model_ptr()); + } + todo.pop_back(); + todo.append(n->children().size(), n->children().c_ptr()); + } + + todo.push_back(m_root); + while (!todo.empty()) { + model_node* n = todo.back(); + model* md = 0; + if (!n->get_model_ptr() && models.find(n->state(), md)) { + model_ref mr(md); + n->set_model(mr); + } + todo.pop_back(); + todo.append(n->children().size(), n->children().c_ptr()); + } + } + /** Extract trace comprising of constraints and predicates that are satisfied from facts to the query. The resulting trace */ - expr_ref model_search::get_trace(context const& ctx) const { + expr_ref model_search::get_trace(context const& ctx) { pred_transformer& pt = get_root().pt(); ast_manager& m = pt.get_manager(); manager& pm = pt.get_pdr_manager(); - datalog::context& dctx = ctx.get_context(); datalog::rule_manager& rm = dctx.get_rule_manager(); expr_ref_vector constraints(m), predicates(m); @@ -974,13 +1003,15 @@ namespace pdr { rule = n->get_rule(); unsigned max_var = vc.get_max_rule_var(*rule); predicates.push_back(rule->get_head()); - children.append(n); + children.push_back(n); bool first = true; + update_models(); while (!children.empty()) { SASSERT(children.size() == predicates.size()); expr_ref_vector binding(m); n = children.back(); children.pop_back(); + TRACE("pdr", n->display(tout, 0);); n->mk_instantiate(r0, rule, binding); max_var = std::max(max_var, vc.get_max_rule_var(*rule)); @@ -1026,7 +1057,7 @@ namespace pdr { return pm.mk_and(constraints); } - proof_ref model_search::get_proof_trace(context const& ctx) const { + proof_ref model_search::get_proof_trace(context const& ctx) { pred_transformer& pt = get_root().pt(); ast_manager& m = pt.get_manager(); datalog::context& dctx = ctx.get_context(); @@ -1042,8 +1073,10 @@ namespace pdr { proof* pr = 0; unifier.set_normalize(false); todo.push_back(m_root); + update_models(); while (!todo.empty()) { model_node* n = todo.back(); + TRACE("pdr", n->display(tout, 0);); if (cache.find(n->state(), pr)) { todo.pop_back(); continue; @@ -1066,12 +1099,14 @@ namespace pdr { continue; } proof_ref rl(m); - expr_ref fml0(m); expr_ref_vector binding(m); n->mk_instantiate(r0, r1, binding); - r0->to_formula(fml0); proof_ref p1(m), p2(m); - p1 = m.mk_asserted(fml0); + p1 = r0->get_proof(); + if (!p1) { + r0->display(dctx, std::cout); + } + SASSERT(p1); pfs[0] = p1; rls[0] = r1; TRACE("pdr", diff --git a/src/muz_qe/pdr_context.h b/src/muz_qe/pdr_context.h index 32f13cdd4..6aa02ef10 100644 --- a/src/muz_qe/pdr_context.h +++ b/src/muz_qe/pdr_context.h @@ -240,6 +240,7 @@ namespace pdr { void erase_leaf(model_node& n); void remove_node(model_node& n); void enqueue_leaf(model_node& n); // add leaf to priority queue. + void update_models(); public: model_search(bool bfs): m_bfs(bfs), m_root(0) {} ~model_search(); @@ -253,8 +254,8 @@ namespace pdr { void set_root(model_node* n); model_node& get_root() const { return *m_root; } std::ostream& display(std::ostream& out) const; - expr_ref get_trace(context const& ctx) const; - proof_ref get_proof_trace(context const& ctx) const; + expr_ref get_trace(context const& ctx); + proof_ref get_proof_trace(context const& ctx); void backtrack_level(bool uses_level, model_node& n); }; @@ -299,7 +300,7 @@ namespace pdr { decl2rel m_rels; // Map from relation predicate to fp-operator. func_decl_ref m_query_pred; pred_transformer* m_query; - model_search m_search; + mutable model_search m_search; lbool m_last_result; unsigned m_inductive_lvl; ptr_vector m_core_generalizers; diff --git a/src/muz_qe/pdr_dl_interface.cpp b/src/muz_qe/pdr_dl_interface.cpp index b55f302ed..08f7acfdd 100644 --- a/src/muz_qe/pdr_dl_interface.cpp +++ b/src/muz_qe/pdr_dl_interface.cpp @@ -85,6 +85,7 @@ lbool dl_interface::query(expr * query) { m_pred2slice.reset(); ast_manager& m = m_ctx.get_manager(); datalog::rule_manager& rule_manager = m_ctx.get_rule_manager(); + datalog::rule_set old_rules(m_ctx.get_rules()); func_decl_ref query_pred(m); datalog::rule_ref_vector query_rules(rule_manager); @@ -105,14 +106,8 @@ lbool dl_interface::query(expr * query) { m_ctx.display_rules(tout); ); - model_converter_ref mc = datalog::mk_skip_model_converter(); - proof_converter_ref pc; - if (m_ctx.get_params().generate_proof_trace()) { - pc = datalog::mk_skip_proof_converter(); - } + m_ctx.set_output_predicate(query_pred); - m_ctx.set_model_converter(mc); - m_ctx.set_proof_converter(pc); m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { @@ -164,8 +159,8 @@ lbool dl_interface::query(expr * query) { datalog::scoped_restore_proof _sc(m); // update_rules may overwrite the proof mode. - m_context->set_proof_converter(pc); - m_context->set_model_converter(mc); + m_context->set_proof_converter(m_ctx.get_proof_converter()); + m_context->set_model_converter(m_ctx.get_model_converter()); m_context->set_query(query_pred); m_context->set_axioms(bg_assertion); m_context->update_rules(m_pdr_rules); diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz_qe/pdr_generalizers.cpp index 4cdfb186e..1b8ea22f9 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz_qe/pdr_generalizers.cpp @@ -228,11 +228,13 @@ namespace pdr { is_lower = !is_lower; } + vector bound; + bound.push_back(std::make_pair(x, i)); if (is_lower) { - m_lb.insert(abs(r), std::make_pair(x, i)); + m_lb.insert(abs(r), bound); } else { - m_ub.insert(abs(r), std::make_pair(x, i)); + m_ub.insert(abs(r), bound); } } diff --git a/src/muz_qe/qe_lite.cpp b/src/muz_qe/qe_lite.cpp index 5f018895c..be3f80f92 100644 --- a/src/muz_qe/qe_lite.cpp +++ b/src/muz_qe/qe_lite.cpp @@ -2492,7 +2492,13 @@ class qe_lite_tactic : public tactic { new_f = f; m_qe(new_f, new_pr); if (produce_proofs) { - new_pr = m.mk_modus_ponens(g->pr(i), new_pr); + expr* fact = m.get_fact(new_pr); + if (to_app(fact)->get_arg(0) != to_app(fact)->get_arg(1)) { + new_pr = m.mk_modus_ponens(g->pr(i), new_pr); + } + else { + new_pr = g->pr(i); + } } g->update(i, new_f, new_pr, g->dep(i)); } diff --git a/src/muz_qe/tab_context.cpp b/src/muz_qe/tab_context.cpp index 681d3d4b2..9ee059f44 100644 --- a/src/muz_qe/tab_context.cpp +++ b/src/muz_qe/tab_context.cpp @@ -1644,9 +1644,7 @@ namespace datalog { void resolve_rule(replace_proof_converter& pc, tb::clause const& r1, tb::clause const& r2, expr_ref_vector const& s1, expr_ref_vector const& s2, tb::clause const& res) const { unsigned idx = r1.get_predicate_index(); - expr_ref fml1 = r1.to_formula(); - expr_ref fml2 = r2.to_formula(); - expr_ref fml3 = res.to_formula(); + expr_ref fml = res.to_formula(); vector substs; svector > positions; substs.push_back(s1); @@ -1654,13 +1652,12 @@ namespace datalog { scoped_proof _sc(m); proof_ref pr(m); proof_ref_vector premises(m); - premises.push_back(m.mk_asserted(fml1)); - premises.push_back(m.mk_asserted(fml2)); + premises.push_back(m.mk_asserted(r1.to_formula())); + premises.push_back(m.mk_asserted(r2.to_formula())); positions.push_back(std::make_pair(idx+1, 0)); - pr = m.mk_hyper_resolve(2, premises.c_ptr(), fml3, positions, substs); + pr = m.mk_hyper_resolve(2, premises.c_ptr(), fml, positions, substs); pc.insert(pr); - } - + } }; tab::tab(context& ctx): diff --git a/src/util/vector.h b/src/util/vector.h index a9d36b202..704452d0f 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -151,23 +151,6 @@ public: } } - vector(T const & e) : - m_data(0) { - push_back(e); - } - - vector(T const & t1, T const & t2) : - m_data(0) { - push_back(t1); - push_back(t2); - } - - vector(T const & t1, T const & t2, T const & t3) : - m_data(0) { - push_back(t1); - push_back(t2); - push_back(t3); - } ~vector() { destroy(); From 7c3ca302f0e50650fe6afdce8013e189a5659539 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Mar 2013 16:56:47 -0700 Subject: [PATCH 48/97] missing hnf Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/quant_hoist.h | 2 +- src/muz_qe/dl_util.cpp | 3 - src/muz_qe/hnf.cpp | 487 ++++++++++++++++++++++++++++++++ src/muz_qe/hnf.h | 49 ++++ src/muz_qe/horn_tactic.cpp | 5 - src/muz_qe/pdr_dl_interface.cpp | 21 -- 6 files changed, 537 insertions(+), 30 deletions(-) create mode 100644 src/muz_qe/hnf.cpp create mode 100644 src/muz_qe/hnf.h diff --git a/src/ast/rewriter/quant_hoist.h b/src/ast/rewriter/quant_hoist.h index df643950a..50cbd1ba4 100644 --- a/src/ast/rewriter/quant_hoist.h +++ b/src/ast/rewriter/quant_hoist.h @@ -66,7 +66,7 @@ public: Return index of maximal variable. */ - unsigned pull_quantifier(bool is_forall, expr_ref& fml, svector* names); + unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector* sorts, svector* names); }; diff --git a/src/muz_qe/dl_util.cpp b/src/muz_qe/dl_util.cpp index 74c16a6ea..6d93dd84c 100644 --- a/src/muz_qe/dl_util.cpp +++ b/src/muz_qe/dl_util.cpp @@ -431,8 +431,6 @@ namespace datalog { } } -<<<<<<< HEAD -======= void rule_counter::count_rule_vars(ast_manager & m, const rule * r, int coef) { count_vars(m, r->get_head(), 1); @@ -453,7 +451,6 @@ namespace datalog { } return get_max_var(has_var); } ->>>>>>> 26f4d3be202606ff0189aefc103de187caf06d5d void del_rule(horn_subsume_model_converter* mc, rule& r) { if (mc) { diff --git a/src/muz_qe/hnf.cpp b/src/muz_qe/hnf.cpp new file mode 100644 index 000000000..88e28699e --- /dev/null +++ b/src/muz_qe/hnf.cpp @@ -0,0 +1,487 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + hnf.cpp + +Abstract: + + Horn normal form conversion. + +Author: + + Nikolaj Bjorner (nbjorner) 3-20-2013 + +Notes: + + Convert formula + + (forall x f(x)) + + into conjunction + + (f1 xy) (f2 xy) (f3 xy) + + such that + + (forall x f(x)) ~ /\ (forall xy (f_i xy)) + + modulo definitions that are introduced. + + + Convert proof with + asserted (forall xy (f' xy)) + + To: + (forall xy (f' xy)) by mp~ 1, 2 + 1. asserted/def-intro (forall xy (f xy)) + 2. (forall xy (f xy)) ~ (forall xy (f' xy)) by trans, 3, 4 + 3. (forall xy (f xy)) ~ (forall xy (f1 xy)) by pull quantifiers (rewrite) + 4. (forall xy (f1 xy)) ~ (forall xy (f' xy)) by oeq_quant_intro 5 + 5. f1 xy ~ f' xy by sub-proof. + + +--*/ +#include"hnf.h" +#include"warning.h" +#include"used_vars.h" +#include"well_sorted.h" +#include"var_subst.h" +#include"name_exprs.h" +#include"act_cache.h" +#include"cooperate.h" +#include"ast_pp.h" +#include"quant_hoist.h" +#include"dl_util.h" +#include"for_each_ast.h" +#include"for_each_expr.h" + +class hnf::imp { + ast_manager& m; + bool m_produce_proofs; + volatile bool m_cancel; + expr_ref_vector m_todo; + proof_ref_vector m_proofs; + expr_ref_vector m_refs; + symbol m_name; + svector m_names; + ptr_vector m_sorts; + quantifier_hoister m_qh; + obj_map m_memoize_disj; + obj_map m_memoize_proof; + func_decl_ref_vector m_fresh_predicates; + +public: + imp(ast_manager & m): + m(m), + m_produce_proofs(false), + m_cancel(false), + m_todo(m), + m_proofs(m), + m_refs(m), + m_qh(m), + m_name("P"), + m_fresh_predicates(m) { + } + + void operator()(expr * n, + proof* p, + expr_ref_vector& result, + proof_ref_vector& ps) { + expr_ref fml(m); + proof_ref pr(m); + m_todo.reset(); + m_proofs.reset(); + m_refs.reset(); + m_memoize_disj.reset(); + m_memoize_proof.reset(); + m_fresh_predicates.reset(); + m_todo.push_back(n); + m_proofs.push_back(p); + m_produce_proofs = p != 0; + while (!m_todo.empty() && !m_cancel) { + fml = m_todo.back(); + pr = m_proofs.back(); + m_todo.pop_back(); + m_proofs.pop_back(); + mk_horn(fml, pr); + if (fml) { + result.push_back(fml); + ps.push_back(pr); + } + } + TRACE("hnf", + tout << mk_pp(n, m) << "\n==>\n"; + for (unsigned i = 0; i < result.size(); ++i) { + tout << mk_pp(result[i].get(), m) << "\n"; + }); + } + + void set_cancel(bool f) { + m_cancel = f; + } + + void set_name(symbol const& n) { + m_name = n; + } + + func_decl_ref_vector const& get_fresh_predicates() { + return m_fresh_predicates; + } + + void reset() { + m_cancel = false; + m_todo.reset(); + m_proofs.reset(); + m_refs.reset(); + m_memoize_disj.reset(); + m_memoize_proof.reset(); + m_fresh_predicates.reset(); + } + + ast_manager& get_manager() { return m; } + +private: + + bool produce_proofs() const { + return m_produce_proofs; + } + + bool is_predicate(expr* p) const { + return is_app(p) && is_predicate(to_app(p)->get_decl()); + } + + bool is_predicate(func_decl* f) const { + return m.is_bool(f->get_range()) && f->get_family_id() == null_family_id; + } + + class contains_predicate_proc { + imp const& m; + public: + struct found {}; + contains_predicate_proc(imp const& m): m(m) {} + void operator()(var * n) {} + void operator()(quantifier * n) {} + void operator()(app* n) { + if (m.is_predicate(n)) throw found(); + } + }; + + bool contains_predicate(expr* fml) const { + contains_predicate_proc proc(*this); + try { + quick_for_each_expr(proc, fml); + } + catch (contains_predicate_proc::found) { + return true; + } + return false; + } + + + void mk_horn(expr_ref& fml, proof_ref& premise) { + expr* e1, *e2; + expr_ref_vector body(m); + proof_ref_vector defs(m); + expr_ref fml0(m), fml1(m), fml2(m), head(m); + proof_ref p(m); + fml0 = fml; + m_names.reset(); + m_sorts.reset(); + m_qh.pull_quantifier(true, fml0, &m_sorts, &m_names); + if (premise){ + fml1 = bind_variables(fml0); + if (!m_sorts.empty()) { + proof* p1 = m.mk_pull_quant(fml, to_quantifier(fml1)); + premise = mk_modus_ponens(premise, p1); + } + } + head = fml0; + while (m.is_implies(head, e1, e2)) { + body.push_back(e1); + head = e2; + } + datalog::flatten_and(body); + if (premise) { + p = m.mk_rewrite(fml0, mk_implies(body, head)); + } + + // + // Case: + // A \/ B -> C + // => + // A -> C + // B -> C + // + if (body.size() == 1 && m.is_or(body[0].get()) && contains_predicate(body[0].get())) { + app* _or = to_app(body[0].get()); + unsigned sz = _or->get_num_args(); + expr* const* args = _or->get_args(); + for (unsigned i = 0; i < sz; ++i) { + m_todo.push_back(bind_variables(m.mk_implies(args[i], head))); + m_proofs.push_back(0); + } + + if (premise) { + expr_ref f1 = bind_variables(mk_implies(body, head)); + expr* f2 = m.mk_and(sz, m_todo.c_ptr()+m_todo.size()-sz); + proof_ref p2(m), p3(m); + p2 = m.mk_def_axiom(m.mk_iff(f1, f2)); + p3 = mk_quant_intro(fml, f1, p); + p2 = mk_transitivity(p3, p2); + p2 = mk_modus_ponens(premise, p2); + for (unsigned i = 0; i < sz; ++i) { + m_proofs[m_proofs.size()-sz+i] = m.mk_and_elim(p2, i); + } + } + fml = 0; + return; + } + + + eliminate_disjunctions(body, defs); + p = mk_congruence(p, body, head, defs); + + eliminate_quantifier_body(body, defs); + p = mk_congruence(p, body, head, defs); + + fml2 = mk_implies(body, head); + + fml = bind_variables(fml2); + + if (premise) { + SASSERT(p); + p = mk_quant_intro(fml1, fml, p); + premise = mk_modus_ponens(premise, p); + } + } + + proof* mk_quant_intro(expr* e1, expr* e2, proof* p) { + if (m_sorts.empty()) { + return p; + } + quantifier* q1 = to_quantifier(e1); + quantifier* q2 = to_quantifier(e2); + if (m.is_iff(m.get_fact(p))) { + return m.mk_quant_intro(q1, q2, p); + } + if (m.is_oeq(m.get_fact(p))) { + return m.mk_oeq_quant_intro(q1, q2, p); + } + UNREACHABLE(); + return p; + } + + + void eliminate_disjunctions(expr_ref_vector::element_ref& body, proof_ref_vector& proofs) { + expr* b = body.get(); + expr* e1; + bool negate_args = false; + bool is_disj = false; + unsigned num_disj = 0; + expr* const* disjs = 0; + if (!contains_predicate(b)) { + return; + } + TRACE("hnf", tout << mk_pp(b, m) << "\n";); + if (m.is_or(b)) { + is_disj = true; + negate_args = false; + num_disj = to_app(b)->get_num_args(); + disjs = to_app(b)->get_args(); + } + if (m.is_not(b, e1) && m.is_and(e1)) { + is_disj = true; + negate_args = true; + num_disj = to_app(e1)->get_num_args(); + disjs = to_app(e1)->get_args(); + } + if (is_disj) { + app* old_head = 0; + if (m_memoize_disj.find(b, old_head)) { + body = old_head; + } + else { + app_ref head = mk_fresh_head(b); + proof_ref_vector defs(m); + for (unsigned i = 0; i < num_disj; ++i) { + expr* e = disjs[i]; + if (negate_args) { + e = m.mk_not(e); + } + m_todo.push_back(bind_variables(m.mk_implies(e, head))); + m_proofs.push_back(0); + if (produce_proofs()) { + defs.push_back(m.mk_def_intro(m_todo.back())); + m_proofs[m_proofs.size()-1] = defs.back(); + } + } + if (produce_proofs()) { + proof* p = m.mk_apply_defs(body.get(), head, defs.size(), defs.c_ptr()); + m_refs.push_back(p); + m_memoize_proof.insert(b, p); + } + m_memoize_disj.insert(b, head); + m_refs.push_back(b); + m_refs.push_back(head); + // update the body to be the newly introduced head relation + body = head; + } + + if (produce_proofs()) { + proofs.push_back(m_memoize_proof.find(b)); + } + } + } + + app_ref mk_fresh_head(expr* e) { + ptr_vector sorts0, sorts1; + get_free_vars(e, sorts0); + expr_ref_vector args(m); + for (unsigned i = 0; i < sorts0.size(); ++i) { + if (sorts0[i]) { + args.push_back(m.mk_var(i, sorts0[i])); + sorts1.push_back(sorts0[i]); + } + } + func_decl_ref f(m); + f = m.mk_fresh_func_decl(m_name.str().c_str(), "", sorts1.size(), sorts1.c_ptr(), m.mk_bool_sort()); + m_fresh_predicates.push_back(f); + return app_ref(m.mk_app(f, args.size(), args.c_ptr()), m); + } + + void eliminate_disjunctions(expr_ref_vector& body, proof_ref_vector& proofs) { + for (unsigned i = 0; i < body.size(); ++i) { + eliminate_disjunctions(body[i], proofs); + } + } + + void eliminate_quantifier_body(expr_ref_vector::element_ref& body, proof_ref_vector& proofs) { + if (is_forall(body.get()) && contains_predicate(body.get())) { + quantifier* q = to_quantifier(body.get()); + expr* e = q->get_expr(); + if (!is_predicate(e)) { + app_ref head = mk_fresh_head(e); + m_todo.push_back(bind_variables(m.mk_implies(e, head))); + m_proofs.push_back(0); + body = m.update_quantifier(q, head); + if (produce_proofs()) { + proof* def_intro = m.mk_def_intro(m_todo.back()); + proof* def_proof = m.mk_apply_def(e, head, def_intro); + proofs.push_back(m.mk_nnf_neg(q, body.get(), 1, &def_proof)); + m_proofs[m_proofs.size()-1] = def_intro; + } + } + } + } + + void eliminate_quantifier_body(expr_ref_vector& body, proof_ref_vector& proofs) { + for (unsigned i = 0; i < body.size(); ++i) { + eliminate_quantifier_body(body[i], proofs); + } + } + + app_ref mk_implies(expr_ref_vector const& body, expr* head) { + switch (body.size()) { + case 0: + return app_ref(to_app(head), m); + case 1: + return app_ref(m.mk_implies(body[0], head), m); + default: + return app_ref(m.mk_implies(m.mk_and(body.size(), body.c_ptr()), head), m); + } + } + + + proof_ref mk_congruence(proof* p1, expr_ref_vector const& body, expr* head, proof_ref_vector& defs) { + if (defs.empty()) { + return proof_ref(p1, m); + } + else { + SASSERT(p1); + proof_ref p2(m), p3(m); + app_ref fml = mk_implies(body, head); + expr* fact = m.get_fact(p1); + if (m.is_iff(fact)) { + p1 = m.mk_iff_oeq(p1); + fact = m.get_fact(p1); + } + VERIFY (m.is_oeq(fact) || m.is_eq(fact)); + app* e2 = to_app(to_app(fact)->get_arg(1)); + p2 = m.mk_oeq_congruence(e2, fml, defs.size(), defs.c_ptr()); + p3 = mk_transitivity(p1, p2); + defs.reset(); + return proof_ref(p3, m); + } + } + + proof_ref mk_modus_ponens(proof* premise, proof* eq) { + proof_ref result(m); + result = m.mk_modus_ponens(premise, eq); + if (m.get_fact(premise) == m.get_fact(result)) { + result = premise; + } + return result; + } + + proof* mk_transitivity(proof* p1, proof* p2) { + if (p1) { + app* f = to_app(m.get_fact(p1)); + if (f->get_arg(0) == f->get_arg(1)) { + return p2; + } + } + if (p2) { + app* f = to_app(m.get_fact(p2)); + if (f->get_arg(0) == f->get_arg(1)) { + return p1; + } + } + return m.mk_transitivity(p1, p2); + } + + expr_ref bind_variables(expr* e) { + SASSERT(m_sorts.size() == m_names.size()); + if (m_sorts.empty()) { + return expr_ref(e, m); + } + return expr_ref(m.mk_forall(m_sorts.size(), m_sorts.c_ptr(), m_names.c_ptr(), e), m); + } + +}; + +hnf::hnf(ast_manager & m) { + m_imp = alloc(imp, m); +} + +hnf::~hnf() { + dealloc(m_imp); +} + +void hnf::operator()(expr * n, proof* p, expr_ref_vector & rs, proof_ref_vector& ps) { + m_imp->operator()(n, p, rs, ps); + TRACE("hnf", + ast_manager& m = rs.get_manager(); + tout << mk_ismt2_pp(n, m) << "\nHNF result:\n"; + for (unsigned i = 0; i < rs.size(); ++i) { + tout << mk_pp(rs[i].get(), m) << "\n"; + } + ); +} + +void hnf::set_cancel(bool f) { + m_imp->set_cancel(f); +} + +void hnf::set_name(symbol const& n) { + m_imp->set_name(n); +} + +void hnf::reset() { + m_imp->reset(); +} + +func_decl_ref_vector const& hnf::get_fresh_predicates() { + return m_imp->get_fresh_predicates(); +} diff --git a/src/muz_qe/hnf.h b/src/muz_qe/hnf.h new file mode 100644 index 000000000..37339540b --- /dev/null +++ b/src/muz_qe/hnf.h @@ -0,0 +1,49 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + hnf.h + +Abstract: + + Horn normal form convertion. +Author: + + +Notes: + + Very similar to NNF. + +--*/ + +#ifndef _HNF_H_ +#define _HNF_H_ + +#include"ast.h" +#include"params.h" +#include"defined_names.h" +#include"proof_converter.h" + +class hnf { + class imp; + imp * m_imp; +public: + hnf(ast_manager & m); + ~hnf(); + + void operator()(expr * n, // [IN] expression that should be put into Horn NF + proof* p, // [IN] proof of n + expr_ref_vector & rs, // [OUT] resultant (conjunction) of expressions + proof_ref_vector& ps // [OUT] proofs of rs + ); + + void cancel() { set_cancel(true); } + void reset_cancel() { set_cancel(false); } + void set_cancel(bool f); + void set_name(symbol const& name); + void reset(); + func_decl_ref_vector const& get_fresh_predicates(); +}; + +#endif /* _HNF_H_ */ diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index 98c21288e..02c41c091 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -275,11 +275,6 @@ class horn_tactic : public tactic { func_decl* query_pred = to_app(q)->get_decl(); m_ctx.set_output_predicate(query_pred); m_ctx.get_rules(); // flush adding rules. -<<<<<<< HEAD - m_ctx.set_model_converter(mc); - m_ctx.set_proof_converter(pc); -======= ->>>>>>> 26f4d3be202606ff0189aefc103de187caf06d5d m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { diff --git a/src/muz_qe/pdr_dl_interface.cpp b/src/muz_qe/pdr_dl_interface.cpp index 033057683..e2232dafe 100644 --- a/src/muz_qe/pdr_dl_interface.cpp +++ b/src/muz_qe/pdr_dl_interface.cpp @@ -90,13 +90,6 @@ lbool dl_interface::query(expr * query) { func_decl_ref query_pred(m); datalog::rule_ref_vector query_rules(rule_manager); datalog::rule_ref query_rule(rule_manager); - model_converter_ref mc = datalog::mk_skip_model_converter(); - proof_converter_ref pc; - if (m_ctx.get_params().generate_proof_trace()) { - pc = datalog::mk_skip_proof_converter(); - } - m_ctx.set_model_converter(mc); - m_ctx.set_proof_converter(pc); rule_manager.mk_query(query, query_pred, query_rules, query_rule); m_ctx.add_rules(query_rules); expr_ref bg_assertion = m_ctx.get_background_assertion(); @@ -113,13 +106,8 @@ lbool dl_interface::query(expr * query) { m_ctx.display_rules(tout); ); -<<<<<<< HEAD - m_ctx.set_output_predicate(query_pred); - -======= m_ctx.set_output_predicate(query_pred); ->>>>>>> 26f4d3be202606ff0189aefc103de187caf06d5d m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { @@ -147,19 +135,10 @@ lbool dl_interface::query(expr * query) { transf1.register_plugin(alloc(datalog::mk_coalesce, m_ctx)); transf2.register_plugin(alloc(datalog::mk_unfold, m_ctx)); if (m_ctx.get_params().coalesce_rules()) { -<<<<<<< HEAD m_ctx.transform_rules(transf1); -======= - transformer1.register_plugin(alloc(datalog::mk_coalesce, m_ctx)); - m_ctx.transform_rules(transformer1); ->>>>>>> 26f4d3be202606ff0189aefc103de187caf06d5d } while (num_unfolds > 0) { -<<<<<<< HEAD m_ctx.transform_rules(transf2); -======= - m_ctx.transform_rules(transformer2); ->>>>>>> 26f4d3be202606ff0189aefc103de187caf06d5d --num_unfolds; } } From 2633dc56abc23dc078b58694eb725fbe38954450 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Sun, 24 Mar 2013 08:59:43 -0700 Subject: [PATCH 49/97] Fix non ASCII character Signed-off-by: Leonardo de Moura --- scripts/mk_util.py | 1 + src/muz_qe/dl_mk_karr_invariants.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 06120e2c4..257b1b295 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -520,6 +520,7 @@ def parse_options(): # Return a list containing a file names included using '#include' in # the given C/C++ file named fname. def extract_c_includes(fname): + print(fname) result = [] # We look for well behaved #include directives std_inc_pat = re.compile("[ \t]*#include[ \t]*\"(.*)\"[ \t]*") diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 18b152589..d44b31979 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -11,7 +11,7 @@ Abstract: The linear invariants are extracted according to Karr's method. A short description is in - Nikolaj Bjørner, Anca Browne and Zohar Manna. Automatic Generation + Nikolaj Bjorner, Anca Browne and Zohar Manna. Automatic Generation of Invariants and Intermediate Assertions, in CP 95. The algorithm is here adapted to Horn clauses. From 5aa84c28a6dc9778e12e7b9d05fc8d5b2e309ed9 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Sun, 24 Mar 2013 09:00:19 -0700 Subject: [PATCH 50/97] Remove trace msg Signed-off-by: Leonardo de Moura --- scripts/mk_util.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 257b1b295..06120e2c4 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -520,7 +520,6 @@ def parse_options(): # Return a list containing a file names included using '#include' in # the given C/C++ file named fname. def extract_c_includes(fname): - print(fname) result = [] # We look for well behaved #include directives std_inc_pat = re.compile("[ \t]*#include[ \t]*\"(.*)\"[ \t]*") From 9d0b0df9859918f96d0c413db68200538064f41f Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Sun, 24 Mar 2013 09:07:51 -0700 Subject: [PATCH 51/97] Fix gcc compilation errors Signed-off-by: Leonardo de Moura --- src/muz_qe/hnf.cpp | 6 ++++-- src/util/bit_vector.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/muz_qe/hnf.cpp b/src/muz_qe/hnf.cpp index 88e28699e..47370e0e6 100644 --- a/src/muz_qe/hnf.cpp +++ b/src/muz_qe/hnf.cpp @@ -353,7 +353,8 @@ private: void eliminate_disjunctions(expr_ref_vector& body, proof_ref_vector& proofs) { for (unsigned i = 0; i < body.size(); ++i) { - eliminate_disjunctions(body[i], proofs); + expr_ref_vector::element_ref r = body[i]; + eliminate_disjunctions(r, proofs); } } @@ -378,7 +379,8 @@ private: void eliminate_quantifier_body(expr_ref_vector& body, proof_ref_vector& proofs) { for (unsigned i = 0; i < body.size(); ++i) { - eliminate_quantifier_body(body[i], proofs); + expr_ref_vector::element_ref r = body[i]; + eliminate_quantifier_body(r, proofs); } } diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index 2328a5849..e3a2bc331 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ - +#include #include"bit_vector.h" #include"trace.h" From 6084cbd065292449ff97b931e42a3fb64fd93029 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2013 11:25:43 -0700 Subject: [PATCH 52/97] fix build breaks Signed-off-by: Nikolaj Bjorner --- src/test/karr.cpp | 2 +- src/util/bit_vector.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/karr.cpp b/src/test/karr.cpp index f6e572670..3ac427a88 100644 --- a/src/test/karr.cpp +++ b/src/test/karr.cpp @@ -43,7 +43,7 @@ namespace karr { hilbert_basis hb; for (unsigned i = 0; i < src.size(); ++i) { vector v(src.A[i]); - v.append(src.b[i]); + v.push_back(src.b[i]); hb.add_eq(v, rational(0)); } for (unsigned i = 0; i < 1 + src.A[0].size(); ++i) { diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index 2328a5849..3b470a3ce 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -18,6 +18,7 @@ Revision History: --*/ #include"bit_vector.h" +#include"util.h" #include"trace.h" #define DEFAULT_CAPACITY 2 From e61fa50dc320bd6f335a572817873c149aec6192 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2013 11:26:46 -0700 Subject: [PATCH 53/97] fix build breaks Signed-off-by: Nikolaj Bjorner --- src/util/bit_vector.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index a24774279..e3a2bc331 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -18,7 +18,6 @@ Revision History: --*/ #include #include"bit_vector.h" -#include"util.h" #include"trace.h" #define DEFAULT_CAPACITY 2 From a71bb549c616b4546c8793e71fed9148984d6c5e Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Sun, 24 Mar 2013 14:59:29 -0700 Subject: [PATCH 54/97] Add option :bv-sort-ac true Signed-off-by: Leonardo de Moura --- src/ast/ast_lt.cpp | 10 ++++++++++ src/ast/ast_lt.h | 1 + src/ast/rewriter/bv_rewriter.cpp | 10 ++++++++-- src/ast/rewriter/bv_rewriter.h | 1 + src/ast/rewriter/bv_rewriter_params.pyg | 3 ++- 5 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/ast/ast_lt.cpp b/src/ast/ast_lt.cpp index 1bf153f4f..2fba4f7a6 100644 --- a/src/ast/ast_lt.cpp +++ b/src/ast/ast_lt.cpp @@ -134,6 +134,16 @@ bool lt(ast * n1, ast * n2) { } } +bool is_sorted(unsigned num, expr * const * ns) { + for (unsigned i = 1; i < num; i++) { + ast * prev = ns[i-1]; + ast * curr = ns[i]; + if (lt(curr, prev)) + return false; + } + return true; +} + bool lex_lt(unsigned num, ast * const * n1, ast * const * n2) { for (unsigned i = 0; i < num; i ++) { if (n1[i] == n2[i]) diff --git a/src/ast/ast_lt.h b/src/ast/ast_lt.h index 5eb268997..b405ab229 100644 --- a/src/ast/ast_lt.h +++ b/src/ast/ast_lt.h @@ -22,6 +22,7 @@ Revision History: class ast; bool lt(ast * n1, ast * n2); +bool is_sorted(unsigned num, expr * const * ns); struct ast_to_lt { bool operator()(ast * n1, ast * n2) const { return lt(n1, n2); } diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 44efe0199..11b09003b 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -64,6 +64,7 @@ void bv_rewriter::updt_local_params(params_ref const & _p) { m_split_concat_eq = p.split_concat_eq(); m_udiv2mul = p.udiv2mul(); m_bvnot2arith = p.bvnot2arith(); + m_bv_sort_ac = p.bv_sort_ac(); m_mkbv2num = _p.get_bool("mkbv2num", false); } @@ -1315,7 +1316,7 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re return BR_REWRITE2; } - if (!flattened && !merged && (num_coeffs == 0 || (num_coeffs == 1 && !v1.is_zero()))) { + if (!flattened && !merged && (num_coeffs == 0 || (num_coeffs == 1 && !v1.is_zero())) && (!m_bv_sort_ac || is_sorted(num, args))) { return BR_FAILED; } @@ -1331,6 +1332,8 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re result = new_args[0]; return BR_DONE; default: + if (m_bv_sort_ac) + std::sort(new_args.begin(), new_args.end(), ast_to_lt()); result = m_util.mk_bv_or(new_args.size(), new_args.c_ptr()); return BR_DONE; } @@ -1456,7 +1459,8 @@ br_status bv_rewriter::mk_bv_xor(unsigned num, expr * const * args, expr_ref & r return BR_REWRITE3; } - if (!merged && !flattened && (num_coeffs == 0 || (num_coeffs == 1 && !v1.is_zero() && v1 != (rational::power_of_two(sz) - numeral(1))))) + if (!merged && !flattened && (num_coeffs == 0 || (num_coeffs == 1 && !v1.is_zero() && v1 != (rational::power_of_two(sz) - numeral(1)))) && + (!m_bv_sort_ac || is_sorted(num, args))) return BR_FAILED; ptr_buffer new_args; @@ -1497,6 +1501,8 @@ br_status bv_rewriter::mk_bv_xor(unsigned num, expr * const * args, expr_ref & r } __fallthrough; default: + if (m_bv_sort_ac) + std::sort(new_args.begin(), new_args.end(), ast_to_lt()); result = m_util.mk_bv_xor(new_args.size(), new_args.c_ptr()); return BR_DONE; } diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index a94fd18c1..6d8c21666 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -68,6 +68,7 @@ class bv_rewriter : public poly_rewriter { bool m_split_concat_eq; bool m_udiv2mul; bool m_bvnot2arith; + bool m_bv_sort_ac; bool is_zero_bit(expr * x, unsigned idx); diff --git a/src/ast/rewriter/bv_rewriter_params.pyg b/src/ast/rewriter/bv_rewriter_params.pyg index d9ee9f7a3..5feece753 100644 --- a/src/ast/rewriter/bv_rewriter_params.pyg +++ b/src/ast/rewriter/bv_rewriter_params.pyg @@ -8,5 +8,6 @@ def_module_params(module_name='rewriter', ("elim_sign_ext", BOOL, True, "expand sign-ext operator using concat and extract"), ("hi_div0", BOOL, True, "use the 'hardware interpretation' for division by zero (for bit-vector terms)"), ("mul2concat", BOOL, False, "replace multiplication by a power of two into a concatenation"), - ("bvnot2arith", BOOL, False, "replace (bvnot x) with (bvsub -1 x)") + ("bvnot2arith", BOOL, False, "replace (bvnot x) with (bvsub -1 x)"), + ("bv_sort_ac", BOOL, False, "sort the arguments of all AC operators") )) From bbe93ef61096578a11ee531e9a18b4a247b50089 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2013 18:26:22 -0700 Subject: [PATCH 55/97] fix build warning, make context simplifier traverse subterms Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/float_rewriter.cpp | 1 - src/muz_qe/hnf.cpp | 2 +- src/smt/tactic/ctx_solver_simplify_tactic.cpp | 70 +++++++++++++------ 3 files changed, 49 insertions(+), 24 deletions(-) diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index 10311598b..70ba09581 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -226,7 +226,6 @@ br_status float_rewriter::mk_abs(expr * arg1, expr_ref & result) { result = arg1; return BR_DONE; } - sort * s = m().get_sort(arg1); result = m().mk_ite(m_util.mk_is_sign_minus(arg1), m_util.mk_uminus(arg1), arg1); diff --git a/src/muz_qe/hnf.cpp b/src/muz_qe/hnf.cpp index 47370e0e6..5a7d1c4ba 100644 --- a/src/muz_qe/hnf.cpp +++ b/src/muz_qe/hnf.cpp @@ -80,8 +80,8 @@ public: m_todo(m), m_proofs(m), m_refs(m), - m_qh(m), m_name("P"), + m_qh(m), m_fresh_predicates(m) { } diff --git a/src/smt/tactic/ctx_solver_simplify_tactic.cpp b/src/smt/tactic/ctx_solver_simplify_tactic.cpp index 0092cdd38..5668ca455 100644 --- a/src/smt/tactic/ctx_solver_simplify_tactic.cpp +++ b/src/smt/tactic/ctx_solver_simplify_tactic.cpp @@ -33,10 +33,14 @@ class ctx_solver_simplify_tactic : public tactic { arith_util m_arith; mk_simplified_app m_mk_app; func_decl_ref m_fn; + obj_map m_fns; unsigned m_num_steps; + volatile bool m_cancel; public: ctx_solver_simplify_tactic(ast_manager & m, params_ref const & p = params_ref()): - m(m), m_params(p), m_solver(m, m_front_p), m_arith(m), m_mk_app(m), m_fn(m), m_num_steps(0) { + m(m), m_params(p), m_solver(m, m_front_p), + m_arith(m), m_mk_app(m), m_fn(m), m_num_steps(0), + m_cancel(false) { sort* i_sort = m_arith.mk_int(); m_fn = m.mk_func_decl(symbol(0xbeef101), i_sort, m.mk_bool_sort()); } @@ -45,7 +49,13 @@ public: return alloc(ctx_solver_simplify_tactic, m, m_params); } - virtual ~ctx_solver_simplify_tactic() {} + virtual ~ctx_solver_simplify_tactic() { + obj_map::iterator it = m_fns.begin(), end = m_fns.end(); + for (; it != end; ++it) { + m.dec_ref(it->m_value); + } + m_fns.reset(); + } virtual void updt_params(params_ref const & p) { m_solver.updt_params(p); @@ -76,15 +86,18 @@ public: virtual void cleanup() { reset_statistics(); m_solver.reset(); + m_cancel = false; } + protected: + virtual void set_cancel(bool f) { m_solver.set_cancel(f); + m_cancel = false; } void reduce(goal& g) { SASSERT(g.is_well_sorted()); - m_num_steps = 0; expr_ref fml(m); tactic_report report("ctx-solver-simplify", g); if (g.inconsistent()) @@ -134,15 +147,16 @@ protected: svector parent_ids, self_ids; expr_ref_vector fresh_vars(m), trail(m); expr_ref res(m), tmp(m); - obj_map > cache; + obj_map > cache; unsigned id = 1; - expr* n2, *fml; + expr_ref n2(m), fml(m); unsigned path_id = 0, self_pos = 0; app * a; unsigned sz; std::pair path_r; ptr_vector found; - expr* n = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); + expr_ref_vector args(m); + expr_ref n = mk_fresh(id, m.mk_bool_sort()); trail.push_back(n); fml = result.get(); @@ -156,9 +170,9 @@ protected: self_ids.push_back(0); m_solver.push(); - while (!todo.empty()) { + while (!todo.empty() && !m_cancel) { expr_ref res(m); - ptr_buffer args; + args.reset(); expr* e = todo.back(); unsigned pos = parent_ids.back(); n = names.back(); @@ -167,10 +181,6 @@ protected: if (cache.contains(e)) { goto done; } - if (!m.is_bool(e)) { - res = e; - goto done; - } if (m.is_bool(e) && !checked && simplify_bool(n, res)) { TRACE("ctx_solver_simplify_tactic", tout << "simplified: " << mk_pp(e, m) << " |-> " << mk_pp(res, m) << "\n";); goto done; @@ -193,14 +203,11 @@ protected: found.reset(); // arguments already simplified. for (unsigned i = 0; i < sz; ++i) { expr* arg = a->get_arg(i); - if (!m.is_bool(arg)) { - args.push_back(arg); - } - else if (cache.find(arg, path_r) && !found.contains(arg)) { + if (cache.find(arg, path_r) && !found.contains(arg)) { // // This is a single traversal version of the context // simplifier. It simplifies only the first occurrence of - // a formula with respect to the context. + // a sub-term with respect to the context. // found.push_back(arg); @@ -208,15 +215,18 @@ protected: TRACE("ctx_solver_simplify_tactic", tout << "cached " << mk_pp(arg, m) << " |-> " << mk_pp(path_r.second, m) << "\n";); args.push_back(path_r.second); } - else { + else if (m.is_bool(arg)) { res = local_simplify(a, n, id, i); TRACE("ctx_solver_simplify_tactic", tout << "Already cached: " << path_r.first << " " << mk_pp(res, m) << "\n";); + args.push_back(res); + } + else { args.push_back(arg); } } else if (!n2 && !found.contains(arg)) { - n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); + n2 = mk_fresh(id, m.get_sort(arg)); trail.push_back(n2); todo.push_back(arg); parent_ids.push_back(self_pos); @@ -254,8 +264,10 @@ protected: is_checked.pop_back(); m_solver.pop(1); } - VERIFY(cache.find(fml, path_r)); - result = path_r.second; + if (!m_cancel) { + VERIFY(cache.find(fml, path_r)); + result = path_r.second; + } } bool simplify_bool(expr* n, expr_ref& res) { @@ -282,11 +294,25 @@ protected: return false; } + expr_ref mk_fresh(unsigned& id, sort* s) { + func_decl* fn; + if (m.is_bool(s)) { + fn = m_fn; + } + else if (!m_fns.find(s, fn)) { + fn = m.mk_func_decl(symbol(0xbeef101 + id), m_arith.mk_int(), s); + m.inc_ref(fn); + m_fns.insert(s, fn); + } + return expr_ref(m.mk_app(fn, m_arith.mk_numeral(rational(id++), true)), m); + } + + expr_ref local_simplify(app* a, expr* n, unsigned& id, unsigned index) { SASSERT(index < a->get_num_args()); SASSERT(m.is_bool(a->get_arg(index))); expr_ref n2(m), result(m), tmp(m); - n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); + n2 = mk_fresh(id, m.get_sort(a->get_arg(index))); ptr_buffer args; for (unsigned i = 0; i < a->get_num_args(); ++i) { if (i == index) { From b427958b9eef053488a57f67cc0125c5f0141e55 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 25 Mar 2013 09:53:11 -0700 Subject: [PATCH 56/97] qe_lite> fix crash in is_var_eq() (by me & Nikolaj) Signed-off-by: Nuno Lopes --- src/muz_qe/qe_lite.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/muz_qe/qe_lite.cpp b/src/muz_qe/qe_lite.cpp index be3f80f92..ff49584ff 100644 --- a/src/muz_qe/qe_lite.cpp +++ b/src/muz_qe/qe_lite.cpp @@ -201,9 +201,15 @@ namespace eq { return (*m_is_variable)(e); } - bool is_neg_var(ast_manager & m, expr * e) { + bool is_neg_var(ast_manager & m, expr * e, var*& v) { expr* e1; - return m.is_not(e, e1) && is_variable(e1); + if (m.is_not(e, e1) && is_variable(e1)) { + v = to_var(e1); + return true; + } + else { + return false; + } } @@ -328,18 +334,19 @@ namespace eq { bool is_var_eq(expr * e, ptr_vector& vs, expr_ref_vector & ts) { expr* lhs, *rhs; + var* v; // (= VAR t), (iff VAR t), (iff (not VAR) t), (iff t (not VAR)) cases if (m.is_eq(e, lhs, rhs) || m.is_iff(e, lhs, rhs)) { // (iff (not VAR) t) (iff t (not VAR)) cases if (!is_variable(lhs) && !is_variable(rhs) && m.is_bool(lhs)) { - if (!is_neg_var(m, lhs)) { + if (!is_neg_var(m, lhs, v)) { std::swap(lhs, rhs); } - if (!is_neg_var(m, lhs)) { + if (!is_neg_var(m, lhs, v)) { return false; } - vs.push_back(to_var(lhs)); + vs.push_back(v); ts.push_back(m.mk_not(rhs)); TRACE("qe_lite", tout << mk_pp(e, m) << "\n";); return true; @@ -378,9 +385,9 @@ namespace eq { } // VAR = false case - if (is_neg_var(m, e)) { + if (is_neg_var(m, e, v)) { ts.push_back(m.mk_false()); - vs.push_back(to_var(to_app(e)->get_arg(0))); + vs.push_back(v); TRACE("qe_lite", tout << mk_pp(e, m) << "\n";); return true; } From df35da1acfece2af81c7bcbab774a86b835f80b2 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 25 Mar 2013 10:48:48 -0700 Subject: [PATCH 57/97] rule_manager::mk(): default initialization of m_proof to null Signed-off-by: Nuno Lopes --- src/muz_qe/dl_rule.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index a13229e7a..14a316e48 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -502,6 +502,7 @@ namespace datalog { r->m_tail_size = n; r->m_positive_cnt = source->m_positive_cnt; r->m_uninterp_cnt = source->m_uninterp_cnt; + r->m_proof = 0; m.inc_ref(r->m_head); for (unsigned i = 0; i < n; i++) { r->m_tail[i] = source->m_tail[i]; From 9abcde9a358f883befbcad910e880263182e5577 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 25 Mar 2013 14:42:18 -0700 Subject: [PATCH 58/97] Fix typos Signed-off-by: Leonardo de Moura --- src/smt/asserted_formulas.cpp | 2 +- src/tactic/bv/max_bv_sharing_tactic.cpp | 2 +- src/tactic/core/propagate_values_tactic.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 3155d9c58..c5d3c08cf 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -653,7 +653,7 @@ void asserted_formulas::propagate_values() { // will be (silently) eliminated, and models produced by Z3 will not contain them. flush_cache(); } - TRACE("propagate_values", tout << "afer:\n"; display(tout);); + TRACE("propagate_values", tout << "after:\n"; display(tout);); } void asserted_formulas::propagate_booleans() { diff --git a/src/tactic/bv/max_bv_sharing_tactic.cpp b/src/tactic/bv/max_bv_sharing_tactic.cpp index 251e2b754..f60487d60 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.cpp +++ b/src/tactic/bv/max_bv_sharing_tactic.cpp @@ -269,7 +269,7 @@ class max_bv_sharing_tactic : public tactic { m_rw.cfg().cleanup(); g->inc_depth(); result.push_back(g.get()); - TRACE("qe", g->display(tout);); + TRACE("max_bv_sharing", g->display(tout);); SASSERT(g->is_well_sorted()); } }; diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 6d9e6ccbd..1e358177f 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -165,7 +165,7 @@ class propagate_values_tactic : public tactic { m_occs(*m_goal); while (true) { - TRACE("propagate_values", m_goal->display(tout);); + TRACE("propagate_values", tout << "while(true) loop\n"; m_goal->display(tout);); if (forward) { for (; m_idx < size; m_idx++) { process_current(); @@ -201,14 +201,14 @@ class propagate_values_tactic : public tactic { if (round >= m_max_rounds) break; IF_VERBOSE(100, verbose_stream() << "starting new round, goal size: " << m_goal->num_exprs() << std::endl;); - TRACE("propgate_values", tout << "round finished\n"; m_goal->display(tout); tout << "\n";); + TRACE("propagate_values", tout << "round finished\n"; m_goal->display(tout); tout << "\n";); } end: m_goal->elim_redundancies(); m_goal->inc_depth(); result.push_back(m_goal); SASSERT(m_goal->is_well_sorted()); - TRACE("propagate_values", m_goal->display(tout);); + TRACE("propagate_values", tout << "end\n"; m_goal->display(tout);); TRACE("propagate_values_core", m_goal->display_with_dependencies(tout);); m_goal = 0; } From da83a6b28c01bbe9b2dfb25d734d2b2fa6c906d9 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 25 Mar 2013 14:48:22 -0700 Subject: [PATCH 59/97] dl_bit_blasting: run simplifier before bit-blasting, in order to comply with its precondition Signed-off-by: Nuno Lopes --- src/muz_qe/dl_mk_bit_blast.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index 1e984f254..e6612022f 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -23,6 +23,7 @@ Revision History: #include "ast_pp.h" #include "expr_safe_replace.h" #include "filter_model_converter.h" +#include "dl_mk_interp_tail_simplifier.h" namespace datalog { @@ -212,18 +213,23 @@ namespace datalog { ast_manager & m; params_ref m_params; rule_ref_vector m_rules; + mk_interp_tail_simplifier m_simplifier; bit_blaster_rewriter m_blaster; expand_mkbv m_rewriter; - bool blast(expr_ref& fml) { + bool blast(rule *r, expr_ref& fml) { proof_ref pr(m); - expr_ref fml1(m), fml2(m); - m_blaster(fml, fml1, pr); - m_rewriter(fml1, fml2); - TRACE("dl", tout << mk_pp(fml, m) << " -> " << mk_pp(fml1, m) << " -> " << mk_pp(fml2, m) << "\n";); - if (fml2 != fml) { - fml = fml2; + expr_ref fml1(m), fml2(m), fml3(m); + rule_ref r2(m_context.get_rule_manager()); + // We need to simplify rule before bit-blasting. + m_simplifier.transform_rule(r, r2); + r2->to_formula(fml1); + m_blaster(fml1, fml2, pr); + m_rewriter(fml2, fml3); + TRACE("dl", tout << mk_pp(fml, m) << " -> " << mk_pp(fml2, m) << " -> " << mk_pp(fml3, m) << "\n";); + if (fml3 != fml) { + fml = fml3; return true; } else { @@ -241,6 +247,7 @@ namespace datalog { m(ctx.get_manager()), m_params(ctx.get_params().p), m_rules(ctx.get_rule_manager()), + m_simplifier(ctx), m_blaster(ctx.get_manager(), m_params), m_rewriter(ctx.get_manager(), ctx, m_rules) { m_params.set_bool("blast_full", true); @@ -261,12 +268,12 @@ namespace datalog { for (unsigned i = 0; i < sz; ++i) { rule * r = source.get_rule(i); r->to_formula(fml); - if (blast(fml)) { + if (blast(r, fml)) { proof_ref pr(m); if (m_context.generate_proof_trace()) { pr = m.mk_asserted(fml); // loses original proof of r. } - rm.mk_rule(fml, pr, m_rules, r->name()); + rm.mk_rule(fml, pr, m_rules, r->name()); } else { m_rules.push_back(r); From f32eaee62ef61ae8fb6d09593bb71f551413c10f Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 25 Mar 2013 15:40:52 -0700 Subject: [PATCH 60/97] Replace std::sort with std::stable_sort when the given relation is just a partial order. This change avoids discrepancies when using different implmentations of std::sort. Signed-off-by: Leonardo de Moura --- src/ast/simplifier/poly_simplifier_plugin.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ast/simplifier/poly_simplifier_plugin.cpp b/src/ast/simplifier/poly_simplifier_plugin.cpp index 13e5748dc..402b078a8 100644 --- a/src/ast/simplifier/poly_simplifier_plugin.cpp +++ b/src/ast/simplifier/poly_simplifier_plugin.cpp @@ -18,6 +18,7 @@ Author: #include"ast_pp.h" #include"ast_util.h" #include"ast_smt2_pp.h" +#include"ast_ll_pp.h" poly_simplifier_plugin::poly_simplifier_plugin(symbol const & fname, ast_manager & m, decl_kind add, decl_kind mul, decl_kind uminus, decl_kind sub, decl_kind num): @@ -173,7 +174,7 @@ void poly_simplifier_plugin::mk_monomial(unsigned num_args, expr * * args, expr_ result = args[0]; break; default: - std::sort(args, args + num_args, monomial_element_lt_proc(*this)); + std::stable_sort(args, args + num_args, monomial_element_lt_proc(*this)); result = mk_mul(num_args, args); SASSERT(wf_monomial(result)); break; @@ -465,7 +466,9 @@ void poly_simplifier_plugin::mk_sum_of_monomials(expr_ref_vector & monomials, ex result = monomials.get(0); break; default: { - std::sort(monomials.c_ptr(), monomials.c_ptr() + monomials.size(), monomial_lt_proc(*this)); + TRACE("mk_sum_sort", tout << "before\n"; for (unsigned i = 0; i < monomials.size(); i++) tout << mk_ll_pp(monomials.get(i), m_manager) << "\n";); + std::stable_sort(monomials.c_ptr(), monomials.c_ptr() + monomials.size(), monomial_lt_proc(*this)); + TRACE("mk_sum_sort", tout << "after\n"; for (unsigned i = 0; i < monomials.size(); i++) tout << mk_ll_pp(monomials.get(i), m_manager) << "\n";); if (is_simple_sum_of_monomials(monomials)) { mk_sum_of_monomials_core(monomials.size(), monomials.c_ptr(), result); return; From 25a41d48dc7367d9042661562380664dbd606e2e Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 25 Mar 2013 15:41:52 -0700 Subject: [PATCH 61/97] speedup bit_vector::num_words() Proof of equivalence w.r.t. previous code: http://rise4fun.com/Z3/aiLV Signed-off-by: Nuno Lopes --- src/util/bit_vector.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index 2e7becee7..1d6083717 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -37,7 +37,8 @@ class bit_vector { } static unsigned num_words(unsigned num_bits) { - return (num_bits % 32) == 0 ? (num_bits / 32) : ((num_bits / 32) + 1); + // return (num_bits % 32) == 0 ? (num_bits / 32) : ((num_bits / 32) + 1); + return (num_bits + 31) / 32; } void expand_to(unsigned new_capacity); From b417ca657d388a3f635b19f371b5d3975835f412 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 25 Mar 2013 16:52:08 -0700 Subject: [PATCH 62/97] Fix set_interruptable usage Signed-off-by: Leonardo de Moura --- src/api/api_algebraic.cpp | 4 ++-- src/api/api_ast.cpp | 2 +- src/api/api_datalog.cpp | 4 ++-- src/api/api_polynomial.cpp | 2 +- src/api/api_solver.cpp | 2 +- src/api/api_solver_old.cpp | 4 ++-- src/api/api_tactic.cpp | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index 7716cbb59..d03a6aff4 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -373,7 +373,7 @@ extern "C" { scoped_anum_vector roots(_am); { cancel_eh eh(_am); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); scoped_timer timer(mk_c(c)->params().m_timeout, &eh); vector_var2anum v2a(as); _am.isolate_roots(_p, v2a, roots); @@ -408,7 +408,7 @@ extern "C" { } { cancel_eh eh(_am); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); scoped_timer timer(mk_c(c)->params().m_timeout, &eh); vector_var2anum v2a(as); int r = _am.eval_sign_at(_p, v2a); diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index e93e1a178..680b59c68 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -681,7 +681,7 @@ extern "C" { th_rewriter m_rw(m, p); expr_ref result(m); cancel_eh eh(m_rw); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); { scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); scoped_timer timer(timeout, &eh); diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 28fe3ed33..0f100e747 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -266,7 +266,7 @@ extern "C" { lbool r = l_undef; cancel_eh eh(*to_fixedpoint_ref(d)); unsigned timeout = to_fixedpoint(d)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); { scoped_timer timer(timeout, &eh); try { @@ -291,7 +291,7 @@ extern "C" { lbool r = l_undef; unsigned timeout = to_fixedpoint(d)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); cancel_eh eh(*to_fixedpoint_ref(d)); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); { scoped_timer timer(timeout, &eh); try { diff --git a/src/api/api_polynomial.cpp b/src/api/api_polynomial.cpp index 3148f972b..25d4ca292 100644 --- a/src/api/api_polynomial.cpp +++ b/src/api/api_polynomial.cpp @@ -67,7 +67,7 @@ extern "C" { expr_ref _r(mk_c(c)->m()); { cancel_eh eh(pm); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); scoped_timer timer(mk_c(c)->params().m_timeout, &eh); pm.psc_chain(_p, _q, v_x, rs); } diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 9ace149af..ac30a0c21 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -243,7 +243,7 @@ extern "C" { unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", false); cancel_eh eh(*to_solver_ref(s)); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); lbool result; { scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); diff --git a/src/api/api_solver_old.cpp b/src/api/api_solver_old.cpp index c89f89873..e0533fbd9 100644 --- a/src/api/api_solver_old.cpp +++ b/src/api/api_solver_old.cpp @@ -73,7 +73,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_SEARCHING(c); cancel_eh eh(mk_c(c)->get_smt_kernel()); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); flet _model(mk_c(c)->fparams().m_model, true); lbool result; try { @@ -123,7 +123,7 @@ extern "C" { expr * const* _assumptions = to_exprs(assumptions); flet _model(mk_c(c)->fparams().m_model, true); cancel_eh eh(mk_c(c)->get_smt_kernel()); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); lbool result; result = mk_c(c)->get_smt_kernel().check(num_assumptions, _assumptions); if (result != l_false && m) { diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index 5bce218e6..911360047 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -410,7 +410,7 @@ extern "C" { to_tactic_ref(t)->updt_params(p); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); { scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); scoped_timer timer(timeout, &eh); From 00e79e6b6b25d5dbb908559bc2c6807830068f96 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Mar 2013 17:31:11 -0700 Subject: [PATCH 63/97] test hilbert-basis with fdds and checked integers Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_bit_blast.cpp | 7 +- src/muz_qe/fdd.cpp | 311 +++++++++++++++++++++++++++++++++ src/muz_qe/fdd.h | 169 ++++++++++++++++++ src/muz_qe/heap_trie.h | 12 +- src/muz_qe/hilbert_basis.cpp | 184 ++++++++++++------- src/muz_qe/hilbert_basis.h | 40 +++-- src/test/fdd.cpp | 87 +++++++++ src/test/heap_trie.cpp | 3 +- src/test/hilbert_basis.cpp | 7 + src/test/main.cpp | 1 + src/util/checked_int64.h | 231 ++++++++++++++++++++++++ 11 files changed, 969 insertions(+), 83 deletions(-) create mode 100644 src/muz_qe/fdd.cpp create mode 100644 src/muz_qe/fdd.h create mode 100644 src/test/fdd.cpp create mode 100644 src/util/checked_int64.h diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index 1e984f254..ccba0d69f 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -212,6 +212,7 @@ namespace datalog { ast_manager & m; params_ref m_params; rule_ref_vector m_rules; + th_rewriter m_theory_rewriter; bit_blaster_rewriter m_blaster; expand_mkbv m_rewriter; @@ -219,6 +220,7 @@ namespace datalog { bool blast(expr_ref& fml) { proof_ref pr(m); expr_ref fml1(m), fml2(m); + m_theory_rewriter(fml); m_blaster(fml, fml1, pr); m_rewriter(fml1, fml2); TRACE("dl", tout << mk_pp(fml, m) << " -> " << mk_pp(fml1, m) << " -> " << mk_pp(fml2, m) << "\n";); @@ -241,8 +243,9 @@ namespace datalog { m(ctx.get_manager()), m_params(ctx.get_params().p), m_rules(ctx.get_rule_manager()), - m_blaster(ctx.get_manager(), m_params), - m_rewriter(ctx.get_manager(), ctx, m_rules) { + m_theory_rewriter(m, m_params), + m_blaster(m, m_params), + m_rewriter(m, ctx, m_rules) { m_params.set_bool("blast_full", true); m_params.set_bool("blast_quant", true); m_blaster.updt_params(m_params); diff --git a/src/muz_qe/fdd.cpp b/src/muz_qe/fdd.cpp new file mode 100644 index 000000000..afb5206cc --- /dev/null +++ b/src/muz_qe/fdd.cpp @@ -0,0 +1,311 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + fdd.cpp + +Abstract: + + Finite decision diagram trie. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-07-03. + +Revision History: + + +--*/ + +#include "fdd.h" +#include "hash.h" +#include "bit_vector.h" +#include "trace.h" + +#define OFFSET_OF(ty, field) (unsigned char*)(&((ty*)(0))->field) - (unsigned char*)(ty*)(0) + +using namespace fdd; + +unsigned node::get_hash() const { + return string_hash((char*)this, OFFSET_OF(node, m_ref_count), 11); +} + +bool node::operator==(node const& other) const { + return + m_var == other.m_var && + m_lo == other.m_lo && + m_hi == other.m_hi; +} + + +// ------------------------------------------ +// manager + +manager::manager() : + m_false(0), + m_true(1), + m_root(m_false), + m_alloc_node(2) +{ + m_nodes.push_back(node()); // false + m_nodes.push_back(node()); // true + inc_ref(m_false); + inc_ref(m_true); + alloc_node(); // pre-allocate a node. +} + +manager::~manager() { +} + +void manager::alloc_node() { + unsigned index; + while (!m_free.empty()) { + index = m_free.back(); + node& n = m_nodes[index]; + m_free.pop_back(); + if (n.get_ref_count() == 0) { + if (!is_leaf(n.lo())) { + m_free.push_back(n.lo()); + } + if (!is_leaf(n.hi())) { + m_free.push_back(n.hi()); + } + m_alloc_node = index; + m_table.erase(n); + return; + } + } + index = m_nodes.size(); + m_nodes.push_back(node()); + m_alloc_node = index; +} + +node_id manager::mk_node(unsigned var, node_id lo, node_id hi) { + if (lo == hi) { + return lo; + } + node n(var, lo, hi); + unsigned index = m_alloc_node; + + node_id result = m_table.insert_if_not_there(n, index).m_value; + + if (result == index) { + alloc_node(); + m_nodes[result] = n; + inc_ref(lo); + inc_ref(hi); + } + + TRACE("mtdd", tout << "mk_node: " << var << " " << lo << " " << hi << " -> " << result << "\n";); + + return result; +} + + +void manager::inc_ref(node_id n) { + TRACE("mtdd", tout << "incref: " << n << "\n";); + if (!is_leaf(n)) { + m_nodes[n].inc_ref(); + } +} + +void manager::dec_ref(node_id n) { + if (!is_leaf(n) && 0 == m_nodes[n].dec_ref()) { + m_free.push_back(n); + } +} + +void manager::setup_keys(Key const* keys) { + for (unsigned i = 0; i < m_num_keys; ++i) { + m_keys[i] = (uint64)keys[i]; + m_sign[i] = keys[i] < 0; + } + +} + +void manager::insert(Key const* keys) { + setup_keys(keys); + node_id result = insert_sign(m_num_idx + m_num_keys, m_root); + inc_ref(result); + dec_ref(m_root); + m_root = result; +} + +node_id manager::insert_sign(unsigned idx, node_id n) { + if (idx > m_num_idx) { + --idx; + bool s = idx2sign(idx); + node nd = m_nodes[n]; + if (!is_leaf(n) && nd.var() == idx) { + if (s) { + return mk_node(idx, insert_sign(idx, nd.lo()), nd.hi()); + } + else { + return mk_node(idx, nd.lo(), insert_sign(idx, nd.hi())); + } + } + else { + if (s) { + return mk_node(idx, insert_sign(idx, n), n); + } + else { + return mk_node(idx, n, insert_sign(idx, n)); + } + } + } + SASSERT(m_num_idx == idx); + return insert(idx, n); +} + +node_id manager::insert(unsigned idx, node_id n) { + node_id result; + SASSERT(0 <= idx && idx <= m_num_idx); + TRACE("mtdd", tout << "insert: " << idx << " " << n << "\n";); + if (is_leaf(n)) { + while (idx > 0) { + --idx; + if (idx2bit(idx) && !is_dont_care(idx2key(idx))) { + return mk_node(idx, n, insert(idx, n)); + } + } + return m_true; + } + + SASSERT(0 < idx); + --idx; + + config c(m_dont_cares, idx, n); + insert_cache::key_data & kd = m_insert_cache.insert_if_not_there2(c, 0)->get_data(); + if (kd.m_value != 0) { + return kd.m_value; + } + + node nd = m_nodes[n]; + SASSERT(idx >= nd.var()); + unsigned idx0 = idx; + while (idx > nd.var()) { + if (idx2bit(idx) && !is_dont_care(idx2key(idx))) { + return mk_node(idx, n, insert(idx, n)); + } + --idx; + } + SASSERT(nd.var() == idx); + unsigned key = idx2key(idx); + if (is_dont_care(key)) { + result = mk_node(idx, insert(idx, nd.lo()), insert(idx, nd.hi())); + } + else { + bool bit = idx2bit(idx); + node_id lo, hi; + if (bit) { + hi = insert(idx, nd.hi()); + lo = nd.lo(); + } + else { + lo = insert(idx, nd.lo()); + scoped_dont_cares _set(*this, key); + hi = insert(idx, nd.hi()); + } + result = mk_node(idx, lo, hi); + } + kd.m_value = result; + return result; +} + +void manager::set_dont_care(unsigned key) { + SASSERT(!is_dont_care(key)); + m_dont_cares |= (1ull << key); +} + +void manager::unset_dont_care(unsigned key) { + m_dont_cares &= ~(1ull << key); +} + +bool manager::is_dont_care(unsigned key) const { + return 0 != (m_dont_cares & (1ull << key)); +} + +void manager::collect_statistics(statistics& st) const { + st.update("fdd.num_nodes", m_nodes.size()); +} + + +void manager::reset(unsigned num_keys) { + m_num_keys = num_keys; + m_num_idx = m_num_keys * m_num_bits; + m_dont_cares = 0; + m_sign.resize(num_keys); + m_keys.resize(num_keys); + SASSERT(num_keys <= 8*sizeof(m_dont_cares)); +} + + + +bool manager::find_le(Key const* keys) { + setup_keys(keys); + unsigned idx = m_num_idx + m_num_keys; + node_id n = m_root; + node nc = m_nodes[n]; + while (n > 1 && idx > m_num_idx) { + --idx; + if (nc.var() == idx) { + if (idx2sign(idx)) { + n = nc.lo(); + } + else { + n = nc.hi(); + } + nc = m_nodes[n]; + } + } + while (n > 1) { + SASSERT(idx > 0); + --idx; + while (nc.var() < idx) { + if (idx2bit(idx)) { + set_dont_care(idx2key(idx)); + } + --idx; + } + if (is_dont_care(idx2key(idx)) || idx2bit(idx)) { + n = nc.hi(); + } + else { + n = nc.lo(); + } + nc = m_nodes[n]; + } + m_dont_cares = 0; + return n == 1; +} + + +std::ostream& manager::display(std::ostream& out, node_id n) const{ + svector mark; + svector nodes; + nodes.push_back(n); + while (!nodes.empty()) { + n = nodes.back(); + nodes.pop_back(); + if (mark.size() <= n) { + mark.resize(n+1, false); + } + node const& nc = m_nodes[n]; + if (is_leaf(n) || mark[n]) { + continue; + } + nodes.push_back(nc.lo()); + nodes.push_back(nc.hi()); + mark[n] = true; + + if (nc.var() >= m_num_idx) { + out << n << " if " << idx2key(nc.var()) << " then " << nc.hi() << " else " << nc.lo() << "\n"; + } + else { + out << n << " if " << idx2key(nc.var()) << ":" << idx2bitnum(nc.var()) << " then " << nc.hi() << " else " << nc.lo() << "\n"; + } + } + return out; +} + diff --git a/src/muz_qe/fdd.h b/src/muz_qe/fdd.h new file mode 100644 index 000000000..e6808375c --- /dev/null +++ b/src/muz_qe/fdd.h @@ -0,0 +1,169 @@ +/*++ +Copyright (c) 2007 Microsoft Corporation + +Module Name: + + fdd.h + +Abstract: + + Finite decision diagram. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-07-03. + +Revision History: + + +--*/ + +#ifndef __FDD_H__ +#define __FDD_H__ + +#include "hashtable.h" +#include "hash.h" +#include "map.h" +#include "vector.h" +#include "statistics.h" + +namespace fdd { + + + typedef unsigned node_id; + + class node { + unsigned m_var; + node_id m_lo; + node_id m_hi; + unsigned m_ref_count; + void reset(); + public: + node() : m_var(0), m_hi(0), m_lo(0), m_ref_count(0) {} + node(unsigned var, node_id l, node_id h): m_var(var), m_lo(l), m_hi(h), m_ref_count(0) {} + + unsigned get_hash() const; + bool operator==(node const& other) const; + + void inc_ref() { ++m_ref_count; } + unsigned dec_ref() { return --m_ref_count; } + unsigned get_ref_count() const { return m_ref_count; } + node_id lo() const { return m_lo; } + node_id hi() const { return m_hi; } + unsigned var() const { return m_var; } + + struct hash { unsigned operator()(node const& n) const { return n.get_hash(); } }; + struct eq { bool operator()(node const& l, node const& r) const { return l == r; } }; + std::ostream& display(std::ostream& out) const { return out << m_var << " " << m_lo << " " << m_hi << ""; } + }; + + inline std::ostream& operator<<(std::ostream& out, node const& n) { return n.display(out); } + + class config { + uint64 m_dont_cares; + unsigned m_idx; + node_id m_node; + public: + + config(): m_dont_cares(0), m_idx(0), m_node(0) {} + + config(uint64 dont_cares, unsigned idx, node_id n): + m_dont_cares(dont_cares), + m_idx(idx), + m_node(n) + {} + + struct hash { + unsigned operator()(config const& c) const { + return string_hash((char*)&c, sizeof(c), 12); + }; + }; + + struct eq { + bool operator()(config const& a, config const& b) const { + return + a.m_dont_cares == b.m_dont_cares && + a.m_idx == b.m_idx && + a.m_node == b.m_node; + } + }; + }; + + + class manager { + public: + typedef int64 Key; + private: + typedef map node_table; + typedef map insert_cache; + node_table m_table; + insert_cache m_insert_cache; + svector m_nodes; + unsigned_vector m_free; + unsigned m_alloc_node; + node_id m_false; + node_id m_true; + node_id m_root; + + static const unsigned m_num_bits = 64; + unsigned m_num_keys; + unsigned m_num_idx; // = m_num_keys * m_num_bits + + // state associated with insert. + svector m_keys; + svector m_sign; + + uint64 m_dont_cares; + + public: + manager(); + ~manager(); + + void reset(unsigned num_keys); + + void insert(Key const* keys); + + bool find_le(Key const* keys); + + void collect_statistics(statistics& st) const; + void reset_statistics() {} + unsigned size() const { return m_nodes.size(); } + + void display(std::ostream& out) const { display(out, m_root); } + + private: + void dec_ref(node_id n); + void inc_ref(node_id n); + node_id mk_node(unsigned var, node_id lo, node_id hi); + inline unsigned get_ref_count(node_id n) { return m_nodes[n].get_ref_count(); } + + std::ostream& display(std::ostream& out, node_id n) const; + + void setup_keys(Key const* keys); + node_id insert(unsigned idx, node_id n); + node_id insert_sign(unsigned idx, node_id n); + bool is_dont_care(unsigned idx) const; + + void set_dont_care(unsigned key); + void unset_dont_care(unsigned key); + + struct scoped_dont_cares { + manager& m; + unsigned m_key; + scoped_dont_cares(manager& m, unsigned key):m(m), m_key(key) { m.set_dont_care(key); } + ~scoped_dont_cares() { m.unset_dont_care(m_key); } + }; + + void alloc_node(); + + unsigned idx2key(unsigned i) const { return i % m_num_keys; } + unsigned idx2bitnum(unsigned i) const { SASSERT(i < m_num_idx); return (i / m_num_keys); } + bool idx2bit(unsigned i) const { return 0 != (m_keys[idx2key(i)] & (1LL << idx2bitnum(i))); } + bool idx2sign(unsigned i) const { return m_sign[idx2key(i)]; } + + bool is_leaf(node_id n) const { return n <= 1; } + + }; +}; + +#endif diff --git a/src/muz_qe/heap_trie.h b/src/muz_qe/heap_trie.h index a99861359..c2a1c52d1 100644 --- a/src/muz_qe/heap_trie.h +++ b/src/muz_qe/heap_trie.h @@ -123,9 +123,9 @@ class heap_trie { } // push nodes whose keys are <= key into vector. - void find_le(Key key, ptr_vector& nodes) { + void find_le(KeyLE& le, Key key, ptr_vector& nodes) { for (unsigned i = 0; i < m_nodes.size(); ++i) { - if (KeyLE::le(m_nodes[i].first, key)) { + if (le.le(m_nodes[i].first, key)) { node* n = m_nodes[i].second; if (n->ref_count() > 0){ nodes.push_back(n); @@ -179,6 +179,7 @@ class heap_trie { }; small_object_allocator m_alloc; + KeyLE& m_le; unsigned m_num_keys; unsigned_vector m_keys; unsigned m_do_reshuffle; @@ -189,8 +190,9 @@ class heap_trie { public: - heap_trie(): + heap_trie(KeyLE& le): m_alloc("heap_trie"), + m_le(le), m_num_keys(0), m_do_reshuffle(4), m_root(0), @@ -255,7 +257,7 @@ public: for (unsigned i = 0; i < num_keys(); ++i) { for (unsigned j = 0; j < todo[index].size(); ++j) { ++m_stats.m_num_find_le_nodes; - to_trie(todo[index][j])->find_le(get_key(keys, i), todo[!index]); + to_trie(todo[index][j])->find_le(m_le, get_key(keys, i), todo[!index]); } todo[index].reset(); index = !index; @@ -577,7 +579,7 @@ private: verbose_stream() << " "; } verbose_stream() << nodes[i].first << " <=? " << key << " rc:" << m->ref_count() << "\n";); - if (m->ref_count() > 0 && KeyLE::le(nodes[i].first, key) && find_le(m, index+1, keys, check)) { + if (m->ref_count() > 0 && m_le.le(nodes[i].first, key) && find_le(m, index+1, keys, check)) { if (i > 0) { std::swap(nodes[i], nodes[0]); } diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index 9fbd8cc2e..221e9a706 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -21,6 +21,7 @@ Revision History: #include "heap.h" #include "map.h" #include "heap_trie.h" +#include "fdd.h" #include "stopwatch.h" @@ -58,14 +59,13 @@ public: m_table.reset(); } - bool find(offset_t idx, values const& vs, offset_t& found_idx) { + bool find(offset_t idx, values const& vs) { // display_profile(idx, std::cout); int_table::iterator it = m_table.begin(), end = m_table.end(); for (; it != end; ++it) { offset_t offs(*it); ++m_stats.m_num_comparisons; if (*it != static_cast(idx.m_offset) && hb.is_subsumed(idx, offs)) { - found_idx = offs; ++m_stats.m_num_hit; return true; } @@ -163,20 +163,21 @@ private: class hilbert_basis::value_index2 { struct key_le { - static bool le(numeral const& n1, numeral const& n2) { - return hilbert_basis::is_abs_geq(n2, n1); + hilbert_basis& hb; + key_le(hilbert_basis& hb): hb(hb) {} + bool le(numeral const& n1, numeral const& n2) const { + return hb.is_abs_geq(n2, n1); } }; typedef heap_trie ht; + struct checker : public ht::check_value { hilbert_basis* hb; offset_t m_value; - offset_t* m_found; - checker(): hb(0), m_found(0) {} - virtual bool operator()(unsigned const& v) { - if (m_value.m_offset != v && hb->is_subsumed(m_value, offset_t(v))) { - *m_found = offset_t(v); + checker(): hb(0) {} + virtual bool operator()(unsigned const& v) { + if (m_value.m_offset != v) { // && hb->is_subsumed(m_value, offset_t(v))) { return true; } else { @@ -185,23 +186,25 @@ class hilbert_basis::value_index2 { } }; hilbert_basis& hb; + key_le m_le; ht m_trie; - vector m_found; - bool m_init; checker m_checker; - vector m_keys; + unsigned m_offset; numeral const* get_keys(values const& vs) { - return vs()-1; + return vs()-m_offset; } public: - value_index2(hilbert_basis& hb): hb(hb), m_init(false) { + value_index2(hilbert_basis& hb): + hb(hb), + m_le(hb), + m_trie(m_le), + m_offset(1) { m_checker.hb = &hb; } void insert(offset_t idx, values const& vs) { - init(); m_trie.insert(get_keys(vs), idx.m_offset); } @@ -209,15 +212,13 @@ public: m_trie.remove(get_keys(vs)); } - void reset() { - m_trie.reset(hb.get_num_vars()+1); - m_keys.resize(hb.get_num_vars()+1); + void reset(unsigned offset) { + m_offset = offset; + m_trie.reset(hb.get_num_vars()+m_offset); } - bool find(offset_t idx, values const& vs, offset_t& found_idx) { - init(); + bool find(offset_t idx, values const& vs) { m_checker.m_value = idx; - m_checker.m_found = &found_idx; return m_trie.find_le(get_keys(vs), m_checker); } @@ -237,15 +238,63 @@ public: // m_trie.display(out); } -private: - void init() { - if (!m_init) { - reset(); - m_init = true; - } - } + }; +class hilbert_basis::value_index3 { + hilbert_basis& hb; + fdd::manager m_fdd; + unsigned m_offset; + svector m_keys; + + int64 const* get_keys(values const& vs) { + numeral const* nums = vs()-m_offset; + for (unsigned i = 0; i < m_keys.size(); ++i) { + m_keys[i] = nums[i].get_int64(); + } + return m_keys.c_ptr(); + } + +public: + + value_index3(hilbert_basis & hb): hb(hb), m_offset(1) {} + + void insert(offset_t, values const& vs) { + m_fdd.insert(get_keys(vs)); + } + + bool find(offset_t, values const& vs) { + return m_fdd.find_le(get_keys(vs)); + } + + void reset(unsigned offset) { + m_offset = offset; + m_fdd.reset(hb.get_num_vars()+m_offset); + m_keys.resize(hb.get_num_vars()+m_offset); + } + + void collect_statistics(statistics& st) const { + m_fdd.collect_statistics(st); + } + + void reset_statistics() { + m_fdd.reset_statistics(); + } + + unsigned size() const { + return m_fdd.size(); + } + + void remove(offset_t idx, values const& vs) { + UNREACHABLE(); + } + + void display(std::ostream& out) const { + // m_fdd.display(out); + } + + +}; class hilbert_basis::index { @@ -253,7 +302,8 @@ class hilbert_basis::index { // for positive weights a shared value index. // typedef value_index1 value_index; - typedef value_index2 value_index; + // typedef value_index2 value_index; + typedef value_index3 value_index; struct stats { unsigned m_num_find; @@ -271,9 +321,10 @@ class hilbert_basis::index { value_index m_pos; value_index m_zero; stats m_stats; + unsigned m_num_ineqs; public: - index(hilbert_basis& hb): hb(hb), m_pos(hb), m_zero(hb) {} + index(hilbert_basis& hb): hb(hb), m_pos(hb), m_zero(hb), m_num_ineqs(0) {} void insert(offset_t idx, values const& vs) { ++m_stats.m_num_insert; @@ -287,6 +338,7 @@ public: value_index* map = 0; if (!m_neg.find(vs.weight(), map)) { map = alloc(value_index, hb); + map->reset(m_num_ineqs); m_neg.insert(vs.weight(), map); } map->insert(idx, vs); @@ -305,29 +357,30 @@ public: } } - bool find(offset_t idx, values const& vs, offset_t& found_idx) { + bool find(offset_t idx, values const& vs) { ++m_stats.m_num_find; if (vs.weight().is_pos()) { - return m_pos.find(idx, vs, found_idx); + return m_pos.find(idx, vs); } else if (vs.weight().is_zero()) { - return m_zero.find(idx, vs, found_idx); + return m_zero.find(idx, vs); } else { value_index* map; return m_neg.find(vs.weight(), map) && - map->find(idx, vs, found_idx); + map->find(idx, vs); } } - void reset() { + void reset(unsigned num_ineqs) { value_map::iterator it = m_neg.begin(), end = m_neg.end(); for (; it != end; ++it) { - it->m_value->reset(); + dealloc(it->m_value); } - m_pos.reset(); - m_zero.reset(); + m_pos.reset(num_ineqs); + m_zero.reset(num_ineqs); + m_num_ineqs = num_ineqs; m_neg.reset(); } @@ -685,7 +738,7 @@ void hilbert_basis::reset() { m_passive->reset(); m_passive2->reset(); m_zero.reset(); - m_index->reset(); + m_index->reset(1); m_ints.reset(); m_cancel = false; } @@ -703,42 +756,46 @@ void hilbert_basis::reset_statistics() { m_index->reset_statistics(); } -void hilbert_basis::add_ge(num_vector const& v, numeral const& b) { +void hilbert_basis::add_ge(rational_vector const& v, rational const& b) { SASSERT(m_ineqs.empty() || v.size() + 1 == m_ineqs.back().size()); num_vector w; - w.push_back(-b); - w.append(v); + w.push_back(to_numeral(-b)); + for (unsigned i = 0; i < v.size(); ++i) { + w.push_back(to_numeral(v[i])); + } m_ineqs.push_back(w); m_iseq.push_back(false); } -void hilbert_basis::add_le(num_vector const& v, numeral const& b) { - num_vector w(v); +void hilbert_basis::add_le(rational_vector const& v, rational const& b) { + rational_vector w(v); for (unsigned i = 0; i < w.size(); ++i) { w[i].neg(); } add_ge(w, -b); } -void hilbert_basis::add_eq(num_vector const& v, numeral const& b) { +void hilbert_basis::add_eq(rational_vector const& v, rational const& b) { SASSERT(m_ineqs.empty() || v.size() + 1 == m_ineqs.back().size()); num_vector w; - w.push_back(-b); - w.append(v); + w.push_back(to_numeral(-b)); + for (unsigned i = 0; i < v.size(); ++i) { + w.push_back(to_numeral(v[i])); + } m_ineqs.push_back(w); m_iseq.push_back(true); } -void hilbert_basis::add_ge(num_vector const& v) { - add_ge(v, numeral(0)); +void hilbert_basis::add_ge(rational_vector const& v) { + add_ge(v, rational(0)); } -void hilbert_basis::add_le(num_vector const& v) { - add_le(v, numeral(0)); +void hilbert_basis::add_le(rational_vector const& v) { + add_le(v, rational(0)); } -void hilbert_basis::add_eq(num_vector const& v) { - add_eq(v, numeral(0)); +void hilbert_basis::add_eq(rational_vector const& v) { + add_eq(v, rational(0)); } void hilbert_basis::set_is_int(unsigned var_index) { @@ -824,7 +881,7 @@ lbool hilbert_basis::saturate_orig(num_vector const& ineq, bool is_eq) { m_active.reset(); m_passive->reset(); m_zero.reset(); - m_index->reset(); + m_index->reset(m_current_ineq+1); int_table support; TRACE("hilbert_basis", display_ineq(tout, ineq, is_eq);); iterator it = begin(); @@ -896,7 +953,7 @@ bool hilbert_basis::vector_lt(offset_t idx1, offset_t idx2) const { lbool hilbert_basis::saturate(num_vector const& ineq, bool is_eq) { m_zero.reset(); - m_index->reset(); + m_index->reset(m_current_ineq+1); m_passive2->reset(); m_sos.reset(); TRACE("hilbert_basis", display_ineq(tout, ineq, is_eq);); @@ -975,19 +1032,21 @@ lbool hilbert_basis::saturate(num_vector const& ineq, bool is_eq) { return m_basis.empty()?l_false:l_true; } -void hilbert_basis::get_basis_solution(unsigned i, num_vector& v, bool& is_initial) { +void hilbert_basis::get_basis_solution(unsigned i, rational_vector& v, bool& is_initial) { offset_t offs = m_basis[i]; v.reset(); for (unsigned i = 1; i < get_num_vars(); ++i) { - v.push_back(vec(offs)[i]); + v.push_back(to_rational(vec(offs)[i])); } is_initial = !vec(offs)[0].is_zero(); } -void hilbert_basis::get_ge(unsigned i, num_vector& v, numeral& b, bool& is_eq) { +void hilbert_basis::get_ge(unsigned i, rational_vector& v, rational& b, bool& is_eq) { v.reset(); - v.append(m_ineqs[i].size() - 1, m_ineqs[i].c_ptr() + 1); - b = -m_ineqs[i][0]; + for (unsigned j = 1; j < m_ineqs[i].size(); ++j) { + v.push_back(to_rational(m_ineqs[i][j])); + } + b = to_rational(-m_ineqs[i][0]); is_eq = m_iseq[i]; } @@ -1122,8 +1181,7 @@ bool hilbert_basis::add_goal(offset_t idx) { bool hilbert_basis::is_subsumed(offset_t idx) { - offset_t found_idx; - if (m_index->find(idx, vec(idx), found_idx)) { + if (m_index->find(idx, vec(idx))) { ++m_stats.m_num_subsumptions; return true; } @@ -1317,7 +1375,7 @@ bool hilbert_basis::is_geq(values const& v, values const& w) const { return true; } -bool hilbert_basis::is_abs_geq(numeral const& v, numeral const& w) { +bool hilbert_basis::is_abs_geq(numeral const& v, numeral const& w) const { if (w.is_neg()) { return v <= w; } diff --git a/src/muz_qe/hilbert_basis.h b/src/muz_qe/hilbert_basis.h index bad4b1fbd..abb59be2d 100644 --- a/src/muz_qe/hilbert_basis.h +++ b/src/muz_qe/hilbert_basis.h @@ -18,6 +18,11 @@ Author: Revision History: + Hilbert basis can be templatized + based on traits that define numeral: + as rational, mpz, checked_int64 + (checked or unchecked). + --*/ #ifndef _HILBERT_BASIS_H_ @@ -26,14 +31,25 @@ Revision History: #include "rational.h" #include "lbool.h" #include "statistics.h" +#include "checked_int64.h" + +typedef vector rational_vector; class hilbert_basis { -public: - typedef rational numeral; + + static const bool check = false; + typedef checked_int64 numeral; typedef vector num_vector; -private: + static checked_int64 to_numeral(rational const& r) { + return checked_int64(r.get_int64()); + } + static rational to_rational(checked_int64 const& i) { + return rational(i.get_int64(), rational::i64()); + } + class value_index1; class value_index2; + class value_index3; class index; class passive; class passive2; @@ -112,7 +128,7 @@ private: unsigned get_num_vars() const; numeral get_weight(values const & val, num_vector const& ineq) const; bool is_geq(values const& v, values const& w) const; - static bool is_abs_geq(numeral const& v, numeral const& w); + bool is_abs_geq(numeral const& v, numeral const& w) const; bool is_subsumed(offset_t idx); bool is_subsumed(offset_t i, offset_t j) const; void recycle(offset_t idx); @@ -147,16 +163,16 @@ public: // add inequality v*x >= 0 // add inequality v*x <= 0 // add equality v*x = 0 - void add_ge(num_vector const& v); - void add_le(num_vector const& v); - void add_eq(num_vector const& v); + void add_ge(rational_vector const& v); + void add_le(rational_vector const& v); + void add_eq(rational_vector const& v); // add inequality v*x >= b // add inequality v*x <= b // add equality v*x = b - void add_ge(num_vector const& v, numeral const& b); - void add_le(num_vector const& v, numeral const& b); - void add_eq(num_vector const& v, numeral const& b); + void add_ge(rational_vector const& v, rational const& b); + void add_le(rational_vector const& v, rational const& b); + void add_eq(rational_vector const& v, rational const& b); void set_is_int(unsigned var_index); bool get_is_int(unsigned var_index) const; @@ -164,10 +180,10 @@ public: lbool saturate(); unsigned get_basis_size() const { return m_basis.size(); } - void get_basis_solution(unsigned i, num_vector& v, bool& is_initial); + void get_basis_solution(unsigned i, rational_vector& v, bool& is_initial); unsigned get_num_ineqs() const { return m_ineqs.size(); } - void get_ge(unsigned i, num_vector& v, numeral& b, bool& is_eq); + void get_ge(unsigned i, rational_vector& v, rational& b, bool& is_eq); void set_cancel(bool f) { m_cancel = f; } diff --git a/src/test/fdd.cpp b/src/test/fdd.cpp new file mode 100644 index 000000000..2a0079456 --- /dev/null +++ b/src/test/fdd.cpp @@ -0,0 +1,87 @@ +#include "fdd.h" + +static void test1() { + fdd::manager m; + + m.reset(2); + int64 keys1[2] = { 1, 2 }; + m.insert(keys1); + m.display(std::cout << "test1\n"); +} + +static void test2() { + fdd::manager m; + + m.reset(2); + int64 keys2[2] = { 2, 1 }; + m.insert(keys2); + m.display(std::cout << "test2\n"); + +} + +static void test3() { + fdd::manager m; + + m.reset(2); + int64 keys1[2] = { 1, 2 }; + int64 keys2[2] = { 2, 1 }; + m.insert(keys1); + m.insert(keys2); + m.display(std::cout << "test3\n"); +} + +static void test4() { + fdd::manager m; + + std::cout << "test4\n"; + + m.reset(2); + int64 keys1[2] = { 1, 2 }; + int64 keys2[2] = { 2, 1 }; + int64 keys3[2] = { 1, 1 }; + int64 keys4[2] = { 2, 2 }; + int64 keys5[2] = { 2, 3 }; + int64 keys6[2] = { 3, 1 }; + int64 keys7[2] = { 3, 4 }; + m.insert(keys1); + m.insert(keys2); + std::cout << m.find_le(keys1) << "\n"; + std::cout << m.find_le(keys2) << "\n"; + std::cout << m.find_le(keys3) << "\n"; + std::cout << m.find_le(keys4) << "\n"; + std::cout << m.find_le(keys5) << "\n"; + std::cout << m.find_le(keys6) << "\n"; + std::cout << m.find_le(keys7) << "\n"; + + SASSERT(m.find_le(keys1)); + SASSERT(m.find_le(keys2)); + SASSERT(!m.find_le(keys3)); + SASSERT(m.find_le(keys4)); + SASSERT(m.find_le(keys5)); + SASSERT(m.find_le(keys6)); + SASSERT(m.find_le(keys7)); +} + +static void test5() { + fdd::manager m; + + std::cout << "test5\n"; + + m.reset(2); + int64 keys1[2] = { 1, 2 }; + int64 keys2[2] = { 2, 1 }; + m.insert(keys1); + m.insert(keys2); + m.insert(keys2); + + m.display(std::cout); + +} + +void tst_fdd() { + test1(); + test2(); + test3(); + test4(); + test5(); +} diff --git a/src/test/heap_trie.cpp b/src/test/heap_trie.cpp index dd04f7b98..92ef97f72 100644 --- a/src/test/heap_trie.cpp +++ b/src/test/heap_trie.cpp @@ -27,7 +27,8 @@ static void find_le(heap_trie_t& ht, unsigned num_keys, unsigned const* keys) { void tst_heap_trie() { - heap_trie_t ht; + unsigned_le le; + heap_trie_t ht(le); ht.reset(3); unsigned keys1[3] = { 1, 2, 3}; diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index bd5d20f8d..a5f554e5e 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -508,6 +508,12 @@ static void tst15() { saturate_basis(hb); } +static void tst16() { + hilbert_basis hb; + hb.add_le(vec(1, 0), R(100)); + saturate_basis(hb); +} + void tst_hilbert_basis() { std::cout << "hilbert basis test\n"; @@ -537,6 +543,7 @@ void tst_hilbert_basis() { tst13(); tst14(); tst15(); + tst16(); gorrila_test(0, 4, 3, 20, 5); gorrila_test(1, 4, 3, 20, 5); //gorrila_test(2, 4, 3, 20, 5); diff --git a/src/test/main.cpp b/src/test/main.cpp index c48f4529e..6ecfd6d4f 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -210,6 +210,7 @@ int main(int argc, char ** argv) { TST(hilbert_basis); TST(heap_trie); TST(karr); + TST(fdd); } void initialize_mam() {} diff --git a/src/util/checked_int64.h b/src/util/checked_int64.h new file mode 100644 index 000000000..3772e5ab0 --- /dev/null +++ b/src/util/checked_int64.h @@ -0,0 +1,231 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + checked_int64.h + +Abstract: + + A class for wrapping checked (and unchecked) int64 operations. + Note: the mpfx class defines a more general class of fixed-point operations. + A tradeoff is that it relies on a manager. + This class several of the most common operations from rational, so + it can be swapped for rational. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-25. + +Revision History: + +--*/ + +#ifndef __CHECKED_INT64_H_ +#define __CHECKED_INT64_H_ + +#include"z3_exception.h" +#include"rational.h" + +template +class checked_int64 { + int64 m_value; + typedef checked_int64 ci; + + rational r64(int64 i) { return rational(i, rational::i64()); } + +public: + + checked_int64(): m_value(0) {} + checked_int64(int64 v): m_value(v) {} + checked_int64(checked_int64 const& other) { m_value = other.m_value; } + + class overflow_exception : public z3_exception { + virtual char const * msg() const { return "checked_int64 overflow/underflow";} + }; + + bool is_zero() const { return m_value == 0; } + bool is_pos() const { return m_value > 0; } + bool is_neg() const { return m_value < 0; } + bool is_one() const { return m_value == 1; } + bool is_minus_one() const { return m_value == -1; } + bool is_nonneg() const { return m_value >= 0; } + bool is_nonpos() const { return m_value <= 0; } + bool is_even() const { return 0 == (m_value ^ 0x1); } + + static checked_int64 zero() { return ci(0); } + static checked_int64 one() { return ci(1); } + static checked_int64 minus_one() { return ci(-1);} + + int64 get_int64() const { return m_value; } + + checked_int64 abs() const { + if (m_value >= 0) { + return *this; + } + if (CHECK && m_value == INT64_MIN) { + throw overflow_exception(); + } + return ci(-m_value); + } + + checked_int64& neg() { + if (CHECK && m_value == INT64_MIN) { + throw overflow_exception(); + } + m_value = -m_value; + return *this; + } + + unsigned hash() const { return static_cast(m_value); } + + struct hash_proc { unsigned operator()(checked_int64 const& r) const { return r.hash(); } }; + + struct eq_proc { bool operator()(checked_int64 const& r1, checked_int64 const& r2) const { return r1 == r2; } }; + + friend inline std::ostream& operator<<(std::ostream& out, checked_int64 const& i) { + return out << i.m_value; + } + + friend inline bool operator==(checked_int64 const& a, checked_int64 const& b) { + return a.m_value == b.m_value; + } + + friend inline bool operator<(checked_int64 const& a, checked_int64 const& b) { + return a.m_value < b.m_value; + } + + checked_int64 & operator++() { + if (CHECK && INT64_MAX == m_value) { + throw overflow_exception(); + } + ++m_value; + return *this; + } + + const checked_int64 operator++(int) { checked_int64 tmp(*this); ++(*this); return tmp; } + + checked_int64 & operator--() { + if (CHECK && m_value == INT64_MIN) { + throw overflow_exception(); + } + --m_value; + return *this; + } + + const checked_int64 operator--(int) { checked_int64 tmp(*this); --(*this); return tmp; } + + checked_int64& operator+=(checked_int64 const& other) { + if (CHECK && m_value > 0 && other.m_value > 0 && + (m_value > INT_MAX || other.m_value > INT_MAX)) { + rational r(r64(m_value) + r64(other.m_value)); + if (!r.is_int64()) { + throw overflow_exception(); + } + m_value = r.get_int64(); + return *this; + } + if (CHECK && m_value < 0 && other.m_value < 0 && + (m_value < INT_MIN || other.m_value < INT_MIN)) { + rational r(r64(m_value) + r64(other.m_value)); + if (!r.is_int64()) { + throw overflow_exception(); + } + m_value = r.get_int64(); + return *this; + } + m_value += other.m_value; + return *this; + } + + checked_int64& operator-=(checked_int64 const& other) { + if (CHECK && m_value > 0 && other.m_value < 0 && + (m_value > INT_MAX || other.m_value < INT_MIN)) { + rational r(r64(m_value) - r64(other.m_value)); + if (!r.is_int64()) { + throw overflow_exception(); + } + m_value = r.get_int64(); + return *this; + } + if (CHECK && m_value < 0 && other.m_value > 0 && + (m_value < INT_MIN || other.m_value > INT_MAX)) { + rational r(r64(m_value) - r64(other.m_value)); + if (!r.is_int64()) { + throw overflow_exception(); + } + m_value = r.get_int64(); + return *this; + } + m_value -= other.m_value; + return *this; + } + + checked_int64& operator*=(checked_int64 const& other) { + if (CHECK) { + rational r(r64(m_value) * r64(other.m_value)); + if (!r.is_int64()) { + throw overflow_exception(); + } + m_value = r.get_int64(); + } + else { + m_value *= other.m_value; + } + return *this; + } + + friend inline checked_int64 abs(checked_int64 const& i) { + return i.abs(); + } + +}; + +template +inline bool operator!=(checked_int64 const & i1, checked_int64 const & i2) { + return !operator==(i1, i2); +} + +template +inline bool operator>(checked_int64 const & i1, checked_int64 const & i2) { + return operator<(i2, i1); +} + +template +inline bool operator<=(checked_int64 const & i1, checked_int64 const & i2) { + return !operator>(i1, i2); +} + +template +inline bool operator>=(checked_int64 const & i1, checked_int64 const & i2) { + return !operator<(i1, i2); +} + +template +inline checked_int64 operator-(checked_int64 const& i) { + checked_int64 result(i); + return result.neg(); +} + +template +inline checked_int64 operator+(checked_int64 const& a, checked_int64 const& b) { + checked_int64 result(a); + result += b; + return result; +} + +template +inline checked_int64 operator-(checked_int64 const& a, checked_int64 const& b) { + checked_int64 result(a); + result -= b; + return result; +} + +template +inline checked_int64 operator*(checked_int64 const& a, checked_int64 const& b) { + checked_int64 result(a); + result *= b; + return result; +} + +#endif From 5c4003b4e5a9a69e35015458ed9889239836a070 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Mar 2013 17:31:59 -0700 Subject: [PATCH 64/97] test hilbert-basis with fdds and checked integers Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_bit_blast.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index ccba0d69f..b3bd3f124 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -212,7 +212,6 @@ namespace datalog { ast_manager & m; params_ref m_params; rule_ref_vector m_rules; - th_rewriter m_theory_rewriter; bit_blaster_rewriter m_blaster; expand_mkbv m_rewriter; @@ -220,7 +219,6 @@ namespace datalog { bool blast(expr_ref& fml) { proof_ref pr(m); expr_ref fml1(m), fml2(m); - m_theory_rewriter(fml); m_blaster(fml, fml1, pr); m_rewriter(fml1, fml2); TRACE("dl", tout << mk_pp(fml, m) << " -> " << mk_pp(fml1, m) << " -> " << mk_pp(fml2, m) << "\n";); @@ -243,7 +241,6 @@ namespace datalog { m(ctx.get_manager()), m_params(ctx.get_params().p), m_rules(ctx.get_rule_manager()), - m_theory_rewriter(m, m_params), m_blaster(m, m_params), m_rewriter(m, ctx, m_rules) { m_params.set_bool("blast_full", true); From 1cece1c1fbec5d67699bcd34ab8f38869973f2e2 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 27 Mar 2013 10:38:50 -0700 Subject: [PATCH 65/97] Datalog improvements: - add cancel status - display statistics on cancel (by me & Nikolaj) Signed-off-by: Nuno Lopes --- src/muz_qe/dl_cmds.cpp | 11 ++++-- src/muz_qe/dl_context.cpp | 25 ++++++++++++-- src/muz_qe/dl_context.h | 8 ++++- src/muz_qe/dl_instruction.cpp | 59 ++++++++++++++++++-------------- src/muz_qe/dl_instruction.h | 38 +++++++++++--------- src/muz_qe/dl_mk_array_blast.cpp | 2 +- src/muz_qe/dl_mk_bit_blast.cpp | 2 +- src/muz_qe/rel_context.cpp | 59 +++++++++++++++++++++----------- src/muz_qe/rel_context.h | 14 ++++---- src/shell/datalog_frontend.cpp | 1 - 10 files changed, 142 insertions(+), 77 deletions(-) diff --git a/src/muz_qe/dl_cmds.cpp b/src/muz_qe/dl_cmds.cpp index d49a8a671..aef14e051 100644 --- a/src/muz_qe/dl_cmds.cpp +++ b/src/muz_qe/dl_cmds.cpp @@ -234,7 +234,6 @@ public: catch (z3_exception& ex) { ctx.regular_stream() << "(error \"query failed: " << ex.msg() << "\")" << std::endl; } - dlctx.cleanup(); } switch (status) { case l_false: @@ -250,6 +249,7 @@ public: ctx.regular_stream() << "unknown\n"; switch(dlctx.get_status()) { case datalog::INPUT_ERROR: + ctx.regular_stream() << "input error\n"; break; case datalog::MEMOUT: @@ -261,14 +261,21 @@ public: break; case datalog::OK: + UNREACHABLE(); + break; + + case datalog::CANCELED: + ctx.regular_stream() << "canceled\n"; + dlctx.display_profile(ctx.regular_stream()); break; default: - // exception was raised. + UNREACHABLE(); break; } break; } + dlctx.cleanup(); print_statistics(ctx); m_target = 0; } diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 89f2fcf4a..592cfaccd 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -229,11 +229,13 @@ namespace datalog { m_pinned(m), m_vars(m), m_rule_set(*this), + m_transformed_rule_set(*this), m_rule_fmls(m), m_background(m), m_mc(0), m_closed(false), m_saturation_was_run(false), + m_last_status(OK), m_last_answer(m), m_engine(LAST_ENGINE), m_cancel(false) { @@ -873,6 +875,11 @@ namespace datalog { m_rule_set.add_rules(rs); } + void context::record_transformed_rules() { + m_transformed_rule_set.reset(); + m_transformed_rule_set.add_rules(m_rule_set); + } + void context::apply_default_transformation() { ensure_closed(); m_transf.reset(); @@ -942,18 +949,18 @@ namespace datalog { void context::cancel() { m_cancel = true; + m_last_status = CANCELED; m_transf.cancel(); if (m_pdr.get()) m_pdr->cancel(); if (m_bmc.get()) m_bmc->cancel(); - if (m_rel.get()) m_rel->cancel(); if (m_tab.get()) m_tab->cancel(); } void context::cleanup() { m_cancel = false; + m_last_status = OK; if (m_pdr.get()) m_pdr->cleanup(); if (m_bmc.get()) m_bmc->cleanup(); - if (m_rel.get()) m_rel->cleanup(); if (m_tab.get()) m_tab->cleanup(); } @@ -1178,6 +1185,20 @@ namespace datalog { } } + void context::display_profile(std::ostream& out) const { + out << "\n---------------\n"; + out << "Original rules\n"; + display_rules(out); + + out << "\n---------------\n"; + out << "Transformed rules\n"; + m_transformed_rule_set.display(out); + + if (m_rel) { + m_rel->display_profile(out); + } + } + void context::reset_statistics() { if (m_pdr) { m_pdr->reset_statistics(); diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index d278d3abc..ddf200b70 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -52,7 +52,8 @@ namespace datalog { OK, TIMEOUT, MEMOUT, - INPUT_ERROR + INPUT_ERROR, + CANCELED }; class context { @@ -92,6 +93,7 @@ namespace datalog { sym2decl m_preds_by_name; pred2syms m_argument_var_names; rule_set m_rule_set; + rule_set m_transformed_rule_set; expr_ref_vector m_rule_fmls; svector m_rule_names; expr_ref_vector m_background; @@ -323,6 +325,7 @@ namespace datalog { void transform_rules(); void transform_rules(rule_transformer& transf); void replace_rules(rule_set & rs); + void record_transformed_rules(); void apply_default_transformation(); @@ -349,6 +352,8 @@ namespace datalog { void display_smt2(unsigned num_queries, expr* const* queries, std::ostream& out); + void display_profile(std::ostream& out) const; + // ----------------------------------- // // basic usage methods @@ -356,6 +361,7 @@ namespace datalog { // ----------------------------------- void cancel(); + bool canceled() const { return m_cancel; } void cleanup(); void reset_cancel() { cleanup(); } diff --git a/src/muz_qe/dl_instruction.cpp b/src/muz_qe/dl_instruction.cpp index 503ffec3b..401a42e98 100644 --- a/src/muz_qe/dl_instruction.cpp +++ b/src/muz_qe/dl_instruction.cpp @@ -58,14 +58,18 @@ namespace datalog { reset_timelimit(); } + rel_context& execution_context::get_rel_context() { + return m_context.get_rel_context(); + } + struct compare_size_proc { typedef std::pair pr; bool operator()(pr const& a, pr const& b) const { return a.second > b.second; } - }; - void execution_context::report_big_relations(unsigned threshold, std::ostream & out) { + + void execution_context::report_big_relations(unsigned threshold, std::ostream & out) const { unsigned n = register_count(); svector > sizes; size_t total_bytes = 0; @@ -110,6 +114,7 @@ namespace datalog { bool execution_context::should_terminate() { return + m_context.canceled() || memory::above_high_watermark() || (m_stopwatch && m_timelimit_ms != 0 && @@ -135,7 +140,7 @@ namespace datalog { process_costs(); } - void instruction::display_indented(rel_context & ctx, std::ostream & out, std::string indentation) const { + void instruction::display_indented(rel_context const & ctx, std::ostream & out, std::string indentation) const { out << indentation; display_head_impl(ctx, out); if (ctx.output_profile()) { @@ -182,7 +187,7 @@ namespace datalog { virtual void make_annotations(execution_context & ctx) { ctx.set_register_annotation(m_reg, m_pred->get_name().bare_str()); } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { const char * rel_name = m_pred->get_name().bare_str(); if (m_store) { out << "store " << m_reg << " into " << rel_name; @@ -213,7 +218,7 @@ namespace datalog { virtual void make_annotations(execution_context & ctx) { ctx.set_register_annotation(m_reg, "alloc"); } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "dealloc " << m_reg; } }; @@ -248,7 +253,7 @@ namespace datalog { ctx.set_register_annotation(m_src, str); } } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << (m_clone ? "clone " : "move ") << m_src << " into " << m_tgt; } }; @@ -304,11 +309,11 @@ namespace datalog { virtual void make_annotations(execution_context & ctx) { m_body->make_annotations(ctx); } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const & ctx, std::ostream & out) const { out << "while"; print_container(m_controls, out); } - virtual void display_body_impl(rel_context & ctx, std::ostream & out, std::string indentation) const { + virtual void display_body_impl(rel_context const & ctx, std::ostream & out, std::string indentation) const { m_body->display_indented(ctx, out, indentation+" "); } }; @@ -385,7 +390,7 @@ namespace datalog { ctx.get_register_annotation(m_rel1, a1); ctx.set_register_annotation(m_res, "join " + a1 + " " + a2); } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const & ctx, std::ostream & out) const { out << "join " << m_rel1; print_container(m_cols1, out); out << " and " << m_rel2; @@ -434,7 +439,7 @@ namespace datalog { a << "filter_equal " << m_col << " val: " << ctx.get_rel_context().get_rmanager().to_nice_string(m_value); ctx.set_register_annotation(m_reg, a.str()); } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "filter_equal " << m_reg << " col: " << m_col << " val: " << ctx.get_rmanager().to_nice_string(m_value); } @@ -476,7 +481,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "filter_identical " << m_reg << " "; print_container(m_cols, out); } @@ -519,7 +524,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "filter_interpreted " << m_reg << " using " << mk_pp(m_cond, m_cond.get_manager()); } @@ -619,12 +624,16 @@ namespace datalog { return true; } virtual void make_annotations(execution_context & ctx) { - std::string str; - if (ctx.get_register_annotation(m_tgt, str) && m_delta!=execution_context::void_register) { - ctx.set_register_annotation(m_delta, "delta of "+str); + std::string str = "union"; + if (!ctx.get_register_annotation(m_tgt, str)) { + ctx.set_register_annotation(m_tgt, "union"); } + if (m_delta != execution_context::void_register) { + str = "delta of " + str; + } + ctx.set_register_annotation(m_delta, str); } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << (m_widen ? "widen " : "union ") << m_src << " into " << m_tgt; if (m_delta!=execution_context::void_register) { out << " with delta " << m_delta; @@ -678,7 +687,7 @@ namespace datalog { return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << (m_projection ? "project " : "rename ") << m_src << " into " << m_tgt; out << (m_projection ? " deleting columns " : " with cycle "); print_container(m_cols, out); @@ -739,7 +748,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "join_project " << m_rel1; print_container(m_cols1, out); out << " and " << m_rel2; @@ -800,7 +809,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "select_equal_and_project " << m_src <<" into " << m_result << " col: " << m_col << " val: " << ctx.get_rmanager().to_nice_string(m_value); } @@ -854,7 +863,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "filter_by_negation on " << m_tgt; print_container(m_cols1, out); out << " with " << m_neg_rel; @@ -892,7 +901,7 @@ namespace datalog { ctx.set_reg(m_tgt, rel); return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "mk_unary_singleton into " << m_tgt << " sort:" << ctx.get_rmanager().to_nice_string(m_sig[0]) << " val:" << ctx.get_rmanager().to_nice_string(m_sig[0], m_fact[0]); @@ -922,7 +931,7 @@ namespace datalog { ctx.set_reg(m_tgt, ctx.get_rel_context().get_rmanager().mk_full_relation(m_sig, m_pred)); return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "mk_total into " << m_tgt << " sort:" << ctx.get_rmanager().to_nice_string(m_sig); } @@ -947,7 +956,7 @@ namespace datalog { ctx.get_rel_context().get_rmanager().mark_saturated(m_pred); return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "mark_saturated " << m_pred->get_name().bare_str(); } virtual void make_annotations(execution_context & ctx) { @@ -970,7 +979,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "instr_assert_signature of " << m_tgt << " signature:"; print_container(m_sig, out); } @@ -1042,7 +1051,7 @@ namespace datalog { } } - void instruction_block::display_indented(rel_context & ctx, std::ostream & out, std::string indentation) const { + void instruction_block::display_indented(rel_context const& ctx, std::ostream & out, std::string indentation) const { instr_seq_type::const_iterator it = m_data.begin(); instr_seq_type::const_iterator end = m_data.end(); for(; it!=end; ++it) { diff --git a/src/muz_qe/dl_instruction.h b/src/muz_qe/dl_instruction.h index 89f95c860..ae6310ba6 100644 --- a/src/muz_qe/dl_instruction.h +++ b/src/muz_qe/dl_instruction.h @@ -31,6 +31,7 @@ namespace datalog { class execution_context; class instruction_block; + class rel_context; inline void check_overflow(unsigned i) { if (i == UINT_MAX) { @@ -78,7 +79,7 @@ namespace datalog { void reset(); - rel_context & get_rel_context() { return m_context.get_rel_context(); }; + rel_context & get_rel_context(); void set_timelimit(unsigned time_in_ms); void reset_timelimit(); @@ -91,10 +92,9 @@ namespace datalog { If register contains zero, it should be treated as if it contains an empty relation. */ - reg_type reg(reg_idx i) { - if (i>=m_registers.size()) { - check_overflow(i); - m_registers.resize(i+1,0); + reg_type reg(reg_idx i) const { + if (i >= m_registers.size()) { + return 0; } return m_registers[i]; } @@ -102,27 +102,29 @@ namespace datalog { \brief Return value of the register and assign zero into it place. */ reg_type release_reg(reg_idx i) { - SASSERT(i=m_registers.size()) { + if (i >= m_registers.size()) { check_overflow(i); m_registers.resize(i+1,0); } - if(m_registers[i]) { + if (m_registers[i]) { m_registers[i]->deallocate(); } - m_registers[i]=val; + m_registers[i] = val; } + void make_empty(reg_idx i) { - if(reg(i)) { + if (reg(i)) { set_reg(i, 0); } } @@ -130,14 +132,16 @@ namespace datalog { unsigned register_count() const { return m_registers.size(); } + bool get_register_annotation(reg_idx reg, std::string & res) const { return m_reg_annotation.find(reg, res); } + void set_register_annotation(reg_idx reg, std::string str) { m_reg_annotation.insert(reg, str); } - void report_big_relations(unsigned threshold, std::ostream & out); + void report_big_relations(unsigned threshold, std::ostream & out) const; }; @@ -208,7 +212,7 @@ namespace datalog { The newline character at the end should not be printed. */ - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const & ctx, std::ostream & out) const { out << ""; } /** @@ -216,7 +220,7 @@ namespace datalog { Each line must be prepended by \c indentation and ended by a newline character. */ - virtual void display_body_impl(rel_context & ctx, std::ostream & out, std::string indentation) const {} + virtual void display_body_impl(rel_context const & ctx, std::ostream & out, std::string indentation) const {} public: typedef execution_context::reg_type reg_type; typedef execution_context::reg_idx reg_idx; @@ -227,10 +231,10 @@ namespace datalog { virtual void make_annotations(execution_context & ctx) = 0; - void display(rel_context & ctx, std::ostream & out) const { + void display(rel_context const& ctx, std::ostream & out) const { display_indented(ctx, out, ""); } - void display_indented(rel_context & ctx, std::ostream & out, std::string indentation) const; + void display_indented(rel_context const & ctx, std::ostream & out, std::string indentation) const; static instruction * mk_load(ast_manager & m, func_decl * pred, reg_idx tgt); /** @@ -329,10 +333,10 @@ namespace datalog { void make_annotations(execution_context & ctx); - void display(rel_context & ctx, std::ostream & out) const { + void display(rel_context const & ctx, std::ostream & out) const { display_indented(ctx, out, ""); } - void display_indented(rel_context & ctx, std::ostream & out, std::string indentation) const; + void display_indented(rel_context const & ctx, std::ostream & out, std::string indentation) const; }; diff --git a/src/muz_qe/dl_mk_array_blast.cpp b/src/muz_qe/dl_mk_array_blast.cpp index 537b0b5ac..048269c5a 100644 --- a/src/muz_qe/dl_mk_array_blast.cpp +++ b/src/muz_qe/dl_mk_array_blast.cpp @@ -213,7 +213,7 @@ namespace datalog { rule_set* rules = alloc(rule_set, m_ctx); rule_set::iterator it = source.begin(), end = source.end(); bool change = false; - for (; it != end; ++it) { + for (; !m_ctx.canceled() && it != end; ++it) { change = blast(**it, *rules) || change; } if (!change) { diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index e6612022f..338eed0b4 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -265,7 +265,7 @@ namespace datalog { expr_ref fml(m); reset(); rule_set * result = alloc(rule_set, m_context); - for (unsigned i = 0; i < sz; ++i) { + for (unsigned i = 0; !m_context.canceled() && i < sz; ++i) { rule * r = source.get_rule(i); r->to_formula(fml); if (blast(r, fml)) { diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 8e22a704c..c79acf67f 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -39,8 +39,8 @@ namespace datalog { m(ctx.get_manager()), m_rmanager(ctx), m_answer(m), - m_cancel(false), - m_last_result_relation(0) { + m_last_result_relation(0), + m_ectx(ctx) { // register plugins for builtin tables @@ -94,9 +94,9 @@ namespace datalog { decl_set original_predicates; m_context.collect_predicates(original_predicates); - instruction_block rules_code; + m_code.reset(); instruction_block termination_code; - execution_context ex_ctx(m_context); + m_ectx.reset(); lbool result; @@ -104,9 +104,13 @@ namespace datalog { while (true) { m_context.transform_rules(); - compiler::compile(m_context, m_context.get_rules(), rules_code, termination_code); + if (m_context.canceled()) { + result = l_undef; + break; + } + compiler::compile(m_context, m_context.get_rules(), m_code, termination_code); - TRACE("dl", rules_code.display(*this, tout); ); + TRACE("dl", m_code.display(*this, tout); ); bool timeout_after_this_round = time_limit && (restart_time==0 || remaining_time_limit<=restart_time); @@ -114,29 +118,32 @@ namespace datalog { unsigned timeout = time_limit ? (restart_time!=0) ? std::min(remaining_time_limit, restart_time) : remaining_time_limit : restart_time; - ex_ctx.set_timelimit(timeout); + m_ectx.set_timelimit(timeout); } - bool early_termination = !rules_code.perform(ex_ctx); - ex_ctx.reset_timelimit(); - VERIFY( termination_code.perform(ex_ctx) ); + bool early_termination = !m_code.perform(m_ectx); + m_ectx.reset_timelimit(); + VERIFY( termination_code.perform(m_ectx) || m_context.canceled()); - rules_code.process_all_costs(); + m_code.process_all_costs(); - IF_VERBOSE(10, ex_ctx.report_big_relations(1000, verbose_stream());); - + IF_VERBOSE(10, m_ectx.report_big_relations(1000, verbose_stream());); + + if (m_context.canceled()) { + result = l_undef; + break; + } if (!early_termination) { m_context.set_status(OK); result = l_true; break; } - if (memory::above_high_watermark()) { m_context.set_status(MEMOUT); result = l_undef; break; } - if (timeout_after_this_round || m_cancel) { + if (timeout_after_this_round) { m_context.set_status(TIMEOUT); result = l_undef; break; @@ -154,9 +161,7 @@ namespace datalog { restart_time = static_cast(new_restart_time); } - rules_code.reset(); - termination_code.reset(); - ex_ctx.reset(); + termination_code.reset(); m_context.reopen(); restrict_predicates(original_predicates); m_context.replace_rules(original_rules); @@ -164,10 +169,12 @@ namespace datalog { } m_context.reopen(); restrict_predicates(original_predicates); + m_context.record_transformed_rules(); m_context.replace_rules(original_rules); m_context.close(); - TRACE("dl", ex_ctx.report_big_relations(100, tout);); - m_cancel = false; + TRACE("dl", m_ectx.report_big_relations(100, tout);); + m_code.process_all_costs(); + m_code.make_annotations(m_ectx); return result; } @@ -504,5 +511,17 @@ namespace datalog { get_rmanager().display(out); } + void rel_context::display_profile(std::ostream& out) const { + out << "\n--------------\n"; + out << "Instructions\n"; + m_code.display(*this, out); + + out << "\n--------------\n"; + out << "Big relations\n"; + m_ectx.report_big_relations(1000, out); + + get_rmanager().display_relation_sizes(out); + } + }; diff --git a/src/muz_qe/rel_context.h b/src/muz_qe/rel_context.h index b05532d14..2e2b5cd9d 100644 --- a/src/muz_qe/rel_context.h +++ b/src/muz_qe/rel_context.h @@ -22,6 +22,7 @@ Revision History: #define _REL_CONTEXT_H_ #include "ast.h" #include "dl_relation_manager.h" +#include "dl_instruction.h" #include "lbool.h" namespace datalog { @@ -35,10 +36,11 @@ namespace datalog { ast_manager& m; relation_manager m_rmanager; expr_ref m_answer; - volatile bool m_cancel; relation_base * m_last_result_relation; decl_set m_output_preds; fact_vector m_table_facts; + execution_context m_ectx; + instruction_block m_code; void reset_negated_tables(); @@ -53,8 +55,8 @@ namespace datalog { relation_manager & get_rmanager(); const relation_manager & get_rmanager() const; - ast_manager& get_manager() { return m; } - context& get_context() { return m_context; } + ast_manager& get_manager() const { return m; } + context& get_context() const { return m_context; } relation_base & get_relation(func_decl * pred); relation_base * try_get_relation(func_decl * pred) const; expr_ref get_last_answer() { return m_answer; } @@ -70,10 +72,6 @@ namespace datalog { void inherit_predicate_kind(func_decl* new_pred, func_decl* orig_pred); - void cancel() { m_cancel = true; } - - void cleanup() { m_cancel = false; } - /** \brief Restrict the set of used predicates to \c res. @@ -107,6 +105,8 @@ namespace datalog { void display_output_facts(std::ostream & out) const; void display_facts(std::ostream & out) const; + void display_profile(std::ostream& out) const; + lbool saturate(); }; diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index 07052609e..fe2699504 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -209,7 +209,6 @@ unsigned read_datalog(char const * file) { rules_code.make_annotations(ex_ctx); ex_ctx.set_timelimit(timeout); - SASSERT(!ex_ctx.should_terminate()); early_termination = !rules_code.perform(ex_ctx); if(early_termination) { From 06e3b6cfb87c7ce86be13b4cc5464411d814ee82 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Mar 2013 08:13:07 -0700 Subject: [PATCH 66/97] remove model converter from transformer operators. Rely on reference in context Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_context.cpp | 2 +- src/muz_qe/dl_context.h | 1 + src/muz_qe/dl_mk_array_blast.cpp | 2 +- src/muz_qe/dl_mk_array_blast.h | 2 +- src/muz_qe/dl_mk_bit_blast.cpp | 10 +++++----- src/muz_qe/dl_mk_bit_blast.h | 2 +- src/muz_qe/dl_mk_coalesce.cpp | 2 +- src/muz_qe/dl_mk_coalesce.h | 2 +- src/muz_qe/dl_mk_coi_filter.cpp | 10 ++++------ src/muz_qe/dl_mk_coi_filter.h | 4 +--- src/muz_qe/dl_mk_explanations.cpp | 8 ++------ src/muz_qe/dl_mk_explanations.h | 2 +- src/muz_qe/dl_mk_extract_quantifiers.cpp | 2 +- src/muz_qe/dl_mk_extract_quantifiers.h | 2 +- src/muz_qe/dl_mk_filter_rules.cpp | 2 +- src/muz_qe/dl_mk_filter_rules.h | 2 +- src/muz_qe/dl_mk_interp_tail_simplifier.cpp | 2 +- src/muz_qe/dl_mk_interp_tail_simplifier.h | 2 +- src/muz_qe/dl_mk_karr_invariants.cpp | 6 +++--- src/muz_qe/dl_mk_karr_invariants.h | 2 +- src/muz_qe/dl_mk_magic_sets.cpp | 4 ++-- src/muz_qe/dl_mk_magic_sets.h | 2 +- src/muz_qe/dl_mk_partial_equiv.cpp | 2 +- src/muz_qe/dl_mk_partial_equiv.h | 2 +- src/muz_qe/dl_mk_rule_inliner.cpp | 14 +++++++------- src/muz_qe/dl_mk_rule_inliner.h | 2 +- src/muz_qe/dl_mk_similarity_compressor.cpp | 2 +- src/muz_qe/dl_mk_similarity_compressor.h | 2 +- src/muz_qe/dl_mk_simple_joins.cpp | 3 +-- src/muz_qe/dl_mk_simple_joins.h | 2 +- src/muz_qe/dl_mk_slice.cpp | 6 +++--- src/muz_qe/dl_mk_slice.h | 2 +- src/muz_qe/dl_mk_subsumption_checker.cpp | 2 +- src/muz_qe/dl_mk_subsumption_checker.h | 2 +- src/muz_qe/dl_mk_unbound_compressor.cpp | 2 +- src/muz_qe/dl_mk_unbound_compressor.h | 2 +- src/muz_qe/dl_mk_unfold.cpp | 2 +- src/muz_qe/dl_mk_unfold.h | 2 +- src/muz_qe/dl_rule_transformer.cpp | 4 ++-- src/muz_qe/dl_rule_transformer.h | 6 ++---- src/muz_qe/hilbert_basis.cpp | 3 --- 41 files changed, 61 insertions(+), 74 deletions(-) diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 592cfaccd..71ef7ad20 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -860,7 +860,7 @@ namespace datalog { void context::transform_rules(rule_transformer& transf) { SASSERT(m_closed); //we must finish adding rules before we start transforming them TRACE("dl", display_rules(tout);); - if (transf(m_rule_set, m_mc)) { + if (transf(m_rule_set)) { //we have already ensured the negation is stratified and transformations //should not break the stratification m_rule_set.ensure_closed(); diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index ddf200b70..0c4558a28 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -319,6 +319,7 @@ namespace datalog { void ensure_opened(); model_converter_ref& get_model_converter() { return m_mc; } + void add_model_converter(model_converter* mc) { m_mc = concat(m_mc.get(), mc); } proof_converter_ref& get_proof_converter() { return m_pc; } void add_proof_converter(proof_converter* pc) { m_pc = concat(m_pc.get(), pc); } diff --git a/src/muz_qe/dl_mk_array_blast.cpp b/src/muz_qe/dl_mk_array_blast.cpp index 048269c5a..1182a2756 100644 --- a/src/muz_qe/dl_mk_array_blast.cpp +++ b/src/muz_qe/dl_mk_array_blast.cpp @@ -208,7 +208,7 @@ namespace datalog { return true; } - rule_set * mk_array_blast::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_array_blast::operator()(rule_set const & source) { rule_set* rules = alloc(rule_set, m_ctx); rule_set::iterator it = source.begin(), end = source.end(); diff --git a/src/muz_qe/dl_mk_array_blast.h b/src/muz_qe/dl_mk_array_blast.h index 94eb64601..c27bb32b3 100644 --- a/src/muz_qe/dl_mk_array_blast.h +++ b/src/muz_qe/dl_mk_array_blast.h @@ -54,7 +54,7 @@ namespace datalog { virtual ~mk_array_blast(); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index 338eed0b4..d14080498 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -255,7 +255,7 @@ namespace datalog { m_blaster.updt_params(m_params); } - rule_set * operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * operator()(rule_set const & source) { // TODO pc if (!m_context.get_params().bit_blast()) { return 0; @@ -284,7 +284,7 @@ namespace datalog { result->add_rule(m_rules.get(i)); } - if (mc) { + if (m_context.get_model_converter()) { filter_model_converter* fmc = alloc(filter_model_converter, m); bit_blast_model_converter* bvmc = alloc(bit_blast_model_converter, m); func_decl_ref_vector const& old_funcs = m_rewriter.m_cfg.old_funcs(); @@ -293,7 +293,7 @@ namespace datalog { fmc->insert(new_funcs[i]); bvmc->insert(old_funcs[i], new_funcs[i]); } - mc = concat(mc.get(), concat(bvmc, fmc)); + m_context.add_model_converter(concat(bvmc, fmc)); } return result; @@ -308,8 +308,8 @@ namespace datalog { dealloc(m_impl); } - rule_set * mk_bit_blast::operator()(rule_set const & source, model_converter_ref& mc) { - return (*m_impl)(source, mc); + rule_set * mk_bit_blast::operator()(rule_set const & source) { + return (*m_impl)(source); } }; diff --git a/src/muz_qe/dl_mk_bit_blast.h b/src/muz_qe/dl_mk_bit_blast.h index 3a6de75e3..60c83f6cb 100644 --- a/src/muz_qe/dl_mk_bit_blast.h +++ b/src/muz_qe/dl_mk_bit_blast.h @@ -44,7 +44,7 @@ namespace datalog { mk_bit_blast(context & ctx, unsigned priority = 35000); ~mk_bit_blast(); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_coalesce.cpp b/src/muz_qe/dl_mk_coalesce.cpp index de5388312..94c42e33b 100644 --- a/src/muz_qe/dl_mk_coalesce.cpp +++ b/src/muz_qe/dl_mk_coalesce.cpp @@ -171,7 +171,7 @@ namespace datalog { return true; } - rule_set * mk_coalesce::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_coalesce::operator()(rule_set const & source) { rule_set* rules = alloc(rule_set, m_ctx); rule_set::decl2rules::iterator it = source.begin_grouped_rules(), end = source.end_grouped_rules(); for (; it != end; ++it) { diff --git a/src/muz_qe/dl_mk_coalesce.h b/src/muz_qe/dl_mk_coalesce.h index ab0b74479..4a4065174 100644 --- a/src/muz_qe/dl_mk_coalesce.h +++ b/src/muz_qe/dl_mk_coalesce.h @@ -52,7 +52,7 @@ namespace datalog { */ mk_coalesce(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_coi_filter.cpp b/src/muz_qe/dl_mk_coi_filter.cpp index 915dd4306..6aa688a3c 100644 --- a/src/muz_qe/dl_mk_coi_filter.cpp +++ b/src/muz_qe/dl_mk_coi_filter.cpp @@ -33,9 +33,7 @@ namespace datalog { // ----------------------------------- - rule_set * mk_coi_filter::operator()( - rule_set const & source, - model_converter_ref& mc) + rule_set * mk_coi_filter::operator()(rule_set const & source) { if (source.get_num_rules()==0) { return 0; @@ -80,7 +78,7 @@ namespace datalog { if (interesting_preds.contains(pred)) { res->add_rule(r); } - else if (mc.get()) { + else if (m_context.get_model_converter()) { pruned_preds.insert(pred); } } @@ -89,14 +87,14 @@ namespace datalog { res = 0; } - if (res && mc) { + if (res && m_context.get_model_converter()) { decl_set::iterator end = pruned_preds.end(); decl_set::iterator it = pruned_preds.begin(); extension_model_converter* mc0 = alloc(extension_model_converter, m); for (; it != end; ++it) { mc0->insert(*it, m.mk_true()); } - mc = concat(mc.get(), mc0); + m_context.add_model_converter(mc0); } return res.detach(); diff --git a/src/muz_qe/dl_mk_coi_filter.h b/src/muz_qe/dl_mk_coi_filter.h index 2191048d3..b02bed9ec 100644 --- a/src/muz_qe/dl_mk_coi_filter.h +++ b/src/muz_qe/dl_mk_coi_filter.h @@ -38,9 +38,7 @@ namespace datalog { m(ctx.get_manager()), m_context(ctx) {} - - rule_set * operator()(rule_set const & source, - model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_explanations.cpp b/src/muz_qe/dl_mk_explanations.cpp index af5b1d97a..646a0bcbe 100644 --- a/src/muz_qe/dl_mk_explanations.cpp +++ b/src/muz_qe/dl_mk_explanations.cpp @@ -174,11 +174,9 @@ namespace datalog { } } -#if 1 virtual void deallocate() { get_plugin().recycle(this); } -#endif public: @@ -875,14 +873,12 @@ namespace datalog { } } - rule_set * mk_explanations::operator()(rule_set const & source, model_converter_ref& mc) { - SASSERT(!mc); + rule_set * mk_explanations::operator()(rule_set const & source) { + if(source.get_num_rules()==0) { return 0; } - m_context.collect_predicates(m_original_preds); - rule_set * res = alloc(rule_set, m_context); transform_facts(m_context.get_rel_context().get_rmanager()); transform_rules(source, *res); diff --git a/src/muz_qe/dl_mk_explanations.h b/src/muz_qe/dl_mk_explanations.h index 40606f8df..4e7e23e98 100644 --- a/src/muz_qe/dl_mk_explanations.h +++ b/src/muz_qe/dl_mk_explanations.h @@ -82,7 +82,7 @@ namespace datalog { return get_union_decl(m_context); } - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); static expr* get_explanation(relation_base const& r); }; diff --git a/src/muz_qe/dl_mk_extract_quantifiers.cpp b/src/muz_qe/dl_mk_extract_quantifiers.cpp index a3d5cc2ab..76e329d79 100644 --- a/src/muz_qe/dl_mk_extract_quantifiers.cpp +++ b/src/muz_qe/dl_mk_extract_quantifiers.cpp @@ -355,7 +355,7 @@ namespace datalog { m_quantifiers.reset(); } - rule_set * mk_extract_quantifiers::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_extract_quantifiers::operator()(rule_set const & source) { reset(); rule_set::iterator it = source.begin(), end = source.end(); for (; !m_has_quantifiers && it != end; ++it) { diff --git a/src/muz_qe/dl_mk_extract_quantifiers.h b/src/muz_qe/dl_mk_extract_quantifiers.h index 7d2f7b149..27b13cd71 100644 --- a/src/muz_qe/dl_mk_extract_quantifiers.h +++ b/src/muz_qe/dl_mk_extract_quantifiers.h @@ -77,7 +77,7 @@ namespace datalog { void set_query(func_decl* q); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); bool has_quantifiers() { return m_has_quantifiers; } diff --git a/src/muz_qe/dl_mk_filter_rules.cpp b/src/muz_qe/dl_mk_filter_rules.cpp index 46fde4bc2..62abd78c4 100644 --- a/src/muz_qe/dl_mk_filter_rules.cpp +++ b/src/muz_qe/dl_mk_filter_rules.cpp @@ -150,7 +150,7 @@ namespace datalog { } } - rule_set * mk_filter_rules::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_filter_rules::operator()(rule_set const & source) { // TODO mc, pc m_tail2filter.reset(); m_result = alloc(rule_set, m_context); diff --git a/src/muz_qe/dl_mk_filter_rules.h b/src/muz_qe/dl_mk_filter_rules.h index daa72e36f..4a247fdb5 100644 --- a/src/muz_qe/dl_mk_filter_rules.h +++ b/src/muz_qe/dl_mk_filter_rules.h @@ -72,7 +72,7 @@ namespace datalog { /** \brief Return a new rule set where only filter rules contain atoms with repeated variables and/or values. */ - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp index a48b7b32f..27b99cf98 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp @@ -572,7 +572,7 @@ namespace datalog { return modified; } - rule_set * mk_interp_tail_simplifier::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_interp_tail_simplifier::operator()(rule_set const & source) { if (source.get_num_rules() == 0) { return 0; } diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.h b/src/muz_qe/dl_mk_interp_tail_simplifier.h index 4cb14914a..247b20755 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.h +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.h @@ -93,7 +93,7 @@ namespace datalog { */ bool transform_rule(rule * r, rule_ref& res); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index d44b31979..982bdfd74 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -520,7 +520,7 @@ namespace datalog { m_hb.set_cancel(true); } - rule_set * mk_karr_invariants::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_karr_invariants::operator()(rule_set const & source) { if (!m_ctx.get_params().karr()) { return 0; } @@ -590,7 +590,7 @@ namespace datalog { for (; it != end; ++it) { update_body(*rules, **it); } - if (mc) { + if (m_ctx.get_model_converter()) { add_invariant_model_converter* kmc = alloc(add_invariant_model_converter, m); rule_set::decl2rules::iterator git = source.begin_grouped_rules(); rule_set::decl2rules::iterator gend = source.end_grouped_rules(); @@ -601,7 +601,7 @@ namespace datalog { kmc->add(p, *M); } } - mc = concat(mc.get(), kmc); + m_ctx.add_model_converter(kmc); } TRACE("dl", rules->display(tout);); return rules; diff --git a/src/muz_qe/dl_mk_karr_invariants.h b/src/muz_qe/dl_mk_karr_invariants.h index 7cd26d495..8abab9d7e 100644 --- a/src/muz_qe/dl_mk_karr_invariants.h +++ b/src/muz_qe/dl_mk_karr_invariants.h @@ -69,7 +69,7 @@ namespace datalog { virtual void cancel(); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; diff --git a/src/muz_qe/dl_mk_magic_sets.cpp b/src/muz_qe/dl_mk_magic_sets.cpp index 990040ab8..6885edc4e 100644 --- a/src/muz_qe/dl_mk_magic_sets.cpp +++ b/src/muz_qe/dl_mk_magic_sets.cpp @@ -317,8 +317,8 @@ namespace datalog { m_rules.push_back(r); } - rule_set * mk_magic_sets::operator()(rule_set const & source, model_converter_ref& mc) { - SASSERT(!mc); + rule_set * mk_magic_sets::operator()(rule_set const & source) { + SASSERT(!m_context.get_model_converter()); unsigned init_rule_cnt = source.get_num_rules(); { func_decl_set intentional; diff --git a/src/muz_qe/dl_mk_magic_sets.h b/src/muz_qe/dl_mk_magic_sets.h index 3f50e6713..2dc91c7e8 100644 --- a/src/muz_qe/dl_mk_magic_sets.h +++ b/src/muz_qe/dl_mk_magic_sets.h @@ -121,7 +121,7 @@ namespace datalog { */ mk_magic_sets(context & ctx, rule * goal_rule); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_partial_equiv.cpp b/src/muz_qe/dl_mk_partial_equiv.cpp index b55f5294e..35f8ff8df 100644 --- a/src/muz_qe/dl_mk_partial_equiv.cpp +++ b/src/muz_qe/dl_mk_partial_equiv.cpp @@ -86,7 +86,7 @@ namespace datalog { } - rule_set * mk_partial_equivalence_transformer::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_partial_equivalence_transformer::operator()(rule_set const & source) { // TODO mc if (source.get_num_rules() == 0) { diff --git a/src/muz_qe/dl_mk_partial_equiv.h b/src/muz_qe/dl_mk_partial_equiv.h index c44d59e8c..54a70b3c0 100644 --- a/src/muz_qe/dl_mk_partial_equiv.h +++ b/src/muz_qe/dl_mk_partial_equiv.h @@ -35,7 +35,7 @@ namespace datalog { m(ctx.get_manager()), m_context(ctx) {} - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); private: diff --git a/src/muz_qe/dl_mk_rule_inliner.cpp b/src/muz_qe/dl_mk_rule_inliner.cpp index 047ed768f..91cfbe3fc 100644 --- a/src/muz_qe/dl_mk_rule_inliner.cpp +++ b/src/muz_qe/dl_mk_rule_inliner.cpp @@ -241,8 +241,10 @@ namespace datalog { return false; } - //these conditions are optional, they avoid possible exponential increase - //in the size of the problem + // + // these conditions are optional, they avoid possible exponential increase + // in the size of the problem + // return //m_head_pred_non_empty_tails_ctr.get(pred)<=1 @@ -837,7 +839,7 @@ namespace datalog { return done_something; } - rule_set * mk_rule_inliner::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_rule_inliner::operator()(rule_set const & source) { bool something_done = false; ref hsmc; @@ -854,7 +856,7 @@ namespace datalog { } - if (mc) { + if (m_context.get_model_converter()) { hsmc = alloc(horn_subsume_model_converter, m); } m_mc = hsmc.get(); @@ -881,9 +883,7 @@ namespace datalog { res = 0; } else { - if (mc) { - mc = concat(mc.get(), hsmc.get()); - } + m_context.add_model_converter(hsmc.get()); } return res.detach(); diff --git a/src/muz_qe/dl_mk_rule_inliner.h b/src/muz_qe/dl_mk_rule_inliner.h index a58b3b473..5ef8db7eb 100644 --- a/src/muz_qe/dl_mk_rule_inliner.h +++ b/src/muz_qe/dl_mk_rule_inliner.h @@ -196,7 +196,7 @@ namespace datalog { {} virtual ~mk_rule_inliner() { } - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_similarity_compressor.cpp b/src/muz_qe/dl_mk_similarity_compressor.cpp index dfd0a4d81..9868c82f6 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.cpp +++ b/src/muz_qe/dl_mk_similarity_compressor.cpp @@ -500,7 +500,7 @@ namespace datalog { } } - rule_set * mk_similarity_compressor::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_similarity_compressor::operator()(rule_set const & source) { // TODO mc m_modified = false; unsigned init_rule_cnt = source.get_num_rules(); diff --git a/src/muz_qe/dl_mk_similarity_compressor.h b/src/muz_qe/dl_mk_similarity_compressor.h index d1ded01e7..6e0ca9db5 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.h +++ b/src/muz_qe/dl_mk_similarity_compressor.h @@ -69,7 +69,7 @@ namespace datalog { public: mk_similarity_compressor(context & ctx, unsigned threshold_count); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_simple_joins.cpp b/src/muz_qe/dl_mk_simple_joins.cpp index f19e34fec..3a3f96acf 100644 --- a/src/muz_qe/dl_mk_simple_joins.cpp +++ b/src/muz_qe/dl_mk_simple_joins.cpp @@ -718,8 +718,7 @@ namespace datalog { } }; - rule_set * mk_simple_joins::operator()(rule_set const & source, model_converter_ref& mc) { - // TODO mc + rule_set * mk_simple_joins::operator()(rule_set const & source) { rule_set rs_aux_copy(m_context); rs_aux_copy.add_rules(source); if(!rs_aux_copy.is_closed()) { diff --git a/src/muz_qe/dl_mk_simple_joins.h b/src/muz_qe/dl_mk_simple_joins.h index df8d3f55c..89832626f 100644 --- a/src/muz_qe/dl_mk_simple_joins.h +++ b/src/muz_qe/dl_mk_simple_joins.h @@ -53,7 +53,7 @@ namespace datalog { public: mk_simple_joins(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_slice.cpp b/src/muz_qe/dl_mk_slice.cpp index 0adab78ce..c98d6503e 100644 --- a/src/muz_qe/dl_mk_slice.cpp +++ b/src/muz_qe/dl_mk_slice.cpp @@ -802,7 +802,7 @@ namespace datalog { } } - rule_set * mk_slice::operator()(rule_set const & src, model_converter_ref& mc) { + rule_set * mk_slice::operator()(rule_set const & src) { for (unsigned i = 0; i < src.get_num_rules(); ++i) { if (src.get_rule(i)->has_quantifiers()) { return 0; @@ -813,7 +813,7 @@ namespace datalog { if (m_ctx.generate_proof_trace()) { spc = alloc(slice_proof_converter, m_ctx); } - if (mc) { + if (m_ctx.get_model_converter()) { smc = alloc(slice_model_converter, *this, m); } m_pc = spc.get(); @@ -836,7 +836,7 @@ namespace datalog { } } m_ctx.add_proof_converter(spc.get()); - mc = concat(mc.get(), smc.get()); + m_ctx.add_model_converter(smc.get()); return result; } diff --git a/src/muz_qe/dl_mk_slice.h b/src/muz_qe/dl_mk_slice.h index 4290ee4b9..1b4312e77 100644 --- a/src/muz_qe/dl_mk_slice.h +++ b/src/muz_qe/dl_mk_slice.h @@ -102,7 +102,7 @@ namespace datalog { virtual ~mk_slice() { } - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); func_decl* get_predicate(func_decl* p) { func_decl* q = p; m_predicates.find(p, q); return q; } diff --git a/src/muz_qe/dl_mk_subsumption_checker.cpp b/src/muz_qe/dl_mk_subsumption_checker.cpp index 2f0d56475..fb55a377c 100644 --- a/src/muz_qe/dl_mk_subsumption_checker.cpp +++ b/src/muz_qe/dl_mk_subsumption_checker.cpp @@ -332,7 +332,7 @@ namespace datalog { } } - rule_set * mk_subsumption_checker::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_subsumption_checker::operator()(rule_set const & source) { // TODO mc m_have_new_total_rule = false; diff --git a/src/muz_qe/dl_mk_subsumption_checker.h b/src/muz_qe/dl_mk_subsumption_checker.h index a95f08c5d..59904b3ef 100644 --- a/src/muz_qe/dl_mk_subsumption_checker.h +++ b/src/muz_qe/dl_mk_subsumption_checker.h @@ -84,7 +84,7 @@ namespace datalog { reset_dealloc_values(m_ground_unconditional_rule_heads); } - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_unbound_compressor.cpp b/src/muz_qe/dl_mk_unbound_compressor.cpp index 54b6f4ebe..40926c2a8 100644 --- a/src/muz_qe/dl_mk_unbound_compressor.cpp +++ b/src/muz_qe/dl_mk_unbound_compressor.cpp @@ -334,7 +334,7 @@ namespace datalog { } } - rule_set * mk_unbound_compressor::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_unbound_compressor::operator()(rule_set const & source) { // TODO mc m_modified = false; diff --git a/src/muz_qe/dl_mk_unbound_compressor.h b/src/muz_qe/dl_mk_unbound_compressor.h index 256be180d..cad953783 100644 --- a/src/muz_qe/dl_mk_unbound_compressor.h +++ b/src/muz_qe/dl_mk_unbound_compressor.h @@ -82,7 +82,7 @@ namespace datalog { public: mk_unbound_compressor(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_unfold.cpp b/src/muz_qe/dl_mk_unfold.cpp index 7af82110a..dfbd87122 100644 --- a/src/muz_qe/dl_mk_unfold.cpp +++ b/src/muz_qe/dl_mk_unfold.cpp @@ -50,7 +50,7 @@ namespace datalog { } } - rule_set * mk_unfold::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_unfold::operator()(rule_set const & source) { rule_set* rules = alloc(rule_set, m_ctx); rule_set::iterator it = source.begin(), end = source.end(); for (; it != end; ++it) { diff --git a/src/muz_qe/dl_mk_unfold.h b/src/muz_qe/dl_mk_unfold.h index 90aefa86e..26f64926d 100644 --- a/src/muz_qe/dl_mk_unfold.h +++ b/src/muz_qe/dl_mk_unfold.h @@ -44,7 +44,7 @@ namespace datalog { */ mk_unfold(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_rule_transformer.cpp b/src/muz_qe/dl_rule_transformer.cpp index 5ecbf2b45..50a3f3310 100644 --- a/src/muz_qe/dl_rule_transformer.cpp +++ b/src/muz_qe/dl_rule_transformer.cpp @@ -73,7 +73,7 @@ namespace datalog { m_dirty=true; } - bool rule_transformer::operator()(rule_set & rules, model_converter_ref& mc) { + bool rule_transformer::operator()(rule_set & rules) { ensure_ordered(); bool modified = false; @@ -87,7 +87,7 @@ namespace datalog { for(; it!=end && !m_cancel; ++it) { plugin & p = **it; - rule_set * new_rules = p(rules, mc); + rule_set * new_rules = p(rules); if (!new_rules) { continue; } diff --git a/src/muz_qe/dl_rule_transformer.h b/src/muz_qe/dl_rule_transformer.h index 3b2140caf..2dbf25118 100644 --- a/src/muz_qe/dl_rule_transformer.h +++ b/src/muz_qe/dl_rule_transformer.h @@ -23,7 +23,6 @@ Revision History: #include"vector.h" #include"dl_rule.h" #include"dl_rule_set.h" -#include"model_converter.h" namespace datalog { @@ -68,7 +67,7 @@ namespace datalog { \brief Transform the rule set using the registered transformation plugins. If the rule set has changed, return true; otherwise return false. */ - bool operator()(rule_set & rules, model_converter_ref& mc); + bool operator()(rule_set & rules); }; class rule_transformer::plugin { @@ -104,8 +103,7 @@ namespace datalog { The caller takes ownership of the returned \c rule_set object. */ - virtual rule_set * operator()(rule_set const & source, - model_converter_ref& mc) = 0; + virtual rule_set * operator()(rule_set const & source) = 0; virtual void cancel() { m_cancel = true; } diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index 9fbd8cc2e..0b6b664ec 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -997,11 +997,9 @@ void hilbert_basis::select_inequality() { unsigned best = m_current_ineq; unsigned non_zeros = get_num_nonzeros(m_ineqs[best]); unsigned prod = get_ineq_product(m_ineqs[best]); - //numeral diff = get_ineq_diff(m_ineqs[best]); for (unsigned j = best+1; prod != 0 && j < m_ineqs.size(); ++j) { unsigned non_zeros2 = get_num_nonzeros(m_ineqs[j]); unsigned prod2 = get_ineq_product(m_ineqs[j]); - //numeral diff2 = get_ineq_diff(m_ineqs[j]); if (prod2 == 0) { prod = prod2; non_zeros = non_zeros2; @@ -1010,7 +1008,6 @@ void hilbert_basis::select_inequality() { } if (non_zeros2 < non_zeros || (non_zeros2 == non_zeros && prod2 < prod)) { prod = prod2; - // diff = diff2; non_zeros = non_zeros2; best = j; } From 6ed266e4dee0cc0526a6f28340e779b620e4785b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Mar 2013 08:53:46 -0700 Subject: [PATCH 67/97] debugging karr invariants Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_array_blast.cpp | 11 +-- src/muz_qe/dl_mk_array_blast.h | 2 + src/muz_qe/dl_mk_bit_blast.cpp | 4 +- src/muz_qe/dl_mk_interp_tail_simplifier.cpp | 43 +++++------ src/muz_qe/dl_mk_karr_invariants.cpp | 67 ++++++++++++----- src/muz_qe/dl_mk_karr_invariants.h | 6 +- src/muz_qe/dl_rule_set.h | 2 +- src/muz_qe/dl_rule_transformer.cpp | 6 +- src/muz_qe/dl_rule_transformer.h | 8 +-- src/muz_qe/fdd.cpp | 17 ++--- src/muz_qe/hilbert_basis.cpp | 6 +- src/test/hilbert_basis.cpp | 12 ++++ src/test/karr.cpp | 80 +++++++++++++++++++++ 13 files changed, 196 insertions(+), 68 deletions(-) diff --git a/src/muz_qe/dl_mk_array_blast.cpp b/src/muz_qe/dl_mk_array_blast.cpp index 048269c5a..adf08662a 100644 --- a/src/muz_qe/dl_mk_array_blast.cpp +++ b/src/muz_qe/dl_mk_array_blast.cpp @@ -30,7 +30,8 @@ namespace datalog { m(ctx.get_manager()), a(m), rm(ctx.get_rule_manager()), - m_rewriter(m, m_params){ + m_rewriter(m, m_params), + m_simplifier(ctx) { m_params.set_bool("expand_select_store",true); m_rewriter.updt_params(m_params); } @@ -202,9 +203,11 @@ namespace datalog { SASSERT(new_rules.size() == 1); TRACE("dl", new_rules[0]->display(m_ctx, tout << "new rule\n");); - - rules.add_rule(new_rules[0].get()); - rm.mk_rule_rewrite_proof(r, *new_rules[0].get()); + rule_ref new_rule(rm); + if (m_simplifier.transform_rule(new_rules[0].get(), new_rule)) { + rules.add_rule(new_rule.get()); + rm.mk_rule_rewrite_proof(r, *new_rule.get()); + } return true; } diff --git a/src/muz_qe/dl_mk_array_blast.h b/src/muz_qe/dl_mk_array_blast.h index 94eb64601..4680821a2 100644 --- a/src/muz_qe/dl_mk_array_blast.h +++ b/src/muz_qe/dl_mk_array_blast.h @@ -22,6 +22,7 @@ Revision History: #include"dl_context.h" #include"dl_rule_set.h" #include"dl_rule_transformer.h" +#include"dl_mk_interp_tail_simplifier.h" #include "equiv_proof_converter.h" #include "array_decl_plugin.h" @@ -37,6 +38,7 @@ namespace datalog { rule_manager& rm; params_ref m_params; th_rewriter m_rewriter; + mk_interp_tail_simplifier m_simplifier; typedef obj_map defs_t; diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index 338eed0b4..9dfd9deba 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -223,7 +223,9 @@ namespace datalog { expr_ref fml1(m), fml2(m), fml3(m); rule_ref r2(m_context.get_rule_manager()); // We need to simplify rule before bit-blasting. - m_simplifier.transform_rule(r, r2); + if (!m_simplifier.transform_rule(r, r2)) { + r2 = r; + } r2->to_formula(fml1); m_blaster(fml1, fml2, pr); m_rewriter(fml2, fml3); diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp index a48b7b32f..35fd630f9 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp @@ -469,7 +469,7 @@ namespace datalog { start: unsigned u_len = r->get_uninterpreted_tail_size(); unsigned len = r->get_tail_size(); - if (u_len==len) { + if (u_len == len) { res = r; return true; } @@ -504,34 +504,29 @@ namespace datalog { expr_ref simp_res(m); simplify_expr(itail.get(), simp_res); - modified |= itail.get()!=simp_res.get(); - - if (is_app(simp_res.get())) { - itail = to_app(simp_res.get()); - } - else if (m.is_bool(simp_res)) { - itail = m.mk_eq(simp_res, m.mk_true()); - } - else { - throw default_exception("simplification resulted in non-boolean non-function"); - } - - if (m.is_false(itail.get())) { - //the tail member is never true, so we may delete the rule + modified |= itail.get() != simp_res.get(); + + if (m.is_false(simp_res)) { TRACE("dl", r->display(m_context, tout << "rule is infeasible\n");); return false; } - if (!m.is_true(itail.get())) { - //if the simplified tail is not a tautology, we add it to the rule - tail.push_back(itail); - tail_neg.push_back(false); - } - else { - modified = true; - } + SASSERT(m.is_bool(simp_res)); - SASSERT(tail.size() == tail_neg.size()); if (modified) { + expr_ref_vector conjs(m); + flatten_and(simp_res, conjs); + for (unsigned i = 0; i < conjs.size(); ++i) { + expr* e = conjs[i].get(); + if (is_app(e)) { + tail.push_back(to_app(e)); + } + else { + tail.push_back(m.mk_eq(e, m.mk_true())); + } + tail_neg.push_back(false); + } + + SASSERT(tail.size() == tail_neg.size()); res = m_context.get_rule_manager().mk(head, tail.size(), tail.c_ptr(), tail_neg.c_ptr()); res->set_accounting_parent_object(m_context, r); } diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index d44b31979..013923045 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -62,12 +62,38 @@ namespace datalog { return *this; } + void mk_karr_invariants::matrix::display_row( + std::ostream& out, vector const& row, rational const& b, bool is_eq) { + for (unsigned j = 0; j < row.size(); ++j) { + out << row[j] << " "; + } + out << (is_eq?" = ":" >= ") << -b << "\n"; + } + + void mk_karr_invariants::matrix::display_ineq( + std::ostream& out, vector const& row, rational const& b, bool is_eq) { + bool first = true; + for (unsigned j = 0; j < row.size(); ++j) { + if (!row[j].is_zero()) { + if (!first && row[j].is_pos()) { + out << "+ "; + } + if (row[j].is_minus_one()) { + out << "- "; + } + if (row[j] > rational(1) || row[j] < rational(-1)) { + out << row[j] << "*"; + } + out << "x" << j << " "; + first = false; + } + } + out << (is_eq?"= ":">= ") << -b << "\n"; + } + void mk_karr_invariants::matrix::display(std::ostream& out) const { for (unsigned i = 0; i < A.size(); ++i) { - for (unsigned j = 0; j < A[i].size(); ++j) { - out << A[i][j] << " "; - } - out << (eq[i]?" = ":" >= ") << -b[i] << "\n"; + display_row(out, A[i], b[i], eq[i]); } } @@ -182,24 +208,28 @@ namespace datalog { M.b.push_back(b); M.eq.push_back(true); } - else if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + else if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { M.A.push_back(row); M.b.push_back(b); M.eq.push_back(false); } - else if ((a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + else if ((a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { M.A.push_back(row); - M.b.push_back(b + rational(1)); + M.b.push_back(b - rational(1)); M.eq.push_back(false); } - else if (m.is_not(e, en) && (a.is_lt(en, e2, e1) || a.is_gt(en, e1, e2)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + else if (m.is_not(e, en) && (a.is_lt(en, e2, e1) || a.is_gt(en, e1, e2)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { M.A.push_back(row); M.b.push_back(b); M.eq.push_back(false); } - else if (m.is_not(e, en) && (a.is_le(en, e2, e1) || a.is_ge(en, e1, e2)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + else if (m.is_not(e, en) && (a.is_le(en, e2, e1) || a.is_ge(en, e1, e2)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { M.A.push_back(row); - M.b.push_back(b + rational(1)); + M.b.push_back(b - rational(1)); M.eq.push_back(false); } else if (m.is_or(e, e1, e2) && is_eq(e1, v, n1) && is_eq(e2, w, n2) && v == w) { @@ -221,7 +251,9 @@ namespace datalog { else { processed = false; } - TRACE("dl", tout << (processed?"+ ":"- ") << mk_pp(e, m) << "\n";); + TRACE("dl", tout << (processed?"+ ":"- ") << mk_pp(e, m) << "\n"; + if (processed) matrix::display_ineq(tout, row, M.b.back(), M.eq.back()); + ); } // intersect with the head predicate. app* head = r.get_head(); @@ -270,6 +302,7 @@ namespace datalog { M.b.push_back(MD.b[i]); M.eq.push_back(true); } + TRACE("dl", M.display(tout << r.get_decl()->get_name() << "\n");); return true; } @@ -322,7 +355,7 @@ namespace datalog { m_hb.set_is_int(i); } lbool is_sat = m_hb.saturate(); - TRACE("dl", m_hb.display(tout);); + TRACE("dl_verbose", m_hb.display(tout);); SASSERT(is_sat == l_true); unsigned basis_size = m_hb.get_basis_size(); for (unsigned i = 0; i < basis_size; ++i) { @@ -353,7 +386,7 @@ namespace datalog { m_hb.set_is_int(i); } lbool is_sat = m_hb.saturate(); - TRACE("dl", m_hb.display(tout);); + TRACE("dl_verbose", m_hb.display(tout);); SASSERT(is_sat == l_true); dst.reset(); unsigned basis_size = m_hb.get_basis_size(); @@ -532,7 +565,7 @@ namespace datalog { } } bool change = true, non_empty = false; - while (!m_cancel && change) { + while (!m_ctx.canceled() && change) { change = false; it = source.begin(); for (; it != end; ++it) { @@ -550,8 +583,8 @@ namespace datalog { dualizeH(P, ND); TRACE("dl", - MD.display(tout << "MD\n"); - P.display(tout << "P\n");); + ND.display(tout << "ND\n"); + P.display(tout << "P\n");); if (!N) { change = true; @@ -569,7 +602,7 @@ namespace datalog { return 0; } - if (m_cancel) { + if (m_ctx.canceled()) { return 0; } diff --git a/src/muz_qe/dl_mk_karr_invariants.h b/src/muz_qe/dl_mk_karr_invariants.h index 7cd26d495..d70fb374b 100644 --- a/src/muz_qe/dl_mk_karr_invariants.h +++ b/src/muz_qe/dl_mk_karr_invariants.h @@ -41,6 +41,10 @@ namespace datalog { matrix& operator=(matrix const& other); void append(matrix const& other) { A.append(other.A); b.append(other.b); eq.append(other.eq); } void display(std::ostream& out) const; + static void display_row( + std::ostream& out, vector const& row, rational const& b, bool is_eq); + static void display_ineq( + std::ostream& out, vector const& row, rational const& b, bool is_eq); }; class add_invariant_model_converter; @@ -67,7 +71,7 @@ namespace datalog { virtual ~mk_karr_invariants(); - virtual void cancel(); + virtual void cancel(); rule_set * operator()(rule_set const & source, model_converter_ref& mc); diff --git a/src/muz_qe/dl_rule_set.h b/src/muz_qe/dl_rule_set.h index fdbbf7626..3079c6072 100644 --- a/src/muz_qe/dl_rule_set.h +++ b/src/muz_qe/dl_rule_set.h @@ -46,7 +46,7 @@ namespace datalog { ast_mark m_visited; - //we need to take care with removing to aviod memory leaks + //we need to take care with removing to avoid memory leaks void remove_m_data_entry(func_decl * key); //sometimes we need to return reference to an empty set, diff --git a/src/muz_qe/dl_rule_transformer.cpp b/src/muz_qe/dl_rule_transformer.cpp index 5ecbf2b45..7e0e951e1 100644 --- a/src/muz_qe/dl_rule_transformer.cpp +++ b/src/muz_qe/dl_rule_transformer.cpp @@ -26,7 +26,7 @@ Revision History: namespace datalog { rule_transformer::rule_transformer(context & ctx) - : m_context(ctx), m_rule_manager(m_context.get_rule_manager()), m_dirty(false), m_cancel(false) { + : m_context(ctx), m_rule_manager(m_context.get_rule_manager()), m_dirty(false) { } @@ -42,11 +42,9 @@ namespace datalog { } m_plugins.reset(); m_dirty = false; - m_cancel = false; } void rule_transformer::cancel() { - m_cancel = true; plugin_vector::iterator it = m_plugins.begin(); plugin_vector::iterator end = m_plugins.end(); for(; it!=end; ++it) { @@ -84,7 +82,7 @@ namespace datalog { ); plugin_vector::iterator it = m_plugins.begin(); plugin_vector::iterator end = m_plugins.end(); - for(; it!=end && !m_cancel; ++it) { + for(; it!=end && !m_context.canceled(); ++it) { plugin & p = **it; rule_set * new_rules = p(rules, mc); diff --git a/src/muz_qe/dl_rule_transformer.h b/src/muz_qe/dl_rule_transformer.h index 3b2140caf..87ff10fb0 100644 --- a/src/muz_qe/dl_rule_transformer.h +++ b/src/muz_qe/dl_rule_transformer.h @@ -41,7 +41,6 @@ namespace datalog { context & m_context; rule_manager & m_rule_manager; bool m_dirty; - volatile bool m_cancel; svector m_plugins; void ensure_ordered(); @@ -81,7 +80,6 @@ namespace datalog { void attach(rule_transformer & transformer) { m_transformer = &transformer; } protected: - volatile bool m_cancel; /** \brief Create a plugin object for rule_transformer. @@ -90,7 +88,7 @@ namespace datalog { (higher priority plugins will be applied first). */ plugin(unsigned priority, bool can_destratify_negation = false) : m_priority(priority), - m_can_destratify_negation(can_destratify_negation), m_transformer(0), m_cancel(false) {} + m_can_destratify_negation(can_destratify_negation), m_transformer(0) {} public: virtual ~plugin() {} @@ -98,6 +96,8 @@ namespace datalog { unsigned get_priority() { return m_priority; } bool can_destratify_negation() const { return m_can_destratify_negation; } + virtual void cancel() {} + /** \brief Return \c rule_set object with containing transformed rules or 0 if no transformation was done. @@ -107,8 +107,6 @@ namespace datalog { virtual rule_set * operator()(rule_set const & source, model_converter_ref& mc) = 0; - virtual void cancel() { m_cancel = true; } - /** Removes duplicate tails. */ diff --git a/src/muz_qe/fdd.cpp b/src/muz_qe/fdd.cpp index afb5206cc..6c3bc0974 100644 --- a/src/muz_qe/fdd.cpp +++ b/src/muz_qe/fdd.cpp @@ -97,14 +97,14 @@ node_id manager::mk_node(unsigned var, node_id lo, node_id hi) { inc_ref(hi); } - TRACE("mtdd", tout << "mk_node: " << var << " " << lo << " " << hi << " -> " << result << "\n";); + TRACE("fdd", tout << "mk_node: " << var << " " << lo << " " << hi << " -> " << result << "\n";); return result; } void manager::inc_ref(node_id n) { - TRACE("mtdd", tout << "incref: " << n << "\n";); + TRACE("fdd", tout << "incref: " << n << "\n";); if (!is_leaf(n)) { m_nodes[n].inc_ref(); } @@ -126,6 +126,7 @@ void manager::setup_keys(Key const* keys) { void manager::insert(Key const* keys) { setup_keys(keys); + m_insert_cache.reset(); node_id result = insert_sign(m_num_idx + m_num_keys, m_root); inc_ref(result); dec_ref(m_root); @@ -161,7 +162,7 @@ node_id manager::insert_sign(unsigned idx, node_id n) { node_id manager::insert(unsigned idx, node_id n) { node_id result; SASSERT(0 <= idx && idx <= m_num_idx); - TRACE("mtdd", tout << "insert: " << idx << " " << n << "\n";); + TRACE("fdd", tout << "insert: " << idx << " " << n << "\n";); if (is_leaf(n)) { while (idx > 0) { --idx; @@ -176,9 +177,8 @@ node_id manager::insert(unsigned idx, node_id n) { --idx; config c(m_dont_cares, idx, n); - insert_cache::key_data & kd = m_insert_cache.insert_if_not_there2(c, 0)->get_data(); - if (kd.m_value != 0) { - return kd.m_value; + if (m_insert_cache.find(c, result)) { + return result; } node nd = m_nodes[n]; @@ -209,7 +209,7 @@ node_id manager::insert(unsigned idx, node_id n) { } result = mk_node(idx, lo, hi); } - kd.m_value = result; + m_insert_cache.insert(c, result); return result; } @@ -263,11 +263,12 @@ bool manager::find_le(Key const* keys) { SASSERT(idx > 0); --idx; while (nc.var() < idx) { - if (idx2bit(idx)) { + if (idx2bit(idx) && is_dont_care(idx2key(idx))) { set_dont_care(idx2key(idx)); } --idx; } + SASSERT(nc.var() == idx); if (is_dont_care(idx2key(idx)) || idx2bit(idx)) { n = nc.hi(); } diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index 221e9a706..69b8765a7 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -290,7 +290,7 @@ public: } void display(std::ostream& out) const { - // m_fdd.display(out); + m_fdd.display(out); } @@ -302,8 +302,8 @@ class hilbert_basis::index { // for positive weights a shared value index. // typedef value_index1 value_index; - // typedef value_index2 value_index; - typedef value_index3 value_index; + typedef value_index2 value_index; + // typedef value_index3 value_index; struct stats { unsigned m_num_find; diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index a5f554e5e..2f58cc3c8 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -514,6 +514,15 @@ static void tst16() { saturate_basis(hb); } +static void tst17() { + hilbert_basis hb; + hb.add_eq(vec(1, 0), R(0)); + hb.add_eq(vec(-1, 0), R(0)); + hb.add_eq(vec(0, 2), R(0)); + hb.add_eq(vec(0, -2), R(0)); + saturate_basis(hb); + +} void tst_hilbert_basis() { std::cout << "hilbert basis test\n"; @@ -522,6 +531,9 @@ void tst_hilbert_basis() { g_use_ordered_support = true; + tst17(); + return; + if (true) { tst1(); tst2(); diff --git a/src/test/karr.cpp b/src/test/karr.cpp index 3ac427a88..8770eac94 100644 --- a/src/test/karr.cpp +++ b/src/test/karr.cpp @@ -165,6 +165,28 @@ namespace karr { return v; } + static vector V(int i, int j, int k, int l, int m) { + vector v; + v.push_back(rational(i)); + v.push_back(rational(j)); + v.push_back(rational(k)); + v.push_back(rational(l)); + v.push_back(rational(m)); + return v; + } + + static vector V(int i, int j, int k, int l, int x, int y, int z) { + vector v; + v.push_back(rational(i)); + v.push_back(rational(j)); + v.push_back(rational(k)); + v.push_back(rational(l)); + v.push_back(rational(x)); + v.push_back(rational(y)); + v.push_back(rational(z)); + return v; + } + #define R(_x_) rational(_x_) @@ -206,8 +228,66 @@ namespace karr { e2.display(std::cout << "e2\n"); } + void tst2() { + /** + 0 0 0 0 0 0 0 = 0 + 0 0 0 0 0 0 0 = 0 + 0 0 0 0 0 0 0 = 0 + 0 0 0 0 0 0 0 = 0 + 0 0 0 0 1 0 0 = 0 + 0 0 0 0 -1 0 0 = 0 + 0 1 0 0 0 0 0 = 0 + 0 -1 0 0 0 0 0 = 0 + 0 0 0 2 0 0 0 = 0 + 0 0 0 -2 0 0 0 = 0 + */ + + matrix ND; + ND.A.push_back(V(0,0,0,0,1,0,0)); ND.b.push_back(R(0)); + ND.A.push_back(V(0,0,0,0,-1,0,0)); ND.b.push_back(R(0)); + ND.A.push_back(V(0,1,0,0,0,0,0)); ND.b.push_back(R(0)); + ND.A.push_back(V(0,-1,0,0,0,0,0)); ND.b.push_back(R(0)); + ND.A.push_back(V(0,0,0,2,0,0,0)); ND.b.push_back(R(0)); + ND.A.push_back(V(0,0,0,-2,0,0,0)); ND.b.push_back(R(0)); + + ND.display(std::cout << "ND\n"); + + matrix N; + dualizeH(N, ND); + + N.display(std::cout << "N\n"); + + + } + + void tst3() { + /** + 0 0 0 0 1 0 0 = 0 + 0 0 0 0 -1 0 0 = 0 + 0 1 0 0 0 0 0 = 0 + 0 -1 0 0 0 0 0 = 0 + 0 0 0 2 0 0 0 = 0 + 0 0 0 -2 0 0 0 = 0 + */ + + matrix ND; + ND.A.push_back(V(1,0)); ND.b.push_back(R(0)); + ND.A.push_back(V(0,2)); ND.b.push_back(R(0)); + + ND.display(std::cout << "ND\n"); + + matrix N; + dualizeH(N, ND); + + N.display(std::cout << "N\n"); + + + } + }; void tst_karr() { + karr::tst3(); + return; karr::tst1(); } From 435c6dd365362737f70b3730b5d084bc111b90e2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Mar 2013 09:05:36 -0700 Subject: [PATCH 68/97] convert mega-bytes to bytes in env_params Signed-off-by: Nikolaj Bjorner --- src/util/env_params.cpp | 2 +- src/util/util.h | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/util/env_params.cpp b/src/util/env_params.cpp index 28d80d92d..b01a1c250 100644 --- a/src/util/env_params.cpp +++ b/src/util/env_params.cpp @@ -26,7 +26,7 @@ void env_params::updt_params() { params_ref p = gparams::get(); set_verbosity_level(p.get_uint("verbose", get_verbosity_level())); enable_warning_messages(p.get_bool("warning", true)); - memory::set_max_size(p.get_uint("memory_max_size", 0)); + memory::set_max_size(megabytes_to_bytes(p.get_uint("memory_max_size", 0))); memory::set_high_watermark(p.get_uint("memory_high_watermark", 0)); } diff --git a/src/util/util.h b/src/util/util.h index 3360c2282..8bcbce4a3 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -394,11 +394,14 @@ public: inline std::ostream & operator<<(std::ostream & out, escaped const & s) { s.display(out); return out; } -inline unsigned long long megabytes_to_bytes(unsigned b) { - if (b == UINT_MAX) - return UINT64_MAX; - else - return static_cast(b) * 1024ull * 1024ull; +inline size_t megabytes_to_bytes(unsigned mb) { + if (mb == UINT_MAX) + return SIZE_MAX; + unsigned long long b = static_cast(mb) * 1024ull * 1024ull; + size_t r = static_cast(b); + if (r != b) // overflow + r = SIZE_MAX; + return r; } void z3_bound_num_procs(); From cd48a5164e8009271fed347d8599ddf2f39f3c46 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Mar 2013 17:05:17 -0700 Subject: [PATCH 69/97] fix bug in hilbert_basis reset method. Missing reset of m_iseq Signed-off-by: Nikolaj Bjorner --- src/muz_qe/hilbert_basis.cpp | 22 ++++++++++++++++------ src/test/hilbert_basis.cpp | 20 +++++++++++++++++++- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index 7aed98487..7b3e67487 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -731,16 +731,26 @@ bool hilbert_basis::is_invalid_offset(offset_t offs) { void hilbert_basis::reset() { m_ineqs.reset(); - m_basis.reset(); + m_iseq.reset(); m_store.reset(); + m_basis.reset(); m_free_list.reset(); - m_active.reset(); - m_passive->reset(); - m_passive2->reset(); + m_sos.reset(); m_zero.reset(); - m_index->reset(1); - m_ints.reset(); + m_active.reset(); + if (m_passive) { + m_passive->reset(); + } + if (m_passive2) { + m_passive2->reset(); + } m_cancel = false; + if (m_index) { + m_index->reset(1); + } + m_ints.reset(); + m_current_ineq = 0; + } void hilbert_basis::collect_statistics(statistics& st) const { diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index 2f58cc3c8..e0a4a8370 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -524,6 +524,20 @@ static void tst17() { } +static void tst18() { + hilbert_basis hb; + hb.add_eq(vec(0, 1), R(0)); + hb.add_eq(vec(1, -1), R(2)); + saturate_basis(hb); +} + +static void tst19() { + hilbert_basis hb; + hb.add_eq(vec(0, 1, 0), R(0)); + hb.add_eq(vec(1, -1, 0), R(2)); + saturate_basis(hb); +} + void tst_hilbert_basis() { std::cout << "hilbert basis test\n"; // tst3(); @@ -531,9 +545,13 @@ void tst_hilbert_basis() { g_use_ordered_support = true; - tst17(); + tst18(); return; + tst19(); + return; + tst17(); + if (true) { tst1(); tst2(); From 4138e17b3f49d2aad4505128bed9260851cee49e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 31 Mar 2013 16:40:10 -0700 Subject: [PATCH 70/97] extract karr invariants as a Datalog relation Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_base.h | 1 + src/muz_qe/dl_compiler.cpp | 12 +- src/muz_qe/dl_context.cpp | 4 +- src/muz_qe/dl_interval_relation.cpp | 8 +- src/muz_qe/dl_interval_relation.h | 1 - src/muz_qe/dl_mk_karr_invariants.cpp | 1311 +++++++++++++++++--------- src/muz_qe/dl_mk_karr_invariants.h | 109 ++- src/muz_qe/dl_relation_manager.cpp | 6 + src/muz_qe/dl_relation_manager.h | 1 + src/muz_qe/dl_rule_set.cpp | 160 ++-- src/muz_qe/dl_rule_set.h | 2 + src/muz_qe/hilbert_basis.cpp | 3 +- src/muz_qe/hilbert_basis.h | 5 +- src/muz_qe/rel_context.cpp | 31 +- src/muz_qe/rel_context.h | 2 +- 15 files changed, 1082 insertions(+), 574 deletions(-) diff --git a/src/muz_qe/dl_base.h b/src/muz_qe/dl_base.h index 872bf7565..6c53a4b27 100644 --- a/src/muz_qe/dl_base.h +++ b/src/muz_qe/dl_base.h @@ -233,6 +233,7 @@ namespace datalog { symbol const& get_name() const { return m_name; } + virtual void set_cancel(bool f) {} relation_manager & get_manager() const { return m_manager; } ast_manager& get_ast_manager() const { return datalog::get_ast_manager_from_rel_manager(m_manager); } diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index cc56df4b7..c898f7964 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -1028,21 +1028,23 @@ namespace datalog { func_decl * head_pred = *preds.begin(); const rule_vector & rules = m_rule_set.get_predicate_rules(head_pred); + + reg_idx output_delta; - if(!output_deltas.find(head_pred, output_delta)) { + if (!output_deltas.find(head_pred, output_delta)) { output_delta = execution_context::void_register; } rule_vector::const_iterator it = rules.begin(); rule_vector::const_iterator end = rules.end(); - for(; it!=end; ++it) { + for (; it != end; ++it) { rule * r = *it; SASSERT(r->get_head()->get_decl()==head_pred); compile_rule_evaluation(r, input_deltas, output_delta, false, acc); } - if(add_saturation_marks) { + if (add_saturation_marks) { //now the predicate is saturated, so we may mark it as such acc.push_back(instruction::mk_mark_saturated(m_context.get_manager(), head_pred)); } @@ -1068,7 +1070,7 @@ namespace datalog { for(; sit!=send; ++sit) { func_decl_set & strat_preds = **sit; - if(all_saturated(strat_preds)) { + if (all_saturated(strat_preds)) { //all predicates in stratum are saturated, so no need to compile rules for them continue; } @@ -1084,7 +1086,7 @@ namespace datalog { tout << "\n"; ); - if(is_nonrecursive_stratum(strat_preds)) { + if (is_nonrecursive_stratum(strat_preds)) { //this stratum contains just a single non-recursive rule compile_nonrecursive_stratum(strat_preds, input_deltas, output_deltas, add_saturation_marks, acc); } diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 71ef7ad20..c667c7775 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -954,6 +954,7 @@ namespace datalog { if (m_pdr.get()) m_pdr->cancel(); if (m_bmc.get()) m_bmc->cancel(); if (m_tab.get()) m_tab->cancel(); + if (m_rel.get()) m_rel->set_cancel(true); } void context::cleanup() { @@ -962,6 +963,7 @@ namespace datalog { if (m_pdr.get()) m_pdr->cleanup(); if (m_bmc.get()) m_bmc->cleanup(); if (m_tab.get()) m_tab->cleanup(); + if (m_rel.get()) m_rel->set_cancel(false); } class context::engine_type_proc { @@ -1231,7 +1233,7 @@ namespace datalog { return m_rel->result_contains_fact(f); } - // TBD: algebraic data-types declarations will not be printed. + // NB: algebraic data-types declarations will not be printed. class free_func_visitor { ast_manager& m; func_decl_set m_funcs; diff --git a/src/muz_qe/dl_interval_relation.cpp b/src/muz_qe/dl_interval_relation.cpp index 150ba1c78..3397f2db0 100644 --- a/src/muz_qe/dl_interval_relation.cpp +++ b/src/muz_qe/dl_interval_relation.cpp @@ -21,6 +21,7 @@ Revision History: #include "optional.h" #include "ast_pp.h" #include "dl_interval_relation.h" +#include "bool_rewriter.h" namespace datalog { @@ -30,8 +31,7 @@ namespace datalog { interval_relation_plugin::interval_relation_plugin(relation_manager& m): relation_plugin(interval_relation_plugin::get_name(), m), m_empty(m_dep), - m_arith(get_ast_manager()), - m_bsimp(get_ast_manager()) { + m_arith(get_ast_manager()) { } bool interval_relation_plugin::can_handle_signature(const relation_signature & sig) { @@ -374,7 +374,6 @@ namespace datalog { void interval_relation::to_formula(expr_ref& fml) const { ast_manager& m = get_plugin().get_ast_manager(); arith_util& arith = get_plugin().m_arith; - basic_simplifier_plugin& bsimp = get_plugin().m_bsimp; expr_ref_vector conjs(m); relation_signature const& sig = get_signature(); for (unsigned i = 0; i < sig.size(); ++i) { @@ -405,7 +404,8 @@ namespace datalog { } } } - bsimp.mk_and(conjs.size(), conjs.c_ptr(), fml); + bool_rewriter br(m); + br.mk_and(conjs.size(), conjs.c_ptr(), fml); } diff --git a/src/muz_qe/dl_interval_relation.h b/src/muz_qe/dl_interval_relation.h index 0ff05719e..1a25f430f 100644 --- a/src/muz_qe/dl_interval_relation.h +++ b/src/muz_qe/dl_interval_relation.h @@ -34,7 +34,6 @@ namespace datalog { v_dependency_manager m_dep; interval m_empty; arith_util m_arith; - basic_simplifier_plugin m_bsimp; class join_fn; class project_fn; diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 77b52f2b9..6dca35cdf 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -33,36 +33,35 @@ Revision History: --*/ #include"dl_mk_karr_invariants.h" +#include"expr_safe_replace.h" +#include"bool_rewriter.h" namespace datalog { + mk_karr_invariants::mk_karr_invariants(context & ctx, unsigned priority): rule_transformer::plugin(priority, false), m_ctx(ctx), m(ctx.get_manager()), rm(ctx.get_rule_manager()), + m_inner_ctx(m, ctx.get_fparams()), a(m) { + params_ref params; + params.set_sym("default_relation", symbol("karr_relation")); + params.set_sym("engine", symbol("datalog")); + params.set_bool("karr", false); + m_inner_ctx.updt_params(params); } - mk_karr_invariants::~mk_karr_invariants() { - obj_map::iterator it = m_constraints.begin(), end = m_constraints.end(); - for (; it != end; ++it) { - dealloc(it->m_value); - } - it = m_dual_constraints.begin(); - end = m_dual_constraints.end(); - for (; it != end; ++it) { - dealloc(it->m_value); - } - } + mk_karr_invariants::~mk_karr_invariants() { } - mk_karr_invariants::matrix& mk_karr_invariants::matrix::operator=(matrix const& other) { + matrix& matrix::operator=(matrix const& other) { reset(); append(other); return *this; } - void mk_karr_invariants::matrix::display_row( + void matrix::display_row( std::ostream& out, vector const& row, rational const& b, bool is_eq) { for (unsigned j = 0; j < row.size(); ++j) { out << row[j] << " "; @@ -70,7 +69,7 @@ namespace datalog { out << (is_eq?" = ":" >= ") << -b << "\n"; } - void mk_karr_invariants::matrix::display_ineq( + void matrix::display_ineq( std::ostream& out, vector const& row, rational const& b, bool is_eq) { bool first = true; for (unsigned j = 0; j < row.size(); ++j) { @@ -91,391 +90,31 @@ namespace datalog { out << (is_eq?"= ":">= ") << -b << "\n"; } - void mk_karr_invariants::matrix::display(std::ostream& out) const { + void matrix::display(std::ostream& out) const { for (unsigned i = 0; i < A.size(); ++i) { display_row(out, A[i], b[i], eq[i]); } } - - bool mk_karr_invariants::is_linear(expr* e, vector& row, rational& b, rational const& mul) { - if (!a.is_int(e)) { - return false; - } - if (is_var(e)) { - row[to_var(e)->get_idx()] += mul; - return true; - } - if (!is_app(e)) { - return false; - } - rational n; - if (a.is_numeral(e, n)) { - b += mul*n; - return true; - } - if (a.is_add(e)) { - for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { - if (!is_linear(to_app(e)->get_arg(i), row, b, mul)) { - return false; - } - } - return true; - } - expr* e1, *e2; - if (a.is_sub(e, e1, e2)) { - return is_linear(e1, row, b, mul) && is_linear(e2, row, b, -mul); - } - if (a.is_mul(e, e1, e2) && a.is_numeral(e1, n)) { - return is_linear(e2, row, b, mul*n); - } - if (a.is_mul(e, e1, e2) && a.is_numeral(e2, n)) { - return is_linear(e1, row, b, mul*n); - } - if (a.is_uminus(e, e1)) { - return is_linear(e1, row, b, -mul); - } - return false; - } - - mk_karr_invariants::matrix* mk_karr_invariants::get_constraints(func_decl* p) { - matrix* result = 0; - m_constraints.find(p, result); - return result; - } - - mk_karr_invariants::matrix& mk_karr_invariants::get_dual_constraints(func_decl* p) { - matrix* result = 0; - if (!m_dual_constraints.find(p, result)) { - result = alloc(matrix); - m_dual_constraints.insert(p, result); - } - return *result; - } - - bool mk_karr_invariants::is_eq(expr* e, var*& v, rational& n) { - expr* e1, *e2; - if (!m.is_eq(e, e1, e2)) { - return false; - } - if (!is_var(e1)) { - std::swap(e1, e2); - } - if (!is_var(e1)) { - return false; - } - v = to_var(e1); - if (!a.is_numeral(e2, n)) { - return false; - } - return true; - } - bool mk_karr_invariants::get_transition_relation(rule const& r, matrix& M) { - unsigned num_vars = rm.get_counter().get_max_rule_var(r)+1; - unsigned arity = r.get_decl()->get_arity(); - unsigned num_columns = arity + num_vars; - unsigned utsz = r.get_uninterpreted_tail_size(); - unsigned tsz = r.get_tail_size(); - M.reset(); - - for (unsigned i = 0; i < utsz; ++i) { - matrix const* Mp = get_constraints(r.get_decl(i)); - if (!Mp) { - return false; - } - TRACE("dl", Mp->display(tout << "Intersect\n");); - intersect_matrix(r.get_tail(i), *Mp, num_columns, M); - } - - rational one(1), mone(-1); - expr* e1, *e2, *en; - var* v, *w; - rational n1, n2; - expr_ref_vector conjs(m); - for (unsigned i = utsz; i < tsz; ++i) { - conjs.push_back(r.get_tail(i)); - } - datalog::flatten_and(conjs); - - for (unsigned i = 0; i < conjs.size(); ++i) { - expr* e = conjs[i].get(); - rational b(0); - vector row; - row.resize(num_columns, rational(0)); - bool processed = true; - if (m.is_eq(e, e1, e2) && is_linear(e1, row, b, one) && is_linear(e2, row, b, mone)) { - M.A.push_back(row); - M.b.push_back(b); - M.eq.push_back(true); - } - else if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && - is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { - M.A.push_back(row); - M.b.push_back(b); - M.eq.push_back(false); - } - else if ((a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) && - is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { - M.A.push_back(row); - M.b.push_back(b - rational(1)); - M.eq.push_back(false); - } - else if (m.is_not(e, en) && (a.is_lt(en, e2, e1) || a.is_gt(en, e1, e2)) && - is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { - M.A.push_back(row); - M.b.push_back(b); - M.eq.push_back(false); - } - else if (m.is_not(e, en) && (a.is_le(en, e2, e1) || a.is_ge(en, e1, e2)) && - is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { - M.A.push_back(row); - M.b.push_back(b - rational(1)); - M.eq.push_back(false); - } - else if (m.is_or(e, e1, e2) && is_eq(e1, v, n1) && is_eq(e2, w, n2) && v == w) { - if (n1 > n2) { - std::swap(n1, n2); - } - SASSERT(n1 <= n2); - row[v->get_idx()] = rational(1); - // v - n1 >= 0 - M.A.push_back(row); - M.b.push_back(-n1); - M.eq.push_back(false); - // -v + n2 >= 0 - row[v->get_idx()] = rational(-1); - M.A.push_back(row); - M.b.push_back(n2); - M.eq.push_back(false); - } - else { - processed = false; - } - TRACE("dl", tout << (processed?"+ ":"- ") << mk_pp(e, m) << "\n"; - if (processed) matrix::display_ineq(tout, row, M.b.back(), M.eq.back()); - ); - } - // intersect with the head predicate. - app* head = r.get_head(); - unsigned sz0 = M.A.size(); - for (unsigned i = 0; i < arity; ++i) { - rational n; - expr* arg = head->get_arg(i); - if (!a.is_int(arg)) { - // no-op - } - else if (is_var(arg)) { - vector row; - row.resize(num_columns, rational(0)); - unsigned idx = to_var(arg)->get_idx(); - row[idx] = rational(-1); - row[num_vars + i] = rational(1); - M.A.push_back(row); - M.b.push_back(rational(0)); - M.eq.push_back(true); - } - else if (a.is_numeral(arg, n)) { - vector row; - row.resize(num_columns, rational(0)); - row[num_vars + i] = rational(1); - M.A.push_back(row); - M.b.push_back(-n); - M.eq.push_back(true); - } - else { - UNREACHABLE(); - } - } - if (M.A.size() == sz0) { - return false; - } - - TRACE("dl", M.display(tout << r.get_decl()->get_name() << "\n");); - matrix MD; - dualizeI(MD, M); - M.reset(); - // project for variables in head. - for (unsigned i = 0; i < MD.size(); ++i) { - vector row; - row.append(arity, MD.A[i].c_ptr() + num_vars); - M.A.push_back(row); - M.b.push_back(MD.b[i]); - M.eq.push_back(true); - } - TRACE("dl", M.display(tout << r.get_decl()->get_name() << "\n");); - - return true; - } - - void mk_karr_invariants::intersect_matrix(app* p, matrix const& Mp, unsigned num_columns, matrix& M) { - for (unsigned j = 0; j < Mp.size(); ++j) { - rational b = Mp.b[j], n; - vector row; - row.resize(num_columns, rational(0)); - for (unsigned i = 0; i < p->get_num_args(); ++i) { - expr* arg = p->get_arg(i); - if (!a.is_int(arg)) { - // no-op - } - else if (is_var(arg)) { - unsigned idx = to_var(arg)->get_idx(); - row[idx] += Mp.A[j][i]; - } - else if (a.is_numeral(arg, n)) { - b += Mp.A[j][i]*n; - } - else { - UNREACHABLE(); - } - } - M.A.push_back(row); - M.b.push_back(b); - M.eq.push_back(Mp.eq[j]); - } - } - - // treat src as a homogeneous matrix. - void mk_karr_invariants::dualizeH(matrix& dst, matrix const& src) { - dst.reset(); - if (src.size() == 0) { - return; - } - m_hb.reset(); - for (unsigned i = 0; i < src.size(); ++i) { - vector v(src.A[i]); - v.push_back(src.b[i]); - if (src.eq[i]) { - m_hb.add_eq(v, rational(0)); - } - else { - m_hb.add_ge(v, rational(0)); - } - } - for (unsigned i = 0; i < 1 + src.A[0].size(); ++i) { - m_hb.set_is_int(i); - } - lbool is_sat = m_hb.saturate(); - TRACE("dl_verbose", m_hb.display(tout);); - SASSERT(is_sat == l_true); - unsigned basis_size = m_hb.get_basis_size(); - for (unsigned i = 0; i < basis_size; ++i) { - bool is_initial; - vector soln; - m_hb.get_basis_solution(i, soln, is_initial); - if (!is_initial) { - dst.b.push_back(soln.back()); - dst.eq.push_back(true); - soln.pop_back(); - dst.A.push_back(soln); - } - } - } - - // treat src as an inhomegeneous matrix. - void mk_karr_invariants::dualizeI(matrix& dst, matrix const& src) { - m_hb.reset(); - for (unsigned i = 0; i < src.size(); ++i) { - if (src.eq[i]) { - m_hb.add_eq(src.A[i], -src.b[i]); - } - else { - m_hb.add_ge(src.A[i], -src.b[i]); - } - } - for (unsigned i = 0; !src.A.empty() && i < src.A[0].size(); ++i) { - m_hb.set_is_int(i); - } - lbool is_sat = m_hb.saturate(); - TRACE("dl_verbose", m_hb.display(tout);); - SASSERT(is_sat == l_true); - dst.reset(); - unsigned basis_size = m_hb.get_basis_size(); - bool first_initial = true; - for (unsigned i = 0; i < basis_size; ++i) { - bool is_initial; - vector soln; - m_hb.get_basis_solution(i, soln, is_initial); - if (is_initial && first_initial) { - dst.A.push_back(soln); - dst.b.push_back(rational(1)); - dst.eq.push_back(true); - first_initial = false; - } - else if (!is_initial) { - dst.A.push_back(soln); - dst.b.push_back(rational(0)); - dst.eq.push_back(true); - } - } - } - - 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); - for (unsigned i = 0; i < tsz; ++i) { - tail.push_back(r.get_tail(i)); - } - for (unsigned i = 0; i < utsz; ++i) { - func_decl* q = r.get_decl(i); - matrix* N = get_constraints(q); - if (!N) { - continue; - } - expr_ref zero(m), lhs(m); - zero = a.mk_numeral(rational(0), true); - for (unsigned j = 0; j < N->size(); ++j) { - rational n; - SASSERT(N->A[j].size() == q->get_arity()); - expr_ref_vector sum(m); - for (unsigned k = 0; k < N->A[j].size(); ++k) { - n = N->A[j][k]; - if (!n.is_zero()) { - expr* arg = r.get_tail(i)->get_arg(k); - sum.push_back(a.mk_mul(a.mk_numeral(n, true), arg)); - } - } - n = N->b[j]; - if (!n.is_zero()) { - sum.push_back(a.mk_numeral(n, true)); - } - lhs = a.mk_add(sum.size(), sum.c_ptr()); - if (N->eq[j]) { - tail.push_back(m.mk_eq(lhs, zero)); - } - else { - tail.push_back(a.mk_ge(lhs, zero)); - } - } - } - rule* new_rule = &r; - if (tail.size() != tsz) { - new_rule = rm.mk(r.get_head(), tail.size(), tail.c_ptr(), 0, r.name()); - } - rules.add_rule(new_rule); - rm.mk_rule_rewrite_proof(r, *new_rule); // should be weakening rule. - } class mk_karr_invariants::add_invariant_model_converter : public model_converter { ast_manager& m; arith_util a; func_decl_ref_vector m_funcs; - ptr_vector m_invs; + expr_ref_vector m_invs; public: - add_invariant_model_converter(ast_manager& m): m(m), a(m), m_funcs(m) {} + add_invariant_model_converter(ast_manager& m): m(m), a(m), m_funcs(m), m_invs(m) {} - virtual ~add_invariant_model_converter() { - for (unsigned i = 0; i < m_invs.size(); ++i) { - dealloc(m_invs[i]); + virtual ~add_invariant_model_converter() { } + + void add(func_decl* p, expr* inv) { + if (!m.is_true(inv)) { + m_funcs.push_back(p); + m_invs.push_back(inv); } } - void add(func_decl* p, matrix& M) { - m_funcs.push_back(p); - m_invs.push_back(alloc(matrix, M)); - } - virtual void operator()(model_ref & mr) { for (unsigned i = 0; i < m_funcs.size(); ++i) { func_decl* p = m_funcs[i].get(); @@ -484,11 +123,9 @@ namespace datalog { unsigned arity = p->get_arity(); SASSERT(0 < arity); if (f) { - matrix const& M = *m_invs[i]; - mk_body(M, body); SASSERT(f->num_entries() == 0); if (!f->is_partial()) { - body = m.mk_and(f->get_else(), body); + bool_rewriter(m).mk_and(f->get_else(), m_invs[i].get(), body); } } else { @@ -503,7 +140,7 @@ namespace datalog { virtual model_converter * translate(ast_translation & translator) { add_invariant_model_converter* mc = alloc(add_invariant_model_converter, m); for (unsigned i = 0; i < m_funcs.size(); ++i) { - mc->add(translator(m_funcs[i].get()), *m_invs[i]); + mc->add(translator(m_funcs[i].get()), m_invs[i].get()); } return mc; } @@ -514,7 +151,7 @@ namespace datalog { for (unsigned i = 0; i < M.size(); ++i) { mk_body(M.A[i], M.b[i], M.eq[i], conj); } - body = m.mk_and(conj.size(), conj.c_ptr()); + bool_rewriter(m).mk_and(conj.size(), conj.c_ptr(), body); } void mk_body(vector const& row, rational const& b, bool is_eq, expr_ref_vector& conj) { @@ -545,12 +182,10 @@ namespace datalog { conj.push_back(a.mk_ge(lhs, zero)); } } - }; void mk_karr_invariants::cancel() { - rule_transformer::plugin::cancel(); - m_hb.set_cancel(true); + m_inner_ctx.cancel(); } rule_set * mk_karr_invariants::operator()(rule_set const & source) { @@ -564,64 +199,27 @@ namespace datalog { return 0; } } - bool change = true, non_empty = false; - while (!m_ctx.canceled() && change) { - change = false; - it = source.begin(); - for (; it != end; ++it) { - rule const& r = **it; - TRACE("dl", r.display(m_ctx, tout);); - matrix MD, P; - if (!get_transition_relation(r, MD)) { - continue; - } - non_empty = true; - func_decl* p = r.get_decl(); - matrix& ND = get_dual_constraints(p); - matrix* N = get_constraints(p); - ND.append(MD); - dualizeH(P, ND); - - TRACE("dl", - ND.display(tout << "ND\n"); - P.display(tout << "P\n");); - - if (!N) { - change = true; - N = alloc(matrix, P); - m_constraints.insert(p, N); - } - else if (P.size() != N->size()) { - change = true; - *N = P; - } - } + rel_context& rctx = m_inner_ctx.get_rel_context(); + ptr_vector heads; + m_inner_ctx.ensure_opened(); + it = source.begin(); + for (; it != end; ++it) { + rule_ref r(*it, m_ctx.get_rule_manager()); + m_inner_ctx.add_rule(r); + m_inner_ctx.register_predicate(r->get_decl()); } - - if (!non_empty) { - return 0; + m_inner_ctx.close(); + rule_set::decl2rules::iterator dit = source.begin_grouped_rules(); + rule_set::decl2rules::iterator dend = source.end_grouped_rules(); + for (; dit != dend; ++dit) { + heads.push_back(dit->m_key); } - - if (m_ctx.canceled()) { - return 0; - } - - TRACE("dl", - rule_set::decl2rules::iterator git = source.begin_grouped_rules(); - rule_set::decl2rules::iterator gend = source.end_grouped_rules(); - for (; git != gend; ++git) { - func_decl* p = git->m_key; - matrix* M = get_constraints(p); - tout << p->get_name() << "\n"; - if (M) { - M->display(tout); - } - }); + m_inner_ctx.rel_query(heads.size(), heads.c_ptr()); rule_set* rules = alloc(rule_set, m_ctx); it = source.begin(); for (; it != end; ++it) { - update_body(*rules, **it); + update_body(rctx, *rules, **it); } if (m_ctx.get_model_converter()) { add_invariant_model_converter* kmc = alloc(add_invariant_model_converter, m); @@ -629,9 +227,11 @@ namespace datalog { rule_set::decl2rules::iterator gend = source.end_grouped_rules(); for (; git != gend; ++git) { func_decl* p = git->m_key; - matrix* M = get_constraints(p); - if (M) { - kmc->add(p, *M); + expr_ref fml(m); + relation_base* rb = rctx.try_get_relation(p); + if (rb) { + rb->to_formula(fml); + kmc->add(p, fml); } } m_ctx.add_model_converter(kmc); @@ -640,5 +240,824 @@ namespace datalog { return rules; } + void mk_karr_invariants::update_body(rel_context& rctx, rule_set& rules, rule& r) { + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + app_ref_vector tail(m); + expr_ref fml(m); + for (unsigned i = 0; i < tsz; ++i) { + 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); + 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)); + } + } + rule* new_rule = &r; + if (tail.size() != tsz) { + new_rule = rm.mk(r.get_head(), tail.size(), tail.c_ptr(), 0, r.name()); + } + rules.add_rule(new_rule); + rm.mk_rule_rewrite_proof(r, *new_rule); // should be weakening rule. + } + + + + class karr_relation : public relation_base { + friend class karr_relation_plugin; + friend class karr_relation_plugin::filter_equal_fn; + + karr_relation_plugin& m_plugin; + ast_manager& m; + mutable arith_util a; + func_decl_ref m_fn; + mutable bool m_empty; + mutable matrix m_ineqs; + mutable bool m_ineqs_valid; + mutable matrix m_basis; + mutable bool m_basis_valid; + + public: + karr_relation(karr_relation_plugin& p, func_decl* f, relation_signature const& s, bool is_empty): + relation_base(p, s), + m_plugin(p), + m(p.get_ast_manager()), + a(m), + m_fn(f, m), + m_empty(is_empty), + m_ineqs_valid(!is_empty), + m_basis_valid(false) + { + } + + virtual bool empty() const { + return m_empty; + } + + virtual void add_fact(const relation_fact & f) { + SASSERT(m_empty); + SASSERT(!m_basis_valid); + m_empty = false; + m_ineqs_valid = true; + for (unsigned i = 0; i < f.size(); ++i) { + rational n; + if (a.is_numeral(f[i], n) && n.is_int()) { + vector row; + row.resize(f.size()); + row[i] = rational(1); + m_ineqs.A.push_back(row); + m_ineqs.b.push_back(-n); + m_ineqs.eq.push_back(true); + } + } + } + + virtual bool contains_fact(const relation_fact & f) const { + UNREACHABLE(); + return false; + } + + virtual void display(std::ostream & out) const { + if (m_fn) { + out << m_fn->get_name() << "\n"; + } + if (empty()) { + out << "empty\n"; + } + else { + if (m_ineqs_valid) { + m_ineqs.display(out << "ineqs:\n"); + } + if (m_basis_valid) { + m_basis.display(out << "basis:\n"); + } + } + } + + virtual karr_relation * clone() const { + karr_relation* result = alloc(karr_relation, m_plugin, m_fn, get_signature(), m_empty); + result->copy(*this); + return result; + } + + virtual karr_relation * complement(func_decl*) const { + UNREACHABLE(); + return 0; + } + + virtual void to_formula(expr_ref& fml) const { + if (empty()) { + fml = m.mk_false(); + } + else { + matrix const& M = get_ineqs(); + expr_ref_vector conj(m); + for (unsigned i = 0; i < M.size(); ++i) { + to_formula(M.A[i], M.b[i], M.eq[i], conj); + } + bool_rewriter(m).mk_and(conj.size(), conj.c_ptr(), fml); + } + } + + karr_relation_plugin& get_plugin() const { return m_plugin; } + + void filter_interpreted(app* cond) { + rational one(1), mone(-1); + expr* e1, *e2, *en; + var* v, *w; + rational n1, n2; + expr_ref_vector conjs(m); + datalog::flatten_and(cond, conjs); + matrix& M = get_ineqs(); + unsigned num_columns = get_signature().size(); + + for (unsigned i = 0; i < conjs.size(); ++i) { + expr* e = conjs[i].get(); + rational b(0); + vector row; + row.resize(num_columns, rational(0)); + bool processed = true; + if (m.is_eq(e, e1, e2) && is_linear(e1, row, b, one) && is_linear(e2, row, b, mone)) { + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(true); + } + else if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(false); + } + else if ((a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b - rational(1)); + M.eq.push_back(false); + } + else if (m.is_not(e, en) && (a.is_lt(en, e2, e1) || a.is_gt(en, e1, e2)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(false); + } + else if (m.is_not(e, en) && (a.is_le(en, e2, e1) || a.is_ge(en, e1, e2)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b - rational(1)); + M.eq.push_back(false); + } + else if (m.is_or(e, e1, e2) && is_eq(e1, v, n1) && is_eq(e2, w, n2) && v == w) { + if (n1 > n2) { + std::swap(n1, n2); + } + SASSERT(n1 <= n2); + row[v->get_idx()] = rational(1); + // v - n1 >= 0 + M.A.push_back(row); + M.b.push_back(-n1); + M.eq.push_back(false); + // -v + n2 >= 0 + row[v->get_idx()] = rational(-1); + M.A.push_back(row); + M.b.push_back(n2); + M.eq.push_back(false); + } + else { + processed = false; + } + TRACE("dl", tout << (processed?"+ ":"- ") << mk_pp(e, m) << "\n"; + if (processed) matrix::display_ineq(tout, row, M.b.back(), M.eq.back()); + ); + } + TRACE("dl", display(tout);); + } + + void mk_join(karr_relation const& r1, karr_relation const& r2, + unsigned col_cnt, unsigned const* cols1, unsigned const* cols2) { + if (r1.empty() || r2.empty()) { + m_empty = true; + return; + } + matrix const& M1 = r1.get_ineqs(); + matrix const& M2 = r2.get_ineqs(); + unsigned sig1_size = r1.get_signature().size(); + unsigned sig_size = get_signature().size(); + m_ineqs.reset(); + for (unsigned i = 0; i < M1.size(); ++i) { + vector row; + row.append(M1.A[i]); + row.resize(sig_size); + m_ineqs.A.push_back(row); + m_ineqs.b.push_back(M1.b[i]); + m_ineqs.eq.push_back(M1.eq[i]); + } + for (unsigned i = 0; i < M2.size(); ++i) { + vector row; + row.resize(sig_size); + for (unsigned j = 0; j < M2.A[i].size(); ++j) { + row[sig1_size + j] = M2.A[i][j]; + } + m_ineqs.A.push_back(row); + m_ineqs.b.push_back(M2.b[i]); + m_ineqs.eq.push_back(M2.eq[i]); + } + for (unsigned i = 0; i < col_cnt; ++i) { + vector row; + row.resize(sig_size); + row[cols1[i]] = rational(1); + row[sig1_size + cols2[i]] = rational(-1); + m_ineqs.A.push_back(row); + m_ineqs.b.push_back(rational(0)); + m_ineqs.eq.push_back(true); + } + m_ineqs_valid = true; + m_basis_valid = false; + m_empty = false; + if (r1.m_fn) { + m_fn = r1.m_fn; + } + if (r2.m_fn) { + m_fn = r2.m_fn; + } + } + + void mk_project(karr_relation const& r, unsigned cnt, unsigned const* cols) { + if (r.m_empty) { + m_empty = true; + return; + } + matrix const& M = r.get_basis(); + m_basis.reset(); + for (unsigned i = 0; i < M.size(); ++i) { + vector row; + unsigned k = 0; + for (unsigned j = 0; j < M.A[i].size(); ++j) { + if (k < cnt && j == cols[k]) { + ++k; + } + else { + row.push_back(M.A[i][j]); + } + } + SASSERT(row.size() + cnt == M.A[i].size()); + SASSERT(M.eq[i]); + m_basis.A.push_back(row); + m_basis.b.push_back(M.b[i]); + m_basis.eq.push_back(true); + } + m_basis_valid = true; + m_ineqs_valid = false; + m_empty = false; + m_fn = r.m_fn; + + TRACE("dl", + for (unsigned i = 0; i < cnt; ++i) { + tout << cols[i] << " "; + } + tout << "\n"; + r.display(tout); + display(tout);); + } + + void mk_rename(const karr_relation & r, unsigned col_cnt, const unsigned * cols) { + if (r.empty()) { + m_empty = true; + return; + } + m_ineqs.reset(); + m_basis.reset(); + m_ineqs_valid = r.m_ineqs_valid; + m_basis_valid = r.m_basis_valid; + if (m_ineqs_valid) { + m_ineqs.append(r.m_ineqs); + mk_rename(m_ineqs, col_cnt, cols); + } + if (m_basis_valid) { + m_basis.append(r.m_basis); + mk_rename(m_basis, col_cnt, cols); + } + m_fn = r.m_fn; + TRACE("dl", r.display(tout); display(tout);); + } + + void mk_union(karr_relation const& src, karr_relation* delta) { + if (src.empty()) { + if (delta) { + delta->m_empty = true; + } + return; + } + matrix const& M = src.get_basis(); + if (empty()) { + m_basis = M; + m_basis_valid = true; + m_empty = false; + m_ineqs_valid = false; + if (delta) { + delta->copy(*this); + } + return; + } + matrix& N = get_basis(); + unsigned N_size = N.size(); + for (unsigned i = 0; i < M.size(); ++i) { + bool found = false; + for (unsigned j = 0; !found && j < N_size; ++j) { + found = + same_row(M.A[i], N.A[j]) && + M.b[i] == N.b[j] && + M.eq[i] == N.eq[j]; + } + if (!found) { + N.A.push_back(M.A[i]); + N.b.push_back(M.b[i]); + N.eq.push_back(M.eq[i]); + } + } + m_ineqs_valid = false; + if (N_size != N.size()) { + if (delta) { + delta->copy(*this); + } + } + } + + matrix const& get_basis() const { + init_basis(); + return m_basis; + } + + matrix& get_basis() { + init_basis(); + return m_basis; + } + + matrix const& get_ineqs() const { + init_ineqs(); + return m_ineqs; + } + + matrix & get_ineqs() { + init_ineqs(); + return m_ineqs; + } + + private: + + void copy(karr_relation const& other) { + m_ineqs = other.m_ineqs; + m_basis = other.m_basis; + m_basis_valid = other.m_basis_valid; + m_ineqs_valid = other.m_ineqs_valid; + m_empty = other.m_empty; + } + + bool same_row(vector const& r1, vector const& r2) const { + SASSERT(r1.size() == r2.size()); + for (unsigned i = 0; i < r1.size(); ++i) { + if (r1[i] != r2[i]) { + return false; + } + } + return true; + } + + void mk_rename(matrix& M, unsigned col_cnt, unsigned const* cols) { + for (unsigned j = 0; j < M.size(); ++j) { + vector & row = M.A[j]; + rational tmp = row[cols[0]]; + for (unsigned i = 0; i + 1 < col_cnt; ++i) { + row[cols[i]] = row[cols[i+1]]; + } + row[cols[col_cnt-1]] = tmp; + } + } + + bool is_eq(expr* e, var*& v, rational& n) { + expr* e1, *e2; + if (!m.is_eq(e, e1, e2)) { + return false; + } + if (!is_var(e1)) { + std::swap(e1, e2); + } + if (!is_var(e1)) { + return false; + } + v = to_var(e1); + if (!a.is_numeral(e2, n)) { + return false; + } + return true; + } + + bool is_linear(expr* e, vector& row, rational& b, rational const& mul) { + if (!a.is_int(e)) { + return false; + } + if (is_var(e)) { + row[to_var(e)->get_idx()] += mul; + return true; + } + if (!is_app(e)) { + return false; + } + rational n; + if (a.is_numeral(e, n)) { + b += mul*n; + return true; + } + if (a.is_add(e)) { + for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { + if (!is_linear(to_app(e)->get_arg(i), row, b, mul)) { + return false; + } + } + return true; + } + expr* e1, *e2; + if (a.is_sub(e, e1, e2)) { + return is_linear(e1, row, b, mul) && is_linear(e2, row, b, -mul); + } + if (a.is_mul(e, e1, e2) && a.is_numeral(e1, n)) { + return is_linear(e2, row, b, mul*n); + } + if (a.is_mul(e, e1, e2) && a.is_numeral(e2, n)) { + return is_linear(e1, row, b, mul*n); + } + if (a.is_uminus(e, e1)) { + return is_linear(e1, row, b, -mul); + } + return false; + } + + void init_ineqs() const { + if (!m_ineqs_valid) { + SASSERT(m_basis_valid); + m_plugin.dualizeH(m_ineqs, m_basis); + m_ineqs_valid = true; + } + } + + void init_basis() const { + if (!m_basis_valid) { + SASSERT(m_ineqs_valid); + if (m_plugin.dualizeI(m_basis, m_ineqs)) { + m_basis_valid = true; + } + else { + m_empty = true; + } + } + } + + void to_formula(vector const& row, rational const& b, bool is_eq, expr_ref_vector& conj) const { + expr_ref_vector sum(m); + expr_ref zero(m), lhs(m); + zero = a.mk_numeral(rational(0), true); + + for (unsigned i = 0; i < row.size(); ++i) { + if (row[i].is_zero()) { + continue; + } + var* var = m.mk_var(i, a.mk_int()); + if (row[i].is_one()) { + sum.push_back(var); + } + else { + sum.push_back(a.mk_mul(a.mk_numeral(row[i], true), var)); + } + } + if (!b.is_zero()) { + sum.push_back(a.mk_numeral(b, true)); + } + lhs = a.mk_add(sum.size(), sum.c_ptr()); + if (is_eq) { + conj.push_back(m.mk_eq(lhs, zero)); + } + else { + conj.push_back(a.mk_ge(lhs, zero)); + } + } + }; + + + karr_relation& karr_relation_plugin::get(relation_base& r) { + return dynamic_cast(r); + } + + karr_relation const & karr_relation_plugin::get(relation_base const& r) { + return dynamic_cast(r); + } + + void karr_relation_plugin::set_cancel(bool f) { + m_hb.set_cancel(f); + } + + relation_base * karr_relation_plugin::mk_empty(const relation_signature & s) { + return alloc(karr_relation, *this, 0, s, true); + } + + relation_base * karr_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { + return alloc(karr_relation, *this, p, s, false); + } + + class karr_relation_plugin::join_fn : public convenient_relation_join_fn { + public: + join_fn(const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2) + : convenient_relation_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2){ + } + + virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { + karr_relation const& r1 = get(_r1); + karr_relation const& r2 = get(_r2); + karr_relation_plugin& p = r1.get_plugin(); + karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + result->mk_join(r1, r2, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); + return result; + } + }; + + relation_join_fn * karr_relation_plugin::mk_join_fn( + const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if (!check_kind(t1) || !check_kind(t2)) { + return 0; + } + return alloc(join_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2); + } + + + class karr_relation_plugin::project_fn : public convenient_relation_project_fn { + public: + project_fn(const relation_signature & orig_sig, unsigned removed_col_cnt, const unsigned * removed_cols) + : convenient_relation_project_fn(orig_sig, removed_col_cnt, removed_cols) { + } + + virtual relation_base * operator()(const relation_base & _r) { + karr_relation const& r = get(_r); + karr_relation_plugin& p = r.get_plugin(); + karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + result->mk_project(r, m_removed_cols.size(), m_removed_cols.c_ptr()); + return result; + } + }; + + relation_transformer_fn * karr_relation_plugin::mk_project_fn(const relation_base & r, + unsigned col_cnt, const unsigned * removed_cols) { + return alloc(project_fn, r.get_signature(), col_cnt, removed_cols); + } + + class karr_relation_plugin::rename_fn : public convenient_relation_rename_fn { + public: + rename_fn(karr_relation_plugin& p, const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) + : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) {} + + virtual relation_base * operator()(const relation_base & _r) { + karr_relation const& r = get(_r); + karr_relation_plugin& p = r.get_plugin(); + karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + result->mk_rename(r, m_cycle.size(), m_cycle.c_ptr()); + return result; + } + }; + + relation_transformer_fn * karr_relation_plugin::mk_rename_fn(const relation_base & r, + unsigned cycle_len, const unsigned * permutation_cycle) { + if (!check_kind(r)) { + return 0; + } + return alloc(rename_fn, *this, r.get_signature(), cycle_len, permutation_cycle); + } + + bool karr_relation_plugin::dualizeI(matrix& dst, matrix const& src) { + dst.reset(); + m_hb.reset(); + for (unsigned i = 0; i < src.size(); ++i) { + if (src.eq[i]) { + m_hb.add_eq(src.A[i], -src.b[i]); + } + else { + m_hb.add_ge(src.A[i], -src.b[i]); + } + } + for (unsigned i = 0; !src.A.empty() && i < src.A[0].size(); ++i) { + m_hb.set_is_int(i); + } + lbool is_sat = l_undef; + + try { + is_sat = m_hb.saturate(); + } + catch (...) { + is_sat = l_undef; + } + TRACE("dl_verbose", m_hb.display(tout);); + if (is_sat == l_false) { + return false; + } + if (is_sat == l_undef) { + return true; + } + unsigned basis_size = m_hb.get_basis_size(); + bool first_initial = true; + for (unsigned i = 0; i < basis_size; ++i) { + bool is_initial; + vector soln; + m_hb.get_basis_solution(i, soln, is_initial); + if (is_initial && first_initial) { + dst.A.push_back(soln); + dst.b.push_back(rational(1)); + dst.eq.push_back(true); + first_initial = false; + } + else if (!is_initial) { + dst.A.push_back(soln); + dst.b.push_back(rational(0)); + dst.eq.push_back(true); + } + } + return true; + } + + void karr_relation_plugin::dualizeH(matrix& dst, matrix const& src) { + dst.reset(); + if (src.size() == 0) { + return; + } + m_hb.reset(); + for (unsigned i = 0; i < src.size(); ++i) { + vector v(src.A[i]); + v.push_back(src.b[i]); + if (src.eq[i]) { + m_hb.add_eq(v, rational(0)); + } + else { + m_hb.add_ge(v, rational(0)); + } + } + for (unsigned i = 0; i < 1 + src.A[0].size(); ++i) { + m_hb.set_is_int(i); + } + lbool is_sat = l_undef; + try { + is_sat = m_hb.saturate(); + } + catch (...) { + is_sat = l_undef; + } + if (is_sat != l_true) { + return; + } + TRACE("dl_verbose", m_hb.display(tout);); + SASSERT(is_sat == l_true); + unsigned basis_size = m_hb.get_basis_size(); + for (unsigned i = 0; i < basis_size; ++i) { + bool is_initial; + vector soln; + m_hb.get_basis_solution(i, soln, is_initial); + if (!is_initial) { + dst.b.push_back(soln.back()); + dst.eq.push_back(true); + soln.pop_back(); + dst.A.push_back(soln); + } + } + } + + + class karr_relation_plugin::union_fn : public relation_union_fn { + karr_relation_plugin& m_plugin; + public: + union_fn(karr_relation_plugin& p) : + m_plugin(p) { + } + + virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + + karr_relation& r = get(_r); + karr_relation const& src = get(_src); + TRACE("dl", r.display(tout << "dst:\n"); src.display(tout << "src:\n");); + + if (_delta) { + karr_relation& d = get(*_delta); + r.mk_union(src, &d); + } + else { + r.mk_union(src, 0); + } + TRACE("dl", r.display(tout << "result:\n");); + } + }; + + relation_union_fn * karr_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { + return 0; + } + return alloc(union_fn, *this); + } + + class karr_relation_plugin::filter_identical_fn : public relation_mutator_fn { + unsigned_vector m_identical_cols; + public: + filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) + : m_identical_cols(col_cnt, identical_cols) {} + + virtual void operator()(relation_base & _r) { + karr_relation & r = get(_r); + TRACE("dl", r.display(tout << "src:\n");); + r.get_ineqs(); + for (unsigned i = 1; i < m_identical_cols.size(); ++i) { + unsigned c1 = m_identical_cols[0]; + unsigned c2 = m_identical_cols[i]; + vector row; + row.resize(r.get_signature().size()); + row[c1] = rational(1); + row[c2] = rational(-1); + r.m_ineqs.A.push_back(row); + r.m_ineqs.b.push_back(rational(0)); + r.m_ineqs.eq.push_back(true); + r.m_basis_valid = false; + } + TRACE("dl", r.display(tout << "result:\n");); + } + }; + + relation_mutator_fn * karr_relation_plugin::mk_filter_identical_fn( + const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { + if(!check_kind(t)) { + return 0; + } + return alloc(filter_identical_fn, col_cnt, identical_cols); + } + + + class karr_relation_plugin::filter_equal_fn : public relation_mutator_fn { + unsigned m_col; + rational m_value; + 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)); + } + + virtual void operator()(relation_base & _r) { + karr_relation & r = get(_r); + karr_relation_plugin & p = r.get_plugin(); + if (m_value.is_int()) { + r.get_ineqs(); + vector row; + row.resize(r.get_signature().size()); + row[m_col] = rational(1); + r.m_ineqs.A.push_back(row); + r.m_ineqs.b.push_back(rational(-1)); + r.m_ineqs.eq.push_back(true); + r.m_basis_valid = false; + } + TRACE("dl", tout << m_value << "\n"; r.display(tout);); + } + }; + + relation_mutator_fn * karr_relation_plugin::mk_filter_equal_fn(const relation_base & r, + const relation_element & value, unsigned col) { + if(check_kind(r)) { + return alloc(filter_equal_fn, get_manager(), value, col); + } + return 0; + } + + + class karr_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { + app_ref m_cond; + public: + filter_interpreted_fn(karr_relation const& t, app* cond): + m_cond(cond, t.get_plugin().get_ast_manager()) { + } + + void operator()(relation_base& t) { + get(t).filter_interpreted(m_cond); + TRACE("dl", tout << mk_pp(m_cond, m_cond.get_manager()) << "\n"; t.display(tout);); + } + }; + + relation_mutator_fn * karr_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { + if (check_kind(t)) { + return alloc(filter_interpreted_fn, get(t), condition); + } + return 0; + } + }; diff --git a/src/muz_qe/dl_mk_karr_invariants.h b/src/muz_qe/dl_mk_karr_invariants.h index 9d611e365..414953e4f 100644 --- a/src/muz_qe/dl_mk_karr_invariants.h +++ b/src/muz_qe/dl_mk_karr_invariants.h @@ -30,41 +30,32 @@ namespace datalog { /** \brief Rule transformer that strengthens bodies with invariants. */ + + struct matrix { + vector > A; + vector b; + svector eq; + unsigned size() const { return A.size(); } + void reset() { A.reset(); b.reset(); eq.reset(); } + matrix& operator=(matrix const& other); + void append(matrix const& other) { A.append(other.A); b.append(other.b); eq.append(other.eq); } + void display(std::ostream& out) const; + static void display_row( + std::ostream& out, vector const& row, rational const& b, bool is_eq); + static void display_ineq( + std::ostream& out, vector const& row, rational const& b, bool is_eq); + }; + class mk_karr_invariants : public rule_transformer::plugin { - struct matrix { - vector > A; - vector b; - svector eq; - unsigned size() const { return A.size(); } - void reset() { A.reset(); b.reset(); eq.reset(); } - matrix& operator=(matrix const& other); - void append(matrix const& other) { A.append(other.A); b.append(other.b); eq.append(other.eq); } - void display(std::ostream& out) const; - static void display_row( - std::ostream& out, vector const& row, rational const& b, bool is_eq); - static void display_ineq( - std::ostream& out, vector const& row, rational const& b, bool is_eq); - }; class add_invariant_model_converter; - + context& m_ctx; ast_manager& m; rule_manager& rm; + context m_inner_ctx; arith_util a; - obj_map m_constraints; - obj_map m_dual_constraints; - hilbert_basis m_hb; - - bool is_linear(expr* e, vector& row, rational& b, rational const& mul); - bool is_eq(expr* e, var*& v, rational& n); - bool get_transition_relation(rule const& r, matrix& M); - void intersect_matrix(app* p, matrix const& Mp, unsigned num_columns, matrix& M); - matrix* get_constraints(func_decl* p); - matrix& get_dual_constraints(func_decl* p); - void dualizeH(matrix& dst, matrix const& src); - void dualizeI(matrix& dst, matrix const& src); - void update_body(rule_set& rules, rule& r); + void update_body(rel_context& rctx, rule_set& result, rule& r); public: mk_karr_invariants(context & ctx, unsigned priority); @@ -77,6 +68,68 @@ namespace datalog { }; + class karr_relation; + + class karr_relation_plugin : public relation_plugin { + arith_util a; + hilbert_basis m_hb; + + class join_fn; + class project_fn; + class rename_fn; + class union_fn; + class filter_equal_fn; + class filter_identical_fn; + class filter_interpreted_fn; + friend class karr_relation; + public: + karr_relation_plugin(relation_manager& rm): + relation_plugin(karr_relation_plugin::get_name(), rm), + a(get_ast_manager()) + {} + + 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; + } + + static symbol get_name() { return symbol("karr_relation"); } + + virtual void set_cancel(bool f); + + virtual relation_base * mk_empty(const relation_signature & s); + + virtual relation_base * mk_full(func_decl* p, const relation_signature & s); + + static karr_relation& get(relation_base& r); + static karr_relation const & get(relation_base const& r); + + virtual relation_join_fn * mk_join_fn( + const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols); + 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); + private: + bool dualizeI(matrix& dst, matrix const& src); + void dualizeH(matrix& dst, matrix const& src); + + + }; + + }; #endif /* _DL_MK_KARR_INVARIANTS_H_ */ diff --git a/src/muz_qe/dl_relation_manager.cpp b/src/muz_qe/dl_relation_manager.cpp index 3407f8fbe..e001dd1a4 100644 --- a/src/muz_qe/dl_relation_manager.cpp +++ b/src/muz_qe/dl_relation_manager.cpp @@ -468,6 +468,12 @@ namespace datalog { } } + void relation_manager::set_cancel(bool f) { + for (unsigned i = 0; i < m_relation_plugins.size(); ++i) { + m_relation_plugins[i]->set_cancel(f); + } + } + std::string relation_manager::to_nice_string(const relation_element & el) const { uint64 val; std::stringstream stm; diff --git a/src/muz_qe/dl_relation_manager.h b/src/muz_qe/dl_relation_manager.h index ecba3d598..6b350642e 100644 --- a/src/muz_qe/dl_relation_manager.h +++ b/src/muz_qe/dl_relation_manager.h @@ -223,6 +223,7 @@ namespace datalog { relation_fact & to); + void set_cancel(bool f); // ----------------------------------- diff --git a/src/muz_qe/dl_rule_set.cpp b/src/muz_qe/dl_rule_set.cpp index caecc76ef..f9ae3620d 100644 --- a/src/muz_qe/dl_rule_set.cpp +++ b/src/muz_qe/dl_rule_set.cpp @@ -30,17 +30,17 @@ namespace datalog { rule_dependencies::rule_dependencies(const rule_dependencies & o, bool reversed): m_context(o.m_context) { - if(reversed) { + if (reversed) { iterator oit = o.begin(); iterator oend = o.end(); - for(; oit!=oend; ++oit) { + for (; oit!=oend; ++oit) { func_decl * pred = oit->m_key; item_set & orig_items = *oit->get_value(); ensure_key(pred); item_set::iterator dit = orig_items.begin(); item_set::iterator dend = orig_items.end(); - for(; dit!=dend; ++dit) { + for (; dit!=dend; ++dit) { func_decl * master_pred = *dit; insert(master_pred, pred); } @@ -49,7 +49,7 @@ namespace datalog { else { iterator oit = o.begin(); iterator oend = o.end(); - for(; oit!=oend; ++oit) { + for (; oit!=oend; ++oit) { func_decl * pred = oit->m_key; item_set & orig_items = *oit->get_value(); m_data.insert(pred, alloc(item_set, orig_items)); @@ -73,7 +73,7 @@ namespace datalog { rule_dependencies::item_set & rule_dependencies::ensure_key(func_decl * pred) { deps_type::obj_map_entry * e = m_data.insert_if_not_there2(pred, 0); - if(!e->get_data().m_value) { + if (!e->get_data().m_value) { e->get_data().m_value = alloc(item_set); } return *e->get_data().m_value; @@ -101,12 +101,13 @@ namespace datalog { void rule_dependencies::populate(unsigned n, rule * const * rules) { SASSERT(m_data.empty()); - for(unsigned i=0; iget_decl()->get_name() << "\n";); m_visited.reset(); func_decl * d = r->get_head()->get_decl(); func_decl_set & s = ensure_key(d); @@ -141,7 +142,7 @@ namespace datalog { const rule_dependencies::item_set & rule_dependencies::get_deps(func_decl * f) const { deps_type::obj_map_entry * e = m_data.find_core(f); - if(!e) { + if (!e) { return m_empty_item_set; } SASSERT(e->get_data().get_value()); @@ -152,9 +153,9 @@ namespace datalog { ptr_vector to_remove; iterator pit = begin(); iterator pend = end(); - for(; pit!=pend; ++pit) { + for (; pit!=pend; ++pit) { func_decl * pred = pit->m_key; - if(!allowed.contains(pred)) { + if (!allowed.contains(pred)) { to_remove.insert(pred); continue; } @@ -163,7 +164,7 @@ namespace datalog { } ptr_vector::iterator rit = to_remove.begin(); ptr_vector::iterator rend = to_remove.end(); - for(; rit!=rend; ++rit) { + for (; rit!=rend; ++rit) { remove_m_data_entry(*rit); } } @@ -172,7 +173,7 @@ namespace datalog { remove_m_data_entry(itm); iterator pit = begin(); iterator pend = end(); - for(; pit!=pend; ++pit) { + for (; pit!=pend; ++pit) { item_set & itms = *pit->get_value(); itms.remove(itm); } @@ -181,12 +182,12 @@ namespace datalog { void rule_dependencies::remove(const item_set & to_remove) { item_set::iterator rit = to_remove.begin(); item_set::iterator rend = to_remove.end(); - for(; rit!=rend; ++rit) { + for (; rit!=rend; ++rit) { remove_m_data_entry(*rit); } iterator pit = begin(); iterator pend = end(); - for(; pit!=pend; ++pit) { + for (; pit!=pend; ++pit) { item_set * itms = pit->get_value(); set_difference(*itms, to_remove); } @@ -196,9 +197,9 @@ namespace datalog { unsigned res = 0; iterator pit = begin(); iterator pend = end(); - for(; pit!=pend; ++pit) { + for (; pit!=pend; ++pit) { item_set & itms = *pit->get_value(); - if(itms.contains(f)) { + if (itms.contains(f)) { res++; } } @@ -214,10 +215,10 @@ namespace datalog { iterator pit = begin(); iterator pend = end(); - for(; pit!=pend; ++pit) { + for (; pit!=pend; ++pit) { func_decl * pred = pit->m_key; unsigned deg = in_degree(pred); - if(deg==0) { + if (deg==0) { res.push_back(pred); } else { @@ -225,25 +226,25 @@ namespace datalog { } } - while(curr_indexget_data().m_value; SASSERT(child_deg>0); child_deg--; - if(child_deg==0) { + if (child_deg==0) { res.push_back(child); } } curr_index++; } - if(res.size()m_key; const item_set & deps = *pit->m_value; item_set::iterator dit=deps.begin(); item_set::iterator dend=deps.end(); - if(dit==dend) { + if (dit == dend) { out<get_name()<<" - \n"; } - for(; dit!=dend; ++dit) { + for (; dit != dend; ++dit) { func_decl * dep = *dit; - out<get_name()<<" -> "<get_name()<<"\n"; + out << pred->get_name() << " -> " << dep->get_name() << "\n"; } } } @@ -292,8 +293,8 @@ namespace datalog { m_deps(rs.m_context), m_stratifier(0) { add_rules(rs); - if(rs.m_stratifier) { - TRUSTME(close()); + if (rs.m_stratifier) { + VERIFY(close()); } } @@ -302,7 +303,7 @@ namespace datalog { } void rule_set::reset() { - if(m_stratifier) { + if (m_stratifier) { m_stratifier = 0; } reset_dealloc_values(m_head2rules); @@ -346,18 +347,19 @@ namespace datalog { void rule_set::ensure_closed() { - if(!is_closed()) { - TRUSTME(close()); + if (!is_closed()) { + VERIFY(close()); } } bool rule_set::close() { SASSERT(!is_closed()); //the rule_set is not already closed + m_deps.populate(*this); m_stratifier = alloc(rule_stratifier, m_deps); - if(!stratified_negation()) { + if (!stratified_negation()) { m_stratifier = 0; m_deps.reset(); return false; @@ -391,7 +393,7 @@ namespace datalog { unsigned head_strat = get_predicate_strat(head_decl); SASSERT(head_strat>=neg_strat); //head strat can never be lower than that of a tail - if(head_strat==neg_strat) { + if (head_strat == neg_strat) { return false; } } @@ -415,7 +417,7 @@ namespace datalog { const rule_vector & rule_set::get_predicate_rules(func_decl * pred) const { decl2rules::obj_map_entry * e = m_head2rules.find_core(pred); - if(!e) { + if (!e) { return m_empty_rule_vector; } return *e->get_data().m_value; @@ -443,7 +445,7 @@ namespace datalog { ptr_vector::iterator end2 = rules->end(); for (; it2 != end2; ++it2) { rule * r = *it2; - if(!r->passes_output_thresholds(m_context)) { + if (!r->passes_output_thresholds(m_context)) { continue; } r->display(m_context, out); @@ -468,23 +470,23 @@ namespace datalog { const pred_set_vector & strats = get_strats(); pred_set_vector::const_iterator sit = strats.begin(); pred_set_vector::const_iterator send = strats.end(); - for(; sit!=send; ++sit) { + for (; sit!=send; ++sit) { func_decl_set & strat = **sit; func_decl_set::iterator fit=strat.begin(); func_decl_set::iterator fend=strat.end(); bool non_empty = false; - for(; fit!=fend; ++fit) { + for (; fit!=fend; ++fit) { func_decl * first = *fit; const func_decl_set & deps = m_deps.get_deps(first); func_decl_set::iterator dit=deps.begin(); func_decl_set::iterator dend=deps.end(); - for(; dit!=dend; ++dit) { + for (; dit!=dend; ++dit) { non_empty = true; func_decl * dep = *dit; out<get_name()<<" -> "<get_name()<<"\n"; } } - if(non_empty && sit!=send) { + if (non_empty && sit!=send) { out << "\n"; } } @@ -499,7 +501,7 @@ namespace datalog { rule_stratifier::~rule_stratifier() { comp_vector::iterator it = m_strats.begin(); comp_vector::iterator end = m_strats.end(); - for(; it!=end; ++it) { + for (; it!=end; ++it) { SASSERT(*it); dealloc(*it); } @@ -507,7 +509,7 @@ namespace datalog { unsigned rule_stratifier::get_predicate_strat(func_decl * pred) const { unsigned num; - if(!m_pred_strat_nums.find(pred, num)) { + if (!m_pred_strat_nums.find(pred, num)) { //the number of the predicate is not stored, therefore it did not appear //in the algorithm and therefore it does not depend on anything and nothing //depends on it. So it is safe to assign zero strate to it, although it is @@ -520,19 +522,19 @@ namespace datalog { void rule_stratifier::traverse(T* el) { unsigned p_num; - if(m_preorder_nums.find(el, p_num)) { - if(p_numinsert(s_el); m_component_nums.insert(s_el, comp_num); - } while(s_el!=el); + } while (s_el!=el); m_stack_P.pop_back(); } } } void rule_stratifier::process() { - if(m_deps.empty()) { + if (m_deps.empty()) { return; } //detect strong components rule_dependencies::iterator it = m_deps.begin(); rule_dependencies::iterator end = m_deps.end(); - for(; it!=end; ++it) { + for (; it!=end; ++it) { T * el = it->m_key; //we take a note of the preorder number with which this sweep started m_first_preorder = m_next_preorder; @@ -593,32 +595,32 @@ namespace datalog { //init in_degrees it = m_deps.begin(); end = m_deps.end(); - for(; it!=end; ++it) { + for (; it != end; ++it) { T * el = it->m_key; item_set * out_edges = it->m_value; unsigned el_comp; - TRUSTME( m_component_nums.find(el, el_comp) ); + VERIFY( m_component_nums.find(el, el_comp) ); - item_set::iterator eit=out_edges->begin(); - item_set::iterator eend=out_edges->end(); - for(; eit!=eend; ++eit) { + item_set::iterator eit = out_edges->begin(); + item_set::iterator eend = out_edges->end(); + for (; eit!=eend; ++eit) { T * tgt = *eit; unsigned tgt_comp = m_component_nums.find(tgt); - if(el_comp!=tgt_comp) { + if (el_comp != tgt_comp) { in_degrees[tgt_comp]++; } } } - //We put components whose indegree is zero to m_strats and assign its - //m_components entry to zero. + // We put components whose indegree is zero to m_strats and assign its + // m_components entry to zero. unsigned comp_cnt = m_components.size(); - for(unsigned i=0; ibegin(); item_set::iterator cend=comp->end(); - for(; cit!=cend; ++cit) { + for (; cit!=cend; ++cit) { T * el = *cit; const item_set & deps = m_deps.get_deps(el); item_set::iterator eit=deps.begin(); item_set::iterator eend=deps.end(); - for(; eit!=eend; ++eit) { + for (; eit!=eend; ++eit) { T * tgt = *eit; unsigned tgt_comp; - TRUSTME( m_component_nums.find(tgt, tgt_comp) ); + VERIFY( m_component_nums.find(tgt, tgt_comp) ); //m_components[tgt_comp]==0 means the edge is intra-component. //Otherwise it would go to another component, but it is not possible, since //as m_components[tgt_comp]==0, its indegree has already reached zero. - if(m_components[tgt_comp]) { + if (m_components[tgt_comp]) { SASSERT(in_degrees[tgt_comp]>0); in_degrees[tgt_comp]--; - if(in_degrees[tgt_comp]==0) { + if (in_degrees[tgt_comp]==0) { m_strats.push_back(m_components[tgt_comp]); m_components[tgt_comp] = 0; } } - - traverse(*cit); } } @@ -669,13 +669,12 @@ namespace datalog { SASSERT(m_pred_strat_nums.empty()); unsigned strat_cnt = m_strats.size(); - for(unsigned strat_index=0; strat_indexbegin(); item_set::iterator cend=comp->end(); - for(; cit!=cend; ++cit) { + for (; cit != cend; ++cit) { T * el = *cit; - m_pred_strat_nums.insert(el, strat_index); } } @@ -686,6 +685,21 @@ namespace datalog { m_stack_P.finalize(); m_component_nums.finalize(); m_components.finalize(); + + } + + void rule_stratifier::display(std::ostream& out) const { + m_deps.display(out << "dependencies\n"); + out << "strata\n"; + for (unsigned i = 0; i < m_strats.size(); ++i) { + item_set::iterator it = m_strats[i]->begin(); + item_set::iterator end = m_strats[i]->end(); + for (; it != end; ++it) { + out << (*it)->get_name() << " "; + } + out << "\n"; + } + } }; diff --git a/src/muz_qe/dl_rule_set.h b/src/muz_qe/dl_rule_set.h index 3079c6072..9aa64425c 100644 --- a/src/muz_qe/dl_rule_set.h +++ b/src/muz_qe/dl_rule_set.h @@ -146,6 +146,8 @@ namespace datalog { const comp_vector & get_strats() const { return m_strats; } unsigned get_predicate_strat(func_decl * pred) const; + + void display( std::ostream & out ) const; }; /** diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index 7b3e67487..62f091dbc 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -744,7 +744,6 @@ void hilbert_basis::reset() { if (m_passive2) { m_passive2->reset(); } - m_cancel = false; if (m_index) { m_index->reset(1); } @@ -867,7 +866,7 @@ lbool hilbert_basis::saturate() { stopwatch sw; sw.start(); lbool r = saturate(m_ineqs[m_current_ineq], m_iseq[m_current_ineq]); - IF_VERBOSE(1, + IF_VERBOSE(3, { statistics st; collect_statistics(st); st.display(verbose_stream()); diff --git a/src/muz_qe/hilbert_basis.h b/src/muz_qe/hilbert_basis.h index abb59be2d..733b3a2f0 100644 --- a/src/muz_qe/hilbert_basis.h +++ b/src/muz_qe/hilbert_basis.h @@ -37,10 +37,13 @@ typedef vector rational_vector; class hilbert_basis { - static const bool check = false; + static const bool check = true; typedef checked_int64 numeral; typedef vector num_vector; static checked_int64 to_numeral(rational const& r) { + if (!r.is_int64()) { + throw checked_int64::overflow_exception(); + } return checked_int64(r.get_int64()); } static rational to_rational(checked_int64 const& i) { diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index c79acf67f..12045047b 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -27,6 +27,7 @@ Revision History: #include"dl_product_relation.h" #include"dl_bound_relation.h" #include"dl_interval_relation.h" +#include"dl_mk_karr_invariants.h" #include"dl_finite_product_relation.h" #include"dl_sparse_table.h" #include"dl_table.h" @@ -54,6 +55,8 @@ namespace datalog { get_rmanager().register_plugin(alloc(bound_relation_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(interval_relation_plugin, get_rmanager())); + get_rmanager().register_plugin(alloc(karr_relation_plugin, get_rmanager())); + } @@ -178,23 +181,23 @@ namespace datalog { return result; } -#define BEGIN_QUERY() \ +#define BEGIN_QUERY() \ rule_set original_rules(m_context.get_rules()); \ - decl_set original_preds; \ - m_context.collect_predicates(original_preds); \ - bool was_closed = m_context.is_closed(); \ - if (was_closed) { \ + decl_set original_preds; \ + m_context.collect_predicates(original_preds); \ + bool was_closed = m_context.is_closed(); \ + if (was_closed) { \ m_context.reopen(); \ - } \ - -#define END_QUERY() \ + } \ + +#define END_QUERY() \ m_context.reopen(); \ m_context.replace_rules(original_rules); \ - restrict_predicates(original_preds); \ - \ - if (was_closed) { \ + restrict_predicates(original_preds); \ + \ + if (was_closed) { \ m_context.close(); \ - } \ + } \ lbool rel_context::query(unsigned num_rels, func_decl * const* rels) { get_rmanager().reset_saturated_marks(); @@ -427,6 +430,10 @@ namespace datalog { get_rmanager().set_predicate_kind(pred, target_kind); } + void rel_context::set_cancel(bool f) { + get_rmanager().set_cancel(f); + } + relation_plugin & rel_context::get_ordinary_relation_plugin(symbol relation_name) { relation_plugin * plugin = get_rmanager().get_relation_plugin(relation_name); if (!plugin) { diff --git a/src/muz_qe/rel_context.h b/src/muz_qe/rel_context.h index 2e2b5cd9d..08ee868c0 100644 --- a/src/muz_qe/rel_context.h +++ b/src/muz_qe/rel_context.h @@ -63,7 +63,6 @@ namespace datalog { bool output_profile() const; - lbool query(expr* q); lbool query(unsigned num_rels, func_decl * const* rels); @@ -72,6 +71,7 @@ namespace datalog { void inherit_predicate_kind(func_decl* new_pred, func_decl* orig_pred); + void set_cancel(bool f); /** \brief Restrict the set of used predicates to \c res. From a2207bc35cbbdb86d4d8b864eb3213b227f584d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Apr 2013 07:52:55 -0700 Subject: [PATCH 71/97] stash --- src/muz_qe/dl_mk_karr_invariants.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 77b52f2b9..458f46628 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -387,6 +387,8 @@ namespace datalog { } lbool is_sat = m_hb.saturate(); TRACE("dl_verbose", m_hb.display(tout);); + // TBD: actually transition function can be unsat. + // in this case the rule can be removed. SASSERT(is_sat == l_true); dst.reset(); unsigned basis_size = m_hb.get_basis_size(); From fbb59453c3bf1f8d1041de9f055f93061a1129b0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Apr 2013 09:10:34 -0700 Subject: [PATCH 72/97] add loop counter v1 Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_bit_blast.h | 21 +----- src/muz_qe/dl_mk_karr_invariants.cpp | 2 +- src/muz_qe/dl_mk_loop_counter.cpp | 104 +++++++++++++++++++++++++++ src/muz_qe/dl_mk_loop_counter.h | 38 ++++++++++ 4 files changed, 146 insertions(+), 19 deletions(-) create mode 100644 src/muz_qe/dl_mk_loop_counter.cpp create mode 100644 src/muz_qe/dl_mk_loop_counter.h diff --git a/src/muz_qe/dl_mk_bit_blast.h b/src/muz_qe/dl_mk_bit_blast.h index 60c83f6cb..da91c5804 100644 --- a/src/muz_qe/dl_mk_bit_blast.h +++ b/src/muz_qe/dl_mk_bit_blast.h @@ -7,7 +7,7 @@ Module Name: Abstract: - + Functor for bit-blasting a rule set Author: @@ -19,31 +19,16 @@ Revision History: #ifndef _DL_MK_BIT_BLAST_H_ #define _DL_MK_BIT_BLAST_H_ -#include - -#include"map.h" -#include"obj_pair_hashtable.h" -#include"dl_context.h" -#include"dl_rule_set.h" #include"dl_rule_transformer.h" namespace datalog { - /** - \brief Functor for bit-blasting a rule set. - */ - class mk_bit_blast : public rule_transformer::plugin { class impl; - - impl* m_impl; - void blast(expr_ref& b); - void reset(); - + impl* m_impl; public: mk_bit_blast(context & ctx, unsigned priority = 35000); - ~mk_bit_blast(); - + ~mk_bit_blast(); rule_set * operator()(rule_set const & source); }; diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 6dca35cdf..2596a7337 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -204,7 +204,7 @@ namespace datalog { m_inner_ctx.ensure_opened(); it = source.begin(); for (; it != end; ++it) { - rule_ref r(*it, m_ctx.get_rule_manager()); + rule_ref r(*it, m_inner_ctx.get_rule_manager()); m_inner_ctx.add_rule(r); m_inner_ctx.register_predicate(r->get_decl()); } diff --git a/src/muz_qe/dl_mk_loop_counter.cpp b/src/muz_qe/dl_mk_loop_counter.cpp new file mode 100644 index 000000000..8c9ad7f52 --- /dev/null +++ b/src/muz_qe/dl_mk_loop_counter.cpp @@ -0,0 +1,104 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_loop_counter.cpp + +Abstract: + + Add loop counter argument to relations. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-31 + +Revision History: + +--*/ + +#include"dl_mk_loop_counter.h" +#include"dl_context.h" + +namespace datalog { + + mk_loop_counter::mk_loop_counter(context & ctx, unsigned priority): + plugin(priority) { + } + + mk_loop_counter::~mk_loop_counter() { } + + app_ref mk_loop_counter::add_arg(ast_manager& m, app* fn, unsigned idx) { + arith_util a(m); + ptr_vector domain; + expr_ref_vector args(m); + domain.append(fn->get_num_args(), fn->get_decl()->get_domain()); + domain.push_back(a.mk_int()); + args.append(fn->get_num_args(), fn->get_args()); + args.push_back(m.mk_var(idx, a.mk_int())); + func_decl_ref new_fn(m); + new_fn = m.mk_func_decl(fn->get_decl()->get_name(), domain.size(), domain.c_ptr(), m.mk_bool_sort()); + return app_ref(m.mk_app(new_fn, args.size(), args.c_ptr()), m); + } + + rule_set * mk_loop_counter::operator()(rule_set const & source) { + context& ctx = source.get_context(); + ast_manager& m = source.get_manager(); + rule_manager& rm = source.get_rule_manager(); + arith_util a(m); + rule_set * result = alloc(rule_set, ctx); + unsigned sz = source.get_num_rules(); + rule_ref new_rule(rm); + app_ref_vector tail(m); + app_ref head(m); + svector neg; + rule_counter& vc = rm.get_counter(); + for (unsigned i = 0; i < sz; ++i) { + tail.reset(); + neg.reset(); + rule & r = *source.get_rule(i); + unsigned cnt = vc.get_max_rule_var(r)+1; + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + for (unsigned j = 0; j < utsz; ++j, ++cnt) { + tail.push_back(add_arg(m, r.get_tail(j), cnt)); + neg.push_back(r.is_neg_tail(j)); + ctx.register_predicate(tail.back()->get_decl()); + } + for (unsigned j = utsz; j < tsz; ++j) { + tail.push_back(r.get_tail(j)); + neg.push_back(false); + } + head = add_arg(m, r.get_head(), cnt); + ctx.register_predicate(head->get_decl()); + // set the loop counter to be an increment of the previous + bool found = false; + unsigned last = head->get_num_args()-1; + for (unsigned j = 0; !found && j < utsz; ++j) { + if (head->get_decl() == tail[j]->get_decl()) { + tail.push_back(m.mk_eq(head->get_arg(last), + a.mk_add(tail[j]->get_arg(last), + a.mk_numeral(rational(1), true)))); + neg.push_back(false); + found = true; + } + } + // initialize loop counter to 0 if none was found. + if (!found) { + expr_ref_vector args(m); + args.append(head->get_num_args(), head->get_args()); + args[last] = a.mk_numeral(rational(0), true); + head = m.mk_app(head->get_decl(), args.size(), args.c_ptr()); + } + + new_rule = rm.mk(head, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); + result->add_rule(new_rule); + } + + // model converter: remove references to extra argument. + // proof converter: etc. + + return result; + } + +}; diff --git a/src/muz_qe/dl_mk_loop_counter.h b/src/muz_qe/dl_mk_loop_counter.h new file mode 100644 index 000000000..ad2c837a9 --- /dev/null +++ b/src/muz_qe/dl_mk_loop_counter.h @@ -0,0 +1,38 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_loop_counter.h + +Abstract: + + Add loop counter argument to relations. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-31 + +Revision History: + +--*/ +#ifndef _DL_MK_LOOP_COUNTER_H_ +#define _DL_MK_LOOP_COUNTER_H_ + +#include"dl_rule_transformer.h" + +namespace datalog { + + class mk_loop_counter : public rule_transformer::plugin { + app_ref add_arg(ast_manager& m, app* fn, unsigned idx); + public: + mk_loop_counter(context & ctx, unsigned priority = 33000); + ~mk_loop_counter(); + + rule_set * operator()(rule_set const & source); + }; + +}; + +#endif /* _DL_MK_LOOP_COUNTER_H_ */ + From 2e0c5f5042df30adf85fada14c94607096ca1028 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Apr 2013 09:15:23 -0700 Subject: [PATCH 73/97] loop counting Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_loop_counter.cpp | 13 ++++++------- src/muz_qe/dl_mk_loop_counter.h | 5 ++++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/muz_qe/dl_mk_loop_counter.cpp b/src/muz_qe/dl_mk_loop_counter.cpp index 8c9ad7f52..1e7d0c3fa 100644 --- a/src/muz_qe/dl_mk_loop_counter.cpp +++ b/src/muz_qe/dl_mk_loop_counter.cpp @@ -23,13 +23,14 @@ Revision History: namespace datalog { mk_loop_counter::mk_loop_counter(context & ctx, unsigned priority): - plugin(priority) { + plugin(priority), + m(ctx.get_manager()), + a(m) { } mk_loop_counter::~mk_loop_counter() { } - app_ref mk_loop_counter::add_arg(ast_manager& m, app* fn, unsigned idx) { - arith_util a(m); + app_ref mk_loop_counter::add_arg(app* fn, unsigned idx) { ptr_vector domain; expr_ref_vector args(m); domain.append(fn->get_num_args(), fn->get_decl()->get_domain()); @@ -43,9 +44,7 @@ namespace datalog { rule_set * mk_loop_counter::operator()(rule_set const & source) { context& ctx = source.get_context(); - ast_manager& m = source.get_manager(); rule_manager& rm = source.get_rule_manager(); - arith_util a(m); rule_set * result = alloc(rule_set, ctx); unsigned sz = source.get_num_rules(); rule_ref new_rule(rm); @@ -61,7 +60,7 @@ namespace datalog { unsigned utsz = r.get_uninterpreted_tail_size(); unsigned tsz = r.get_tail_size(); for (unsigned j = 0; j < utsz; ++j, ++cnt) { - tail.push_back(add_arg(m, r.get_tail(j), cnt)); + tail.push_back(add_arg(r.get_tail(j), cnt)); neg.push_back(r.is_neg_tail(j)); ctx.register_predicate(tail.back()->get_decl()); } @@ -69,7 +68,7 @@ namespace datalog { tail.push_back(r.get_tail(j)); neg.push_back(false); } - head = add_arg(m, r.get_head(), cnt); + head = add_arg(r.get_head(), cnt); ctx.register_predicate(head->get_decl()); // set the loop counter to be an increment of the previous bool found = false; diff --git a/src/muz_qe/dl_mk_loop_counter.h b/src/muz_qe/dl_mk_loop_counter.h index ad2c837a9..c16159b1c 100644 --- a/src/muz_qe/dl_mk_loop_counter.h +++ b/src/muz_qe/dl_mk_loop_counter.h @@ -20,11 +20,14 @@ Revision History: #define _DL_MK_LOOP_COUNTER_H_ #include"dl_rule_transformer.h" +#include"arith_decl_plugin.h" namespace datalog { class mk_loop_counter : public rule_transformer::plugin { - app_ref add_arg(ast_manager& m, app* fn, unsigned idx); + ast_manager& m; + arith_util a; + app_ref add_arg(app* fn, unsigned idx); public: mk_loop_counter(context & ctx, unsigned priority = 33000); ~mk_loop_counter(); From 65e64d100669c3f0fde64d5b0cd154a0317a2c50 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Apr 2013 09:54:32 -0700 Subject: [PATCH 74/97] loop counting Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_loop_counter.cpp | 24 +++++++++++++++++------- src/muz_qe/dl_mk_loop_counter.h | 6 ++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/muz_qe/dl_mk_loop_counter.cpp b/src/muz_qe/dl_mk_loop_counter.cpp index 1e7d0c3fa..172198746 100644 --- a/src/muz_qe/dl_mk_loop_counter.cpp +++ b/src/muz_qe/dl_mk_loop_counter.cpp @@ -25,24 +25,34 @@ namespace datalog { mk_loop_counter::mk_loop_counter(context & ctx, unsigned priority): plugin(priority), m(ctx.get_manager()), - a(m) { + a(m), + m_refs(m) { } mk_loop_counter::~mk_loop_counter() { } app_ref mk_loop_counter::add_arg(app* fn, unsigned idx) { - ptr_vector domain; expr_ref_vector args(m); - domain.append(fn->get_num_args(), fn->get_decl()->get_domain()); - domain.push_back(a.mk_int()); + func_decl* new_fn, *old_fn = fn->get_decl(); args.append(fn->get_num_args(), fn->get_args()); args.push_back(m.mk_var(idx, a.mk_int())); - func_decl_ref new_fn(m); - new_fn = m.mk_func_decl(fn->get_decl()->get_name(), domain.size(), domain.c_ptr(), m.mk_bool_sort()); + + if (!m_old2new.find(old_fn, new_fn)) { + ptr_vector domain; + domain.append(fn->get_num_args(), old_fn->get_domain()); + domain.push_back(a.mk_int()); + new_fn = m.mk_func_decl(old_fn->get_name(), domain.size(), domain.c_ptr(), old_fn->get_range()); + m_old2new.insert(old_fn, new_fn); + m_new2old.insert(new_fn, old_fn); + m_refs.push_back(new_fn); + } return app_ref(m.mk_app(new_fn, args.size(), args.c_ptr()), m); } rule_set * mk_loop_counter::operator()(rule_set const & source) { + m_refs.reset(); + m_old2new.reset(); + m_new2old.reset(); context& ctx = source.get_context(); rule_manager& rm = source.get_rule_manager(); rule_set * result = alloc(rule_set, ctx); @@ -95,7 +105,7 @@ namespace datalog { } // model converter: remove references to extra argument. - // proof converter: etc. + // proof converter: remove references to extra argument as well. return result; } diff --git a/src/muz_qe/dl_mk_loop_counter.h b/src/muz_qe/dl_mk_loop_counter.h index c16159b1c..6601f837f 100644 --- a/src/muz_qe/dl_mk_loop_counter.h +++ b/src/muz_qe/dl_mk_loop_counter.h @@ -27,12 +27,18 @@ namespace datalog { class mk_loop_counter : public rule_transformer::plugin { ast_manager& m; arith_util a; + func_decl_ref_vector m_refs; + obj_map m_new2old; + obj_map m_old2new; + app_ref add_arg(app* fn, unsigned idx); public: mk_loop_counter(context & ctx, unsigned priority = 33000); ~mk_loop_counter(); rule_set * operator()(rule_set const & source); + + func_decl* get_old(func_decl* f) const { return m_new2old.find(f); } }; }; From 4c353ec7204a6a16f9b87eb1bbae694db40076cb Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 2 Apr 2013 13:45:42 +0100 Subject: [PATCH 75/97] FPA: bugfix for model completion. Thanks to Levent Erkok. Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 9 +++++++++ src/ast/float_decl_plugin.h | 1 + src/tactic/fpa/fpa2bv_converter.cpp | 19 ++++++++++++------- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 62ec3a4cf..26131bc28 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -491,6 +491,15 @@ void float_decl_plugin::get_sort_names(svector & sort_names, symbo sort_names.push_back(builtin_name("RoundingMode", ROUNDING_MODE_SORT)); } +expr * float_decl_plugin::get_some_value(sort * s) { + SASSERT(s->is_sort_of(m_family_id, FLOAT_SORT)); + mpf tmp; + m_fm.mk_nan(s->get_parameter(0).get_int(), s->get_parameter(1).get_int(), tmp); + expr * res = this->mk_value(tmp); + m_fm.del(tmp); + return res; +} + bool float_decl_plugin::is_value(app * e) const { if (e->get_family_id() != m_family_id) return false; diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index 6f1ef5ec2..4ec17addf 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -140,6 +140,7 @@ public: unsigned arity, sort * const * domain, sort * range); virtual void get_op_names(svector & op_names, symbol const & logic); virtual void get_sort_names(svector & sort_names, symbol const & logic); + virtual expr * get_some_value(sort * s); virtual bool is_value(app* e) const; virtual bool is_unique_value(app* e) const { return is_value(e); } diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 79f86ac46..838090045 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1263,6 +1263,9 @@ void fpa2bv_converter::mk_float_eq(func_decl * f, unsigned num, expr * const * a expr * x = args[0], * y = args[1]; + TRACE("fpa2bv_float_eq", tout << "X = " << mk_ismt2_pp(x, m) << std::endl; + tout << "Y = " << mk_ismt2_pp(y, m) << std::endl;); + expr_ref c1(m), c2(m), x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m); mk_is_nan(x, x_is_nan); mk_is_nan(y, y_is_nan); @@ -1290,6 +1293,8 @@ void fpa2bv_converter::mk_float_eq(func_decl * f, unsigned num, expr * const * a m_simp.mk_ite(c2, m.mk_true(), c3t4, c2else); m_simp.mk_ite(c1, m.mk_false(), c2else, result); + + TRACE("fpa2bv_float_eq", tout << "FLOAT_EQ = " << mk_ismt2_pp(result, m) << std::endl; ); } void fpa2bv_converter::mk_float_lt(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -2314,9 +2319,10 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { unsigned ebits = fu.get_ebits(var->get_range()); unsigned sbits = fu.get_sbits(var->get_range()); - expr * sgn = bv_mdl->get_const_interp(to_app(a->get_arg(0))->get_decl()); - expr * sig = bv_mdl->get_const_interp(to_app(a->get_arg(1))->get_decl()); - expr * exp = bv_mdl->get_const_interp(to_app(a->get_arg(2))->get_decl()); + expr_ref sgn(m), sig(m), exp(m); + sgn = bv_mdl->get_const_interp(to_app(a->get_arg(0))->get_decl()); + sig = bv_mdl->get_const_interp(to_app(a->get_arg(1))->get_decl()); + exp = bv_mdl->get_const_interp(to_app(a->get_arg(2))->get_decl()); seen.insert(to_app(a->get_arg(0))->get_decl()); seen.insert(to_app(a->get_arg(1))->get_decl()); @@ -2385,12 +2391,11 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { for (unsigned i = 0; i < sz; i++) { func_decl * c = bv_mdl->get_constant(i); - if (seen.contains(c)) - continue; - float_mdl->register_decl(c, bv_mdl->get_const_interp(c)); + if (!seen.contains(c)) + float_mdl->register_decl(c, bv_mdl->get_const_interp(c)); } -// And keep everything else + // And keep everything else sz = bv_mdl->get_num_functions(); for (unsigned i = 0; i < sz; i++) { From 3d486c4c98b2a6d07ca397f4fd2d2d5257d19e95 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Apr 2013 15:28:45 -0700 Subject: [PATCH 76/97] add abstraction and instantiation Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/expr_safe_replace.cpp | 6 + src/ast/rewriter/expr_safe_replace.h | 2 + src/muz_qe/dl_context.cpp | 4 + src/muz_qe/dl_mk_quantifier_abstraction.cpp | 206 ++++++++++++ src/muz_qe/dl_mk_quantifier_abstraction.h | 61 ++++ src/muz_qe/dl_mk_quantifier_instantiation.cpp | 295 ++++++++++++++++++ src/muz_qe/dl_mk_quantifier_instantiation.h | 120 +++++++ src/muz_qe/fixedpoint_params.pyg | 2 + 8 files changed, 696 insertions(+) create mode 100644 src/muz_qe/dl_mk_quantifier_abstraction.cpp create mode 100644 src/muz_qe/dl_mk_quantifier_abstraction.h create mode 100644 src/muz_qe/dl_mk_quantifier_instantiation.cpp create mode 100644 src/muz_qe/dl_mk_quantifier_instantiation.h diff --git a/src/ast/rewriter/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp index b3b4d5138..1ec810414 100644 --- a/src/ast/rewriter/expr_safe_replace.cpp +++ b/src/ast/rewriter/expr_safe_replace.cpp @@ -100,3 +100,9 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) { } res = cache.find(e); } + +void expr_safe_replace::reset() { + m_src.reset(); + m_dst.reset(); + m_subst.reset(); +} diff --git a/src/ast/rewriter/expr_safe_replace.h b/src/ast/rewriter/expr_safe_replace.h index 6af819596..b6131906a 100644 --- a/src/ast/rewriter/expr_safe_replace.h +++ b/src/ast/rewriter/expr_safe_replace.h @@ -38,6 +38,8 @@ public: void operator()(expr_ref& e) { (*this)(e.get(), e); } void operator()(expr* src, expr_ref& e); + + void reset(); }; #endif /* __EXPR_SAFE_REPLACE_H__ */ diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index c667c7775..9207fbe61 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -46,6 +46,7 @@ Revision History: #include"dl_mk_bit_blast.h" #include"dl_mk_array_blast.h" #include"dl_mk_karr_invariants.h" +#include"dl_mk_quantifier_abstraction.h" #include"datatype_decl_plugin.h" #include"expr_abstract.h" @@ -905,6 +906,9 @@ namespace datalog { m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34890)); m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880)); + + m_transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, *this, 33000)); + m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 36010)); diff --git a/src/muz_qe/dl_mk_quantifier_abstraction.cpp b/src/muz_qe/dl_mk_quantifier_abstraction.cpp new file mode 100644 index 000000000..511ab7b9a --- /dev/null +++ b/src/muz_qe/dl_mk_quantifier_abstraction.cpp @@ -0,0 +1,206 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_quantifier_abstraction.cpp + +Abstract: + + Create quantified Horn clauses from benchmarks with arrays. + +Author: + + Ken McMillan + Andrey Rybalchenko + Nikolaj Bjorner (nbjorner) 2013-04-02 + +Revision History: + +--*/ + +#include "dl_mk_quantifier_abstraction.h" +#include "dl_context.h" + +namespace datalog { + + mk_quantifier_abstraction::mk_quantifier_abstraction( + context & ctx, unsigned priority): + plugin(priority), + m(ctx.get_manager()), + m_ctx(ctx), + a(m), + m_refs(m) { + } + + mk_quantifier_abstraction::~mk_quantifier_abstraction() { + + } + + func_decl* mk_quantifier_abstraction::declare_pred(func_decl* old_p) { + + unsigned sz = old_p->get_arity(); + unsigned num_arrays = 0; + for (unsigned i = 0; i < sz; ++i) { + if (a.is_array(old_p->get_domain(i))) { + num_arrays++; + } + } + if (num_arrays == 0) { + return 0; + } + + func_decl* new_p = 0; + if (!m_old2new.find(old_p, new_p)) { + sort_ref_vector domain(m); + for (unsigned i = 0; i < sz; ++i) { + sort* s = old_p->get_domain(i); + while (a.is_array(s)) { + unsigned arity = get_array_arity(s); + for (unsigned j = 0; j < arity; ++j) { + domain.push_back(get_array_domain(s, j)); + } + s = get_array_range(s); + } + domain.push_back(s); + } + SASSERT(old_p->get_range() == m.mk_bool_sort()); + new_p = m.mk_func_decl(old_p->get_name(), domain.size(), domain.c_ptr(), old_p->get_range()); + m_refs.push_back(new_p); + m_ctx.register_predicate(new_p); + } + return new_p; + } + + app_ref mk_quantifier_abstraction::mk_head(app* p, unsigned idx) { + func_decl* new_p = declare_pred(p->get_decl()); + if (!new_p) { + return app_ref(p, m); + } + expr_ref_vector args(m); + expr_ref arg(m); + unsigned sz = p->get_num_args(); + for (unsigned i = 0; i < sz; ++i) { + arg = p->get_arg(i); + sort* s = m.get_sort(arg); + while (a.is_array(s)) { + unsigned arity = get_array_arity(s); + for (unsigned j = 0; j < arity; ++j) { + args.push_back(m.mk_var(idx++, get_array_domain(s, j))); + } + ptr_vector args2; + args2.push_back(arg); + args2.append(arity, args.c_ptr()-arity); + arg = a.mk_select(args2.size(), args2.c_ptr()); + s = get_array_range(s); + } + args.push_back(arg); + } + return app_ref(m.mk_app(new_p, args.size(), args.c_ptr()), m); + } + + app_ref mk_quantifier_abstraction::mk_tail(app* p) { + func_decl* old_p = p->get_decl(); + func_decl* new_p = declare_pred(old_p); + if (!new_p) { + return app_ref(p, m); + } + SASSERT(new_p->get_arity() > old_p->get_arity()); + unsigned num_extra_args = new_p->get_arity() - old_p->get_arity(); + var_shifter shift(m); + expr_ref p_shifted(m); + shift(p, num_extra_args, p_shifted); + app* ps = to_app(p_shifted); + expr_ref_vector args(m); + app_ref_vector pats(m); + sort_ref_vector vars(m); + svector names; + expr_ref arg(m); + unsigned idx = 0; + unsigned sz = p->get_num_args(); + for (unsigned i = 0; i < sz; ++i) { + arg = ps->get_arg(i); + sort* s = m.get_sort(arg); + bool is_pattern = false; + while (a.is_array(s)) { + is_pattern = true; + unsigned arity = get_array_arity(s); + for (unsigned j = 0; j < arity; ++j) { + vars.push_back(get_array_domain(s, j)); + names.push_back(symbol(idx)); + args.push_back(m.mk_var(idx++, vars.back())); + } + ptr_vector args2; + args2.push_back(arg); + args2.append(arity, args.c_ptr()-arity); + arg = a.mk_select(args2.size(), args2.c_ptr()); + s = get_array_range(s); + } + if (is_pattern) { + pats.push_back(to_app(arg)); + } + args.push_back(arg); + } + expr* pat = 0; + expr_ref pattern(m); + pattern = m.mk_pattern(pats.size(), pats.c_ptr()); + pat = pattern.get(); + app_ref result(m); + symbol qid, skid; + result = m.mk_app(new_p, args.size(), args.c_ptr()); + result = m.mk_eq(m.mk_forall(vars.size(), vars.c_ptr(), names.c_ptr(), result, 1, qid, skid, 1, &pat), m.mk_true()); + return result; + } + + rule_set * mk_quantifier_abstraction::operator()(rule_set const & source) { + if (!m_ctx.get_params().quantify_arrays()) { + return 0; + } + m_refs.reset(); + m_old2new.reset(); + m_new2old.reset(); + rule_manager& rm = source.get_rule_manager(); + rule_set * result = alloc(rule_set, m_ctx); + unsigned sz = source.get_num_rules(); + rule_ref new_rule(rm); + app_ref_vector tail(m); + app_ref head(m); + svector neg; + rule_counter& vc = rm.get_counter(); + + for (unsigned i = 0; i < sz; ++i) { + tail.reset(); + neg.reset(); + rule & r = *source.get_rule(i); + unsigned cnt = vc.get_max_rule_var(r)+1; + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + for (unsigned j = 0; j < utsz; ++j) { + tail.push_back(mk_tail(r.get_tail(j))); + neg.push_back(r.is_neg_tail(j)); + } + for (unsigned j = utsz; j < tsz; ++j) { + tail.push_back(r.get_tail(j)); + neg.push_back(false); + } + head = mk_head(r.get_head(), cnt); + + new_rule = rm.mk(head, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); + result->add_rule(new_rule); + + } + + // model converter: TBD. + // proof converter: TBD. + + if (m_old2new.empty()) { + dealloc(result); + result = 0; + } + return result; + } + + +}; + + diff --git a/src/muz_qe/dl_mk_quantifier_abstraction.h b/src/muz_qe/dl_mk_quantifier_abstraction.h new file mode 100644 index 000000000..8c26e277a --- /dev/null +++ b/src/muz_qe/dl_mk_quantifier_abstraction.h @@ -0,0 +1,61 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_quantifier_abstraction.h + +Abstract: + + Convert clauses with array arguments to predicates + into Quantified Horn clauses. + +Author: + + Ken McMillan + Andrey Rybalchenko + Nikolaj Bjorner (nbjorner) 2013-04-02 + +Revision History: + + Based on approach suggested in SAS 2013 paper + "On Solving Universally Quantified Horn Clauses" + +--*/ +#ifndef _DL_MK_QUANTIFIER_ABSTRACTION_H_ +#define _DL_MK_QUANTIFIER_ABSTRACTION_H_ + + +#include"dl_rule_transformer.h" +#include"array_decl_plugin.h" + +namespace datalog { + + class context; + + class mk_quantifier_abstraction : public rule_transformer::plugin { + ast_manager& m; + context& m_ctx; + array_util a; + func_decl_ref_vector m_refs; + obj_map m_new2old; + obj_map m_old2new; + + func_decl* declare_pred(func_decl* old_p); + app_ref mk_head(app* p, unsigned idx); + app_ref mk_tail(app* p); + + public: + mk_quantifier_abstraction(context & ctx, unsigned priority); + + virtual ~mk_quantifier_abstraction(); + + rule_set * operator()(rule_set const & source); + }; + + + +}; + +#endif /* _DL_MK_QUANTIFIER_ABSTRACTION_H_ */ + diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.cpp b/src/muz_qe/dl_mk_quantifier_instantiation.cpp new file mode 100644 index 000000000..a5b80af4f --- /dev/null +++ b/src/muz_qe/dl_mk_quantifier_instantiation.cpp @@ -0,0 +1,295 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_quantifier_instantiation.cpp + +Abstract: + + Convert Quantified Horn clauses into non-quantified clauses using + instantiation. + +Author: + + Ken McMillan + Andrey Rybalchenko + Nikolaj Bjorner (nbjorner) 2013-04-02 + +Revision History: + + Based on approach suggested in SAS 2013 paper + "On Solving Universally Quantified Horn Clauses" + +--*/ + +#include "dl_mk_quantifier_instantiation.h" +#include "dl_context.h" + +namespace datalog { + + mk_quantifier_instantiation::mk_quantifier_instantiation( + context & ctx, unsigned priority): + plugin(priority), + m(ctx.get_manager()), + m_ctx(ctx), + m_var2cnst(m), + m_cnst2var(m), + a(m) { + } + + mk_quantifier_instantiation::~mk_quantifier_instantiation() { + + } + + void mk_quantifier_instantiation::extract_quantifiers(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs) { + conjs.reset(); + qs.reset(); + unsigned tsz = r.get_tail_size(); + for (unsigned j = 0; j < tsz; ++j) { + conjs.push_back(r.get_tail(j)); + + } + datalog::flatten_and(conjs); + for (unsigned j = 0; j < conjs.size(); ++j) { + expr* e = conjs[j].get(); + quantifier* q; + if (rule_manager::is_forall(m, e, q)) { + qs.push_back(q); + conjs[j] = conjs.back(); + conjs.pop_back(); + --j; + } + } + } + + void mk_quantifier_instantiation::instantiate_quantifier(quantifier* q, expr_ref_vector & conjs) { + expr_ref qe(m); + qe = q; + m_var2cnst(qe); + q = to_quantifier(qe); + unsigned num_patterns = q->get_num_patterns(); + for (unsigned i = 0; i < num_patterns; ++i) { + expr * pat = q->get_pattern(i); + SASSERT(m.is_pattern(pat)); + instantiate_quantifier(q, to_app(pat), conjs); + } + } + + + void mk_quantifier_instantiation::instantiate_quantifier(quantifier* q, app* pat, expr_ref_vector & conjs) { + unsigned sz = pat->get_num_args(); + m_binding.reset(); + m_binding.resize(q->get_num_decls()); + term_pairs todo; + match(0, pat, 0, todo, q, conjs); + } + + void mk_quantifier_instantiation::match(unsigned i, app* pat, unsigned j, term_pairs& todo, quantifier* q, expr_ref_vector& conjs) { + while (j < todo.size()) { + expr* p = todo[j].first; + expr* t = todo[j].second; + if (is_var(p)) { + unsigned idx = to_var(p)->get_idx(); + expr* t2 = m_binding[idx]; + if (!t2) { + m_binding[idx] = t; + match(i, pat, j + 1, todo, q, conjs); + m_binding[idx] = 0; + return; + } + else if (m_uf.find(t2->get_id()) != m_uf.find(t->get_id())) { + // matching failed. + return; + } + j += 1; + continue; + } + if (!is_app(p)) { + return; + } + app* a1 = to_app(p); + unsigned id = t->get_id(); + unsigned next_id = id; + unsigned sz = todo.size(); + do { + expr* t2 = m_terms[next_id]; + if (is_app(t2)) { + app* a2 = to_app(t2); + if (a1->get_decl() == a2->get_decl() && + a1->get_num_args() == a2->get_num_args()) { + for (unsigned k = 0; k < a1->get_num_args(); ++k) { + todo.push_back(std::make_pair(a1->get_arg(k), a2->get_arg(k))); + } + match(i, pat, j + 1, todo, q, conjs); + todo.resize(sz); + } + } + next_id = m_uf.next(id); + } + while (next_id != id); + return; + } + + if (i == pat->get_num_args()) { + yield_binding(q, conjs); + return; + } + expr* arg = pat->get_arg(i); + ptr_vector* terms = 0; + + if (m_funs.find(to_app(arg)->get_decl(), terms)) { + for (unsigned k = 0; k < terms->size(); ++k) { + todo.push_back(std::make_pair(arg, (*terms)[k])); + match(i + 1, pat, j, todo, q, conjs); + todo.pop_back(); + } + } + } + + void mk_quantifier_instantiation::yield_binding(quantifier* q, expr_ref_vector& conjs) { + DEBUG_CODE( + for (unsigned i = 0; i < m_binding.size(); ++i) { + SASSERT(m_binding[i]); + }); + m_binding.reverse(); + expr_ref res(m); + instantiate(m, q, m_binding.c_ptr(), res); + m_binding.reverse(); + conjs.push_back(res); + } + + void mk_quantifier_instantiation::merge(expr* e1, expr* e2) { + unsigned i1 = e1->get_id(); + unsigned i2 = e2->get_id(); + unsigned n = std::max(i1, i2); + while (n >= m_uf.get_num_vars()) { + m_uf.mk_var(); + } + m_uf.merge(i1, i2); + } + + void mk_quantifier_instantiation::collect_egraph(expr* e) { + expr* e1, *e2; + m_todo.push_back(e); + expr_fast_mark1 visited; + while (!m_todo.empty()) { + e = m_todo.back(); + m_todo.pop_back(); + if (visited.is_marked(e)) { + continue; + } + if (e->get_id() >= m_terms.size()) { + m_terms.resize(e->get_id()+1); + } + m_terms[e->get_id()] = e; + visited.mark(e); + if (m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) { + merge(e1, e2); + } + if (is_app(e)) { + app* ap = to_app(e); + ptr_vector* terms = 0; + if (m_funs.find(ap->get_decl(), terms)) { + terms = alloc(ptr_vector); + m_funs.insert(ap->get_decl(), terms); + } + terms->push_back(e); + m_todo.append(ap->get_num_args(), ap->get_args()); + } + } + } + + void mk_quantifier_instantiation::instantiate_rule(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs, rule_set& rules) { + rule_manager& rm = m_ctx.get_rule_manager(); + expr_ref fml(m), cnst(m); + var_ref var(m); + ptr_vector sorts; + r.get_vars(sorts); + m_uf.reset(); + m_terms.reset(); + m_var2cnst.reset(); + m_cnst2var.reset(); + fml = m.mk_and(conjs.size(), conjs.c_ptr()); + + for (unsigned i = 0; i < sorts.size(); ++i) { + if (!sorts[i]) { + sorts[i] = m.mk_bool_sort(); + } + var = m.mk_var(i, sorts[i]); + cnst = m.mk_fresh_const("C", sorts[i]); + m_var2cnst.insert(var, cnst); + m_cnst2var.insert(cnst, var); + } + + fml = m.mk_and(conjs.size(), conjs.c_ptr()); + m_var2cnst(fml); + collect_egraph(fml); + + for (unsigned i = 0; i < qs.size(); ++i) { + instantiate_quantifier(qs[i].get(), conjs); + } + obj_map*>::iterator it = m_funs.begin(), end = m_funs.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + m_funs.reset(); + + fml = m.mk_and(conjs.size(), conjs.c_ptr()); + fml = m.mk_implies(fml, r.get_head()); + + rule_ref_vector added_rules(rm); + proof_ref pr(m); // proofs are TBD. + rm.mk_rule(fml, pr, added_rules); + rules.add_rules(added_rules.size(), added_rules.c_ptr()); + } + + rule_set * mk_quantifier_instantiation::operator()(rule_set const & source) { + if (!m_ctx.get_params().instantiate_quantifiers()) { + return 0; + } + bool has_quantifiers = false; + unsigned sz = source.get_num_rules(); + for (unsigned i = 0; !has_quantifiers && i < sz; ++i) { + rule& r = *source.get_rule(i); + has_quantifiers = has_quantifiers || r.has_quantifiers(); + if (r.has_negation()) { + return 0; + } + } + if (!has_quantifiers) { + return 0; + } + + expr_ref_vector conjs(m); + quantifier_ref_vector qs(m); + rule_set * result = alloc(rule_set, m_ctx); + + bool instantiated = false; + + for (unsigned i = 0; i < sz; ++i) { + rule * r = source.get_rule(i); + extract_quantifiers(*r, conjs, qs); + if (qs.empty()) { + result->add_rule(r); + } + else { + instantiate_rule(*r, conjs, qs, *result); + instantiated = true; + } + } + + // model converter: TBD. + // proof converter: TBD. + + if (!instantiated) { + dealloc(result); + result = 0; + } + return result; + } + + +}; + + diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.h b/src/muz_qe/dl_mk_quantifier_instantiation.h new file mode 100644 index 000000000..81a77e86a --- /dev/null +++ b/src/muz_qe/dl_mk_quantifier_instantiation.h @@ -0,0 +1,120 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_quantifier_instantiation.h + +Abstract: + + Convert Quantified Horn clauses into non-quantified clauses using + instantiation. + +Author: + + Ken McMillan + Andrey Rybalchenko + Nikolaj Bjorner (nbjorner) 2013-04-02 + +Revision History: + + Based on approach suggested in SAS 2013 paper + "On Solving Universally Quantified Horn Clauses" + +--*/ +#ifndef _DL_MK_QUANTIFIER_INSTANTIATION_H_ +#define _DL_MK_QUANTIFIER_INSTANTIATION_H_ + + +#include"dl_rule_transformer.h" +#include"array_decl_plugin.h" +#include"expr_safe_replace.h" + + +namespace datalog { + + class context; + + class mk_quantifier_instantiation : public rule_transformer::plugin { + typedef svector > term_pairs; + + class union_find { + unsigned_vector m_find; + unsigned_vector m_size; + unsigned_vector m_next; + public: + unsigned mk_var() { + unsigned r = m_find.size(); + m_find.push_back(r); + m_size.push_back(1); + m_next.push_back(r); + return r; + } + unsigned get_num_vars() const { return m_find.size(); } + + unsigned find(unsigned v) const { + while (true) { + unsigned new_v = m_find[v]; + if (new_v == v) + return v; + v = new_v; + } + } + + unsigned next(unsigned v) const { return m_next[v]; } + + bool is_root(unsigned v) const { return m_find[v] == v; } + + void merge(unsigned v1, unsigned v2) { + unsigned r1 = find(v1); + unsigned r2 = find(v2); + if (r1 == r2) + return; + if (m_size[r1] > m_size[r2]) + std::swap(r1, r2); + m_find[r1] = r2; + m_size[r2] += m_size[r1]; + std::swap(m_next[r1], m_next[r2]); + } + + void reset() { + m_find.reset(); + m_next.reset(); + m_size.reset(); + } + }; + ast_manager& m; + context& m_ctx; + expr_safe_replace m_var2cnst; + expr_safe_replace m_cnst2var; + array_util a; + union_find m_uf; + ptr_vector m_todo; + ptr_vector m_terms; + ptr_vector m_binding; + obj_map*> m_funs; + + + void merge(expr* e1, expr* e2); + void extract_quantifiers(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs); + void collect_egraph(expr* e); + void instantiate_rule(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs, rule_set& rules); + void instantiate_quantifier(quantifier* q, expr_ref_vector & conjs); + void mk_quantifier_instantiation::instantiate_quantifier(quantifier* q, app* pat, expr_ref_vector & conjs); + void mk_quantifier_instantiation::match(unsigned i, app* pat, unsigned j, term_pairs& todo, quantifier* q, expr_ref_vector& conjs); + void mk_quantifier_instantiation::yield_binding(quantifier* q, expr_ref_vector& conjs); + + public: + mk_quantifier_instantiation(context & ctx, unsigned priority); + + virtual ~mk_quantifier_instantiation(); + + rule_set * operator()(rule_set const & source); + }; + + + +}; + +#endif /* _DL_MK_QUANTIFIER_INSTANTIATION_H_ */ + diff --git a/src/muz_qe/fixedpoint_params.pyg b/src/muz_qe/fixedpoint_params.pyg index 7a3316c56..774559cdb 100644 --- a/src/muz_qe/fixedpoint_params.pyg +++ b/src/muz_qe/fixedpoint_params.pyg @@ -42,6 +42,8 @@ def_module_params('fixedpoint', ('simplify_formulas_post', BOOL, False, "PDR: simplify derived formulas after inductive propagation"), ('slice', BOOL, True, "PDR: simplify clause set using slicing"), ('karr', BOOL, False, "Add linear invariants to clauses using Karr's method"), + ('quantify_arrays', BOOL, False, "create quantified Horn clauses from clauses with arrays"), + ('instantiate_quantifiers', BOOL, False, "instantiate quantified Horn clauses using E-matching heuristic"), ('coalesce_rules', BOOL, False, "BMC: coalesce rules"), ('use_multicore_generalizer', BOOL, False, "PDR: extract multiple cores for blocking states"), ('use_inductive_generalizer', BOOL, True, "PDR: generalize lemmas using induction strengthening"), From cda29bc03b8e0e64099a4f7b95792fc181471a46 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Apr 2013 15:29:52 -0700 Subject: [PATCH 77/97] add abstraction and instantiation Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_context.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 9207fbe61..44852a52f 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -47,6 +47,7 @@ Revision History: #include"dl_mk_array_blast.h" #include"dl_mk_karr_invariants.h" #include"dl_mk_quantifier_abstraction.h" +#include"dl_mk_quantifier_instantiation.h" #include"datatype_decl_plugin.h" #include"expr_abstract.h" @@ -908,6 +909,7 @@ namespace datalog { m_transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, *this, 33000)); + m_transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, *this, 32000)); m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); From 477e8cc46a10c61a211aba23acbdcd77b337dcf1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Apr 2013 20:33:22 -0700 Subject: [PATCH 78/97] debugging quantifier instantiation Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_quantifier_instantiation.cpp | 35 +++++++++------ src/muz_qe/dl_mk_quantifier_instantiation.h | 45 +++++++++++++------ 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.cpp b/src/muz_qe/dl_mk_quantifier_instantiation.cpp index a5b80af4f..11c039bf8 100644 --- a/src/muz_qe/dl_mk_quantifier_instantiation.cpp +++ b/src/muz_qe/dl_mk_quantifier_instantiation.cpp @@ -18,13 +18,14 @@ Author: Revision History: - Based on approach suggested in SAS 2013 paper + Based on approach suggested in the SAS 2013 paper "On Solving Universally Quantified Horn Clauses" --*/ #include "dl_mk_quantifier_instantiation.h" #include "dl_context.h" +#include "pattern_inference.h" namespace datalog { @@ -34,12 +35,10 @@ namespace datalog { m(ctx.get_manager()), m_ctx(ctx), m_var2cnst(m), - m_cnst2var(m), - a(m) { + m_cnst2var(m) { } - mk_quantifier_instantiation::~mk_quantifier_instantiation() { - + mk_quantifier_instantiation::~mk_quantifier_instantiation() { } void mk_quantifier_instantiation::extract_quantifiers(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs) { @@ -66,8 +65,15 @@ namespace datalog { void mk_quantifier_instantiation::instantiate_quantifier(quantifier* q, expr_ref_vector & conjs) { expr_ref qe(m); qe = q; - m_var2cnst(qe); + m_var2cnst(qe); q = to_quantifier(qe); + if (q->get_num_patterns() == 0) { + proof_ref new_pr(m); + pattern_inference_params params; + pattern_inference infer(m, params); + infer(q, qe, new_pr); + q = to_quantifier(qe); + } unsigned num_patterns = q->get_num_patterns(); for (unsigned i = 0; i < num_patterns; ++i) { expr * pat = q->get_pattern(i); @@ -86,6 +92,7 @@ namespace datalog { } void mk_quantifier_instantiation::match(unsigned i, app* pat, unsigned j, term_pairs& todo, quantifier* q, expr_ref_vector& conjs) { + TRACE("dl", tout << "match" << mk_pp(pat, m) << "\n";); while (j < todo.size()) { expr* p = todo[j].first; expr* t = todo[j].second; @@ -102,7 +109,7 @@ namespace datalog { // matching failed. return; } - j += 1; + ++j; continue; } if (!is_app(p)) { @@ -125,7 +132,7 @@ namespace datalog { todo.resize(sz); } } - next_id = m_uf.next(id); + next_id = m_uf.next(next_id); } while (next_id != id); return; @@ -156,16 +163,14 @@ namespace datalog { expr_ref res(m); instantiate(m, q, m_binding.c_ptr(), res); m_binding.reverse(); + m_cnst2var(res); conjs.push_back(res); + TRACE("dl", tout << mk_pp(q, m) << "\n==>\n" << mk_pp(res, m) << "\n";); } void mk_quantifier_instantiation::merge(expr* e1, expr* e2) { unsigned i1 = e1->get_id(); unsigned i2 = e2->get_id(); - unsigned n = std::max(i1, i2); - while (n >= m_uf.get_num_vars()) { - m_uf.mk_var(); - } m_uf.merge(i1, i2); } @@ -179,7 +184,8 @@ namespace datalog { if (visited.is_marked(e)) { continue; } - if (e->get_id() >= m_terms.size()) { + unsigned n = e->get_id(); + if (n >= m_terms.size()) { m_terms.resize(e->get_id()+1); } m_terms[e->get_id()] = e; @@ -190,7 +196,7 @@ namespace datalog { if (is_app(e)) { app* ap = to_app(e); ptr_vector* terms = 0; - if (m_funs.find(ap->get_decl(), terms)) { + if (!m_funs.find(ap->get_decl(), terms)) { terms = alloc(ptr_vector); m_funs.insert(ap->get_decl(), terms); } @@ -237,6 +243,7 @@ namespace datalog { fml = m.mk_and(conjs.size(), conjs.c_ptr()); fml = m.mk_implies(fml, r.get_head()); + TRACE("dl", r.display(m_ctx, tout); tout << mk_pp(fml, m) << "\n";); rule_ref_vector added_rules(rm); proof_ref pr(m); // proofs are TBD. diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.h b/src/muz_qe/dl_mk_quantifier_instantiation.h index 81a77e86a..969a0bf23 100644 --- a/src/muz_qe/dl_mk_quantifier_instantiation.h +++ b/src/muz_qe/dl_mk_quantifier_instantiation.h @@ -18,7 +18,7 @@ Author: Revision History: - Based on approach suggested in SAS 2013 paper + Based on approach suggested in the SAS 2013 paper "On Solving Universally Quantified Horn Clauses" --*/ @@ -27,7 +27,6 @@ Revision History: #include"dl_rule_transformer.h" -#include"array_decl_plugin.h" #include"expr_safe_replace.h" @@ -42,6 +41,12 @@ namespace datalog { unsigned_vector m_find; unsigned_vector m_size; unsigned_vector m_next; + + void ensure_size(unsigned v) { + while (v >= get_num_vars()) { + mk_var(); + } + } public: unsigned mk_var() { unsigned r = m_find.size(); @@ -53,6 +58,9 @@ namespace datalog { unsigned get_num_vars() const { return m_find.size(); } unsigned find(unsigned v) const { + if (v >= get_num_vars()) { + return v; + } while (true) { unsigned new_v = m_find[v]; if (new_v == v) @@ -61,15 +69,24 @@ namespace datalog { } } - unsigned next(unsigned v) const { return m_next[v]; } + unsigned next(unsigned v) const { + if (v >= get_num_vars()) { + return v; + } + return m_next[v]; + } - bool is_root(unsigned v) const { return m_find[v] == v; } + bool is_root(unsigned v) const { + return v >= get_num_vars() || m_find[v] == v; + } void merge(unsigned v1, unsigned v2) { unsigned r1 = find(v1); unsigned r2 = find(v2); if (r1 == r2) return; + ensure_size(v1); + ensure_size(v2); if (m_size[r1] > m_size[r2]) std::swap(r1, r2); m_find[r1] = r2; @@ -83,15 +100,15 @@ namespace datalog { m_size.reset(); } }; - ast_manager& m; - context& m_ctx; + + ast_manager& m; + context& m_ctx; expr_safe_replace m_var2cnst; expr_safe_replace m_cnst2var; - array_util a; - union_find m_uf; - ptr_vector m_todo; - ptr_vector m_terms; - ptr_vector m_binding; + union_find m_uf; + ptr_vector m_todo; + ptr_vector m_terms; + ptr_vector m_binding; obj_map*> m_funs; @@ -100,9 +117,9 @@ namespace datalog { void collect_egraph(expr* e); void instantiate_rule(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs, rule_set& rules); void instantiate_quantifier(quantifier* q, expr_ref_vector & conjs); - void mk_quantifier_instantiation::instantiate_quantifier(quantifier* q, app* pat, expr_ref_vector & conjs); - void mk_quantifier_instantiation::match(unsigned i, app* pat, unsigned j, term_pairs& todo, quantifier* q, expr_ref_vector& conjs); - void mk_quantifier_instantiation::yield_binding(quantifier* q, expr_ref_vector& conjs); + void instantiate_quantifier(quantifier* q, app* pat, expr_ref_vector & conjs); + void match(unsigned i, app* pat, unsigned j, term_pairs& todo, quantifier* q, expr_ref_vector& conjs); + void yield_binding(quantifier* q, expr_ref_vector& conjs); public: mk_quantifier_instantiation(context & ctx, unsigned priority); From 67e9d746533b1fe81a8de567b1d9644c7c5be688 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 3 Apr 2013 09:44:31 -0700 Subject: [PATCH 79/97] constify a few functions Signed-off-by: Nuno Lopes --- src/ast/bv_decl_plugin.cpp | 4 ++-- src/ast/bv_decl_plugin.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 0ef3b60d6..8b77244f9 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -766,7 +766,7 @@ bool bv_recognizers::is_zero(expr const * n) const { return decl->get_parameter(0).get_rational().is_zero(); } -bool bv_recognizers::is_extract(expr const* e, unsigned& low, unsigned& high, expr*& b) { +bool bv_recognizers::is_extract(expr const* e, unsigned& low, unsigned& high, expr*& b) const { if (!is_extract(e)) return false; low = get_extract_low(e); high = get_extract_high(e); @@ -774,7 +774,7 @@ bool bv_recognizers::is_extract(expr const* e, unsigned& low, unsigned& high, ex return true; } -bool bv_recognizers::is_bv2int(expr const* e, expr*& r) { +bool bv_recognizers::is_bv2int(expr const* e, expr*& r) const { if (!is_bv2int(e)) return false; r = to_app(e)->get_arg(0); return true; diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index 8ea90f844..c5ebfb2d9 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -288,10 +288,10 @@ public: bool is_extract(expr const * e) const { return is_app_of(e, get_fid(), OP_EXTRACT); } unsigned get_extract_high(func_decl const * f) const { return f->get_parameter(0).get_int(); } unsigned get_extract_low(func_decl const * f) const { return f->get_parameter(1).get_int(); } - unsigned get_extract_high(expr const * n) { SASSERT(is_extract(n)); return get_extract_high(to_app(n)->get_decl()); } - unsigned get_extract_low(expr const * n) { SASSERT(is_extract(n)); return get_extract_low(to_app(n)->get_decl()); } - bool is_extract(expr const * e, unsigned & low, unsigned & high, expr * & b); - bool is_bv2int(expr const * e, expr * & r); + unsigned get_extract_high(expr const * n) const { SASSERT(is_extract(n)); return get_extract_high(to_app(n)->get_decl()); } + unsigned get_extract_low(expr const * n) const { SASSERT(is_extract(n)); return get_extract_low(to_app(n)->get_decl()); } + bool is_extract(expr const * e, unsigned & low, unsigned & high, expr * & b) const; + bool is_bv2int(expr const * e, expr * & r) const; bool is_bv_add(expr const * e) const { return is_app_of(e, get_fid(), OP_BADD); } bool is_bv_sub(expr const * e) const { return is_app_of(e, get_fid(), OP_BSUB); } bool is_bv_mul(expr const * e) const { return is_app_of(e, get_fid(), OP_BMUL); } From 2a745d5224c416ce81bcf8f5d586cdc24a879d1e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 3 Apr 2013 14:46:58 -0700 Subject: [PATCH 80/97] adding model convertion to quantifier transformation Signed-off-by: Nikolaj Bjorner --- src/api/api_datalog.cpp | 4 +- src/muz_qe/datalog_parser.cpp | 4 +- src/muz_qe/dl_cmds.cpp | 1 + src/muz_qe/dl_context.cpp | 11 +- src/muz_qe/dl_context.h | 14 +- src/muz_qe/dl_mk_karr_invariants.cpp | 2 +- src/muz_qe/dl_mk_loop_counter.cpp | 4 +- src/muz_qe/dl_mk_quantifier_abstraction.cpp | 160 ++++++++++++++++-- src/muz_qe/dl_mk_quantifier_abstraction.h | 5 +- src/muz_qe/dl_mk_quantifier_instantiation.cpp | 38 ++--- src/muz_qe/dl_mk_quantifier_instantiation.h | 1 - src/muz_qe/dl_rule.cpp | 2 +- src/muz_qe/horn_tactic.cpp | 2 +- 13 files changed, 188 insertions(+), 60 deletions(-) diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 0f100e747..f6eadfea0 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -358,7 +358,7 @@ extern "C" { v->m_ast_vector.push_back(coll.m_queries[i].get()); } for (unsigned i = 0; i < coll.m_rels.size(); ++i) { - to_fixedpoint_ref(d)->ctx().register_predicate(coll.m_rels[i].get()); + to_fixedpoint_ref(d)->ctx().register_predicate(coll.m_rels[i].get(), true); } for (unsigned i = 0; i < coll.m_rules.size(); ++i) { to_fixedpoint_ref(d)->add_rule(coll.m_rules[i].get(), coll.m_names[i]); @@ -415,7 +415,7 @@ extern "C" { void Z3_API Z3_fixedpoint_register_relation(Z3_context c,Z3_fixedpoint d, Z3_func_decl f) { Z3_TRY; LOG_Z3_fixedpoint_register_relation(c, d, f); - to_fixedpoint_ref(d)->ctx().register_predicate(to_func_decl(f)); + to_fixedpoint_ref(d)->ctx().register_predicate(to_func_decl(f), true); Z3_CATCH; } diff --git a/src/muz_qe/datalog_parser.cpp b/src/muz_qe/datalog_parser.cpp index cfe283410..545f3e14a 100644 --- a/src/muz_qe/datalog_parser.cpp +++ b/src/muz_qe/datalog_parser.cpp @@ -441,6 +441,7 @@ protected: unsigned m_sym_idx; std::string m_path; str2sort m_sort_dict; + // true if an error occured during the current call to the parse_stream // function @@ -812,7 +813,8 @@ protected: } f = m_manager.mk_func_decl(s, domain.size(), domain.c_ptr(), m_manager.mk_bool_sort()); - m_context.register_predicate(f); + m_context.register_predicate(f, true); + while (tok == TK_ID) { char const* pred_pragma = m_lexer->get_token_data(); if(strcmp(pred_pragma, "printtuples")==0 || strcmp(pred_pragma, "outputtuples")==0) { diff --git a/src/muz_qe/dl_cmds.cpp b/src/muz_qe/dl_cmds.cpp index aef14e051..c1e3f85f9 100644 --- a/src/muz_qe/dl_cmds.cpp +++ b/src/muz_qe/dl_cmds.cpp @@ -229,6 +229,7 @@ public: status = dlctx.query(m_target); } catch (z3_error & ex) { + ctx.regular_stream() << "(error \"query failed: " << ex.msg() << "\")" << std::endl; throw ex; } catch (z3_exception& ex) { diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 44852a52f..a928d7ba7 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -302,14 +302,6 @@ namespace datalog { return m_preds.contains(pred); } - func_decl * context::try_get_predicate_decl(symbol pred_name) const { - func_decl * res; - if (!m_preds_by_name.find(pred_name, res)) { - return 0; - } - return res; - } - void context::register_variable(func_decl* var) { m_vars.push_back(m.mk_const(var)); } @@ -361,7 +353,6 @@ namespace datalog { m_pinned.push_back(decl); m_preds.insert(decl); if (named) { - SASSERT(!m_preds_by_name.contains(decl->get_name())); m_preds_by_name.insert(decl->get_name(), decl); } } @@ -448,7 +439,7 @@ namespace datalog { func_decl* new_pred = m.mk_fresh_func_decl(prefix, suffix, arity, domain, m.mk_bool_sort()); - register_predicate(new_pred); + register_predicate(new_pred, true); if (m_rel.get()) { m_rel->inherit_predicate_kind(new_pred, orig_pred); diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index 0c4558a28..cb432d4e9 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -183,18 +183,22 @@ namespace datalog { retrieved by the try_get_predicate_decl() function. Auxiliary predicates introduced e.g. by rule transformations do not need to be named. */ - void register_predicate(func_decl * pred, bool named = true); + void register_predicate(func_decl * pred, bool named); bool is_predicate(func_decl * pred) const; - + /** \brief If a predicate name has a \c func_decl object assigned, return pointer to it; otherwise return 0. - + Not all \c func_decl object used as relation identifiers need to be assigned to their names. Generally, the names coming from the parses are registered here. - */ - func_decl * try_get_predicate_decl(symbol pred_name) const; + */ + func_decl * try_get_predicate_decl(symbol const& pred_name) const { + func_decl * res = 0; + m_preds_by_name.find(pred_name, res); + return res; + } /** \brief Create a fresh head predicate declaration. diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 2596a7337..7932735fe 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -206,7 +206,7 @@ namespace datalog { for (; it != end; ++it) { rule_ref r(*it, m_inner_ctx.get_rule_manager()); m_inner_ctx.add_rule(r); - m_inner_ctx.register_predicate(r->get_decl()); + m_inner_ctx.register_predicate(r->get_decl(), false); } m_inner_ctx.close(); rule_set::decl2rules::iterator dit = source.begin_grouped_rules(); diff --git a/src/muz_qe/dl_mk_loop_counter.cpp b/src/muz_qe/dl_mk_loop_counter.cpp index 172198746..6b95671f2 100644 --- a/src/muz_qe/dl_mk_loop_counter.cpp +++ b/src/muz_qe/dl_mk_loop_counter.cpp @@ -72,14 +72,14 @@ namespace datalog { for (unsigned j = 0; j < utsz; ++j, ++cnt) { tail.push_back(add_arg(r.get_tail(j), cnt)); neg.push_back(r.is_neg_tail(j)); - ctx.register_predicate(tail.back()->get_decl()); + ctx.register_predicate(tail.back()->get_decl(), false); } for (unsigned j = utsz; j < tsz; ++j) { tail.push_back(r.get_tail(j)); neg.push_back(false); } head = add_arg(r.get_head(), cnt); - ctx.register_predicate(head->get_decl()); + ctx.register_predicate(head->get_decl(), false); // set the loop counter to be an increment of the previous bool found = false; unsigned last = head->get_num_args()-1; diff --git a/src/muz_qe/dl_mk_quantifier_abstraction.cpp b/src/muz_qe/dl_mk_quantifier_abstraction.cpp index 511ab7b9a..0dd48ef53 100644 --- a/src/muz_qe/dl_mk_quantifier_abstraction.cpp +++ b/src/muz_qe/dl_mk_quantifier_abstraction.cpp @@ -21,9 +21,110 @@ Revision History: #include "dl_mk_quantifier_abstraction.h" #include "dl_context.h" +#include "expr_safe_replace.h" +#include "expr_abstract.h" namespace datalog { + + // model converter: + // Given model for P^(x, y, i, a[i]) + // create model: P(x,y,a) == forall i . P^(x,y,i,a[i]) + // requires substitution and list of bound variables. + + class mk_quantifier_abstraction::qa_model_converter : public model_converter { + ast_manager& m; + func_decl_ref_vector m_old_funcs; + func_decl_ref_vector m_new_funcs; + vector m_subst; + vector > m_bound; + + public: + + qa_model_converter(ast_manager& m): + m(m), m_old_funcs(m), m_new_funcs(m) {} + + virtual ~qa_model_converter() {} + + virtual model_converter * translate(ast_translation & translator) { + return alloc(qa_model_converter, m); + } + + void insert(func_decl* old_p, func_decl* new_p, expr_ref_vector& sub, svector const& bound) { + m_old_funcs.push_back(old_p); + m_new_funcs.push_back(new_p); + m_subst.push_back(sub); + m_bound.push_back(bound); + } + + virtual void operator()(model_ref & model) { + for (unsigned i = 0; i < m_new_funcs.size(); ++i) { + func_decl* p = m_new_funcs[i].get(); + func_decl* q = m_old_funcs[i].get(); + expr_ref_vector const& s = m_subst[i]; + svector const& is_bound = m_bound[i]; + func_interp* f = model->get_func_interp(p); + expr_ref body(m); + unsigned arity_p = p->get_arity(); + unsigned arity_q = q->get_arity(); + SASSERT(0 < arity_p); + model->register_decl(p, f); + func_interp* g = alloc(func_interp, m, arity_q); + + if (f) { + body = f->get_interp(); + SASSERT(!f->is_partial()); + SASSERT(body); + } + else { + body = m.mk_false(); + } + // TBD. create quantifier wrapper around body. + + // 1. replace variables by the compound terms from + // the original predicate. + expr_safe_replace sub(m); + for (unsigned i = 0; i < s.size(); ++i) { + sub.insert(m.mk_var(i, m.get_sort(s[i])), s[i]); + } + sub(body); + sub.reset(); + + // 2. replace bound variables by constants. + expr_ref_vector consts(m), bound(m), free(m); + ptr_vector sorts; + svector names; + for (unsigned i = 0; i < q->get_arity(); ++i) { + sort* s = q->get_domain(i); + consts.push_back(m.mk_fresh_const("C", s)); + sub.insert(m.mk_var(i, s), consts.back()); + if (is_bound[i]) { + bound.push_back(consts.back()); + names.push_back(symbol(i)); + sorts.push_back(s); + } + else { + free.push_back(consts.back()); + } + } + sub(body); + sub.reset(); + + // 3. abstract and quantify those variables that should be bound. + expr_abstract(m, 0, bound.size(), bound.c_ptr(), body, body); + body = m.mk_forall(names.size(), sorts.c_ptr(), names.c_ptr(), body); + + // 4. replace remaining constants by variables. + for (unsigned i = 0; i < free.size(); ++i) { + sub.insert(free[i].get(), m.mk_var(i, m.get_sort(free[i].get()))); + } + sub(body); + g->set_else(body); + model->register_decl(q, g); + } + } + }; + mk_quantifier_abstraction::mk_quantifier_abstraction( context & ctx, unsigned priority): plugin(priority), @@ -33,8 +134,7 @@ namespace datalog { m_refs(m) { } - mk_quantifier_abstraction::~mk_quantifier_abstraction() { - + mk_quantifier_abstraction::~mk_quantifier_abstraction() { } func_decl* mk_quantifier_abstraction::declare_pred(func_decl* old_p) { @@ -52,22 +152,41 @@ namespace datalog { func_decl* new_p = 0; if (!m_old2new.find(old_p, new_p)) { + expr_ref_vector sub(m); + svector bound; sort_ref_vector domain(m); + expr_ref arg(m); for (unsigned i = 0; i < sz; ++i) { sort* s = old_p->get_domain(i); + unsigned lookahead = 0; + sort* s0 = s; + while (a.is_array(s0)) { + lookahead += get_array_arity(s0); + s0 = get_array_range(s0); + } + arg = m.mk_var(bound.size() + lookahead, s); while (a.is_array(s)) { unsigned arity = get_array_arity(s); + expr_ref_vector args(m); for (unsigned j = 0; j < arity; ++j) { domain.push_back(get_array_domain(s, j)); + args.push_back(m.mk_var(bound.size(), domain.back())); + bound.push_back(true); } + arg = mk_select(arg, args.size(), args.c_ptr()); s = get_array_range(s); } domain.push_back(s); + bound.push_back(false); + sub.push_back(arg); } SASSERT(old_p->get_range() == m.mk_bool_sort()); new_p = m.mk_func_decl(old_p->get_name(), domain.size(), domain.c_ptr(), old_p->get_range()); m_refs.push_back(new_p); - m_ctx.register_predicate(new_p); + m_ctx.register_predicate(new_p, false); + if (m_mc) { + m_mc->insert(old_p, new_p, sub, bound); + } } return new_p; } @@ -88,10 +207,7 @@ namespace datalog { for (unsigned j = 0; j < arity; ++j) { args.push_back(m.mk_var(idx++, get_array_domain(s, j))); } - ptr_vector args2; - args2.push_back(arg); - args2.append(arity, args.c_ptr()-arity); - arg = a.mk_select(args2.size(), args2.c_ptr()); + arg = mk_select(arg, arity, args.c_ptr()+args.size()-arity); s = get_array_range(s); } args.push_back(arg); @@ -130,10 +246,7 @@ namespace datalog { names.push_back(symbol(idx)); args.push_back(m.mk_var(idx++, vars.back())); } - ptr_vector args2; - args2.push_back(arg); - args2.append(arity, args.c_ptr()-arity); - arg = a.mk_select(args2.size(), args2.c_ptr()); + arg = mk_select(arg, arity, args.c_ptr()+args.size()-arity); s = get_array_range(s); } if (is_pattern) { @@ -151,8 +264,16 @@ namespace datalog { result = m.mk_eq(m.mk_forall(vars.size(), vars.c_ptr(), names.c_ptr(), result, 1, qid, skid, 1, &pat), m.mk_true()); return result; } + + expr * mk_quantifier_abstraction::mk_select(expr* arg, unsigned num_args, expr* const* args) { + ptr_vector args2; + args2.push_back(arg); + args2.append(num_args, args); + return a.mk_select(args2.size(), args2.c_ptr()); + } rule_set * mk_quantifier_abstraction::operator()(rule_set const & source) { + TRACE("dl", tout << "quantify " << source.get_num_rules() << " " << m_ctx.get_params().quantify_arrays() << "\n";); if (!m_ctx.get_params().quantify_arrays()) { return 0; } @@ -168,6 +289,10 @@ namespace datalog { svector neg; rule_counter& vc = rm.get_counter(); + if (m_ctx.get_model_converter()) { + m_mc = alloc(qa_model_converter, m); + } + for (unsigned i = 0; i < sz; ++i) { tail.reset(); neg.reset(); @@ -186,17 +311,22 @@ namespace datalog { head = mk_head(r.get_head(), cnt); new_rule = rm.mk(head, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); + TRACE("dl", r.display(m_ctx, tout); new_rule->display(m_ctx, tout);); result->add_rule(new_rule); - } - - // model converter: TBD. - // proof converter: TBD. + + // proof converter: proofs are not necessarily preserved using this transformation. if (m_old2new.empty()) { dealloc(result); + dealloc(m_mc); result = 0; } + else { + m_ctx.add_model_converter(m_mc); + } + m_mc = 0; + return result; } diff --git a/src/muz_qe/dl_mk_quantifier_abstraction.h b/src/muz_qe/dl_mk_quantifier_abstraction.h index 8c26e277a..c7e6c6bb4 100644 --- a/src/muz_qe/dl_mk_quantifier_abstraction.h +++ b/src/muz_qe/dl_mk_quantifier_abstraction.h @@ -34,16 +34,19 @@ namespace datalog { class context; class mk_quantifier_abstraction : public rule_transformer::plugin { + class qa_model_converter; ast_manager& m; context& m_ctx; array_util a; - func_decl_ref_vector m_refs; + func_decl_ref_vector m_refs; obj_map m_new2old; obj_map m_old2new; + qa_model_converter* m_mc; func_decl* declare_pred(func_decl* old_p); app_ref mk_head(app* p, unsigned idx); app_ref mk_tail(app* p); + expr* mk_select(expr* a, unsigned num_args, expr* const* args); public: mk_quantifier_abstraction(context & ctx, unsigned priority); diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.cpp b/src/muz_qe/dl_mk_quantifier_instantiation.cpp index 11c039bf8..993e5ada5 100644 --- a/src/muz_qe/dl_mk_quantifier_instantiation.cpp +++ b/src/muz_qe/dl_mk_quantifier_instantiation.cpp @@ -46,8 +46,7 @@ namespace datalog { qs.reset(); unsigned tsz = r.get_tail_size(); for (unsigned j = 0; j < tsz; ++j) { - conjs.push_back(r.get_tail(j)); - + conjs.push_back(r.get_tail(j)); } datalog::flatten_and(conjs); for (unsigned j = 0; j < conjs.size(); ++j) { @@ -98,17 +97,12 @@ namespace datalog { expr* t = todo[j].second; if (is_var(p)) { unsigned idx = to_var(p)->get_idx(); - expr* t2 = m_binding[idx]; - if (!t2) { + if (!m_binding[idx]) { m_binding[idx] = t; match(i, pat, j + 1, todo, q, conjs); m_binding[idx] = 0; return; } - else if (m_uf.find(t2->get_id()) != m_uf.find(t->get_id())) { - // matching failed. - return; - } ++j; continue; } @@ -168,12 +162,6 @@ namespace datalog { TRACE("dl", tout << mk_pp(q, m) << "\n==>\n" << mk_pp(res, m) << "\n";); } - void mk_quantifier_instantiation::merge(expr* e1, expr* e2) { - unsigned i1 = e1->get_id(); - unsigned i2 = e2->get_id(); - m_uf.merge(i1, i2); - } - void mk_quantifier_instantiation::collect_egraph(expr* e) { expr* e1, *e2; m_todo.push_back(e); @@ -186,12 +174,12 @@ namespace datalog { } unsigned n = e->get_id(); if (n >= m_terms.size()) { - m_terms.resize(e->get_id()+1); + m_terms.resize(n+1); } - m_terms[e->get_id()] = e; + m_terms[n] = e; visited.mark(e); if (m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) { - merge(e1, e2); + m_uf.merge(e1->get_id(), e2->get_id()); } if (is_app(e)) { app* ap = to_app(e); @@ -246,12 +234,23 @@ namespace datalog { TRACE("dl", r.display(m_ctx, tout); tout << mk_pp(fml, m) << "\n";); rule_ref_vector added_rules(rm); - proof_ref pr(m); // proofs are TBD. + proof_ref pr(m); rm.mk_rule(fml, pr, added_rules); + if (r.get_proof()) { + // use def-axiom to encode that new rule is a weakening of the original. + proof* p1 = r.get_proof(); + for (unsigned i = 0; i < added_rules.size(); ++i) { + rule* r2 = added_rules[i].get(); + r2->to_formula(fml); + pr = m.mk_modus_ponens(m.mk_def_axiom(m.mk_implies(m.get_fact(p1), fml)), p1); + r2->set_proof(m, pr); + } + } rules.add_rules(added_rules.size(), added_rules.c_ptr()); } rule_set * mk_quantifier_instantiation::operator()(rule_set const & source) { + TRACE("dl", tout << m_ctx.get_params().instantiate_quantifiers() << "\n";); if (!m_ctx.get_params().instantiate_quantifiers()) { return 0; } @@ -286,8 +285,7 @@ namespace datalog { } } - // model converter: TBD. - // proof converter: TBD. + // model convertion: identity function. if (!instantiated) { dealloc(result); diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.h b/src/muz_qe/dl_mk_quantifier_instantiation.h index 969a0bf23..138d5abee 100644 --- a/src/muz_qe/dl_mk_quantifier_instantiation.h +++ b/src/muz_qe/dl_mk_quantifier_instantiation.h @@ -112,7 +112,6 @@ namespace datalog { obj_map*> m_funs; - void merge(expr* e1, expr* e2); void extract_quantifiers(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs); void collect_egraph(expr* e); void instantiate_rule(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs, rule_set& rules); diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index 14a316e48..b7d6d9fae 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -135,7 +135,7 @@ namespace datalog { h.set_name(name); h(fml, p, fmls, prs); for (unsigned i = 0; i < h.get_fresh_predicates().size(); ++i) { - m_ctx.register_predicate(h.get_fresh_predicates()[i]); + m_ctx.register_predicate(h.get_fresh_predicates()[i], false); } for (unsigned i = 0; i < fmls.size(); ++i) { mk_rule_core2(fmls[i].get(), prs[i].get(), rules, name); diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index 02c41c091..1a8f562d9 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -92,7 +92,7 @@ class horn_tactic : public tactic { void register_predicate(expr* a) { SASSERT(is_predicate(a)); - m_ctx.register_predicate(to_app(a)->get_decl(), true); + m_ctx.register_predicate(to_app(a)->get_decl(), false); } void check_predicate(ast_mark& mark, expr* a) { From 1c96a7d52f48b42891e5f40fa47e0b38c77a0b2e Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Wed, 3 Apr 2013 15:51:09 -0700 Subject: [PATCH 81/97] Add option smt.bv.enable_int2bv in the new parameter setting framework. This is the new name for the old parameter :bv-enable-int2bv-propagation. This modification addresses an issue reported at http://stackoverflow.com/questions/15798984/bv-enable-int2bv-propagation-option. Signed-off-by: Leonardo de Moura --- src/smt/params/smt_params_helper.pyg | 1 + src/smt/params/theory_bv_params.cpp | 1 + src/util/gparams.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 43dd1b586..21b5c6281 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -29,6 +29,7 @@ def_module_params(module_name='smt', ('qi.cost', STRING, '(+ weight generation)', 'expression specifying what is the cost of a given quantifier instantiation'), ('qi.max_multi_patterns', UINT, 0, 'specify the number of extra multi patterns'), ('bv.reflect', BOOL, True, 'create enode for every bit-vector term'), + ('bv.enable_int2bv', BOOL, False, 'enable support for int2bv and bv2int operators'), ('arith.random_initial_value', BOOL, False, 'use random initial values in the simplex-based procedure for linear arithmetic'), ('arith.solver', UINT, 2, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination'), ('arith.nl', BOOL, True, '(incomplete) nonlinear arithmetic support based on Groebner basis and interval propagation'), diff --git a/src/smt/params/theory_bv_params.cpp b/src/smt/params/theory_bv_params.cpp index c2a31c59d..d3f386ab4 100644 --- a/src/smt/params/theory_bv_params.cpp +++ b/src/smt/params/theory_bv_params.cpp @@ -22,4 +22,5 @@ Revision History: void theory_bv_params::updt_params(params_ref const & _p) { smt_params_helper p(_p); m_bv_reflect = p.bv_reflect(); + m_bv_enable_int2bv2int = p.bv_enable_int2bv(); } diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index 8b1fbe40e..3b2e8edc1 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -49,6 +49,7 @@ char const * g_params_renames[] = { "restart_factor", "smt.restart_factor", "arith_random_initial_value", "smt.arith.random_initial_value", "bv_reflect", "smt.bv.reflect", + "bv_enable_int2bv_propagation", "smt.bv.enable_int2bv", "qi_cost", "smt.qi.cost", "qi_eager_threshold", "smt.qi.eager_threshold", "nl_arith", "smt.arith.nl", From 0b7a270883dc8b66070b88ed2ca132aa5a6d5b48 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 3 Apr 2013 16:53:09 -0700 Subject: [PATCH 82/97] debug quantifier transforms Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_context.cpp | 5 +- src/muz_qe/dl_mk_quantifier_abstraction.cpp | 125 ++++++++++++-------- src/muz_qe/dl_rule_set.h | 1 - 3 files changed, 82 insertions(+), 49 deletions(-) diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index a928d7ba7..852d8f847 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -899,7 +899,10 @@ namespace datalog { m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880)); - m_transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, *this, 33000)); + if (get_params().quantify_arrays()) { + m_transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, *this, 33000)); + m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 32500)); + } m_transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, *this, 32000)); m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); diff --git a/src/muz_qe/dl_mk_quantifier_abstraction.cpp b/src/muz_qe/dl_mk_quantifier_abstraction.cpp index 0dd48ef53..d4abb1ffc 100644 --- a/src/muz_qe/dl_mk_quantifier_abstraction.cpp +++ b/src/muz_qe/dl_mk_quantifier_abstraction.cpp @@ -37,6 +37,7 @@ namespace datalog { func_decl_ref_vector m_old_funcs; func_decl_ref_vector m_new_funcs; vector m_subst; + vector m_sorts; vector > m_bound; public: @@ -50,25 +51,27 @@ namespace datalog { return alloc(qa_model_converter, m); } - void insert(func_decl* old_p, func_decl* new_p, expr_ref_vector& sub, svector const& bound) { + void insert(func_decl* old_p, func_decl* new_p, expr_ref_vector& sub, sort_ref_vector& sorts, svector const& bound) { m_old_funcs.push_back(old_p); m_new_funcs.push_back(new_p); m_subst.push_back(sub); m_bound.push_back(bound); + m_sorts.push_back(sorts); } - virtual void operator()(model_ref & model) { + virtual void operator()(model_ref & old_model) { + model_ref new_model = alloc(model, m); for (unsigned i = 0; i < m_new_funcs.size(); ++i) { func_decl* p = m_new_funcs[i].get(); func_decl* q = m_old_funcs[i].get(); - expr_ref_vector const& s = m_subst[i]; + expr_ref_vector const& sub = m_subst[i]; + sort_ref_vector const& sorts = m_sorts[i]; svector const& is_bound = m_bound[i]; - func_interp* f = model->get_func_interp(p); + func_interp* f = old_model->get_func_interp(p); expr_ref body(m); unsigned arity_p = p->get_arity(); unsigned arity_q = q->get_arity(); SASSERT(0 < arity_p); - model->register_decl(p, f); func_interp* g = alloc(func_interp, m, arity_q); if (f) { @@ -79,49 +82,56 @@ namespace datalog { else { body = m.mk_false(); } - // TBD. create quantifier wrapper around body. + // Create quantifier wrapper around body. + TRACE("dl", tout << mk_pp(body, m) << "\n";); // 1. replace variables by the compound terms from // the original predicate. - expr_safe_replace sub(m); - for (unsigned i = 0; i < s.size(); ++i) { - sub.insert(m.mk_var(i, m.get_sort(s[i])), s[i]); + expr_safe_replace rep(m); + for (unsigned i = 0; i < sub.size(); ++i) { + rep.insert(m.mk_var(i, m.get_sort(sub[i])), sub[i]); } - sub(body); - sub.reset(); + rep(body); + rep.reset(); + TRACE("dl", tout << mk_pp(body, m) << "\n";); // 2. replace bound variables by constants. expr_ref_vector consts(m), bound(m), free(m); - ptr_vector sorts; svector names; - for (unsigned i = 0; i < q->get_arity(); ++i) { - sort* s = q->get_domain(i); + ptr_vector bound_sorts; + for (unsigned i = 0; i < sorts.size(); ++i) { + sort* s = sorts[i]; consts.push_back(m.mk_fresh_const("C", s)); - sub.insert(m.mk_var(i, s), consts.back()); + rep.insert(m.mk_var(i, s), consts.back()); if (is_bound[i]) { bound.push_back(consts.back()); names.push_back(symbol(i)); - sorts.push_back(s); + bound_sorts.push_back(s); } else { free.push_back(consts.back()); } } - sub(body); - sub.reset(); + rep(body); + rep.reset(); + TRACE("dl", tout << mk_pp(body, m) << "\n";); // 3. abstract and quantify those variables that should be bound. expr_abstract(m, 0, bound.size(), bound.c_ptr(), body, body); - body = m.mk_forall(names.size(), sorts.c_ptr(), names.c_ptr(), body); + body = m.mk_forall(names.size(), bound_sorts.c_ptr(), names.c_ptr(), body); + TRACE("dl", tout << mk_pp(body, m) << "\n";); // 4. replace remaining constants by variables. for (unsigned i = 0; i < free.size(); ++i) { - sub.insert(free[i].get(), m.mk_var(i, m.get_sort(free[i].get()))); + rep.insert(free[i].get(), m.mk_var(i, m.get_sort(free[i].get()))); } - sub(body); + rep(body); g->set_else(body); - model->register_decl(q, g); + TRACE("dl", tout << mk_pp(body, m) << "\n";); + + new_model->register_decl(q, g); } + old_model = new_model; } }; @@ -139,6 +149,10 @@ namespace datalog { func_decl* mk_quantifier_abstraction::declare_pred(func_decl* old_p) { + if (m_ctx.is_output_predicate(old_p)) { + return 0; + } + unsigned sz = old_p->get_arity(); unsigned num_arrays = 0; for (unsigned i = 0; i < sz; ++i) { @@ -152,26 +166,29 @@ namespace datalog { func_decl* new_p = 0; if (!m_old2new.find(old_p, new_p)) { - expr_ref_vector sub(m); - svector bound; - sort_ref_vector domain(m); + expr_ref_vector sub(m), vars(m); + svector bound; + sort_ref_vector domain(m), sorts(m); expr_ref arg(m); for (unsigned i = 0; i < sz; ++i) { - sort* s = old_p->get_domain(i); + sort* s0 = old_p->get_domain(i); unsigned lookahead = 0; - sort* s0 = s; - while (a.is_array(s0)) { - lookahead += get_array_arity(s0); - s0 = get_array_range(s0); + sort* s = s0; + while (a.is_array(s)) { + lookahead += get_array_arity(s); + s = get_array_range(s); } - arg = m.mk_var(bound.size() + lookahead, s); + arg = m.mk_var(bound.size() + lookahead, s0); + s = s0; while (a.is_array(s)) { unsigned arity = get_array_arity(s); expr_ref_vector args(m); for (unsigned j = 0; j < arity; ++j) { - domain.push_back(get_array_domain(s, j)); - args.push_back(m.mk_var(bound.size(), domain.back())); + sort* s1 = get_array_domain(s, j); + domain.push_back(s1); + args.push_back(m.mk_var(bound.size(), s1)); bound.push_back(true); + sorts.push_back(s1); } arg = mk_select(arg, args.size(), args.c_ptr()); s = get_array_range(s); @@ -179,14 +196,16 @@ namespace datalog { domain.push_back(s); bound.push_back(false); sub.push_back(arg); + sorts.push_back(s0); } SASSERT(old_p->get_range() == m.mk_bool_sort()); new_p = m.mk_func_decl(old_p->get_name(), domain.size(), domain.c_ptr(), old_p->get_range()); m_refs.push_back(new_p); m_ctx.register_predicate(new_p, false); if (m_mc) { - m_mc->insert(old_p, new_p, sub, bound); + m_mc->insert(old_p, new_p, sub, sorts, bound); } + m_old2new.insert(old_p, new_p); } return new_p; } @@ -212,6 +231,11 @@ namespace datalog { } args.push_back(arg); } + TRACE("dl", + tout << mk_pp(new_p, m) << "\n"; + for (unsigned i = 0; i < args.size(); ++i) { + tout << mk_pp(args[i].get(), m) << "\n"; + }); return app_ref(m.mk_app(new_p, args.size(), args.c_ptr()), m); } @@ -237,7 +261,7 @@ namespace datalog { for (unsigned i = 0; i < sz; ++i) { arg = ps->get_arg(i); sort* s = m.get_sort(arg); - bool is_pattern = false; + bool is_pattern = false; while (a.is_array(s)) { is_pattern = true; unsigned arity = get_array_arity(s); @@ -277,42 +301,49 @@ namespace datalog { if (!m_ctx.get_params().quantify_arrays()) { return 0; } + unsigned sz = source.get_num_rules(); + for (unsigned i = 0; i < sz; ++i) { + rule& r = *source.get_rule(i); + if (r.has_negation()) { + return 0; + } + } + m_refs.reset(); m_old2new.reset(); m_new2old.reset(); rule_manager& rm = source.get_rule_manager(); - rule_set * result = alloc(rule_set, m_ctx); - unsigned sz = source.get_num_rules(); rule_ref new_rule(rm); - app_ref_vector tail(m); + expr_ref_vector tail(m); app_ref head(m); - svector neg; + expr_ref fml(m); rule_counter& vc = rm.get_counter(); if (m_ctx.get_model_converter()) { m_mc = alloc(qa_model_converter, m); } + rule_set * result = alloc(rule_set, m_ctx); - for (unsigned i = 0; i < sz; ++i) { + for (unsigned i = 0; i < sz; ++i) { tail.reset(); - neg.reset(); rule & r = *source.get_rule(i); + TRACE("dl", r.display(m_ctx, tout); ); unsigned cnt = vc.get_max_rule_var(r)+1; unsigned utsz = r.get_uninterpreted_tail_size(); unsigned tsz = r.get_tail_size(); for (unsigned j = 0; j < utsz; ++j) { tail.push_back(mk_tail(r.get_tail(j))); - neg.push_back(r.is_neg_tail(j)); } for (unsigned j = utsz; j < tsz; ++j) { tail.push_back(r.get_tail(j)); - neg.push_back(false); } head = mk_head(r.get_head(), cnt); - - new_rule = rm.mk(head, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); - TRACE("dl", r.display(m_ctx, tout); new_rule->display(m_ctx, tout);); - result->add_rule(new_rule); + fml = m.mk_implies(m.mk_and(tail.size(), tail.c_ptr()), head); + rule_ref_vector added_rules(rm); + proof_ref pr(m); + rm.mk_rule(fml, pr, added_rules); + result->add_rules(added_rules.size(), added_rules.c_ptr()); + TRACE("dl", added_rules.back()->display(m_ctx, tout);); } // proof converter: proofs are not necessarily preserved using this transformation. diff --git a/src/muz_qe/dl_rule_set.h b/src/muz_qe/dl_rule_set.h index 9aa64425c..58427ca87 100644 --- a/src/muz_qe/dl_rule_set.h +++ b/src/muz_qe/dl_rule_set.h @@ -20,7 +20,6 @@ Revision History: #define _DL_RULE_SET_H_ #include"obj_hashtable.h" - #include"dl_rule.h" namespace datalog { From afd83f41b800e7aef366f154e976dc59adf893d4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 3 Apr 2013 17:03:07 -0700 Subject: [PATCH 83/97] fix compiler warnings and errors Signed-off-by: Nikolaj Bjorner --- src/muz_qe/fdd.h | 10 +++++++--- src/test/hilbert_basis.cpp | 2 ++ src/test/karr.cpp | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/muz_qe/fdd.h b/src/muz_qe/fdd.h index e6808375c..59d5a78f5 100644 --- a/src/muz_qe/fdd.h +++ b/src/muz_qe/fdd.h @@ -39,7 +39,7 @@ namespace fdd { unsigned m_ref_count; void reset(); public: - node() : m_var(0), m_hi(0), m_lo(0), m_ref_count(0) {} + node() : m_var(0), m_lo(0), m_hi(0), m_ref_count(0) {} node(unsigned var, node_id l, node_id h): m_var(var), m_lo(l), m_hi(h), m_ref_count(0) {} unsigned get_hash() const; @@ -93,9 +93,13 @@ namespace fdd { class manager { public: typedef int64 Key; + typedef node::hash node_hash; + typedef node::eq node_eq; + typedef config::hash config_hash; + typedef config::eq config_eq; private: - typedef map node_table; - typedef map insert_cache; + typedef map node_table; + typedef map insert_cache; node_table m_table; insert_cache m_insert_cache; svector m_nodes; diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index e0a4a8370..4752dd78d 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -220,6 +220,7 @@ static void on_ctrl_c(int) { raise(SIGINT); } +#if 0 static void validate_sat(hilbert_basis& hb) { ast_manager m; reg_decl_plugins(m); @@ -239,6 +240,7 @@ static void validate_sat(hilbert_basis& hb) { lbool r = sol->check_sat(0,0); std::cout << r << "\n"; } +#endif static void saturate_basis(hilbert_basis& hb) { signal(SIGINT, on_ctrl_c); diff --git a/src/test/karr.cpp b/src/test/karr.cpp index 8770eac94..87debf662 100644 --- a/src/test/karr.cpp +++ b/src/test/karr.cpp @@ -54,7 +54,6 @@ namespace karr { SASSERT(is_sat == l_true); dst.reset(); unsigned basis_size = hb.get_basis_size(); - bool first_initial = true; for (unsigned i = 0; i < basis_size; ++i) { bool is_initial; vector soln; @@ -165,6 +164,7 @@ namespace karr { return v; } +#if 0 static vector V(int i, int j, int k, int l, int m) { vector v; v.push_back(rational(i)); @@ -174,6 +174,7 @@ namespace karr { v.push_back(rational(m)); return v; } +#endif static vector V(int i, int j, int k, int l, int x, int y, int z) { vector v; From 359d2326f8a10f2f870b8e78d5d78d63db3be94b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 3 Apr 2013 17:06:45 -0700 Subject: [PATCH 84/97] stash Signed-off-by: Nikolaj Bjorner --- src/api/api_datalog.cpp | 4 ++-- src/ast/rewriter/expr_safe_replace.cpp | 6 ++++++ src/ast/rewriter/expr_safe_replace.h | 2 ++ src/muz_qe/dl_cmds.cpp | 1 + src/muz_qe/dl_context.cpp | 20 ++++++++++---------- src/muz_qe/dl_context.h | 14 +++++++++----- src/muz_qe/dl_mk_karr_invariants.cpp | 2 +- src/muz_qe/dl_mk_loop_counter.cpp | 4 ++-- src/muz_qe/dl_rule.cpp | 2 +- src/muz_qe/dl_rule_set.h | 1 - src/muz_qe/fixedpoint_params.pyg | 2 ++ src/muz_qe/horn_tactic.cpp | 2 +- 12 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 0f100e747..f6eadfea0 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -358,7 +358,7 @@ extern "C" { v->m_ast_vector.push_back(coll.m_queries[i].get()); } for (unsigned i = 0; i < coll.m_rels.size(); ++i) { - to_fixedpoint_ref(d)->ctx().register_predicate(coll.m_rels[i].get()); + to_fixedpoint_ref(d)->ctx().register_predicate(coll.m_rels[i].get(), true); } for (unsigned i = 0; i < coll.m_rules.size(); ++i) { to_fixedpoint_ref(d)->add_rule(coll.m_rules[i].get(), coll.m_names[i]); @@ -415,7 +415,7 @@ extern "C" { void Z3_API Z3_fixedpoint_register_relation(Z3_context c,Z3_fixedpoint d, Z3_func_decl f) { Z3_TRY; LOG_Z3_fixedpoint_register_relation(c, d, f); - to_fixedpoint_ref(d)->ctx().register_predicate(to_func_decl(f)); + to_fixedpoint_ref(d)->ctx().register_predicate(to_func_decl(f), true); Z3_CATCH; } diff --git a/src/ast/rewriter/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp index b3b4d5138..1ec810414 100644 --- a/src/ast/rewriter/expr_safe_replace.cpp +++ b/src/ast/rewriter/expr_safe_replace.cpp @@ -100,3 +100,9 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) { } res = cache.find(e); } + +void expr_safe_replace::reset() { + m_src.reset(); + m_dst.reset(); + m_subst.reset(); +} diff --git a/src/ast/rewriter/expr_safe_replace.h b/src/ast/rewriter/expr_safe_replace.h index 6af819596..b6131906a 100644 --- a/src/ast/rewriter/expr_safe_replace.h +++ b/src/ast/rewriter/expr_safe_replace.h @@ -38,6 +38,8 @@ public: void operator()(expr_ref& e) { (*this)(e.get(), e); } void operator()(expr* src, expr_ref& e); + + void reset(); }; #endif /* __EXPR_SAFE_REPLACE_H__ */ diff --git a/src/muz_qe/dl_cmds.cpp b/src/muz_qe/dl_cmds.cpp index aef14e051..c1e3f85f9 100644 --- a/src/muz_qe/dl_cmds.cpp +++ b/src/muz_qe/dl_cmds.cpp @@ -229,6 +229,7 @@ public: status = dlctx.query(m_target); } catch (z3_error & ex) { + ctx.regular_stream() << "(error \"query failed: " << ex.msg() << "\")" << std::endl; throw ex; } catch (z3_exception& ex) { diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index c667c7775..852d8f847 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -46,6 +46,8 @@ Revision History: #include"dl_mk_bit_blast.h" #include"dl_mk_array_blast.h" #include"dl_mk_karr_invariants.h" +#include"dl_mk_quantifier_abstraction.h" +#include"dl_mk_quantifier_instantiation.h" #include"datatype_decl_plugin.h" #include"expr_abstract.h" @@ -300,14 +302,6 @@ namespace datalog { return m_preds.contains(pred); } - func_decl * context::try_get_predicate_decl(symbol pred_name) const { - func_decl * res; - if (!m_preds_by_name.find(pred_name, res)) { - return 0; - } - return res; - } - void context::register_variable(func_decl* var) { m_vars.push_back(m.mk_const(var)); } @@ -359,7 +353,6 @@ namespace datalog { m_pinned.push_back(decl); m_preds.insert(decl); if (named) { - SASSERT(!m_preds_by_name.contains(decl->get_name())); m_preds_by_name.insert(decl->get_name(), decl); } } @@ -446,7 +439,7 @@ namespace datalog { func_decl* new_pred = m.mk_fresh_func_decl(prefix, suffix, arity, domain, m.mk_bool_sort()); - register_predicate(new_pred); + register_predicate(new_pred, true); if (m_rel.get()) { m_rel->inherit_predicate_kind(new_pred, orig_pred); @@ -905,6 +898,13 @@ namespace datalog { m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34890)); m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880)); + + if (get_params().quantify_arrays()) { + m_transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, *this, 33000)); + m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 32500)); + } + m_transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, *this, 32000)); + m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 36010)); diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index 0c4558a28..cb432d4e9 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -183,18 +183,22 @@ namespace datalog { retrieved by the try_get_predicate_decl() function. Auxiliary predicates introduced e.g. by rule transformations do not need to be named. */ - void register_predicate(func_decl * pred, bool named = true); + void register_predicate(func_decl * pred, bool named); bool is_predicate(func_decl * pred) const; - + /** \brief If a predicate name has a \c func_decl object assigned, return pointer to it; otherwise return 0. - + Not all \c func_decl object used as relation identifiers need to be assigned to their names. Generally, the names coming from the parses are registered here. - */ - func_decl * try_get_predicate_decl(symbol pred_name) const; + */ + func_decl * try_get_predicate_decl(symbol const& pred_name) const { + func_decl * res = 0; + m_preds_by_name.find(pred_name, res); + return res; + } /** \brief Create a fresh head predicate declaration. diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 2596a7337..7932735fe 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -206,7 +206,7 @@ namespace datalog { for (; it != end; ++it) { rule_ref r(*it, m_inner_ctx.get_rule_manager()); m_inner_ctx.add_rule(r); - m_inner_ctx.register_predicate(r->get_decl()); + m_inner_ctx.register_predicate(r->get_decl(), false); } m_inner_ctx.close(); rule_set::decl2rules::iterator dit = source.begin_grouped_rules(); diff --git a/src/muz_qe/dl_mk_loop_counter.cpp b/src/muz_qe/dl_mk_loop_counter.cpp index 172198746..6b95671f2 100644 --- a/src/muz_qe/dl_mk_loop_counter.cpp +++ b/src/muz_qe/dl_mk_loop_counter.cpp @@ -72,14 +72,14 @@ namespace datalog { for (unsigned j = 0; j < utsz; ++j, ++cnt) { tail.push_back(add_arg(r.get_tail(j), cnt)); neg.push_back(r.is_neg_tail(j)); - ctx.register_predicate(tail.back()->get_decl()); + ctx.register_predicate(tail.back()->get_decl(), false); } for (unsigned j = utsz; j < tsz; ++j) { tail.push_back(r.get_tail(j)); neg.push_back(false); } head = add_arg(r.get_head(), cnt); - ctx.register_predicate(head->get_decl()); + ctx.register_predicate(head->get_decl(), false); // set the loop counter to be an increment of the previous bool found = false; unsigned last = head->get_num_args()-1; diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index 14a316e48..b7d6d9fae 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -135,7 +135,7 @@ namespace datalog { h.set_name(name); h(fml, p, fmls, prs); for (unsigned i = 0; i < h.get_fresh_predicates().size(); ++i) { - m_ctx.register_predicate(h.get_fresh_predicates()[i]); + m_ctx.register_predicate(h.get_fresh_predicates()[i], false); } for (unsigned i = 0; i < fmls.size(); ++i) { mk_rule_core2(fmls[i].get(), prs[i].get(), rules, name); diff --git a/src/muz_qe/dl_rule_set.h b/src/muz_qe/dl_rule_set.h index 9aa64425c..58427ca87 100644 --- a/src/muz_qe/dl_rule_set.h +++ b/src/muz_qe/dl_rule_set.h @@ -20,7 +20,6 @@ Revision History: #define _DL_RULE_SET_H_ #include"obj_hashtable.h" - #include"dl_rule.h" namespace datalog { diff --git a/src/muz_qe/fixedpoint_params.pyg b/src/muz_qe/fixedpoint_params.pyg index 7a3316c56..774559cdb 100644 --- a/src/muz_qe/fixedpoint_params.pyg +++ b/src/muz_qe/fixedpoint_params.pyg @@ -42,6 +42,8 @@ def_module_params('fixedpoint', ('simplify_formulas_post', BOOL, False, "PDR: simplify derived formulas after inductive propagation"), ('slice', BOOL, True, "PDR: simplify clause set using slicing"), ('karr', BOOL, False, "Add linear invariants to clauses using Karr's method"), + ('quantify_arrays', BOOL, False, "create quantified Horn clauses from clauses with arrays"), + ('instantiate_quantifiers', BOOL, False, "instantiate quantified Horn clauses using E-matching heuristic"), ('coalesce_rules', BOOL, False, "BMC: coalesce rules"), ('use_multicore_generalizer', BOOL, False, "PDR: extract multiple cores for blocking states"), ('use_inductive_generalizer', BOOL, True, "PDR: generalize lemmas using induction strengthening"), diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index 02c41c091..1a8f562d9 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -92,7 +92,7 @@ class horn_tactic : public tactic { void register_predicate(expr* a) { SASSERT(is_predicate(a)); - m_ctx.register_predicate(to_app(a)->get_decl(), true); + m_ctx.register_predicate(to_app(a)->get_decl(), false); } void check_predicate(ast_mark& mark, expr* a) { From 65dff93e935f3b76537645f0afa1825ebc3f6f68 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 3 Apr 2013 17:11:33 -0700 Subject: [PATCH 85/97] fix more compiler warnings Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_karr_invariants.cpp | 1 - src/muz_qe/fdd.cpp | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 7932735fe..c4a6a3cdb 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -1015,7 +1015,6 @@ namespace datalog { virtual void operator()(relation_base & _r) { karr_relation & r = get(_r); - karr_relation_plugin & p = r.get_plugin(); if (m_value.is_int()) { r.get_ineqs(); vector row; diff --git a/src/muz_qe/fdd.cpp b/src/muz_qe/fdd.cpp index 6c3bc0974..6b23f3a3f 100644 --- a/src/muz_qe/fdd.cpp +++ b/src/muz_qe/fdd.cpp @@ -42,11 +42,11 @@ bool node::operator==(node const& other) const { // ------------------------------------------ // manager -manager::manager() : +manager::manager() : + m_alloc_node(2), m_false(0), m_true(1), - m_root(m_false), - m_alloc_node(2) + m_root(m_false) { m_nodes.push_back(node()); // false m_nodes.push_back(node()); // true @@ -183,7 +183,6 @@ node_id manager::insert(unsigned idx, node_id n) { node nd = m_nodes[n]; SASSERT(idx >= nd.var()); - unsigned idx0 = idx; while (idx > nd.var()) { if (idx2bit(idx) && !is_dont_care(idx2key(idx))) { return mk_node(idx, n, insert(idx, n)); From 5ef0fdc9c86eafed39c518525387703ccc96e374 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 4 Apr 2013 21:39:20 -0700 Subject: [PATCH 86/97] dealing with build warnings Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_quantifier_instantiation.cpp | 1 - src/muz_qe/fdd.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.cpp b/src/muz_qe/dl_mk_quantifier_instantiation.cpp index 993e5ada5..1d80d9b77 100644 --- a/src/muz_qe/dl_mk_quantifier_instantiation.cpp +++ b/src/muz_qe/dl_mk_quantifier_instantiation.cpp @@ -83,7 +83,6 @@ namespace datalog { void mk_quantifier_instantiation::instantiate_quantifier(quantifier* q, app* pat, expr_ref_vector & conjs) { - unsigned sz = pat->get_num_args(); m_binding.reset(); m_binding.resize(q->get_num_decls()); term_pairs todo; diff --git a/src/muz_qe/fdd.cpp b/src/muz_qe/fdd.cpp index 6b23f3a3f..9ca5f758a 100644 --- a/src/muz_qe/fdd.cpp +++ b/src/muz_qe/fdd.cpp @@ -23,12 +23,12 @@ Revision History: #include "bit_vector.h" #include "trace.h" -#define OFFSET_OF(ty, field) (unsigned char*)(&((ty*)(0))->field) - (unsigned char*)(ty*)(0) +#define OFFSET_OF(th, ty, field) (unsigned char*)(&((ty*)(th))->field) - (unsigned char*)(ty*)(th) using namespace fdd; unsigned node::get_hash() const { - return string_hash((char*)this, OFFSET_OF(node, m_ref_count), 11); + return string_hash((char*)this, static_cast(OFFSET_OF(this, node, m_ref_count)), 11); } bool node::operator==(node const& other) const { From 26efb3c7f1c0812dcd141d5bb4da0a8af351b1c2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 5 Apr 2013 12:45:28 +0100 Subject: [PATCH 87/97] FPA bugfixes for denormal numbers. Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 139 +++++++++++++++++----------- src/tactic/fpa/fpa2bv_converter.h | 2 +- 2 files changed, 85 insertions(+), 56 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 838090045..6d39dbfc4 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -423,9 +423,9 @@ void fpa2bv_converter::mk_add(func_decl * f, unsigned num, expr * const * args, unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); - expr_ref a_sgn(m), a_sig(m), a_exp(m), b_sgn(m), b_sig(m), b_exp(m); - unpack(x, a_sgn, a_sig, a_exp, true); - unpack(y, b_sgn, b_sig, b_exp, false); + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m), b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, false); + unpack(y, b_sgn, b_sig, b_exp, b_lz, false); dbg_decouple("fpa2bv_add_unpack_a_sgn", a_sgn); dbg_decouple("fpa2bv_add_unpack_a_sig", a_sig); @@ -511,7 +511,7 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, mk_nzero(f, nzero); mk_pzero(f, pzero); mk_minus_inf(f, ninf); - mk_plus_inf(f, pinf); + mk_plus_inf(f, pinf); expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m); expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_inf(m); @@ -575,13 +575,21 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, unsigned sbits = m_util.get_sbits(f->get_range()); SASSERT(ebits <= sbits); - expr_ref a_sgn(m), a_sig(m), a_exp(m), b_sgn(m), b_sig(m), b_exp(m); - unpack(x, a_sgn, a_sig, a_exp, true); - unpack(y, b_sgn, b_sig, b_exp, true); + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m), b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + unpack(y, b_sgn, b_sig, b_exp, b_lz, true); - expr_ref lz_a(m), lz_b(m); - mk_leading_zeros(a_sig, ebits+2, lz_a); - mk_leading_zeros(b_sig, ebits+2, lz_b); + dbg_decouple("fpa2bv_mul_a_sig", a_sig); + dbg_decouple("fpa2bv_mul_a_exp", a_exp); + dbg_decouple("fpa2bv_mul_b_sig", b_sig); + dbg_decouple("fpa2bv_mul_b_exp", b_exp); + + expr_ref a_lz_ext(m), b_lz_ext(m); + a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz); + b_lz_ext = m_bv_util.mk_zero_extend(2, b_lz); + + dbg_decouple("fpa2bv_mul_lz_a", a_lz); + dbg_decouple("fpa2bv_mul_lz_b", b_lz); expr_ref a_sig_ext(m), b_sig_ext(m); a_sig_ext = m_bv_util.mk_zero_extend(sbits, a_sig); @@ -597,9 +605,9 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, dbg_decouple("fpa2bv_mul_res_sgn", res_sgn); - res_exp = m_bv_util.mk_bv_sub( - m_bv_util.mk_bv_add(a_exp_ext, b_exp_ext), - m_bv_util.mk_bv_add(lz_a, lz_b)); + res_exp = m_bv_util.mk_bv_add( + m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext), + m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext)); expr_ref product(m); product = m_bv_util.mk_bv_mul(a_sig_ext, b_sig_ext); @@ -614,11 +622,11 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, if (sbits >= 4) { expr_ref sticky(m); - sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(sbits-4, 0, l_p)); - rbits = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits-1, sbits-3, l_p), sticky); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(sbits-4, 0, product)); + rbits = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits-1, sbits-3, product), sticky); } else - rbits = m_bv_util.mk_concat(l_p, m_bv_util.mk_numeral(0, 4 - m_bv_util.get_bv_size(l_p))); + rbits = m_bv_util.mk_concat(l_p, m_bv_util.mk_numeral(0, 4 - sbits)); SASSERT(m_bv_util.get_bv_size(rbits) == 4); res_sig = m_bv_util.mk_concat(h_p, rbits); @@ -719,9 +727,9 @@ void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, unsigned sbits = m_util.get_sbits(f->get_range()); SASSERT(ebits <= sbits); - expr_ref a_sgn(m), a_sig(m), a_exp(m), b_sgn(m), b_sig(m), b_exp(m); - unpack(x, a_sgn, a_sig, a_exp, true); - unpack(y, b_sgn, b_sig, b_exp, true); + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m), b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + unpack(y, b_sgn, b_sig, b_exp, b_lz, true); unsigned extra_bits = sbits+2; expr_ref a_sig_ext(m), b_sig_ext(m); @@ -736,7 +744,13 @@ void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, expr * signs[2] = { a_sgn, b_sgn }; res_sgn = m_bv_util.mk_bv_xor(2, signs); - res_exp = m_bv_util.mk_bv_sub(a_exp_ext, b_exp_ext); + expr_ref a_lz_ext(m), b_lz_ext(m); + a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz); + b_lz_ext = m_bv_util.mk_zero_extend(2, b_lz); + + res_exp = m_bv_util.mk_bv_sub( + m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext), + m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext)); expr_ref quotient(m); quotient = m.mk_app(m_bv_util.get_fid(), OP_BUDIV, a_sig_ext, b_sig_ext); @@ -829,10 +843,10 @@ void fpa2bv_converter::mk_remainder(func_decl * f, unsigned num, expr * const * unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); - expr_ref a_sgn(m), a_sig(m), a_exp(m); - expr_ref b_sgn(m), b_sig(m), b_exp(m); - unpack(x, a_sgn, a_sig, a_exp, true); - unpack(y, b_sgn, b_sig, b_exp, true); + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m); + expr_ref b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + unpack(y, b_sgn, b_sig, b_exp, b_lz, true); BVSLT(a_exp, b_exp, c6); v6 = x; @@ -1062,16 +1076,16 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar expr_ref rm_is_to_neg(m); mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg); - expr_ref a_sgn(m), a_sig(m), a_exp(m); - expr_ref b_sgn(m), b_sig(m), b_exp(m); - expr_ref c_sgn(m), c_sig(m), c_exp(m); - unpack(x, a_sgn, a_sig, a_exp, true); - unpack(y, b_sgn, b_sig, b_exp, true); - unpack(z, c_sgn, c_sig, c_exp, false); + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m); + expr_ref b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + expr_ref c_sgn(m), c_sig(m), c_exp(m), c_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + unpack(y, b_sgn, b_sig, b_exp, b_lz, true); + unpack(z, c_sgn, c_sig, c_exp, c_lz, false); - expr_ref lz_a(m), lz_b(m); - mk_leading_zeros(a_sig, ebits+2, lz_a); - mk_leading_zeros(b_sig, ebits+2, lz_b); + expr_ref a_lz_ext(m), b_lz_ext(m); + a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz); + b_lz_ext = m_bv_util.mk_zero_extend(2, b_lz); expr_ref a_sig_ext(m), b_sig_ext(m); a_sig_ext = m_bv_util.mk_zero_extend(sbits, a_sig); @@ -1089,7 +1103,7 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar mul_exp = m_bv_util.mk_bv_sub( m_bv_util.mk_bv_add(a_exp_ext, b_exp_ext), - m_bv_util.mk_bv_add(lz_a, lz_b)); + m_bv_util.mk_bv_add(a_lz_ext, b_lz_ext)); mul_sig = m_bv_util.mk_bv_mul(a_sig_ext, b_sig_ext); @@ -1209,8 +1223,11 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr * unsigned sbits = m_util.get_sbits(f->get_range()); SASSERT(ebits < sbits); - expr_ref a_sgn(m), a_sig(m), a_exp(m); - unpack(x, a_sgn, a_sig, a_exp, true); + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + + dbg_decouple("fpa2bv_r2i_unpacked_sig", a_sig); + dbg_decouple("fpa2bv_r2i_unpacked_exp", a_exp); expr_ref exp_is_small(m), exp_h(m), one_1(m); exp_h = m_bv_util.mk_extract(ebits-1, ebits-1, a_exp); @@ -1456,8 +1473,8 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a // otherwise: the actual conversion with rounding. sort * s = f->get_range(); - expr_ref sgn(m), sig(m), exp(m); - unpack(x, sgn, sig, exp, true); + expr_ref sgn(m), sig(m), exp(m), lz(m); + unpack(x, sgn, sig, exp, lz, true); expr_ref res_sgn(m), res_sig(m), res_exp(m); @@ -1818,7 +1835,7 @@ void fpa2bv_converter::mk_unbias(expr * e, expr_ref & result) { result = m_bv_util.mk_concat(n_leading, rest); } -void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp, bool normalize) { +void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & lz, bool normalize) { SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_TO_FLOAT)); SASSERT(to_app(e)->get_num_args() == 3); @@ -1837,23 +1854,29 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref expr_ref normal_sig(m), normal_exp(m); normal_sig = m_bv_util.mk_concat(m_bv_util.mk_numeral(1, 1), sig); mk_unbias(exp, normal_exp); + dbg_decouple("fpa2bv_unpack_normal_exp", normal_exp); expr_ref denormal_sig(m), denormal_exp(m); - denormal_sig = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, 1), sig); + denormal_sig = m_bv_util.mk_zero_extend(1, sig); denormal_exp = m_bv_util.mk_numeral(1, ebits); mk_unbias(denormal_exp, denormal_exp); + dbg_decouple("fpa2bv_unpack_denormal_exp", denormal_exp); - dbg_decouple("fpa2bv_unpack_denormal_exp", denormal_exp); + expr_ref zero_e(m); + zero_e = m_bv_util.mk_numeral(0, ebits); if (normalize) { - expr_ref is_sig_zero(m), shift(m), lz(m), zero_s(m), zero_e(m); - zero_s = m_bv_util.mk_numeral(0, sbits-1); - zero_e = m_bv_util.mk_numeral(0, ebits); - m_simp.mk_eq(zero_s, sig, is_sig_zero); - mk_leading_zeros(sig, ebits, lz); - m_simp.mk_ite(is_sig_zero, zero_e, lz, shift); - SASSERT(is_well_sorted(m, is_sig_zero)); - SASSERT(is_well_sorted(m, lz)); + expr_ref lz_d(m); + mk_leading_zeros(denormal_sig, ebits, lz_d); + m_simp.mk_ite(is_normal, zero_e, lz_d, lz); + dbg_decouple("fpa2bv_unpack_lz", lz); + + expr_ref is_sig_zero(m), shift(m), zero_s(m); + zero_s = m_bv_util.mk_numeral(0, sbits); + m_simp.mk_eq(zero_s, denormal_sig, is_sig_zero); + m_simp.mk_ite(is_sig_zero, zero_e, lz, shift); + dbg_decouple("fpa2bv_unpack_shift", shift); + SASSERT(is_well_sorted(m, is_sig_zero)); SASSERT(is_well_sorted(m, shift)); SASSERT(m_bv_util.get_bv_size(shift) == ebits); if (ebits <= sbits) { @@ -1872,10 +1895,11 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref m_simp.mk_eq(zero_s, sh, is_sh_zero); short_shift = m_bv_util.mk_extract(sbits-1, 0, shift); m_simp.mk_ite(is_sh_zero, short_shift, sbits_s, sl); - denormal_sig = m_bv_util.mk_bv_shl(denormal_sig, sl); - } - denormal_exp = m_bv_util.mk_bv_sub(denormal_exp, shift); + denormal_sig = m_bv_util.mk_bv_shl(denormal_sig, sl); + } } + else + lz = zero_e; SASSERT(is_well_sorted(m, normal_sig)); SASSERT(is_well_sorted(m, denormal_sig)); @@ -2020,8 +2044,12 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & dbg_decouple("fpa2bv_rnd_beta", beta); - expr_ref sigma(m), sigma_add(m); - sigma_add = m_bv_util.mk_bv_add(exp, m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits-1), ebits+2)); + dbg_decouple("fpa2bv_rnd_e_min", e_min); + dbg_decouple("fpa2bv_rnd_e_max", e_max); + + expr_ref sigma(m), sigma_add(m), e_min_p2(m); + sigma_add = m_bv_util.mk_bv_sub(exp, m_bv_util.mk_sign_extend(2, e_min)); + sigma_add = m_bv_util.mk_bv_add(sigma_add, m_bv_util.mk_numeral(1, ebits+2)); m_simp.mk_ite(TINY, sigma_add, lz, sigma); dbg_decouple("fpa2bv_rnd_sigma", sigma); @@ -2034,7 +2062,8 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & unsigned sig_size = m_bv_util.get_bv_size(sig); SASSERT(sig_size == sbits+4); - unsigned sigma_size = m_bv_util.get_bv_size(sigma); + SASSERT(m_bv_util.get_bv_size(sigma) == ebits+2); + unsigned sigma_size = ebits+2; expr_ref sigma_neg(m), sigma_cap(m), sigma_neg_capped(m), sigma_lt_zero(m), sig_ext(m), rs_sig(m), ls_sig(m), big_sh_sig(m), sigma_le_cap(m); diff --git a/src/tactic/fpa/fpa2bv_converter.h b/src/tactic/fpa/fpa2bv_converter.h index 6ac1d2b8b..e5d546763 100644 --- a/src/tactic/fpa/fpa2bv_converter.h +++ b/src/tactic/fpa/fpa2bv_converter.h @@ -135,7 +135,7 @@ protected: void mk_bias(expr * e, expr_ref & result); void mk_unbias(expr * e, expr_ref & result); - void unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp, bool normalize); + void unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & lz, bool normalize); void round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & result); void add_core(unsigned sbits, unsigned ebits, expr_ref & rm, From 5915533170b069e1b74a1e7fe5e14b263a48e299 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 5 Apr 2013 15:27:05 +0100 Subject: [PATCH 88/97] FPA: bugfix for corner-case sign of division Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 6d39dbfc4..84a1efaff 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -711,11 +711,11 @@ void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, mk_is_ninf(y, c5); mk_ite(x_is_inf, nan, xy_zero, v5); - // (y is 0) -> if (x is 0) then NaN else inf with x's sign. + // (y is 0) -> if (x is 0) then NaN else inf with xor sign. c6 = y_is_zero; - expr_ref x_sgn_inf(m); - mk_ite(x_is_pos, pinf, ninf, x_sgn_inf); - mk_ite(x_is_zero, nan, x_sgn_inf, v6); + expr_ref sgn_inf(m); + mk_ite(signs_xor, ninf, pinf, sgn_inf); + mk_ite(x_is_zero, nan, sgn_inf, v6); // (x is 0) -> result is zero with sgn = x.sgn^y.sgn // This is a special case to avoid problems with the unpacking of zero. From 5f298b69659a9955b50e96100f541989e2ce58b8 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 5 Apr 2013 18:02:41 -0700 Subject: [PATCH 89/97] spread some static love Signed-off-by: Nuno Lopes --- src/muz_qe/dl_mk_similarity_compressor.cpp | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/muz_qe/dl_mk_similarity_compressor.cpp b/src/muz_qe/dl_mk_similarity_compressor.cpp index 9868c82f6..9855196c9 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.cpp +++ b/src/muz_qe/dl_mk_similarity_compressor.cpp @@ -42,7 +42,7 @@ namespace datalog { /** Allows to traverse head and positive tails in a single for loop starting from -1 */ - app * get_by_tail_index(rule * r, int idx) { + static app * get_by_tail_index(rule * r, int idx) { if(idx==-1) { return r->get_head(); } @@ -51,11 +51,11 @@ namespace datalog { } template - int aux_compare(T a, T b) { + static int aux_compare(T a, T b) { return (a>b) ? 1 : ( (a==b) ? 0 : -1); } - int compare_var_args(app* t1, app* t2) { + static int compare_var_args(app* t1, app* t2) { SASSERT(t1->get_num_args()==t2->get_num_args()); int res; unsigned n = t1->get_num_args(); @@ -73,7 +73,7 @@ namespace datalog { return 0; } - int compare_args(app* t1, app* t2, int & skip_countdown) { + static int compare_args(app* t1, app* t2, int & skip_countdown) { SASSERT(t1->get_num_args()==t2->get_num_args()); int res; unsigned n = t1->get_num_args(); @@ -98,7 +98,7 @@ namespace datalog { Two rules are in the same rough similarity class if they differ only in constant arguments of positive uninterpreted predicates. */ - int rough_compare(rule * r1, rule * r2) { + static int rough_compare(rule * r1, rule * r2) { int res = aux_compare(r1->get_tail_size(), r2->get_tail_size()); if(res!=0) { return res; } res = aux_compare(r1->get_uninterpreted_tail_size(), r2->get_uninterpreted_tail_size()); @@ -129,7 +129,7 @@ namespace datalog { \c r1 and \c r2 must be equal according to the \c rough_compare function for this function to be called. */ - int total_compare(rule * r1, rule * r2, int skipped_arg_index = INT_MAX) { + static int total_compare(rule * r1, rule * r2, int skipped_arg_index = INT_MAX) { SASSERT(rough_compare(r1, r2)==0); int pos_tail_sz = r1->get_positive_tail_size(); for(int i=-1; i info_vector; - void collect_const_indexes(app * t, int tail_index, info_vector & res) { + static void collect_const_indexes(app * t, int tail_index, info_vector & res) { unsigned n = t->get_num_args(); for(unsigned i=0; iget_arg(i))) { @@ -175,7 +175,7 @@ namespace datalog { } } - void collect_const_indexes(rule * r, info_vector & res) { + static void collect_const_indexes(rule * r, info_vector & res) { collect_const_indexes(r->get_head(), -1, res); unsigned pos_tail_sz = r->get_positive_tail_size(); for(unsigned i=0; i - void collect_orphan_consts(rule * r, const info_vector & const_infos, T & tgt) { + static void collect_orphan_consts(rule * r, const info_vector & const_infos, T & tgt) { unsigned const_cnt = const_infos.size(); tgt.reset(); for(unsigned i=0; i - void collect_orphan_sorts(rule * r, const info_vector & const_infos, T & tgt) { + static void collect_orphan_sorts(rule * r, const info_vector & const_infos, T & tgt) { unsigned const_cnt = const_infos.size(); tgt.reset(); for(unsigned i=0; i1); unsigned const_cnt = const_infos.size(); @@ -252,7 +252,7 @@ namespace datalog { first constant that is equal to it in all the rules. If there is no such, it will contain its own index. */ - void detect_equal_constants(rule_vector::iterator first, rule_vector::iterator after_last, + static void detect_equal_constants(rule_vector::iterator first, rule_vector::iterator after_last, info_vector & const_infos) { SASSERT(first!=after_last); unsigned const_cnt = const_infos.size(); @@ -302,7 +302,7 @@ namespace datalog { } } - unsigned get_constant_count(rule * r) { + static unsigned get_constant_count(rule * r) { unsigned res = r->get_head()->get_num_args() - count_variable_arguments(r->get_head()); unsigned pos_tail_sz = r->get_positive_tail_size(); for(unsigned i=0; i0; } return total_compare(r1, r2)>0; From 1ef17cbe679884c434a95c2039959f2c0cd61034 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 5 Apr 2013 18:12:58 -0700 Subject: [PATCH 90/97] add dl_context::has_facts(pred) Signed-off-by: Nuno Lopes --- src/muz_qe/dl_context.cpp | 4 ++++ src/muz_qe/dl_context.h | 1 + src/muz_qe/rel_context.cpp | 5 +++++ src/muz_qe/rel_context.h | 7 ++++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 852d8f847..7a1e3b8fc 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -780,6 +780,10 @@ namespace datalog { add_fact(head->get_decl(), fact); } + bool context::has_facts(func_decl * pred) const { + return m_rel && m_rel->has_facts(pred); + } + void context::add_table_fact(func_decl * pred, const table_fact & fact) { if (get_engine() == DATALOG_ENGINE) { ensure_rel(); diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index cb432d4e9..d23cf2c0c 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -249,6 +249,7 @@ namespace datalog { void add_fact(app * head); void add_fact(func_decl * pred, const relation_fact & fact); + bool has_facts(func_decl * pred) const; void add_rule(rule_ref& r); void add_rules(rule_ref_vector& rs); diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 12045047b..58263b9d0 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -497,6 +497,11 @@ namespace datalog { } } + bool rel_context::has_facts(func_decl * pred) const { + relation_base* r = try_get_relation(pred); + return r && !r->empty(); + } + void rel_context::store_relation(func_decl * pred, relation_base * rel) { get_rmanager().store_relation(pred, rel); } diff --git a/src/muz_qe/rel_context.h b/src/muz_qe/rel_context.h index 08ee868c0..d2f6973da 100644 --- a/src/muz_qe/rel_context.h +++ b/src/muz_qe/rel_context.h @@ -92,9 +92,14 @@ namespace datalog { */ bool result_contains_fact(relation_fact const& f); + /** \brief add facts to relation + */ void add_fact(func_decl* pred, relation_fact const& fact); - void add_fact(func_decl* pred, table_fact const& fact); + + /** \brief check if facts were added to relation + */ + bool has_facts(func_decl * pred) const; /** \brief Store the relation \c rel under the predicate \c pred. The \c context object From 03c1b24dea7a5eec1747968a829ae7e014aa4809 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 8 Apr 2013 14:25:25 -0700 Subject: [PATCH 91/97] Fix get_int64 and is_int64 methods in mpz. Fix INT64_MAX constant definition. Signed-off-by: Leonardo de Moura --- src/util/mpz.cpp | 15 ++++----------- src/util/mpz.h | 24 ++++++++++++++++++++++++ src/util/util.h | 2 +- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index c77978647..9473621cf 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -1299,9 +1299,9 @@ bool mpz_manager::is_int64(mpz const & a) const { if (is_small(a)) return true; #ifndef _MP_GMP - if (!is_uint64(a)) + if (!is_abs_uint64(a)) return false; - uint64 num = get_uint64(a); + uint64 num = big_abs_to_uint64(a); uint64 msb = static_cast(1) << 63; uint64 msb_val = msb & num; if (a.m_val >= 0) { @@ -1327,14 +1327,7 @@ uint64 mpz_manager::get_uint64(mpz const & a) const { return static_cast(a.m_val); #ifndef _MP_GMP SASSERT(a.m_ptr->m_size > 0); - if (a.m_ptr->m_size == 1) - return digits(a)[0]; - if (sizeof(digit_t) == sizeof(uint64)) - // 64-bit machine - return digits(a)[0]; - else - // 32-bit machine - return ((static_cast(digits(a)[1]) << 32) | (static_cast(digits(a)[0]))); + return big_abs_to_uint64(a); #else // GMP version if (sizeof(uint64) == sizeof(unsigned long)) { @@ -1359,7 +1352,7 @@ int64 mpz_manager::get_int64(mpz const & a) const { return static_cast(a.m_val); #ifndef _MP_GMP SASSERT(is_int64(a)); - uint64 num = get_uint64(a); + uint64 num = big_abs_to_uint64(a); if (a.m_val < 0) { if (num != 0 && (num << 1) == 0) return INT64_MIN; diff --git a/src/util/mpz.h b/src/util/mpz.h index b5c301d82..7b40a89f5 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -211,6 +211,30 @@ class mpz_manager { static digit_t * digits(mpz const & c) { return c.m_ptr->m_digits; } + // Return true if the absolute value fits in a UINT64 + static bool is_abs_uint64(mpz const & a) { + if (is_small(a)) + return true; + if (sizeof(digit_t) == sizeof(uint64)) + return size(a) <= 1; + else + return size(a) <= 2; + } + + // CAST the absolute value into a UINT64 + static uint64 big_abs_to_uint64(mpz const & a) { + SASSERT(is_abs_uint64(a)); + SASSERT(!is_small(a)); + if (a.m_ptr->m_size == 1) + return digits(a)[0]; + if (sizeof(digit_t) == sizeof(uint64)) + // 64-bit machine + return digits(a)[0]; + else + // 32-bit machine + return ((static_cast(digits(a)[1]) << 32) | (static_cast(digits(a)[0]))); + } + template void get_sign_cell(mpz const & a, int & sign, mpz_cell * & cell) { if (is_small(a)) { diff --git a/src/util/util.h b/src/util/util.h index 8bcbce4a3..0aa8f881d 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -45,7 +45,7 @@ COMPILE_TIME_ASSERT(sizeof(int64) == 8); #define INT64_MIN static_cast(0x8000000000000000ull) #endif #ifndef INT64_MAX -#define INT64_MAX static_cast(0x0fffffffffffffffull) +#define INT64_MAX static_cast(0x7fffffffffffffffull) #endif #ifndef UINT64_MAX #define UINT64_MAX 0xffffffffffffffffull From 3d34aa7f010cab7dceacd756ddbf7dbd8c74687a Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 8 Apr 2013 14:50:17 -0700 Subject: [PATCH 92/97] Fix is_int64 bug in mpz when compiling with GMP Signed-off-by: Leonardo de Moura --- src/test/rational.cpp | 2 +- src/util/mpz.cpp | 5 ++++- src/util/mpz.h | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/rational.cpp b/src/test/rational.cpp index 9cbcdb00e..834aab92f 100644 --- a/src/test/rational.cpp +++ b/src/test/rational.cpp @@ -171,7 +171,7 @@ static void tst2() { rational int64_max("9223372036854775807"); - rational int64_min(-int64_max - rational(1)); + rational int64_min((-int64_max) - rational(1)); // is_int64 SASSERT(int64_max.is_int64()); SASSERT(int64_min.is_int64()); diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 9473621cf..a7c904c64 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -128,6 +128,8 @@ mpz_manager::mpz_manager(): mpz_mul(m_int64_max, m_tmp, m_int64_max); mpz_set_ui(m_tmp, max_l); mpz_add(m_int64_max, m_tmp, m_int64_max); + mpz_neg(m_int64_min, m_int64_max); + mpz_sub_ui(m_int64_min, m_int64_min, 1); #endif mpz one(1); @@ -152,6 +154,7 @@ mpz_manager::~mpz_manager() { deallocate(m_arg[1]); mpz_clear(m_uint64_max); mpz_clear(m_int64_max); + mpz_clear(m_int64_min); #endif if (SYNCH) omp_destroy_nest_lock(&m_lock); @@ -1317,7 +1320,7 @@ bool mpz_manager::is_int64(mpz const & a) const { } #else // GMP version - return mpz_cmp(*a.m_ptr, m_int64_max) <= 0; + return mpz_cmp(m_int64_min, *a.m_ptr) <= 0 && mpz_cmp(*a.m_ptr, m_int64_max) <= 0; #endif } diff --git a/src/util/mpz.h b/src/util/mpz.h index 7b40a89f5..923d5b3a7 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -168,6 +168,7 @@ class mpz_manager { mpz_t * m_arg[2]; mpz_t m_uint64_max; mpz_t m_int64_max; + mpz_t m_int64_min; mpz_t * allocate() { mpz_t * cell = reinterpret_cast(m_allocator.allocate(sizeof(mpz_t))); From 75ad174567627e7da15fa365e8a564f1ee96122c Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 8 Apr 2013 15:02:51 -0700 Subject: [PATCH 93/97] Initialize int64_min constant when using GMP Signed-off-by: Leonardo de Moura --- src/util/mpz.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index a7c904c64..bd7f30a76 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -120,6 +120,7 @@ mpz_manager::mpz_manager(): mpz_set_ui(m_tmp, max_l); mpz_add(m_uint64_max, m_uint64_max, m_tmp); mpz_init(m_int64_max); + mpz_init(m_int64_min); max_l = static_cast(INT64_MAX % static_cast(UINT_MAX)); max_h = static_cast(INT64_MAX / static_cast(UINT_MAX)); From 90c808bde91fc010b699003076345327017f074b Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 8 Apr 2013 17:14:43 -0700 Subject: [PATCH 94/97] [datalog] fix memory leak in union instructions the source operand was never cleaned up Signed-off-by: Nuno Lopes --- src/muz_qe/dl_compiler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index c898f7964..acedc3619 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -707,6 +707,7 @@ namespace datalog { //update the head relation make_union(new_head_reg, head_reg, delta_reg, use_widening, acc); + make_dealloc_non_void(new_head_reg, acc); } finish: From 93297fa9e72f750fc8115f0568217f474888563e Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 8 Apr 2013 18:00:43 -0700 Subject: [PATCH 95/97] Fix bug in purify_arith reported at https://z3.codeplex.com/workitem/32 Signed-off-by: Leonardo de Moura --- src/tactic/arith/purify_arith_tactic.cpp | 61 +++++++++++------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 169e27927..1a38ac10e 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -29,6 +29,7 @@ Revision History: #include"th_rewriter.h" #include"filter_model_converter.h" #include"ast_smt2_pp.h" +#include"expr_replacer.h" /* ---- @@ -131,18 +132,16 @@ struct purify_arith_proc { proof_ref_vector m_new_cnstr_prs; expr_ref m_subst; proof_ref m_subst_pr; - bool m_in_q; - unsigned m_var_idx; + expr_ref_vector m_new_vars; - rw_cfg(purify_arith_proc & o, bool in_q): + rw_cfg(purify_arith_proc & o): m_owner(o), m_pinned(o.m()), m_new_cnstrs(o.m()), m_new_cnstr_prs(o.m()), m_subst(o.m()), m_subst_pr(o.m()), - m_in_q(in_q), - m_var_idx(0) { + m_new_vars(o.m()) { } ast_manager & m() { return m_owner.m(); } @@ -155,14 +154,9 @@ struct purify_arith_proc { bool elim_inverses() const { return m_owner.m_elim_inverses; } expr * mk_fresh_var(bool is_int) { - if (m_in_q) { - unsigned idx = m_var_idx; - m_var_idx++; - return m().mk_var(idx, is_int ? u().mk_int() : u().mk_real()); - } - else { - return m().mk_fresh_const(0, is_int ? u().mk_int() : u().mk_real()); - } + expr * r = m().mk_fresh_const(0, is_int ? u().mk_int() : u().mk_real()); + m_new_vars.push_back(r); + return r; } expr * mk_fresh_real_var() { return mk_fresh_var(false); } @@ -596,9 +590,9 @@ struct purify_arith_proc { struct rw : public rewriter_tpl { rw_cfg m_cfg; - rw(purify_arith_proc & o, bool in_q): + rw(purify_arith_proc & o): rewriter_tpl(o.m(), o.m_produce_proofs, m_cfg), - m_cfg(o, in_q) { + m_cfg(o) { } }; @@ -661,40 +655,43 @@ struct purify_arith_proc { void process_quantifier(quantifier * q, expr_ref & result, proof_ref & result_pr) { result_pr = 0; - num_vars_proc p(u(), m_elim_root_objs); - expr_ref body(m()); - unsigned num_vars = p(q->get_expr()); - if (num_vars > 0) { - // open space for aux vars - var_shifter shifter(m()); - shifter(q->get_expr(), num_vars, body); - } - else { - body = q->get_expr(); - } - - rw r(*this, true); + rw r(*this); expr_ref new_body(m()); proof_ref new_body_pr(m()); - r(body, new_body, new_body_pr); + r(q->get_expr(), new_body, new_body_pr); + unsigned num_vars = r.cfg().m_new_vars.size(); TRACE("purify_arith", tout << "num_vars: " << num_vars << "\n"; - tout << "body: " << mk_ismt2_pp(body, m()) << "\nnew_body: " << mk_ismt2_pp(new_body, m()) << "\n";); + tout << "body: " << mk_ismt2_pp(q->get_expr(), m()) << "\nnew_body: " << mk_ismt2_pp(new_body, m()) << "\n";); if (num_vars == 0) { + SASSERT(r.cfg().m_new_cnstrs.empty()); result = m().update_quantifier(q, new_body); if (m_produce_proofs) result_pr = m().mk_quant_intro(q, to_quantifier(result.get()), result_pr); } else { + // Add new constraints expr_ref_vector & cnstrs = r.cfg().m_new_cnstrs; cnstrs.push_back(new_body); new_body = m().mk_and(cnstrs.size(), cnstrs.c_ptr()); + // Open space for new variables + var_shifter shifter(m()); + shifter(new_body, num_vars, new_body); + // Rename fresh constants in r.cfg().m_new_vars to variables ptr_buffer sorts; buffer names; + expr_substitution subst(m(), false, false); for (unsigned i = 0; i < num_vars; i++) { - sorts.push_back(u().mk_real()); + expr * c = r.cfg().m_new_vars.get(i); + sort * s = get_sort(c); + sorts.push_back(s); names.push_back(m().mk_fresh_var_name("x")); + unsigned idx = num_vars - i - 1; + subst.insert(c, m().mk_var(idx, s)); } + scoped_ptr replacer = mk_default_expr_replacer(m()); + replacer->set_substitution(&subst); + (*replacer)(new_body, new_body); new_body = m().mk_exists(num_vars, sorts.c_ptr(), names.c_ptr(), new_body); result = m().update_quantifier(q, new_body); if (m_produce_proofs) { @@ -708,7 +705,7 @@ struct purify_arith_proc { } void operator()(goal & g, model_converter_ref & mc, bool produce_models) { - rw r(*this, false); + rw r(*this); // purify expr_ref new_curr(m()); proof_ref new_pr(m()); From 8627f6f1d5e5afc23335c29ad150ef375d07cb16 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 8 Apr 2013 18:02:28 -0700 Subject: [PATCH 96/97] Remove dead code Signed-off-by: Leonardo de Moura --- src/tactic/arith/purify_arith_tactic.cpp | 57 ------------------------ 1 file changed, 57 deletions(-) diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 1a38ac10e..f2ddd86ce 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -595,63 +595,6 @@ struct purify_arith_proc { m_cfg(o) { } }; - - /** - \brief Return the number of (auxiliary) variables needed for converting an expression. - */ - struct num_vars_proc { - arith_util & m_util; - expr_fast_mark1 m_visited; - ptr_vector m_todo; - unsigned m_num_vars; - bool m_elim_root_objs; - - num_vars_proc(arith_util & u, bool elim_root_objs): - m_util(u), - m_elim_root_objs(elim_root_objs) { - } - - void visit(expr * t) { - if (m_visited.is_marked(t)) - return; - m_visited.mark(t); - m_todo.push_back(t); - } - - void process(app * t) { - if (t->get_family_id() == m_util.get_family_id()) { - if (m_util.is_power(t)) { - rational k; - if (m_util.is_numeral(t->get_arg(1), k) && (k.is_zero() || !k.is_int())) { - m_num_vars++; - } - } - else if (m_util.is_div(t) || - m_util.is_idiv(t) || - m_util.is_mod(t) || - m_util.is_to_int(t) || - (m_util.is_irrational_algebraic_numeral(t) && m_elim_root_objs)) { - m_num_vars++; - } - } - unsigned num_args = t->get_num_args(); - for (unsigned i = 0; i < num_args; i++) - visit(t->get_arg(i)); - } - - unsigned operator()(expr * t) { - m_num_vars = 0; - visit(t); - while (!m_todo.empty()) { - expr * t = m_todo.back(); - m_todo.pop_back(); - if (is_app(t)) - process(to_app(t)); - } - m_visited.reset(); - return m_num_vars; - } - }; void process_quantifier(quantifier * q, expr_ref & result, proof_ref & result_pr) { result_pr = 0; From d26f0e1c28e9784e5c931dc326cc300089d8d03b Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Tue, 9 Apr 2013 08:42:14 -0700 Subject: [PATCH 97/97] Fix bug in the SAT solver. Signed-off-by: Leonardo de Moura --- src/sat/sat_solver.cpp | 54 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 399fb2c61..3e9b60260 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1745,6 +1745,12 @@ namespace sat { mark_lit(m_lemma[i]); } + literal l0 = m_lemma[0]; + // l0 is the FUIP, and we never remove the FUIP. + // + // In the following loop, we use unmark_lit(l) to remove a + // literal from m_lemma. + for (unsigned i = 0; i < sz; i++) { literal l = m_lemma[i]; if (!is_marked_lit(l)) @@ -1754,9 +1760,15 @@ namespace sat { watch_list::const_iterator it = wlist.begin(); watch_list::const_iterator end = wlist.end(); for (; it != end; ++it) { + // In this for-loop, the conditions l0 != ~l2 and l0 != ~l3 + // are not really needed if the solver does not miss unit propagations. + // However, we add them anyway because we don't want to rely on this + // property of the propagator. + // For example, if this property is relaxed in the future, then the code + // without the conditions l0 != ~l2 and l0 != ~l3 may remove the FUIP if (it->is_binary_clause()) { literal l2 = it->get_literal(); - if (is_marked_lit(~l2)) { + if (is_marked_lit(~l2) && l0 != ~l2) { // eliminate ~l2 from lemma because we have the clause l \/ l2 unmark_lit(~l2); } @@ -1764,11 +1776,11 @@ namespace sat { else if (it->is_ternary_clause()) { literal l2 = it->get_literal1(); literal l3 = it->get_literal2(); - if (is_marked_lit(l2) && is_marked_lit(~l3)) { + if (is_marked_lit(l2) && is_marked_lit(~l3) && l0 != ~l3) { // eliminate ~l3 from lemma because we have the clause l \/ l2 \/ l3 unmark_lit(~l3); } - else if (is_marked_lit(~l2) && is_marked_lit(l3)) { + else if (is_marked_lit(~l2) && is_marked_lit(l3) && l0 != ~l2) { // eliminate ~l2 from lemma because we have the clause l \/ l2 \/ l3 unmark_lit(~l2); } @@ -1786,7 +1798,41 @@ namespace sat { literal_vector::iterator end = implied_lits->end(); for (; it != end; ++it) { literal l2 = *it; - if (is_marked_lit(~l2)) { + // Here, we must check l0 != ~l2. + // l \/ l2 is an implied binary clause. + // However, it may have been deduced using a lemma that has been deleted. + // For example, consider the following sequence of events: + // + // 1. Initial clause database: + // + // l \/ ~p1 + // p1 \/ ~p2 + // p2 \/ ~p3 + // p3 \/ ~p4 + // q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 + // q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 + // ~q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 + // ~q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 + // ... + // + // 2. Now suppose we learned the lemma + // + // p1 \/ p2 \/ p3 \/ p4 \/ l2 (*) + // + // 3. Probing is executed and we notice hat (~l => l2) when we assign l to false. + // That is, l \/ l2 is an implied clause. Note that probing does not add + // this clause to the clause database (there are too many). + // + // 4. Lemma (*) is deleted (garbage collected). + // + // 5. l is decided to be false, p1, p2, p3 and p4 are propagated using BCP, + // but l2 is not since the lemma (*) was deleted. + // + // Probing module still "knows" that l \/ l2 is valid binary clause + // + // 6. A new lemma is created where ~l2 is the FUIP and the lemma also contains l. + // If we remove l0 != ~l2 may try to delete the FUIP. + if (is_marked_lit(~l2) && l0 != ~l2) { // eliminate ~l2 from lemma because we have the clause l \/ l2 unmark_lit(~l2); }