3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-05 09:04:07 +00:00

integrate lambda expressions

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2018-06-26 07:23:04 -07:00
parent bf4edef761
commit 520ce9a5ee
139 changed files with 2243 additions and 1506 deletions

View file

@ -27,6 +27,7 @@ Version 4.8.0
Use sat.acce=true to enable the full repertoire of inprocessing methods. By default, clauses that are "eliminated" by acce are tagged
as lemmas (redundant) and are garbage collected if their glue level is high.
- Substantial overhaul of the spacer horn clause engine.
- Added basic features to support Lambda expressions.
- Removed features:
- interpolation API

View file

@ -47,6 +47,7 @@ extern "C" {
Z3_CATCH_RETURN(nullptr);
}
Z3_ast Z3_API Z3_mk_select(Z3_context c, Z3_ast a, Z3_ast i) {
Z3_TRY;
LOG_Z3_mk_select(c, a, i);
@ -99,6 +100,7 @@ extern "C" {
Z3_CATCH_RETURN(nullptr);
}
Z3_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v) {
Z3_TRY;
LOG_Z3_mk_store(c, a, i, v);
@ -155,6 +157,7 @@ extern "C" {
Z3_CATCH_RETURN(nullptr);
}
Z3_ast Z3_API Z3_mk_map(Z3_context c, Z3_func_decl f, unsigned n, Z3_ast const* args) {
Z3_TRY;
LOG_Z3_mk_map(c, f, n, args);

View file

@ -808,8 +808,7 @@ extern "C" {
expr * a = to_expr(_a);
expr * const * to = to_exprs(_to);
var_subst subst(m, false);
expr_ref new_a(m);
subst(a, num_exprs, to, new_a);
expr_ref new_a = subst(a, num_exprs, to);
mk_c(c)->save_ast_trail(new_a);
RETURN_Z3(of_expr(new_a.get()));
Z3_CATCH_RETURN(nullptr);
@ -910,6 +909,7 @@ extern "C" {
case PR_TRANSITIVITY_STAR: return Z3_OP_PR_TRANSITIVITY_STAR;
case PR_MONOTONICITY: return Z3_OP_PR_MONOTONICITY;
case PR_QUANT_INTRO: return Z3_OP_PR_QUANT_INTRO;
case PR_BIND: return Z3_OP_PR_BIND;
case PR_DISTRIBUTIVITY: return Z3_OP_PR_DISTRIBUTIVITY;
case PR_AND_ELIM: return Z3_OP_PR_AND_ELIM;
case PR_NOT_OR_ELIM: return Z3_OP_PR_NOT_OR_ELIM;

View file

@ -173,6 +173,7 @@ extern "C" {
to_optimize_ptr(o)->get_model(_m);
Z3_model_ref * m_ref = alloc(Z3_model_ref, *mk_c(c));
if (_m) {
if (mk_c(c)->params().m_model_compress) _m->compress();
m_ref->m_model = _m;
}
else {

View file

@ -90,7 +90,7 @@ extern "C" {
expr_ref result(mk_c(c)->m());
if (num_decls > 0) {
result = mk_c(c)->m().mk_quantifier(
(0 != is_forall),
is_forall ? forall_k : exists_k,
names.size(), ts, names.c_ptr(), to_expr(body),
weight,
qid,
@ -144,6 +144,61 @@ extern "C" {
return Z3_mk_quantifier(c, 0, weight, num_patterns, patterns, num_decls, types, decl_names, body);
}
Z3_ast Z3_API Z3_mk_lambda(Z3_context c,
unsigned num_decls, Z3_sort const types[],
Z3_symbol const decl_names[],
Z3_ast body) {
Z3_TRY;
LOG_Z3_mk_lambda(c, num_decls, types, decl_names, body);
RESET_ERROR_CODE();
expr_ref result(mk_c(c)->m());
if (num_decls == 0) {
SET_ERROR_CODE(Z3_INVALID_USAGE);
RETURN_Z3(0);
}
sort* const* ts = reinterpret_cast<sort * const*>(types);
svector<symbol> names;
for (unsigned i = 0; i < num_decls; ++i) {
names.push_back(to_symbol(decl_names[i]));
}
result = mk_c(c)->m().mk_lambda(names.size(), ts, names.c_ptr(), to_expr(body));
mk_c(c)->save_ast_trail(result.get());
return of_ast(result.get());
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_mk_lambda_const(Z3_context c,
unsigned num_decls, Z3_app const vars[],
Z3_ast body) {
Z3_TRY;
LOG_Z3_mk_lambda_const(c, num_decls, vars, body);
RESET_ERROR_CODE();
if (num_decls == 0) {
SET_ERROR_CODE(Z3_INVALID_USAGE);
RETURN_Z3(0);
}
svector<symbol> _names;
ptr_vector<sort> _vars;
ptr_vector<expr> _args;
for (unsigned i = 0; i < num_decls; ++i) {
app* a = to_app(vars[i]);
_names.push_back(to_app(a)->get_decl()->get_name());
_args.push_back(a);
_vars.push_back(mk_c(c)->m().get_sort(a));
}
expr_ref result(mk_c(c)->m());
expr_abstract(mk_c(c)->m(), 0, num_decls, _args.c_ptr(), to_expr(body), result);
result = mk_c(c)->m().mk_lambda(_vars.size(), _vars.c_ptr(), _names.c_ptr(), result);
mk_c(c)->save_ast_trail(result.get());
return of_ast(result.get());
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_mk_quantifier_const_ex(Z3_context c,
Z3_bool is_forall,
@ -292,17 +347,27 @@ extern "C" {
Z3_TRY;
LOG_Z3_is_quantifier_forall(c, a);
RESET_ERROR_CODE();
ast * _a = to_ast(a);
if (_a->get_kind() == AST_QUANTIFIER) {
return to_quantifier(_a)->is_forall();
}
else {
SET_ERROR_CODE(Z3_SORT_ERROR);
return Z3_FALSE;
}
return ::is_forall(to_ast(a)) ? Z3_TRUE : Z3_FALSE;
Z3_CATCH_RETURN(Z3_FALSE);
}
Z3_bool Z3_API Z3_is_quantifier_exists(Z3_context c, Z3_ast a) {
Z3_TRY;
LOG_Z3_is_quantifier_exists(c, a);
RESET_ERROR_CODE();
return ::is_exists(to_ast(a)) ? Z3_TRUE : Z3_FALSE;
Z3_CATCH_RETURN(Z3_FALSE);
}
Z3_bool Z3_API Z3_is_lambda(Z3_context c, Z3_ast a) {
Z3_TRY;
LOG_Z3_is_lambda(c, a);
RESET_ERROR_CODE();
return ::is_lambda(to_ast(a)) ? Z3_TRUE : Z3_FALSE;
Z3_CATCH_RETURN(Z3_FALSE);
}
unsigned Z3_API Z3_get_quantifier_weight(Z3_context c, Z3_ast a) {
Z3_TRY;
LOG_Z3_get_quantifier_weight(c, a);
@ -485,3 +550,4 @@ extern "C" {
}
};

View file

@ -433,6 +433,9 @@ extern "C" {
SET_ERROR_CODE(Z3_INVALID_USAGE);
RETURN_Z3(nullptr);
}
if (_m) {
if (mk_c(c)->params().m_model_compress) _m->compress();
}
Z3_model_ref * m_ref = alloc(Z3_model_ref, *mk_c(c));
m_ref->m_model = _m;
mk_c(c)->save_object(m_ref);

View file

@ -252,7 +252,6 @@ namespace z3 {
*/
sort array_sort(sort d, sort r);
sort array_sort(sort_vector const& 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,
@ -675,7 +674,21 @@ namespace z3 {
\brief Return true if this expression is a quantifier.
*/
bool is_quantifier() const { return kind() == Z3_QUANTIFIER_AST; }
/**
\brief Return true if this expression is a universal quantifier.
*/
bool is_forall() const { return 0 != Z3_is_quantifier_forall(ctx(), m_ast); }
/**
\brief Return true if this expression is an existential quantifier.
*/
bool is_exists() const { return 0 != Z3_is_quantifier_exists(ctx(), m_ast); }
/**
\brief Return true if this expression is a lambda expression.
*/
bool is_lambda() const { return 0 != Z3_is_lambda(ctx(), m_ast); }
/**
\brief Return true if this expression is a variable.
*/
bool is_var() const { return kind() == Z3_VAR_AST; }
@ -1638,6 +1651,31 @@ namespace z3 {
array<Z3_app> vars(xs);
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr lambda(expr const & x, expr const & b) {
check_context(x, b);
Z3_app vars[] = {(Z3_app) x};
Z3_ast r = Z3_mk_lambda_const(b.ctx(), 1, vars, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr lambda(expr const & x1, expr const & x2, expr const & b) {
check_context(x1, b); check_context(x2, b);
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2};
Z3_ast r = Z3_mk_lambda_const(b.ctx(), 2, vars, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr lambda(expr const & x1, expr const & x2, expr const & x3, expr const & b) {
check_context(x1, b); check_context(x2, b); check_context(x3, b);
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 };
Z3_ast r = Z3_mk_lambda_const(b.ctx(), 3, vars, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr lambda(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) {
check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b);
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 };
Z3_ast r = Z3_mk_lambda_const(b.ctx(), 4, vars, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr lambda(expr_vector const & xs, expr const & b) {
array<Z3_app> vars(xs);
Z3_ast r = Z3_mk_lambda_const(b.ctx(), vars.size(), vars.ptr(), b); b.check_error(); return expr(b.ctx(), r);
}
inline expr pble(expr_vector const& es, int const* coeffs, int bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
@ -2521,7 +2559,6 @@ namespace z3 {
array<Z3_sort> dom(d);
Z3_sort s = Z3_mk_array_sort_n(m_ctx, dom.size(), dom.ptr(), 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<Z3_symbol> _enum_names(n);
for (unsigned i = 0; i < n; i++) { _enum_names[i] = Z3_mk_string_symbol(*this, enum_names[i]); }
@ -2785,12 +2822,8 @@ namespace z3 {
a.check_error();
return expr(a.ctx(), r);
}
inline expr select(expr const & a, int i) { return select(a, a.ctx().num_val(i, a.get_sort().array_domain())); }
inline expr store(expr const & a, expr const & i, expr const & v) {
check_context(a, i); check_context(a, v);
Z3_ast r = Z3_mk_store(a.ctx(), a, i, v);
a.check_error();
return expr(a.ctx(), r);
inline expr select(expr const & a, int i) {
return select(a, a.ctx().num_val(i, a.get_sort().array_domain()));
}
inline expr select(expr const & a, expr_vector const & i) {
check_context(a, i);
@ -2800,6 +2833,13 @@ namespace z3 {
return expr(a.ctx(), r);
}
inline expr store(expr const & a, expr const & i, expr const & v) {
check_context(a, i); check_context(a, v);
Z3_ast r = Z3_mk_store(a.ctx(), a, i, v);
a.check_error();
return expr(a.ctx(), r);
}
inline expr store(expr const & a, int i, expr const & v) { return store(a, a.ctx().num_val(i, a.get_sort().array_domain()), v); }
inline expr store(expr const & a, expr i, int v) { return store(a, i, a.ctx().num_val(v, a.get_sort().array_range())); }
inline expr store(expr const & a, int i, int v) {

View file

@ -37,6 +37,6 @@ namespace Microsoft.Z3
{
Contract.Requires(ctx != null);
}
#endregion
#endregion
}
}

View file

@ -84,6 +84,7 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE
IntNum.cs
IntSort.cs
IntSymbol.cs
Lambda.cs
ListSort.cs
Log.cs
Model.cs

View file

@ -3292,6 +3292,53 @@ namespace Microsoft.Z3
return MkExists(boundConstants, body, weight, patterns, noPatterns, quantifierID, skolemID);
}
/// <summary>
/// Create a lambda expression.
/// </summary>
/// <remarks>
/// Creates a lambda expression.
/// <paramref name="sorts"/> is an array
/// with the sorts of the bound variables, <paramref name="names"/> is an array with the
/// 'names' of the bound variables, and <paramref name="body"/> is the body of the
/// lambda.
/// Note that the bound variables are de-Bruijn indices created using <see cref="MkBound"/>.
/// Z3 applies the convention that the last element in <paramref name="names"/> and
/// <paramref name="sorts"/> refers to the variable with index 0, the second to last element
/// of <paramref name="names"/> and <paramref name="sorts"/> refers to the variable
/// with index 1, etc.
/// </remarks>
/// <param name="sorts">the sorts of the bound variables.</param>
/// <param name="names">names of the bound variables</param>
/// <param name="body">the body of the quantifier.</param>
public Lambda MkLambda(Sort[] sorts, Symbol[] names, Expr body)
{
Contract.Requires(sorts != null);
Contract.Requires(names != null);
Contract.Requires(body != null);
Contract.Requires(sorts.Length == names.Length);
Contract.Requires(Contract.ForAll(sorts, s => s != null));
Contract.Requires(Contract.ForAll(names, n => n != null));
Contract.Ensures(Contract.Result<Lambda>() != null);
return new Lambda(this, sorts, names, body);
}
/// <summary>
/// Create a lambda expression.
/// </summary>
/// <remarks>
/// Creates a lambda expression using a list of constants that will
/// form the set of bound variables.
/// <seealso cref="MkLambda(Sort[], Symbol[], Expr)"/>
/// </remarks>
public Lambda MkLambda(Expr[] boundConstants, Expr body)
{
Contract.Requires(body != null);
Contract.Requires(boundConstants != null && Contract.ForAll(boundConstants, b => b != null));
Contract.Ensures(Contract.Result<Lambda>() != null);
return new Lambda(this, boundConstants, body);
}
#endregion
#endregion // Expr

View file

@ -41,7 +41,7 @@ namespace Microsoft.Z3
/// </summary>
public bool IsExistential
{
get { return !IsUniversal; }
get { return Native.Z3_is_quantifier_exists(Context.nCtx, NativeObject) != 0; }
}
/// <summary>

View file

@ -141,6 +141,7 @@ set(Z3_JAVA_JAR_SOURCE_FILES
IntNum.java
IntSort.java
IntSymbol.java
Lambda.java
ListSort.java
Log.java
ModelDecRefQueue.java

View file

@ -518,7 +518,7 @@ public class Context implements AutoCloseable {
/**
* Creates a fresh constant function declaration with a name prefixed with
* {@code prefix"}.
* {@code prefix}.
* @see #mkFuncDecl(String,Sort,Sort)
* @see #mkFuncDecl(String,Sort[],Sort)
**/
@ -696,7 +696,7 @@ public class Context implements AutoCloseable {
}
/**
* Creates the equality {@code x"/> = <paramref name="y}.
* Creates the equality {@code x = y}
**/
public BoolExpr mkEq(Expr x, Expr y)
{
@ -2498,6 +2498,40 @@ public class Context implements AutoCloseable {
quantifierID, skolemID);
}
/**
* Create a lambda expression.
*
* {@code sorts} is an array
* with the sorts of the bound variables, {@code names} is an array with the
* 'names' of the bound variables, and {@code body} is the body of the
* lambda.
* Note that the bound variables are de-Bruijn indices created using {@see #MkBound}
* Z3 applies the convention that the last element in {@code names} and
* {@code sorts} refers to the variable with index 0, the second to last element
* of {@code names} and {@code sorts} refers to the variable
* with index 1, etc.
*
* @param sorts the sorts of the bound variables.
* @param names names of the bound variables.
* @param body the body of the quantifier.
**/
public Lambda mkLambda(Sort[] sorts, Symbol[] names, Expr body)
{
return Lambda.of(this, sorts, names, body);
}
/**
* Create a lambda expression.
*
* Creates a lambda expression using a list of constants that will
* form the set of bound variables.
**/
public Lambda mkLambda(Expr[] boundConstants, Expr body)
{
return Lambda.of(this, boundConstants, body);
}
/**
* Selects the format used for pretty-printing expressions.
* Remarks: The
@ -2653,7 +2687,7 @@ public class Context implements AutoCloseable {
/**
* Create a tactic that applies {@code t1} to a Goal and then
* {@code t2"/> to every subgoal produced by <paramref name="t1}.
* {@code t2} to every subgoal produced by {@code t1}
**/
public Tactic andThen(Tactic t1, Tactic t2, Tactic... ts)
@ -2734,7 +2768,7 @@ public class Context implements AutoCloseable {
/**
* Create a tactic that applies {@code t1} to a given goal if the
* probe {@code p"/> evaluates to true and <paramref name="t2}
* probe {@code p} evaluates to true and {@code t2}
* otherwise.
**/
public Tactic cond(Probe p, Tactic t1, Tactic t2)
@ -2895,7 +2929,7 @@ public class Context implements AutoCloseable {
}
/**
* Create a probe that evaluates to "true" when the value returned by
* Create a probe that evaluates to {@code true} when the value returned by
* {@code p1} is less than the value returned by {@code p2}
**/
public Probe lt(Probe p1, Probe p2)
@ -2907,7 +2941,7 @@ public class Context implements AutoCloseable {
}
/**
* Create a probe that evaluates to "true" when the value returned by
* Create a probe that evaluates to {@code true} when the value returned by
* {@code p1} is greater than the value returned by {@code p2}
**/
public Probe gt(Probe p1, Probe p2)
@ -2919,7 +2953,7 @@ public class Context implements AutoCloseable {
}
/**
* Create a probe that evaluates to "true" when the value returned by
* Create a probe that evaluates to {@code true} when the value returned by
* {@code p1} is less than or equal the value returned by
* {@code p2}
**/
@ -2932,7 +2966,7 @@ public class Context implements AutoCloseable {
}
/**
* Create a probe that evaluates to "true" when the value returned by
* Create a probe that evaluates to {@code true} when the value returned by
* {@code p1} is greater than or equal the value returned by
* {@code p2}
**/
@ -2945,7 +2979,7 @@ public class Context implements AutoCloseable {
}
/**
* Create a probe that evaluates to "true" when the value returned by
* Create a probe that evaluates to {@code true} when the value returned by
* {@code p1} is equal to the value returned by {@code p2}
**/
public Probe eq(Probe p1, Probe p2)
@ -2957,7 +2991,7 @@ public class Context implements AutoCloseable {
}
/**
* Create a probe that evaluates to "true" when the value {@code p1} and {@code p2} evaluate to "true".
* Create a probe that evaluates to {@code true} when the value {@code p1} and {@code p2} evaluate to {@code true}.
**/
public Probe and(Probe p1, Probe p2)
{
@ -2968,7 +3002,7 @@ public class Context implements AutoCloseable {
}
/**
* Create a probe that evaluates to "true" when the value {@code p1} or {@code p2} evaluate to "true".
* Create a probe that evaluates to {@code true} when the value {@code p1} or {@code p2} evaluate to {@code true}.
**/
public Probe or(Probe p1, Probe p2)
{
@ -2979,7 +3013,7 @@ public class Context implements AutoCloseable {
}
/**
* Create a probe that evaluates to "true" when the value {@code p} does not evaluate to "true".
* Create a probe that evaluates to {@code true} when the value {@code p} does not evaluate to {@code true}.
**/
public Probe not(Probe p)
{

View file

@ -37,7 +37,7 @@ public class Quantifier extends BoolExpr
**/
public boolean isExistential()
{
return !isUniversal();
return Native.isQuantifierExists(getContext().nCtx(), getNativeObject());
}
/**

View file

@ -1766,6 +1766,34 @@ class QuantifierRef(BoolRef):
"""
return Z3_is_quantifier_forall(self.ctx_ref(), self.ast)
def is_exists(self):
"""Return `True` if `self` is an existential quantifier.
>>> f = Function('f', IntSort(), IntSort())
>>> x = Int('x')
>>> q = ForAll(x, f(x) == 0)
>>> q.is_exists()
False
>>> q = Exists(x, f(x) != 0)
>>> q.is_exists()
True
"""
return Z3_is_quantifier_exists(self.ctx_ref(), self.ast)
def is_lambda(self):
"""Return `True` if `self` is a lambda expression.
>>> f = Function('f', IntSort(), IntSort())
>>> x = Int('x')
>>> q = Lambda(x, f(x))
>>> q.is_lambda()
True
>>> q = Exists(x, f(x) != 0)
>>> q.is_lambda()
False
"""
return Z3_is_lambda(self.ctx_ref(), self.ast)
def weight(self):
"""Return the weight annotation of `self`.
@ -1973,6 +2001,26 @@ def Exists(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]):
"""
return _mk_quantifier(False, vs, body, weight, qid, skid, patterns, no_patterns)
def Lambda(vs, body):
"""Create a Z3 lambda expression.
>>> f = Function('f', IntSort(), IntSort(), IntSort())
>>> mem0 = Array('mem0', IntSort(), IntSort())
>>> lo, hi, e, i = Ints('lo hi e i')
>>> mem1 = Lambda([i], If(And(lo <= i, i <= hi), e, mem0[i]))
>>> mem1
Lambda(i, If(And(lo <= i, i <= hi), e, mem0[i]))
"""
ctx = body.ctx
if is_app(vs):
vs = [vs]
num_vars = len(vs)
_vs = (Ast * num_vars)()
for i in range(num_vars):
## TODO: Check if is constant
_vs[i] = vs[i].as_ast()
return QuantifierRef(Z3_mk_lambda_const(ctx.ref(), num_vars, _vs, body.as_ast()), ctx)
#########################################
#
# Arithmetic
@ -5582,7 +5630,7 @@ class FuncEntry:
>>> m = s.model()
>>> f_i = m[f]
>>> f_i.num_entries()
3
1
>>> e = f_i.entry(0)
>>> e.num_args()
2
@ -5600,16 +5648,16 @@ class FuncEntry:
>>> m = s.model()
>>> f_i = m[f]
>>> f_i.num_entries()
3
1
>>> e = f_i.entry(0)
>>> e
[0, 1, 10]
[1, 2, 20]
>>> e.num_args()
2
>>> e.arg_value(0)
0
>>> e.arg_value(1)
1
>>> e.arg_value(1)
2
>>> try:
... e.arg_value(2)
... except IndexError:
@ -5631,14 +5679,14 @@ class FuncEntry:
>>> m = s.model()
>>> f_i = m[f]
>>> f_i.num_entries()
3
1
>>> e = f_i.entry(0)
>>> e
[0, 1, 10]
[1, 2, 20]
>>> e.num_args()
2
>>> e.value()
10
20
"""
return _to_expr_ref(Z3_func_entry_get_value(self.ctx.ref(), self.entry), self.ctx)
@ -5652,10 +5700,10 @@ class FuncEntry:
>>> m = s.model()
>>> f_i = m[f]
>>> f_i.num_entries()
3
1
>>> e = f_i.entry(0)
>>> e.as_list()
[0, 1, 10]
[1, 2, 20]
"""
args = [ self.arg_value(i) for i in range(self.num_args())]
args.append(self.value())
@ -5693,7 +5741,7 @@ class FuncInterp(Z3PPObject):
sat
>>> m = s.model()
>>> m[f]
[0 -> 1, 1 -> 1, 2 -> 0, else -> 1]
[2 -> 0, else -> 1]
>>> m[f].else_value()
1
"""
@ -5713,9 +5761,9 @@ class FuncInterp(Z3PPObject):
sat
>>> m = s.model()
>>> m[f]
[0 -> 1, 1 -> 1, 2 -> 0, else -> 1]
[2 -> 0, else -> 1]
>>> m[f].num_entries()
3
1
"""
return int(Z3_func_interp_get_num_entries(self.ctx.ref(), self.f))
@ -5743,14 +5791,10 @@ class FuncInterp(Z3PPObject):
sat
>>> m = s.model()
>>> m[f]
[0 -> 1, 1 -> 1, 2 -> 0, else -> 1]
[2 -> 0, else -> 1]
>>> m[f].num_entries()
3
1
>>> m[f].entry(0)
[0, 1]
>>> m[f].entry(1)
[1, 1]
>>> m[f].entry(2)
[2, 0]
"""
if idx >= self.num_entries():
@ -5777,9 +5821,9 @@ class FuncInterp(Z3PPObject):
sat
>>> m = s.model()
>>> m[f]
[0 -> 1, 1 -> 1, 2 -> 0, else -> 1]
[2 -> 0, else -> 1]
>>> m[f].as_list()
[[0, 1], [1, 1], [2, 0], 1]
[[2, 0], 1]
"""
r = [ self.entry(i).as_list() for i in range(self.num_entries())]
r.append(self.else_value())
@ -5891,7 +5935,7 @@ class ModelRef(Z3PPObject):
>>> m[x]
1
>>> m[f]
[1 -> 0, else -> 0]
[else -> 0]
"""
if __debug__:
_z3_assert(isinstance(decl, FuncDeclRef) or is_const(decl), "Z3 declaration expected")
@ -6008,10 +6052,10 @@ class ModelRef(Z3PPObject):
>>> m[x]
1
>>> m[f]
[1 -> 0, else -> 0]
[else -> 0]
>>> for d in m: print("%s -> %s" % (d, m[d]))
x -> 1
f -> [1 -> 0, else -> 0]
f -> [else -> 0]
"""
if _is_int(idx):
if idx >= len(self):

View file

@ -959,8 +959,10 @@ class Formatter:
ys_pp = seq3(ys, '[', ']')
if a.is_forall():
header = 'ForAll'
else:
elif a.is_exists():
header = 'Exists'
else:
header = 'Lambda'
return seq1(header, (ys_pp, body_pp))
def pp_expr(self, a, d, xs):

View file

@ -482,6 +482,10 @@ typedef enum
T1: (~ p q)
[quant-intro T1]: (~ (forall (x) p) (forall (x) q))
- Z3_OP_PR_BIND: Given a proof p, produces a proof of lambda x . p, where x are free variables in p.
T1: f
[proof-bind T1] forall (x) f
- Z3_OP_PR_DISTRIBUTIVITY: Distributivity proof object.
Given that f (= or) distributes over g (= and), produces a proof for
@ -1109,6 +1113,7 @@ typedef enum {
Z3_OP_PR_TRANSITIVITY_STAR,
Z3_OP_PR_MONOTONICITY,
Z3_OP_PR_QUANT_INTRO,
Z3_OP_PR_BIND,
Z3_OP_PR_DISTRIBUTIVITY,
Z3_OP_PR_AND_ELIM,
Z3_OP_PR_NOT_OR_ELIM,
@ -1857,7 +1862,6 @@ extern "C" {
*/
Z3_sort Z3_API Z3_mk_array_sort_n(Z3_context c, unsigned n, Z3_sort const * domain, Z3_sort range);
/**
\brief Create a tuple type.
@ -2946,6 +2950,8 @@ extern "C" {
*/
Z3_ast Z3_API Z3_mk_select(Z3_context c, Z3_ast a, Z3_ast i);
/**
\brief n-ary Array read.
The argument \c a is the array and \c idxs are the indices of the array that gets read.
@ -2955,6 +2961,7 @@ extern "C" {
*/
Z3_ast Z3_API Z3_mk_select_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs);
/**
\brief Array update.
@ -2973,6 +2980,7 @@ extern "C" {
*/
Z3_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v);
/**
\brief n-ary Array update.
@ -3763,6 +3771,54 @@ extern "C" {
Z3_ast body
);
/**
\brief Create a lambda expression. It taks an expression \c body that contains bound variables
of the same sorts as the sorts listed in the array \c sorts. The bound variables are de-Bruijn indices created
using #Z3_mk_bound. The array \c decl_names contains the names that the quantified formula uses for the
bound variables. Z3 applies the convention that the last element in the \c decl_names and \c sorts array
refers to the variable with index 0, the second to last element of \c decl_names and \c sorts refers
to the variable with index 1, etc.
The sort of the resulting expression is \c (Array sorts range) where \c range is the sort of \c body.
For example, if the lambda binds two variables of sort \c Int and \c Bool, and the \c body has sort \c Real,
the sort of the expression is \c (Array Int Bool Real).
\param c logical context
\param num_decls number of variables to be bound.
\param sorts the sorts of the bound variables.
\param decl_names names of the bound variables
\param body the body of the lambda expression.
\sa Z3_mk_bound
\sa Z3_mk_forall
\sa Z3_mk_lambda_const
def_API('Z3_mk_lambda', AST, (_in(CONTEXT), _in(UINT), _in_array(1, SORT), _in_array(1, SYMBOL), _in(AST)))
*/
Z3_ast Z3_API Z3_mk_lambda(Z3_context c,
unsigned num_decls, Z3_sort const sorts[],
Z3_symbol const decl_names[],
Z3_ast body);
/**
\brief Create a lambda expression using a list of constants that form the set
of bound variables
\param c logical context.
\param num_bound number of constants to be abstracted into bound variables.
\param bound array of constants to be abstracted into bound variables.
\param body the body of the lambda expression.
\sa Z3_mk_bound
\sa Z3_mk_forall
\sa Z3_mk_lambda
def_API('Z3_mk_lambda_const', AST, (_in(CONTEXT), _in(UINT), _in_array(1, APP), _in(AST)))
*/
Z3_ast Z3_API Z3_mk_lambda_const(Z3_context c,
unsigned num_bound, Z3_app const bound[],
Z3_ast body);
/*@}*/
/** @name Accessors */
@ -4529,14 +4585,29 @@ extern "C" {
unsigned Z3_API Z3_get_index_value(Z3_context c, Z3_ast a);
/**
\brief Determine if quantifier is universal.
\pre Z3_get_ast_kind(a) == Z3_QUANTIFIER_AST
\brief Determine if an ast is a universal quantifier.
def_API('Z3_is_quantifier_forall', BOOL, (_in(CONTEXT), _in(AST)))
*/
Z3_bool Z3_API Z3_is_quantifier_forall(Z3_context c, Z3_ast a);
/**
\brief Determine if ast is an existential quantifier.
def_API('Z3_is_quantifier_exists', BOOL, (_in(CONTEXT), _in(AST)))
*/
Z3_bool Z3_API Z3_is_quantifier_exists(Z3_context c, Z3_ast a);
/**
\brief Determine if ast is a lambda expresion.
\pre Z3_get_ast_kind(a) == Z3_QUANTIFIER_AST
def_API('Z3_is_lambda', BOOL, (_in(CONTEXT), _in(AST)))
*/
Z3_bool Z3_API Z3_is_lambda(Z3_context c, Z3_ast a);
/**
\brief Obtain weight of quantifier.

View file

@ -26,6 +26,9 @@ Revision History:
#include "util/string_buffer.h"
#include "ast/ast_util.h"
#include "ast/ast_smt2_pp.h"
#include "ast/array_decl_plugin.h"
#include "ast/ast_translation.h"
// -----------------------------------
//
@ -360,13 +363,14 @@ app::app(func_decl * decl, unsigned num_args, expr * const * args):
//
// -----------------------------------
quantifier::quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body,
quantifier::quantifier(quantifier_kind k, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, sort* s,
int weight, symbol const & qid, symbol const & skid, unsigned num_patterns, expr * const * patterns,
unsigned num_no_patterns, expr * const * no_patterns):
expr(AST_QUANTIFIER),
m_forall(forall),
m_kind(k),
m_num_decls(num_decls),
m_expr(body),
m_sort(s),
m_depth(::get_depth(body) + 1),
m_weight(weight),
m_has_unused_vars(true),
@ -385,6 +389,25 @@ quantifier::quantifier(bool forall, unsigned num_decls, sort * const * decl_sort
memcpy(const_cast<expr **>(get_no_patterns()), no_patterns, sizeof(expr *) * num_no_patterns);
}
quantifier::quantifier(unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, sort* s):
expr(AST_QUANTIFIER),
m_kind(lambda_k),
m_num_decls(num_decls),
m_expr(body),
m_sort(s),
m_depth(::get_depth(body) + 1),
m_weight(0),
m_has_unused_vars(true),
m_has_labels(::has_labels(body)),
m_qid(symbol()),
m_skid(symbol()),
m_num_patterns(0),
m_num_no_patterns(0) {
memcpy(const_cast<sort **>(get_decl_sorts()), decl_sorts, sizeof(sort *) * num_decls);
memcpy(const_cast<symbol*>(get_decl_names()), decl_names, sizeof(symbol) * num_decls);
}
// -----------------------------------
//
// Auxiliary functions
@ -392,21 +415,16 @@ quantifier::quantifier(bool forall, unsigned num_decls, sort * const * decl_sort
// -----------------------------------
sort * get_sort(expr const * n) {
while (true) {
switch(n->get_kind()) {
case AST_APP:
return to_app(n)->get_decl()->get_range();
case AST_VAR:
return to_var(n)->get_sort();
case AST_QUANTIFIER:
// The sort of the quantifier is the sort of the nested expression.
// This code assumes the given expression is well-sorted.
n = to_quantifier(n)->get_expr();
break;
default:
UNREACHABLE();
return nullptr;
}
switch(n->get_kind()) {
case AST_APP:
return to_app(n)->get_decl()->get_range();
case AST_VAR:
return to_var(n)->get_sort();
case AST_QUANTIFIER:
return to_quantifier(n)->get_sort();
default:
UNREACHABLE();
return 0;
}
}
@ -466,7 +484,7 @@ bool compare_nodes(ast const * n1, ast const * n2) {
to_var(n1)->get_sort() == to_var(n2)->get_sort();
case AST_QUANTIFIER:
return
to_quantifier(n1)->is_forall() == to_quantifier(n2)->is_forall() &&
to_quantifier(n1)->get_kind() == to_quantifier(n2)->get_kind() &&
to_quantifier(n1)->get_num_decls() == to_quantifier(n2)->get_num_decls() &&
compare_arrays(to_quantifier(n1)->get_decl_sorts(),
to_quantifier(n2)->get_decl_sorts(),
@ -566,7 +584,7 @@ unsigned get_node_hash(ast const * n) {
case AST_QUANTIFIER:
a = ast_array_hash(to_quantifier(n)->get_decl_sorts(),
to_quantifier(n)->get_num_decls(),
to_quantifier(n)->is_forall() ? 31 : 19);
to_quantifier(n)->get_kind() == forall_k ? 31 : 19);
b = to_quantifier(n)->get_num_patterns();
c = to_quantifier(n)->get_expr()->hash();
mix(a,b,c);
@ -689,7 +707,8 @@ bool basic_decl_plugin::check_proof_sorts(basic_op_kind k, unsigned arity, sort
for (unsigned i = 0; i < arity - 1; i++)
if (domain[i] != m_proof_sort)
return false;
return domain[arity-1] == m_bool_sort || domain[arity-1] == m_proof_sort;
#define is_array(_x_) true
return domain[arity-1] == m_bool_sort || domain[arity-1] == m_proof_sort || is_array(domain[arity-1]);
}
}
@ -704,7 +723,8 @@ bool basic_decl_plugin::check_proof_args(basic_op_kind k, unsigned num_args, exp
return false;
return
m_manager->get_sort(args[num_args - 1]) == m_bool_sort ||
m_manager->get_sort(args[num_args - 1]) == m_proof_sort;
m_manager->get_sort(args[num_args - 1]) == m_proof_sort ||
is_lambda(args[num_args-1]);
}
}
@ -818,6 +838,7 @@ func_decl * basic_decl_plugin::mk_proof_decl(basic_op_kind k, unsigned num_paren
case PR_TRANSITIVITY_STAR: return mk_proof_decl("trans*", k, num_parents, m_transitivity_star_decls);
case PR_MONOTONICITY: return mk_proof_decl("monotonicity", k, num_parents, m_monotonicity_decls);
case PR_QUANT_INTRO: return mk_proof_decl("quant-intro", k, 1, m_quant_intro_decl);
case PR_BIND: UNREACHABLE();
case PR_DISTRIBUTIVITY: return mk_proof_decl("distributivity", k, num_parents, m_distributivity_decls);
case PR_AND_ELIM: return mk_proof_decl("and-elim", k, 1, m_and_elim_decl);
case PR_NOT_OR_ELIM: return mk_proof_decl("not-or-elim", k, 1, m_not_or_elim_decl);
@ -1054,6 +1075,10 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
// eq and oeq must have at least two arguments, they can have more since they are chainable
case OP_EQ: return arity >= 2 ? mk_eq_decl_core("=", OP_EQ, join(arity, domain), m_eq_decls) : nullptr;
case OP_OEQ: return arity >= 2 ? mk_eq_decl_core("~", OP_OEQ, join(arity, domain), m_oeq_decls) : nullptr;
case PR_BIND: {
func_decl_info info(m_family_id, PR_BIND);
return m_manager->mk_func_decl(symbol("proof-bind"), arity, domain, m_proof_sort, info);
}
case OP_DISTINCT: {
func_decl_info info(m_family_id, OP_DISTINCT);
info.set_pairwise();
@ -1097,6 +1122,11 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
case OP_OEQ: return num_args >= 2 ? mk_eq_decl_core("~", OP_OEQ, join(num_args, args), m_oeq_decls) : nullptr;
case OP_DISTINCT:
return decl_plugin::mk_func_decl(k, num_parameters, parameters, num_args, args, range);
case PR_BIND: {
ptr_buffer<sort> sorts;
for (unsigned i = 0; i < num_args; ++i) sorts.push_back(m_manager->get_sort(args[i]));
return mk_func_decl(k, num_parameters, parameters, num_args, sorts.c_ptr(), range);
}
default:
break;
}
@ -1218,7 +1248,6 @@ func_decl * model_value_decl_plugin::mk_func_decl(decl_kind k, unsigned num_para
unsigned arity, sort * const * domain, sort * range) {
SASSERT(k == OP_MODEL_VALUE);
if (arity != 0 || num_parameters != 2 || !parameters[0].is_int() || !parameters[1].is_ast() || !is_sort(parameters[1].get_ast())) {
UNREACHABLE();
m_manager->raise_exception("invalid model value");
return nullptr;
}
@ -1290,7 +1319,8 @@ ast_manager::ast_manager(proof_gen_mode m, char const * trace_file, bool is_form
m_proof_mode(m),
m_trace_stream(nullptr),
m_trace_stream_owner(false),
m_rec_fun(":rec-fun") {
m_rec_fun(":rec-fun"),
m_lambda_def(":lambda-def") {
if (trace_file) {
m_trace_stream = alloc(std::fstream, trace_file, std::ios_base::out);
@ -1312,7 +1342,8 @@ ast_manager::ast_manager(proof_gen_mode m, std::fstream * trace_stream, bool is_
m_proof_mode(m),
m_trace_stream(trace_stream),
m_trace_stream_owner(false),
m_rec_fun(":rec-fun") {
m_rec_fun(":rec-fun"),
m_lambda_def(":lambda-def") {
if (!is_format_manager)
m_format_manager = alloc(ast_manager, PGM_DISABLED, trace_stream, true);
@ -1508,7 +1539,6 @@ void ast_manager::raise_exception(char const * msg) {
throw ast_exception(msg);
}
#include "ast/ast_translation.h"
void ast_manager::copy_families_plugins(ast_manager const & from) {
TRACE("copy_families_plugins",
@ -1761,6 +1791,7 @@ ast * ast_manager::register_node_core(ast * n) {
case AST_QUANTIFIER:
inc_array_ref(to_quantifier(n)->get_num_decls(), to_quantifier(n)->get_decl_sorts());
inc_ref(to_quantifier(n)->get_expr());
inc_ref(to_quantifier(n)->get_sort());
inc_array_ref(to_quantifier(n)->get_num_patterns(), to_quantifier(n)->get_patterns());
inc_array_ref(to_quantifier(n)->get_num_no_patterns(), to_quantifier(n)->get_no_patterns());
break;
@ -1824,6 +1855,7 @@ void ast_manager::delete_node(ast * n) {
case AST_QUANTIFIER:
dec_array_ref(worklist, to_quantifier(n)->get_num_decls(), to_quantifier(n)->get_decl_sorts());
dec_ref(worklist, to_quantifier(n)->get_expr());
dec_ref(worklist, to_quantifier(n)->get_sort());
dec_array_ref(worklist, to_quantifier(n)->get_num_patterns(), to_quantifier(n)->get_patterns());
dec_array_ref(worklist, to_quantifier(n)->get_num_no_patterns(), to_quantifier(n)->get_no_patterns());
break;
@ -2338,7 +2370,7 @@ bool ast_manager::is_pattern(expr const * n, ptr_vector<expr> &args) {
}
quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names,
quantifier * ast_manager::mk_quantifier(quantifier_kind k, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names,
expr * body, int weight , symbol const & qid, symbol const & skid,
unsigned num_patterns, expr * const * patterns,
unsigned num_no_patterns, expr * const * no_patterns) {
@ -2353,7 +2385,17 @@ quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort *
}});
unsigned sz = quantifier::get_obj_size(num_decls, num_patterns, num_no_patterns);
void * mem = allocate_node(sz);
quantifier * new_node = new (mem) quantifier(forall, num_decls, decl_sorts, decl_names, body,
sort* s = nullptr;
if (k == lambda_k) {
array_util autil(*this);
s = autil.mk_array_sort(num_decls, decl_sorts, ::get_sort(body));
}
else {
s = mk_bool_sort();
}
quantifier * new_node = new (mem) quantifier(k, num_decls, decl_sorts, decl_names, body, s,
weight, qid, skid, num_patterns, patterns,
num_no_patterns, no_patterns);
quantifier * r = register_node(new_node);
@ -2370,6 +2412,18 @@ quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort *
return r;
}
quantifier * ast_manager::mk_lambda(unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body) {
SASSERT(body);
unsigned sz = quantifier::get_obj_size(num_decls, 0, 0);
void * mem = allocate_node(sz);
array_util autil(*this);
sort* s = autil.mk_array_sort(num_decls, decl_sorts, ::get_sort(body));
quantifier * new_node = new (mem) quantifier(num_decls, decl_sorts, decl_names, body, s);
quantifier * r = register_node(new_node);
return r;
}
// Return true if the patterns of q are the given ones.
static bool same_patterns(quantifier * q, unsigned num_patterns, expr * const * patterns) {
if (num_patterns != q->get_num_patterns())
@ -2393,7 +2447,7 @@ static bool same_no_patterns(quantifier * q, unsigned num_no_patterns, expr * co
quantifier * ast_manager::update_quantifier(quantifier * q, unsigned num_patterns, expr * const * patterns, expr * body) {
if (q->get_expr() == body && same_patterns(q, num_patterns, patterns))
return q;
return mk_quantifier(q->is_forall(),
return mk_quantifier(q->get_kind(),
q->get_num_decls(),
q->get_decl_sorts(),
q->get_decl_names(),
@ -2410,7 +2464,7 @@ quantifier * ast_manager::update_quantifier(quantifier * q, unsigned num_pattern
quantifier * ast_manager::update_quantifier(quantifier * q, unsigned num_patterns, expr * const * patterns, unsigned num_no_patterns, expr * const * no_patterns, expr * body) {
if (q->get_expr() == body && same_patterns(q, num_patterns, patterns) && same_no_patterns(q, num_no_patterns, no_patterns))
return q;
return mk_quantifier(q->is_forall(),
return mk_quantifier(q->get_kind(),
q->get_num_decls(),
q->get_decl_sorts(),
q->get_decl_names(),
@ -2427,7 +2481,7 @@ quantifier * ast_manager::update_quantifier(quantifier * q, unsigned num_pattern
quantifier * ast_manager::update_quantifier(quantifier * q, expr * body) {
if (q->get_expr() == body)
return q;
return mk_quantifier(q->is_forall(),
return mk_quantifier(q->get_kind(),
q->get_num_decls(),
q->get_decl_sorts(),
q->get_decl_names(),
@ -2445,7 +2499,7 @@ quantifier * ast_manager::update_quantifier_weight(quantifier * q, int w) {
if (q->get_weight() == w)
return q;
TRACE("update_quantifier_weight", tout << "#" << q->get_id() << " " << q->get_weight() << " -> " << w << "\n";);
return mk_quantifier(q->is_forall(),
return mk_quantifier(q->get_kind(),
q->get_num_decls(),
q->get_decl_sorts(),
q->get_decl_names(),
@ -2459,10 +2513,10 @@ quantifier * ast_manager::update_quantifier_weight(quantifier * q, int w) {
q->get_no_patterns());
}
quantifier * ast_manager::update_quantifier(quantifier * q, bool is_forall, expr * body) {
if (q->get_expr() == body && q->is_forall() == is_forall)
quantifier * ast_manager::update_quantifier(quantifier * q, quantifier_kind k, expr * body) {
if (q->get_expr() == body && q->get_kind() == k)
return q;
return mk_quantifier(is_forall,
return mk_quantifier(k,
q->get_num_decls(),
q->get_decl_sorts(),
q->get_decl_names(),
@ -2476,10 +2530,10 @@ quantifier * ast_manager::update_quantifier(quantifier * q, bool is_forall, expr
q->get_no_patterns());
}
quantifier * ast_manager::update_quantifier(quantifier * q, bool is_forall, unsigned num_patterns, expr * const * patterns, expr * body) {
if (q->get_expr() == body && q->is_forall() == is_forall && same_patterns(q, num_patterns, patterns))
quantifier * ast_manager::update_quantifier(quantifier * q, quantifier_kind k, unsigned num_patterns, expr * const * patterns, expr * body) {
if (q->get_expr() == body && q->get_kind() == k && same_patterns(q, num_patterns, patterns))
return q;
return mk_quantifier(is_forall,
return mk_quantifier(k,
q->get_num_decls(),
q->get_decl_sorts(),
q->get_decl_names(),
@ -2786,11 +2840,17 @@ proof * ast_manager::mk_oeq_congruence(app * f1, app * f2, unsigned num_proofs,
return mk_monotonicity(mk_func_decl(m_basic_family_id, OP_OEQ, 0, nullptr, 2, d), f1, f2, num_proofs, proofs);
}
proof * ast_manager::mk_bind_proof(quantifier * q, proof * p) {
expr* b = mk_lambda(q->get_num_decls(), q->get_decl_sorts(), q->get_decl_names(), p);
return mk_app(m_basic_family_id, PR_BIND, b);
}
proof * ast_manager::mk_quant_intro(quantifier * q1, quantifier * q2, proof * p) {
if (!p) return nullptr;
SASSERT(q1->get_num_decls() == q2->get_num_decls());
SASSERT(has_fact(p));
SASSERT(is_eq(get_fact(p)));
if (!p) return nullptr;
SASSERT(q1->get_num_decls() == q2->get_num_decls());
SASSERT(has_fact(p));
SASSERT(is_eq(get_fact(p)) || is_lambda(get_fact(p)));
return mk_app(m_basic_family_id, PR_QUANT_INTRO, p, mk_iff(q1, q2));
}

View file

@ -793,11 +793,18 @@ public:
//
// -----------------------------------
enum quantifier_kind {
forall_k,
exists_k,
lambda_k
};
class quantifier : public expr {
friend class ast_manager;
bool m_forall;
quantifier_kind m_kind;
unsigned m_num_decls;
expr * m_expr;
sort * m_sort;
unsigned m_depth;
// extra fields
int m_weight;
@ -813,12 +820,18 @@ class quantifier : public expr {
return sizeof(quantifier) + num_decls * (sizeof(sort *) + sizeof(symbol)) + (num_patterns + num_no_patterns) * sizeof(expr*);
}
quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body,
quantifier(quantifier_kind k, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, sort* s,
int weight, symbol const & qid, symbol const & skid, unsigned num_patterns, expr * const * patterns,
unsigned num_no_patterns, expr * const * no_patterns);
quantifier(unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, sort* sort);
public:
bool is_forall() const { return m_forall; }
bool is_exists() const { return !m_forall; }
quantifier_kind get_kind() const { return m_kind; }
// bool is_forall() const { return m_kind == forall_k; }
// bool is_exists() const { return m_kind == exists_k; }
// bool is_lambda() const { return m_kind == lambda_k; }
unsigned get_num_decls() const { return m_num_decls; }
sort * const * get_decl_sorts() const { return reinterpret_cast<sort * const *>(m_patterns_decls); }
symbol const * get_decl_names() const { return reinterpret_cast<symbol const *>(get_decl_sorts() + m_num_decls); }
@ -826,6 +839,8 @@ public:
symbol const & get_decl_name(unsigned idx) const { return get_decl_names()[idx]; }
expr * get_expr() const { return m_expr; }
sort * get_sort() const { return m_sort; }
unsigned get_depth() const { return m_depth; }
int get_weight() const { return m_weight; }
@ -844,6 +859,7 @@ public:
void set_no_unused_vars() { m_has_unused_vars = false; }
bool has_labels() const { return m_has_labels; }
unsigned get_num_children() const { return 1 + get_num_patterns() + get_num_no_patterns(); }
expr * get_child(unsigned idx) const {
@ -871,8 +887,9 @@ inline bool is_app(ast const * n) { return n->get_kind() == AST_APP; }
inline bool is_var(ast const * n) { return n->get_kind() == AST_VAR; }
inline bool is_var(ast const * n, unsigned& idx) { return is_var(n) && (idx = static_cast<var const*>(n)->get_idx(), true); }
inline bool is_quantifier(ast const * n) { return n->get_kind() == AST_QUANTIFIER; }
inline bool is_forall(ast const * n) { return is_quantifier(n) && static_cast<quantifier const *>(n)->is_forall(); }
inline bool is_exists(ast const * n) { return is_quantifier(n) && static_cast<quantifier const *>(n)->is_exists(); }
inline bool is_forall(ast const * n) { return is_quantifier(n) && static_cast<quantifier const *>(n)->get_kind() == forall_k; }
inline bool is_exists(ast const * n) { return is_quantifier(n) && static_cast<quantifier const *>(n)->get_kind() == exists_k; }
inline bool is_lambda(ast const * n) { return is_quantifier(n) && static_cast<quantifier const *>(n)->get_kind() == lambda_k; }
// -----------------------------------
//
@ -950,7 +967,7 @@ protected:
family_id m_family_id;
virtual void set_manager(ast_manager * m, family_id id) {
SASSERT(m_manager == 0);
SASSERT(m_manager == nullptr);
m_manager = m;
m_family_id = id;
}
@ -1043,7 +1060,7 @@ enum basic_sort_kind {
enum basic_op_kind {
OP_TRUE, OP_FALSE, OP_EQ, OP_DISTINCT, OP_ITE, OP_AND, OP_OR, OP_XOR, OP_NOT, OP_IMPLIES, OP_OEQ, LAST_BASIC_OP,
PR_UNDEF, PR_TRUE, PR_ASSERTED, PR_GOAL, PR_MODUS_PONENS, PR_REFLEXIVITY, PR_SYMMETRY, PR_TRANSITIVITY, PR_TRANSITIVITY_STAR, PR_MONOTONICITY, PR_QUANT_INTRO,
PR_UNDEF, PR_TRUE, PR_ASSERTED, PR_GOAL, PR_MODUS_PONENS, PR_REFLEXIVITY, PR_SYMMETRY, PR_TRANSITIVITY, PR_TRANSITIVITY_STAR, PR_MONOTONICITY, PR_QUANT_INTRO, PR_BIND,
PR_DISTRIBUTIVITY, PR_AND_ELIM, PR_NOT_OR_ELIM, PR_REWRITE, PR_REWRITE_STAR, PR_PULL_QUANT,
PR_PUSH_QUANT, PR_ELIM_UNUSED_VARS, PR_DER, PR_QUANT_INST,
@ -1487,6 +1504,7 @@ protected:
#endif
ast_manager * m_format_manager; // hack for isolating format objects in a different manager.
symbol m_rec_fun;
symbol m_lambda_def;
void init();
@ -1594,9 +1612,12 @@ public:
bool contains(ast * a) const { return m_ast_table.contains(a); }
bool is_rec_fun_def(quantifier* q) const { return q->get_qid() == m_rec_fun; }
bool is_lambda_def(quantifier* q) const { return q->get_qid() == m_lambda_def; }
symbol const& rec_fun_qid() const { return m_rec_fun; }
symbol const& lambda_def_qid() const { return m_lambda_def; }
unsigned get_num_asts() const { return m_ast_table.size(); }
void debug_ref_count() { m_debug_ref_count = true; }
@ -1892,7 +1913,7 @@ public:
public:
quantifier * mk_quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body,
quantifier * mk_quantifier(quantifier_kind k, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body,
int weight = 0, symbol const & qid = symbol::null, symbol const & skid = symbol::null,
unsigned num_patterns = 0, expr * const * patterns = nullptr,
unsigned num_no_patterns = 0, expr * const * no_patterns = nullptr);
@ -1901,7 +1922,7 @@ public:
int weight = 0, symbol const & qid = symbol::null, symbol const & skid = symbol::null,
unsigned num_patterns = 0, expr * const * patterns = nullptr,
unsigned num_no_patterns = 0, expr * const * no_patterns = nullptr) {
return mk_quantifier(true, num_decls, decl_sorts, decl_names, body, weight, qid, skid, num_patterns, patterns,
return mk_quantifier(forall_k, num_decls, decl_sorts, decl_names, body, weight, qid, skid, num_patterns, patterns,
num_no_patterns, no_patterns);
}
@ -1909,10 +1930,12 @@ public:
int weight = 0, symbol const & qid = symbol::null, symbol const & skid = symbol::null,
unsigned num_patterns = 0, expr * const * patterns = nullptr,
unsigned num_no_patterns = 0, expr * const * no_patterns = nullptr) {
return mk_quantifier(false, num_decls, decl_sorts, decl_names, body, weight, qid, skid, num_patterns, patterns,
return mk_quantifier(exists_k, num_decls, decl_sorts, decl_names, body, weight, qid, skid, num_patterns, patterns,
num_no_patterns, no_patterns);
}
quantifier * mk_lambda(unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body);
quantifier * update_quantifier(quantifier * q, unsigned new_num_patterns, expr * const * new_patterns, expr * new_body);
quantifier * update_quantifier(quantifier * q, unsigned new_num_patterns, expr * const * new_patterns, unsigned new_num_no_patterns, expr * const * new_no_patterns, expr * new_body);
@ -1921,9 +1944,9 @@ public:
quantifier * update_quantifier_weight(quantifier * q, int new_weight);
quantifier * update_quantifier(quantifier * q, bool new_is_forall, expr * new_body);
quantifier * update_quantifier(quantifier * q, quantifier_kind new_kind, expr * new_body);
quantifier * update_quantifier(quantifier * q, bool new_is_forall, unsigned new_num_patterns, expr * const * new_patterns, expr * new_body);
quantifier * update_quantifier(quantifier * q, quantifier_kind new_kind, unsigned new_num_patterns, expr * const * new_patterns, expr * new_body);
// -----------------------------------
//
@ -2213,6 +2236,7 @@ public:
proof * mk_rewrite(expr * s, expr * t);
proof * mk_oeq_rewrite(expr * s, expr * t);
proof * mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs);
proof * mk_bind_proof(quantifier * q, proof * p);
proof * mk_pull_quant(expr * e, quantifier * q);
proof * mk_push_quant(quantifier * q, expr * e);
proof * mk_elim_unused_vars(quantifier * q, expr * r);

View file

@ -242,7 +242,7 @@ public:
void operator()(quantifier * n) {
display_def_header(n);
m_out << "(" << (n->is_forall() ? "forall" : "exists") << " ";
m_out << "(" << (n->get_kind() == forall_k ? "forall" : (n->get_kind() == exists_k ? "exists" : "lambda")) << " ";
unsigned num_decls = n->get_num_decls();
m_out << "(vars ";
for (unsigned i = 0; i < num_decls; i++) {

View file

@ -102,7 +102,7 @@ bool lt(ast * n1, ast * n2) {
UNREACHABLE();
return false;
case AST_QUANTIFIER:
check_bool(to_quantifier(n1)->is_forall(), to_quantifier(n2)->is_forall());
check_value(to_quantifier(n1)->get_kind(), to_quantifier(n2)->get_kind());
check_value(to_quantifier(n1)->get_num_decls(), to_quantifier(n2)->get_num_decls());
check_value(to_quantifier(n1)->get_num_patterns(), to_quantifier(n2)->get_num_patterns());
check_value(to_quantifier(n1)->get_num_no_patterns(), to_quantifier(n2)->get_num_no_patterns());

View file

@ -994,7 +994,7 @@ class smt2_printer {
}
format * f_decls = pp_var_decls(q);
format * fs[2] = { f_decls, f_body };
char const * header = q->is_forall() ? "forall" : "exists";
char const * header = q->get_kind() == forall_k ? "forall" : (q->get_kind() == exists_k ? "exists" : "lambda");
format * f = mk_seq3<format**, f2f>(m(), fs, fs+2, f2f(), header, 1, SMALL_INDENT);
info f_info = m_info_stack.back();

View file

@ -495,11 +495,10 @@ class smt_printer {
m_qlists.push_back(q);
m_out << "(";
if (q->is_forall()) {
m_out << "forall ";
}
else {
m_out << "exists ";
switch (q->get_kind()) {
case forall_k: m_out << "forall "; break;
case exists_k: m_out << "exists "; break;
case lambda_k: m_out << "lambda "; break;
}
m_out << "(";
for (unsigned i = 0; i < q->get_num_decls(); ++i) {

View file

@ -279,7 +279,7 @@ ast * ast_translation::process(ast const * _n) {
expr ** pats = reinterpret_cast<expr**>(m_result_stack.c_ptr() + fr.m_rpos + num_decls + 1);
unsigned num_no_pats = to_quantifier(n)->get_num_no_patterns();
expr ** no_pats = pats + num_pats;
quantifier * new_q = m_to_manager.mk_quantifier(to_quantifier(n)->is_forall(),
quantifier * new_q = m_to_manager.mk_quantifier(to_quantifier(n)->get_kind(),
num_decls,
dsorts,
dnames,

View file

@ -115,7 +115,7 @@ void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* cons
tout << result << "\n";);
}
expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
expr_ref mk_quantifier(quantifier_kind k, ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
expr_ref result(m);
expr_abstract(m, 0, num_bound, (expr* const*)bound, n, result);
if (num_bound > 0) {
@ -125,7 +125,7 @@ expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app*
sorts.push_back(m.get_sort(bound[i]));
names.push_back(bound[i]->get_decl()->get_name());
}
result = m.mk_quantifier(is_forall, num_bound, sorts.c_ptr(), names.c_ptr(), result);
result = m.mk_quantifier(k, num_bound, sorts.c_ptr(), names.c_ptr(), result);
}
TRACE("expr_abstract",
tout << expr_ref(n, m) << "\n";
@ -137,9 +137,9 @@ expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app*
}
expr_ref mk_forall(ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
return mk_quantifier(true, m, num_bound, bound, n);
return mk_quantifier(forall_k, m, num_bound, bound, n);
}
expr_ref mk_exists(ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
return mk_quantifier(false, m, num_bound, bound, n);
return mk_quantifier(exists_k, m, num_bound, bound, n);
}

View file

@ -194,6 +194,9 @@ bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
if (is_lambda(old_q)) {
return false;
}
unsigned curr_sz = m_bindings.size();
SASSERT(old_q->get_num_decls() <= curr_sz);
unsigned num_decls = old_q->get_num_decls();
@ -217,7 +220,7 @@ bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q,
new_decl_names.push_back(n);
}
}
result = m().mk_quantifier(old_q->is_forall(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(),
result = m().mk_quantifier(old_q->get_kind(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(),
new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(),
old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns);
result_pr = nullptr;

View file

@ -23,7 +23,7 @@ Revision History:
#include "ast/ast_ll_pp.h"
bool macro_finder::is_macro(expr * n, app_ref & head, expr_ref & def) {
if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
if (!is_forall(n))
return false;
TRACE("macro_finder", tout << "processing: " << mk_pp(n, m) << "\n";);
expr * body = to_quantifier(n)->get_expr();
@ -46,7 +46,7 @@ bool macro_finder::is_macro(expr * n, app_ref & head, expr_ref & def) {
For case 2 & 3, the new quantifiers are stored in new_exprs and new_prs.
*/
bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_dependency * dep, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps) {
if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
if (!is_forall(n))
return false;
expr * body = to_quantifier(n)->get_expr();
unsigned num_decls = to_quantifier(n)->get_num_decls();
@ -117,7 +117,7 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_dependency * dep, e
}
bool macro_finder::is_arith_macro(expr * n, proof * pr, vector<justified_expr>& new_fmls) {
if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
if (!is_forall(n))
return false;
expr * body = to_quantifier(n)->get_expr();
unsigned num_decls = to_quantifier(n)->get_num_decls();

View file

@ -283,13 +283,11 @@ struct macro_manager::macro_expander_cfg : public default_rewriter_cfg {
subst_args[nidx] = n->get_arg(i);
}
var_subst s(m);
expr_ref rr(m);
s(def, num, subst_args.c_ptr(), rr);
expr_ref rr = s(def, num, subst_args.c_ptr());
m_trail.push_back(rr);
r = rr;
if (m.proofs_enabled()) {
expr_ref instance(m);
s(q->get_expr(), num, subst_args.c_ptr(), instance);
expr_ref instance = s(q->get_expr(), num, subst_args.c_ptr());
proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.c_ptr());
proof * q_pr = nullptr;
mm.m_decl2macro_pr.find(d, q_pr);

View file

@ -334,7 +334,7 @@ bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, ap
where t is a ground term, (f X) is the head.
*/
bool macro_util::is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def) {
if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
if (!is_forall(n))
return false;
TRACE("macro_util", tout << "processing: " << mk_pp(n, m_manager) << "\n";);
expr * body = to_quantifier(n)->get_expr();
@ -485,7 +485,7 @@ void macro_util::normalize_expr(app * head, unsigned num_decls, expr * t, expr_r
if (var_mapping[i] != 0)
tout << "#" << i << " -> " << mk_ll_pp(var_mapping[i], m_manager);
});
subst(t, var_mapping.size(), var_mapping.c_ptr(), norm_t);
norm_t = subst(t, var_mapping.size(), var_mapping.c_ptr());
}
else {
norm_t = t;

View file

@ -155,7 +155,7 @@ bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const {
// f[X] contains all universally quantified variables, and f does not occur in T[X].
TRACE("quasi_macros", tout << "Checking for quasi macro: " << mk_pp(e, m_manager) << std::endl;);
if (is_quantifier(e) && to_quantifier(e)->is_forall()) {
if (is_forall(e)) {
quantifier * q = to_quantifier(e);
expr * qe = q->get_expr();
if ((m_manager.is_eq(qe))) {
@ -251,7 +251,7 @@ void quasi_macros::quasi_macro_to_macro(quantifier * q, app * a, expr * t, quant
eq = m_manager.mk_eq(appl, ite);
macro = m_manager.mk_quantifier(true, new_var_names_rev.size(),
macro = m_manager.mk_quantifier(forall_k, new_var_names_rev.size(),
new_qsorts_rev.c_ptr(), new_var_names_rev.c_ptr(), eq);
}

View file

@ -16,17 +16,19 @@ Author:
Revision History:
--*/
#include "ast/normal_forms/defined_names.h"
#include "util/obj_hashtable.h"
#include "ast/normal_forms/defined_names.h"
#include "ast/used_vars.h"
#include "ast/rewriter/var_subst.h"
#include "ast/ast_smt2_pp.h"
#include "ast/ast_pp.h"
#include "ast/ast_util.h"
#include "ast/array_decl_plugin.h"
struct defined_names::impl {
typedef obj_map<expr, app *> expr2name;
typedef obj_map<expr, proof *> expr2proof;
ast_manager & m_manager;
ast_manager & m;
symbol m_z3name;
/**
@ -60,9 +62,9 @@ struct defined_names::impl {
app * gen_name(expr * e, sort_ref_buffer & var_sorts, buffer<symbol> & var_names);
void cache_new_name(expr * e, app * name);
void cache_new_name_intro_proof(expr * e, proof * pr);
void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result);
void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result);
virtual void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def);
void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result, symbol const& qid = symbol::null);
void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result, symbol const& qid = symbol::null);
virtual void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> & var_names, expr_ref & new_def);
bool mk_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr);
void push_scope();
void pop_scope(unsigned num_scopes);
@ -74,12 +76,13 @@ struct defined_names::impl {
struct defined_names::pos_impl : public defined_names::impl {
pos_impl(ast_manager & m, char const * fresh_prefix):impl(m, fresh_prefix) {}
void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def) override;
void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> & var_names, expr_ref & new_def) override;
};
defined_names::impl::impl(ast_manager & m, char const * prefix):
m_manager(m),
m(m),
m_exprs(m),
m_names(m),
m_apply_proofs(m) {
@ -107,20 +110,20 @@ app * defined_names::impl::gen_name(expr * e, sort_ref_buffer & var_sorts, buffe
sort * s = uv.get(i);
if (s) {
domain.push_back(s);
new_args.push_back(m_manager.mk_var(i, s));
new_args.push_back(m.mk_var(i, s));
var_sorts.push_back(s);
}
else {
var_sorts.push_back(m_manager.mk_bool_sort()); // could be any sort.
var_sorts.push_back(m.mk_bool_sort()); // could be any sort.
}
var_names.push_back(symbol(i));
}
sort * range = m_manager.get_sort(e);
func_decl * new_skolem_decl = m_manager.mk_fresh_func_decl(m_z3name, symbol::null, domain.size(), domain.c_ptr(), range);
app * n = m_manager.mk_app(new_skolem_decl, new_args.size(), new_args.c_ptr());
TRACE("mk_definition_bug", tout << "gen_name: " << mk_ismt2_pp(n, m_manager) << "\n";
for (unsigned i = 0; i < var_sorts.size(); i++) tout << mk_pp(var_sorts[i], m_manager) << " ";
sort * range = m.get_sort(e);
func_decl * new_skolem_decl = m.mk_fresh_func_decl(m_z3name, symbol::null, domain.size(), domain.c_ptr(), range);
app * n = m.mk_app(new_skolem_decl, new_args.size(), new_args.c_ptr());
TRACE("mk_definition_bug", tout << "gen_name: " << mk_ismt2_pp(n, m) << "\n";
for (unsigned i = 0; i < var_sorts.size(); i++) tout << mk_pp(var_sorts[i], m) << " ";
tout << "\n";);
return n;
}
@ -148,22 +151,22 @@ void defined_names::impl::cache_new_name_intro_proof(expr * e, proof * pr) {
A quantifier is added around \c def_conjunct, if sorts and names are not empty.
In this case, The application \c name is used as a pattern for the new quantifier.
*/
void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result) {
void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result, symbol const& qid) {
SASSERT(sorts.size() == names.size());
if (sorts.empty())
result = def_conjunct;
else {
expr * patterns[1] = { m_manager.mk_pattern(name) };
quantifier_ref q(m_manager);
q = m_manager.mk_forall(sorts.size(),
expr * patterns[1] = { m.mk_pattern(name) };
quantifier_ref q(m);
q = m.mk_forall(sorts.size(),
sorts.c_ptr(),
names.c_ptr(),
def_conjunct,
1, symbol::null, symbol::null,
1, qid, symbol::null,
1, patterns);
TRACE("mk_definition_bug", tout << "before elim_unused_vars:\n" << mk_ismt2_pp(q, m_manager) << "\n";);
elim_unused_vars(m_manager, q, params_ref(), result);
TRACE("mk_definition_bug", tout << "after elim_unused_vars:\n" << mk_ismt2_pp(result, m_manager) << "\n";);
TRACE("mk_definition_bug", tout << "before elim_unused_vars:\n" << mk_ismt2_pp(q, m) << "\n";);
result = elim_unused_vars(m, q, params_ref());
TRACE("mk_definition_bug", tout << "after elim_unused_vars:\n" << result << "\n";);
}
}
@ -172,44 +175,81 @@ void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbo
A quantifier is added around \c def_conjunct, if sorts and names are not empty.
In this case, The application \c name is used as a pattern for the new quantifier.
*/
void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result) {
expr_ref tmp(m_manager);
bound_vars(sorts, names, def_conjunct, name, tmp);
void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result, symbol const& qid) {
expr_ref tmp(m);
bound_vars(sorts, names, def_conjunct, name, tmp, qid);
result.push_back(tmp);
}
#define MK_OR m_manager.mk_or
#define MK_NOT m_manager.mk_not
#define MK_EQ m_manager.mk_eq
#define MK_OR m.mk_or
#define MK_NOT m.mk_not
#define MK_EQ m.mk_eq
void defined_names::impl::mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def) {
expr_ref_buffer defs(m_manager);
if (m_manager.is_bool(e)) {
void defined_names::impl::mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> & var_names, expr_ref & new_def) {
expr_ref_buffer defs(m);
if (m.is_bool(e)) {
bound_vars(var_sorts, var_names, MK_OR(MK_NOT(n), e), n, defs);
bound_vars(var_sorts, var_names, MK_OR(n, MK_NOT(e)), n, defs);
}
else if (m_manager.is_term_ite(e)) {
else if (m.is_term_ite(e)) {
bound_vars(var_sorts, var_names, MK_OR(MK_NOT(to_app(e)->get_arg(0)), MK_EQ(n, to_app(e)->get_arg(1))), n, defs);
bound_vars(var_sorts, var_names, MK_OR(to_app(e)->get_arg(0), MK_EQ(n, to_app(e)->get_arg(2))), n, defs);
}
else if (is_lambda(e)) {
// n(y) = \x . M[x,y]
// =>
// n(y)[x] = M, forall x y
//
// NB. The pattern is incomplete.
// consider store(a, i, v) == \lambda j . if i = j then v else a[j]
// the instantiation rules for store(a, i, v) are:
// sotre(a, i, v)[j] = if i = j then v else a[j] with patterns {a[j], store(a, i, v)} { store(a, i, v)[j] }
// The first pattern is not included.
// TBD use a model-based scheme for exracting instantiations instead of
// using multi-patterns.
//
quantifier* q = to_quantifier(e);
expr_ref_vector args(m);
expr_ref n2(m), n3(m);
var_shifter vs(m);
vs(n, q->get_num_decls(), n2);
args.push_back(n2);
var_sorts.append(q->get_num_decls(), q->get_decl_sorts());
var_names.append(q->get_num_decls(), q->get_decl_names());
for (unsigned i = 0; i < q->get_num_decls(); ++i) {
args.push_back(m.mk_var(q->get_num_decls() - i - 1, q->get_decl_sort(i)));
}
array_util autil(m);
func_decl * f = 0;
if (autil.is_as_array(n2, f)) {
n3 = m.mk_app(f, args.size()-1, args.c_ptr() + 1);
}
else {
n3 = autil.mk_select(args.size(), args.c_ptr());
}
bound_vars(var_sorts, var_names, MK_EQ(q->get_expr(), n3), to_app(n3), defs, m.lambda_def_qid());
}
else {
bound_vars(var_sorts, var_names, MK_EQ(e, n), n, defs);
}
new_def = defs.size() == 1 ? defs[0] : m_manager.mk_and(defs.size(), defs.c_ptr());
new_def = mk_and(m, defs.size(), defs.c_ptr());
}
void defined_names::pos_impl::mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def) {
void defined_names::pos_impl::mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> & var_names, expr_ref & new_def) {
bound_vars(var_sorts, var_names, MK_OR(MK_NOT(n), e), n, new_def);
}
bool defined_names::impl::mk_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr) {
TRACE("mk_definition_bug", tout << "making name for:\n" << mk_ismt2_pp(e, m_manager) << "\n";);
TRACE("mk_definition_bug", tout << "making name for:\n" << mk_ismt2_pp(e, m) << "\n";);
app * n_ptr;
if (m_expr2name.find(e, n_ptr)) {
TRACE("mk_definition_bug", tout << "name for expression is already cached..., returning false...\n";);
n = n_ptr;
if (m_manager.proofs_enabled()) {
if (m.proofs_enabled()) {
proof * pr_ptr = nullptr;
m_expr2proof.find(e, pr_ptr);
SASSERT(pr_ptr);
@ -218,24 +258,24 @@ bool defined_names::impl::mk_name(expr * e, expr_ref & new_def, proof_ref & new_
return false;
}
else {
sort_ref_buffer var_sorts(m_manager);
sort_ref_buffer var_sorts(m);
buffer<symbol> var_names;
n = gen_name(e, var_sorts, var_names);
cache_new_name(e, n);
TRACE("mk_definition_bug", tout << "name: " << mk_ismt2_pp(n, m_manager) << "\n";);
TRACE("mk_definition_bug", tout << "name: " << mk_ismt2_pp(n, m) << "\n";);
// variables are in reverse order in quantifiers
std::reverse(var_sorts.c_ptr(), var_sorts.c_ptr() + var_sorts.size());
std::reverse(var_names.c_ptr(), var_names.c_ptr() + var_names.size());
mk_definition(e, n, var_sorts, var_names, new_def);
TRACE("mk_definition_bug", tout << "new_def:\n" << mk_ismt2_pp(new_def, m_manager) << "\n";);
TRACE("mk_definition_bug", tout << "new_def:\n" << mk_ismt2_pp(new_def, m) << "\n";);
if (m_manager.proofs_enabled()) {
new_def_pr = m_manager.mk_def_intro(new_def);
pr = m_manager.mk_apply_def(e, n, new_def_pr);
if (m.proofs_enabled()) {
new_def_pr = m.mk_def_intro(new_def);
pr = m.mk_apply_def(e, n, new_def_pr);
cache_new_name_intro_proof(e, pr);
}
return true;
@ -257,7 +297,7 @@ void defined_names::impl::pop_scope(unsigned num_scopes) {
SASSERT(sz == m_names.size());
while (old_sz != sz) {
--sz;
if (m_manager.proofs_enabled()) {
if (m.proofs_enabled()) {
m_expr2proof.erase(m_exprs.back());
m_apply_proofs.pop_back();
}
@ -296,6 +336,15 @@ bool defined_names::mk_pos_name(expr * e, expr_ref & new_def, proof_ref & new_de
return m_pos_impl->mk_name(e, new_def, new_def_pr, n, pr);
}
expr_ref defined_names::mk_definition(expr * e, app * n) {
ast_manager& m = m_impl->m;
sort_ref_buffer var_sorts(m);
expr_ref new_def(m);
buffer<symbol> var_names;
m_impl->mk_definition(e, n, var_sorts, var_names, new_def);
return new_def;
}
void defined_names::push() {
m_impl->push_scope();
m_pos_impl->push_scope();

View file

@ -77,6 +77,11 @@ public:
*/
bool mk_pos_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr);
/**
\brief Create a definition for 'n' using 'e'.
*/
expr_ref mk_definition(expr * e, app * n);
void push();
void pop(unsigned num_scopes);
void reset();

View file

@ -22,7 +22,7 @@ Notes:
class name_exprs_core : public name_exprs {
struct cfg : public default_rewriter_cfg {
ast_manager & m_manager;
ast_manager & m;
defined_names & m_defined_names;
expr_predicate & m_pred;
@ -33,7 +33,7 @@ class name_exprs_core : public name_exprs {
proof_ref_vector * m_def_proofs;
cfg(ast_manager & m, defined_names & n, expr_predicate & pred):
m_manager(m),
m(m),
m_defined_names(n),
m_pred(pred),
m_r(m),
@ -43,12 +43,12 @@ class name_exprs_core : public name_exprs {
}
void gen_name_for_expr(expr * n, expr * & t, proof * & t_pr) {
expr_ref new_def(m_manager);
proof_ref new_def_pr(m_manager);
expr_ref new_def(m);
proof_ref new_def_pr(m);
if (m_defined_names.mk_name(n, new_def, new_def_pr, m_r, m_pr)) {
m_def_exprs->push_back(new_def);
if (m_manager.proofs_enabled())
if (m.proofs_enabled())
m_def_proofs->push_back(new_def_pr);
}
@ -57,7 +57,7 @@ class name_exprs_core : public name_exprs {
}
bool get_subst(expr * s, expr * & t, proof * & t_pr) {
TRACE("name_exprs", tout << "get_subst:\n" << mk_ismt2_pp(s, m_manager) << "\n";);
TRACE("name_exprs", tout << "get_subst:\n" << mk_ismt2_pp(s, m) << "\n";);
if (m_pred(s)) {
gen_name_for_expr(s, t, t_pr);
return true;
@ -84,7 +84,7 @@ public:
m_cfg.m_def_exprs = &new_defs;
m_cfg.m_def_proofs = &new_def_proofs;
m_rw(n, r, p);
TRACE("name_exprs", tout << mk_ismt2_pp(n, m_rw.m()) << "\n---->\n" << mk_ismt2_pp(r, m_rw.m()) << "\n";);
TRACE("name_exprs", tout << mk_ismt2_pp(n, m_rw.m()) << "\n---->\n" << r << "\n";);
}
@ -99,11 +99,11 @@ name_exprs * mk_expr_namer(ast_manager & m, defined_names & n, expr_predicate &
class name_quantifier_labels : public name_exprs_core {
class pred : public expr_predicate {
ast_manager & m_manager;
ast_manager & m;
public:
pred(ast_manager & m):m_manager(m) {}
pred(ast_manager & m):m(m) {}
bool operator()(expr * t) override {
return is_quantifier(t) || m_manager.is_label(t);
return is_quantifier(t) || m.is_label(t);
}
};
@ -124,16 +124,16 @@ name_exprs * mk_quantifier_label_namer(ast_manager & m, defined_names & n) {
class name_nested_formulas : public name_exprs_core {
struct pred : public expr_predicate {
ast_manager & m_manager;
ast_manager & m;
expr * m_root;
pred(ast_manager & m):m_manager(m), m_root(nullptr) {}
pred(ast_manager & m):m(m), m_root(0) {}
bool operator()(expr * t) override {
TRACE("name_exprs", tout << "name_nested_formulas::pred:\n" << mk_ismt2_pp(t, m_manager) << "\n";);
TRACE("name_exprs", tout << "name_nested_formulas::pred:\n" << mk_ismt2_pp(t, m) << "\n";);
if (is_app(t))
return to_app(t)->get_family_id() == m_manager.get_basic_family_id() && to_app(t)->get_num_args() > 0 && t != m_root;
return m_manager.is_label(t) || is_quantifier(t);
return to_app(t)->get_family_id() == m.get_basic_family_id() && to_app(t)->get_num_args() > 0 && t != m_root;
return m.is_label(t) || is_quantifier(t);
}
};

View file

@ -17,16 +17,16 @@ Notes:
Major revision on 2011-10-06
--*/
#include "util/warning.h"
#include "util/cooperate.h"
#include "ast/normal_forms/nnf.h"
#include "ast/normal_forms/nnf_params.hpp"
#include "util/warning.h"
#include "ast/used_vars.h"
#include "ast/well_sorted.h"
#include "ast/rewriter/var_subst.h"
#include "ast/normal_forms/name_exprs.h"
#include "ast/act_cache.h"
#include "util/cooperate.h"
#include "ast/rewriter/var_subst.h"
#include "ast/normal_forms/name_exprs.h"
#include "ast/ast_smt2_pp.h"
@ -67,36 +67,42 @@ enum nnf_mode {
class skolemizer {
typedef act_cache cache;
ast_manager & m_manager;
ast_manager & m;
symbol m_sk_hack;
bool m_sk_hack_enabled;
cache m_cache;
cache m_cache_pr;
void process(quantifier * q, expr_ref & r, proof_ref & p) {
if (q->get_kind() == lambda_k) {
TRACE("nnf", tout << expr_ref(q, m) << "\n";);
r = q;
p = nullptr;
return;
}
used_vars uv;
uv(q);
SASSERT(is_well_sorted(m(), q));
SASSERT(is_well_sorted(m, q));
unsigned sz = uv.get_max_found_var_idx_plus_1();
ptr_buffer<sort> sorts;
expr_ref_vector args(m());
expr_ref_vector args(m);
for (unsigned i = 0; i < sz; i++) {
sort * s = uv.get(i);
if (s != nullptr) {
sorts.push_back(s);
args.push_back(m().mk_var(i, s));
args.push_back(m.mk_var(i, s));
}
}
TRACE("skolemizer", tout << "skid: " << q->get_skid() << "\n";);
expr_ref_vector substitution(m());
expr_ref_vector substitution(m);
unsigned num_decls = q->get_num_decls();
for (unsigned i = num_decls; i > 0; ) {
--i;
sort * r = q->get_decl_sort(i);
func_decl * sk_decl = m().mk_fresh_func_decl(q->get_decl_name(i), q->get_skid(), sorts.size(), sorts.c_ptr(), r);
app * sk = m().mk_app(sk_decl, args.size(), args.c_ptr());
func_decl * sk_decl = m.mk_fresh_func_decl(q->get_decl_name(i), q->get_skid(), sorts.size(), sorts.c_ptr(), r);
app * sk = m.mk_app(sk_decl, args.size(), args.c_ptr());
substitution.push_back(sk);
}
//
@ -106,7 +112,7 @@ class skolemizer {
for (unsigned i = 0; i < sz; i++) {
sort * s = uv.get(i);
if (s != nullptr)
substitution.push_back(m().mk_var(i, s));
substitution.push_back(m.mk_var(i, s));
else
substitution.push_back(nullptr);
}
@ -118,9 +124,9 @@ class skolemizer {
//
// (VAR 0) should be in the last position of substitution.
//
var_subst s(m());
SASSERT(is_well_sorted(m(), q->get_expr()));
expr_ref tmp(m());
var_subst s(m);
SASSERT(is_well_sorted(m, q->get_expr()));
expr_ref tmp(m);
expr * body = q->get_expr();
if (m_sk_hack_enabled) {
unsigned num_patterns = q->get_num_patterns();
@ -128,27 +134,27 @@ class skolemizer {
expr * p = q->get_pattern(i);
if (is_sk_hack(p)) {
expr * sk_hack = to_app(p)->get_arg(0);
if (q->is_forall()) // check whether is in negative/positive context.
tmp = m().mk_or(body, m().mk_not(sk_hack)); // negative context
if (q->get_kind() == forall_k) // check whether is in negative/positive context.
tmp = m.mk_or(body, m.mk_not(sk_hack)); // negative context
else
tmp = m().mk_and(body, sk_hack); // positive context
tmp = m.mk_and(body, sk_hack); // positive context
body = tmp;
}
}
}
s(body, substitution.size(), substitution.c_ptr(), r);
r = s(body, substitution.size(), substitution.c_ptr());
p = nullptr;
if (m().proofs_enabled()) {
if (q->is_forall())
p = m().mk_skolemization(m().mk_not(q), m().mk_not(r));
if (m.proofs_enabled()) {
if (q->get_kind() == forall_k)
p = m.mk_skolemization(m.mk_not(q), m.mk_not(r));
else
p = m().mk_skolemization(q, r);
p = m.mk_skolemization(q, r);
}
}
public:
skolemizer(ast_manager & m):
m_manager(m),
m(m),
m_sk_hack("sk_hack"),
m_sk_hack_enabled(false),
m_cache(m),
@ -159,25 +165,23 @@ public:
m_sk_hack_enabled = f;
}
ast_manager & m() const { return m_manager; }
void operator()(quantifier * q, expr_ref & r, proof_ref & p) {
r = m_cache.find(q);
if (r.get() != nullptr) {
p = nullptr;
if (m().proofs_enabled())
if (m.proofs_enabled())
p = static_cast<proof*>(m_cache_pr.find(q));
}
else {
process(q, r, p);
m_cache.insert(q, r);
if (m().proofs_enabled())
if (m.proofs_enabled())
m_cache_pr.insert(q, p);
}
}
bool is_sk_hack(expr * p) const {
SASSERT(m().is_pattern(p));
SASSERT(m.is_pattern(p));
if (to_app(p)->get_num_args() != 1)
return false;
expr * body = to_app(p)->get_arg(0);
@ -186,7 +190,7 @@ public:
func_decl * f = to_app(body)->get_decl();
if (!(f->get_name() == m_sk_hack && f->get_arity() == 1))
return false;
if (!m().is_bool(body)) {
if (!m.is_bool(body)) {
warning_msg("sk_hack constant must return a Boolean");
return false;
}
@ -233,8 +237,8 @@ struct nnf::imp {
#define POS_NQ_CIDX 1 // positive polarity and not nested in a quantifier
#define NEG_Q_CIDX 2 // negative polarity and nested in a quantifier
#define POS_Q_CIDX 3 // positive polarity and nested in a quantifier
ast_manager & m_manager;
ast_manager & m;
vector<frame> m_frame_stack;
expr_ref_vector m_result_stack;
@ -263,7 +267,7 @@ struct nnf::imp {
unsigned long long m_max_memory; // in bytes
imp(ast_manager & m, defined_names & n, params_ref const & p):
m_manager(m),
m(m),
m_result_stack(m),
m_todo_defs(m),
m_todo_proofs(m),
@ -279,9 +283,9 @@ struct nnf::imp {
m_name_quant = mk_quantifier_label_namer(m, n);
}
ast_manager & m() const { return m_manager; }
// ast_manager & m() const { return m; }
bool proofs_enabled() const { return m().proofs_enabled(); }
bool proofs_enabled() const { return m.proofs_enabled(); }
~imp() {
for (unsigned i = 0; i < 4; i++) {
@ -334,7 +338,7 @@ struct nnf::imp {
}
void push_frame(expr * t, bool pol, bool in_q, bool cache_res) {
m_frame_stack.push_back(frame(expr_ref(t, m()), pol, in_q, cache_res, m_result_stack.size()));
m_frame_stack.push_back(frame(expr_ref(t, m), pol, in_q, cache_res, m_result_stack.size()));
}
static unsigned get_cache_idx(bool pol, bool in_q) {
@ -382,8 +386,8 @@ struct nnf::imp {
cooperate("nnf");
if (memory::get_allocation_size() > m_max_memory)
throw nnf_exception(Z3_MAX_MEMORY_MSG);
if (m().canceled())
throw nnf_exception(m().limit().get_cancel_msg());
if (m.canceled())
throw nnf_exception(m.limit().get_cancel_msg());
}
void set_new_child_flag() {
@ -397,16 +401,16 @@ struct nnf::imp {
}
void skip(expr * t, bool pol) {
expr * r = pol ? t : m().mk_not(t);
expr * r = pol ? t : m.mk_not(t);
m_result_stack.push_back(r);
if (proofs_enabled()) {
m_result_pr_stack.push_back(m().mk_oeq_reflexivity(r));
m_result_pr_stack.push_back(m.mk_oeq_reflexivity(r));
SASSERT(m_result_stack.size() == m_result_pr_stack.size());
}
}
bool visit(expr * t, bool pol, bool in_q) {
SASSERT(m().is_bool(t));
SASSERT(m.is_bool(t));
if (m_mode == NNF_SKOLEM || (m_mode == NNF_QUANT && !in_q)) {
if (!has_quantifiers(t) && !has_labels(t)) {
@ -456,12 +460,12 @@ struct nnf::imp {
proof * mk_proof(bool pol, unsigned num_parents, proof * const * parents, app * old_e, app * new_e) {
if (pol) {
if (old_e->get_decl() == new_e->get_decl())
return m().mk_oeq_congruence(old_e, new_e, num_parents, parents);
else
return m().mk_nnf_pos(old_e, new_e, num_parents, parents);
return m.mk_oeq_congruence(old_e, new_e, num_parents, parents);
else
return m.mk_nnf_pos(old_e, new_e, num_parents, parents);
}
else
return m().mk_nnf_neg(old_e, new_e, num_parents, parents);
else
return m.mk_nnf_neg(old_e, new_e, num_parents, parents);
}
bool process_and_or(app * t, frame & fr) {
@ -473,11 +477,11 @@ struct nnf::imp {
return false;
}
app * r;
if (m().is_and(t) == fr.m_pol)
r = m().mk_and(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos);
if (m.is_and(t) == fr.m_pol)
r = m.mk_and(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos);
else
r = m().mk_or(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos);
r = m.mk_or(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos);
m_result_stack.shrink(fr.m_spos);
m_result_stack.push_back(r);
if (proofs_enabled()) {
@ -500,7 +504,7 @@ struct nnf::imp {
if (proofs_enabled()) {
pr = m_result_pr_stack.back();
if (!fr.m_pol) {
pr = m().mk_nnf_neg(t, r, 1, &pr);
pr = m.mk_nnf_neg(t, r, 1, &pr);
m_result_pr_stack.pop_back();
m_result_pr_stack.push_back(pr);
SASSERT(m_result_stack.size() == m_result_pr_stack.size());
@ -526,10 +530,10 @@ struct nnf::imp {
app * r;
if (fr.m_pol)
r = m().mk_or(2, m_result_stack.c_ptr() + fr.m_spos);
r = m.mk_or(2, m_result_stack.c_ptr() + fr.m_spos);
else
r = m().mk_and(2, m_result_stack.c_ptr() + fr.m_spos);
r = m.mk_and(2, m_result_stack.c_ptr() + fr.m_spos);
m_result_stack.shrink(fr.m_spos);
m_result_stack.push_back(r);
if (proofs_enabled()) {
@ -570,7 +574,7 @@ struct nnf::imp {
expr * _then = rs[2];
expr * _else = rs[3];
app * r = m().mk_and(m().mk_or(_not_cond, _then), m().mk_or(_cond, _else));
app * r = m.mk_and(m.mk_or(_not_cond, _then), m.mk_or(_cond, _else));
m_result_stack.shrink(fr.m_spos);
m_result_stack.push_back(r);
if (proofs_enabled()) {
@ -582,7 +586,7 @@ struct nnf::imp {
return true;
}
bool is_eq(app * t) const { return m().is_eq(t); }
bool is_eq(app * t) const { return m.is_eq(t); }
bool process_iff_xor(app * t, frame & fr) {
SASSERT(t->get_num_args() == 2);
@ -614,10 +618,10 @@ struct nnf::imp {
expr * not_rhs = rs[3];
app * r;
if (is_eq(t) == fr.m_pol)
r = m().mk_and(m().mk_or(not_lhs, rhs), m().mk_or(lhs, not_rhs));
if (is_eq(t) == fr.m_pol)
r = m.mk_and(m.mk_or(not_lhs, rhs), m.mk_or(lhs, not_rhs));
else
r = m().mk_and(m().mk_or(lhs, rhs), m().mk_or(not_lhs, not_rhs));
r = m.mk_and(m.mk_or(lhs, rhs), m.mk_or(not_lhs, not_rhs));
m_result_stack.shrink(fr.m_spos);
m_result_stack.push_back(r);
if (proofs_enabled()) {
@ -630,7 +634,7 @@ struct nnf::imp {
}
bool process_eq(app * t, frame & fr) {
if (m().is_iff(t))
if (m.is_bool(t->get_arg(0)))
return process_iff_xor(t, fr);
else
return process_default(t, fr);
@ -639,21 +643,20 @@ struct nnf::imp {
bool process_default(app * t, frame & fr) {
SASSERT(fr.m_i == 0);
if (m_mode == NNF_FULL || t->has_quantifiers() || t->has_labels()) {
expr_ref n2(m());
proof_ref pr2(m());
expr_ref n2(m);
proof_ref pr2(m);
if (m_mode == NNF_FULL || (m_mode != NNF_SKOLEM && fr.m_in_q))
m_name_nested_formulas->operator()(t, m_todo_defs, m_todo_proofs, n2, pr2);
else
m_name_quant->operator()(t, m_todo_defs, m_todo_proofs, n2, pr2);
if (!fr.m_pol)
n2 = m().mk_not(n2);
n2 = m.mk_not(n2);
m_result_stack.push_back(n2);
if (proofs_enabled()) {
if (!fr.m_pol) {
proof * prs[1] = { pr2 };
pr2 = m().mk_oeq_congruence(m().mk_not(t), static_cast<app*>(n2.get()), 1, prs);
pr2 = m.mk_oeq_congruence(m.mk_not(t), static_cast<app*>(n2.get()), 1, prs);
}
m_result_pr_stack.push_back(pr2);
SASSERT(m_result_stack.size() == m_result_pr_stack.size());
@ -681,24 +684,24 @@ struct nnf::imp {
buffer<symbol> names;
bool pos;
m().is_label(t, pos, names);
expr_ref r(m());
proof_ref pr(m());
m.is_label(t, pos, names);
expr_ref r(m);
proof_ref pr(m);
if (fr.m_pol == pos) {
expr * lbl_lit = m().mk_label_lit(names.size(), names.c_ptr());
r = m().mk_and(arg, lbl_lit);
expr * lbl_lit = m.mk_label_lit(names.size(), names.c_ptr());
r = m.mk_and(arg, lbl_lit);
if (proofs_enabled()) {
expr_ref aux(m_manager);
aux = m().mk_label(true, names.size(), names.c_ptr(), arg);
pr = m().mk_transitivity(mk_proof(fr.m_pol, 1, &arg_pr, t, to_app(aux)),
m().mk_iff_oeq(m().mk_rewrite(aux, r)));
expr_ref aux(m);
aux = m.mk_label(true, names.size(), names.c_ptr(), arg);
pr = m.mk_transitivity(mk_proof(fr.m_pol, 1, &arg_pr, t, to_app(aux)),
m.mk_iff_oeq(m.mk_rewrite(aux, r)));
}
}
else {
r = arg;
if (proofs_enabled()) {
proof * p1 = m().mk_iff_oeq(m().mk_rewrite(t, t->get_arg(0)));
pr = m().mk_transitivity(p1, arg_pr);
proof * p1 = m.mk_iff_oeq(m.mk_rewrite(t, t->get_arg(0)));
pr = m.mk_transitivity(p1, arg_pr);
}
}
@ -713,9 +716,9 @@ struct nnf::imp {
}
bool process_app(app * t, frame & fr) {
TRACE("nnf", tout << mk_ismt2_pp(t, m()) << "\n";);
SASSERT(m().is_bool(t));
if (t->get_family_id() == m().get_basic_family_id()) {
TRACE("nnf", tout << mk_ismt2_pp(t, m) << "\n";);
SASSERT(m.is_bool(t));
if (t->get_family_id() == m.get_basic_family_id()) {
switch (static_cast<basic_op_kind>(t->get_decl_kind())) {
case OP_AND: case OP_OR:
return process_and_or(t, fr);
@ -734,7 +737,7 @@ struct nnf::imp {
}
}
if (m().is_label(t)) {
if (m.is_label(t)) {
return process_label(t, fr);
}
@ -747,28 +750,51 @@ struct nnf::imp {
}
bool process_quantifier(quantifier * q, frame & fr) {
expr_ref r(m());
proof_ref pr(m());
TRACE("nnf", tout << expr_ref(q, m) << "\n";);
expr_ref r(m);
proof_ref pr(m);
if (fr.m_i == 0) {
fr.m_i = 1;
if (q->is_forall() == fr.m_pol || !m_skolemize) {
if (is_lambda(q)) {
if (!visit(q->get_expr(), fr.m_pol, true))
return false;
}
else if (is_forall(q) == fr.m_pol || !m_skolemize) {
if (!visit(q->get_expr(), fr.m_pol, true))
return false;
}
else {
m_skolemizer(q, r, pr);
if (!visit(r, !q->is_forall(), fr.m_in_q))
if (!visit(r, !is_forall(q), fr.m_in_q))
return false;
}
}
if (q->is_forall() == fr.m_pol || !m_skolemize) {
if (is_lambda(q)) {
expr * new_expr = m_result_stack.back();
quantifier * new_q = m.update_quantifier(q, new_expr);
proof * new_q_pr = nullptr;
if (proofs_enabled()) {
// proof * new_expr_pr = m_result_pr_stack.back();
new_q_pr = m.mk_rewrite(q, new_q); // TBD use new_expr_pr
}
m_result_stack.pop_back();
m_result_stack.push_back(new_q);
if (proofs_enabled()) {
m_result_pr_stack.pop_back();
m_result_pr_stack.push_back(new_q_pr);
SASSERT(m_result_stack.size() == m_result_pr_stack.size());
}
return true;
}
else if (is_forall(q) == fr.m_pol || !m_skolemize) {
expr * new_expr = m_result_stack.back();
proof * new_expr_pr = proofs_enabled() ? m_result_pr_stack.back() : nullptr;
ptr_buffer<expr> new_patterns;
if (q->is_forall() == fr.m_pol) {
if (is_forall(q) == fr.m_pol) {
// collect non sk_hack patterns
unsigned num_patterns = q->get_num_patterns();
for (unsigned i = 0; i < num_patterns; i++) {
@ -785,14 +811,19 @@ struct nnf::imp {
quantifier * new_q = nullptr;
proof * new_q_pr = nullptr;
if (fr.m_pol) {
new_q = m().update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(), new_expr);
if (proofs_enabled())
new_q_pr = m().mk_nnf_pos(q, new_q, 1, &new_expr_pr);
new_q = m.update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(), new_expr);
if (proofs_enabled()) {
new_expr_pr = m.mk_bind_proof(q, new_expr_pr);
new_q_pr = m.mk_nnf_pos(q, new_q, 1, &new_expr_pr);
}
}
else {
new_q = m().update_quantifier(q, !q->is_forall(), new_patterns.size(), new_patterns.c_ptr(), new_expr);
if (proofs_enabled())
new_q_pr = m().mk_nnf_neg(q, new_q, 1, &new_expr_pr);
quantifier_kind k = is_forall(q)? exists_k : forall_k;
new_q = m.update_quantifier(q, k, new_patterns.size(), new_patterns.c_ptr(), new_expr);
if (proofs_enabled()) {
new_expr_pr = m.mk_bind_proof(q, new_expr_pr);
new_q_pr = m.mk_nnf_neg(q, new_q, 1, &new_expr_pr);
}
}
m_result_stack.pop_back();
@ -809,7 +840,7 @@ struct nnf::imp {
// However, the proof must be updated
if (proofs_enabled()) {
m_skolemizer(q, r, pr); // retrieve the proof
pr = m().mk_transitivity(pr, m_result_pr_stack.back());
pr = m.mk_transitivity(pr, m_result_pr_stack.back());
m_result_pr_stack.pop_back();
m_result_pr_stack.push_back(pr);
SASSERT(m_result_stack.size() == m_result_pr_stack.size());
@ -827,14 +858,14 @@ struct nnf::imp {
result_pr = m_result_pr_stack.back();
m_result_pr_stack.pop_back();
if (result_pr.get() == nullptr)
result_pr = m().mk_reflexivity(t);
result_pr = m.mk_reflexivity(t);
SASSERT(m_result_pr_stack.empty());
}
}
void process(expr * t, expr_ref & result, proof_ref & result_pr) {
TRACE("nnf", tout << "processing:\n" << mk_ismt2_pp(t, m()) << "\n";);
SASSERT(m().is_bool(t));
TRACE("nnf", tout << "processing:\n" << mk_ismt2_pp(t, m) << "\n";);
SASSERT(m.is_bool(t));
if (visit(t, true /* positive polarity */, false /* not nested in quantifier */)) {
recover_result(t, result, result_pr);
@ -883,13 +914,13 @@ struct nnf::imp {
unsigned old_sz2 = new_def_proofs.size();
for (unsigned i = 0; i < m_todo_defs.size(); i++) {
expr_ref dr(m());
proof_ref dpr(m());
expr_ref dr(m);
proof_ref dpr(m);
process(m_todo_defs.get(i), dr, dpr);
new_defs.push_back(dr);
if (proofs_enabled()) {
proof * new_pr = m().mk_modus_ponens(m_todo_proofs.get(i), dpr);
new_def_proofs.push_back(new_pr);
proof * new_pr = m.mk_modus_ponens(m_todo_proofs.get(i), dpr);
new_def_proofs.push_back(new_pr);
}
}
std::reverse(new_defs.c_ptr() + old_sz1, new_defs.c_ptr() + new_defs.size());
@ -909,7 +940,7 @@ nnf::~nnf() {
void nnf::operator()(expr * n, expr_ref_vector & new_defs, proof_ref_vector & new_def_proofs, expr_ref & r, proof_ref & p) {
m_imp->operator()(n, new_defs, new_def_proofs, r, p);
TRACE("nnf_result", tout << mk_ismt2_pp(n, m_imp->m()) << "\nNNF result:\n" << mk_ismt2_pp(r, m_imp->m()) << "\n";);
TRACE("nnf_result", tout << expr_ref(n, r.get_manager()) << "\nNNF result:\n" << new_defs << "\n" << r << "\n";);
}
void nnf::updt_params(params_ref const & p) {

View file

@ -49,7 +49,8 @@ struct pull_quant::imp {
if (is_quantifier(child)) {
quantifier * q = to_quantifier(child);
expr * body = q->get_expr();
result = m_manager.update_quantifier(q, !q->is_forall(), m_manager.mk_not(body));
quantifier_kind k = q->get_kind() == forall_k ? exists_k : forall_k;
result = m_manager.update_quantifier(q, k, m_manager.mk_not(body));
return true;
}
else {
@ -149,7 +150,7 @@ struct pull_quant::imp {
// 3) MBQI
std::reverse(var_sorts.begin(), var_sorts.end());
std::reverse(var_names.begin(), var_names.end());
result = m_manager.mk_quantifier(forall_children,
result = m_manager.mk_quantifier(forall_children ? forall_k : exists_k,
var_sorts.size(),
var_sorts.c_ptr(),
var_names.c_ptr(),
@ -220,9 +221,7 @@ struct pull_quant::imp {
expr_ref_buffer new_args(m_manager);
expr_ref new_arg(m_manager);
ptr_buffer<proof> proofs;
unsigned num = to_app(n)->get_num_args();
for (unsigned i = 0; i < num; i++) {
expr * arg = to_app(n)->get_arg(i);
for (expr * arg : *to_app(n)) {
pull_quant1(arg , new_arg);
new_args.push_back(new_arg);
if (new_arg != arg)
@ -277,10 +276,13 @@ struct pull_quant::imp {
expr_ref & result,
proof_ref & result_pr) {
if (old_q->is_exists()) {
if (is_exists(old_q)) {
UNREACHABLE();
return false;
}
if (is_lambda(old_q)) {
return false;
}
if (!is_forall(new_body))
return false;

View file

@ -53,7 +53,7 @@ expr_pattern_match::match_quantifier(quantifier* qf, app_ref_vector& patterns, u
m_regs[0] = qf->get_expr();
for (unsigned i = 0; i < m_precompiled.size(); ++i) {
quantifier* qf2 = m_precompiled[i].get();
if (qf2->is_forall() != qf->is_forall()) {
if (qf2->get_kind() != qf->get_kind() || is_lambda(qf)) {
continue;
}
if (qf2->get_num_decls() != qf->get_num_decls()) {

View file

@ -582,7 +582,7 @@ bool pattern_inference_cfg::reduce_quantifier(
proof_ref & result_pr) {
TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m) << "\n";);
if (!q->is_forall()) {
if (!is_forall(q)) {
return false;
}
@ -673,6 +673,7 @@ bool pattern_inference_cfg::reduce_quantifier(
new_q = m.update_quantifier_weight(new_q, weight);
if (m.proofs_enabled()) {
proof* new_body_pr = m.mk_reflexivity(new_body);
new_body_pr = m.mk_bind_proof(new_q, new_body_pr);
result_pr = m.mk_quant_intro(q, new_q, new_body_pr);
}
@ -690,7 +691,7 @@ bool pattern_inference_cfg::reduce_quantifier(
}
new_q = m.update_quantifier(result2, new_patterns.size(), (expr**) new_patterns.c_ptr(), result2->get_expr());
if (m.proofs_enabled()) {
result_pr = m.mk_transitivity(new_pr, m.mk_quant_intro(result2, new_q, m.mk_reflexivity(new_q->get_expr())));
result_pr = m.mk_transitivity(new_pr, m.mk_quant_intro(result2, new_q, m.mk_bind_proof(new_q, m.mk_reflexivity(new_q->get_expr()))));
}
TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m) << "\n";);
}

View file

@ -346,7 +346,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
to_quantifier(t1.get())->get_expr() == s1.get() &&
to_quantifier(t2.get())->get_expr() == s2.get() &&
to_quantifier(t1.get())->get_num_decls() == to_quantifier(t2.get())->get_num_decls() &&
to_quantifier(t1.get())->is_forall() == to_quantifier(t2.get())->is_forall()) {
to_quantifier(t1.get())->get_kind() == to_quantifier(t2.get())->get_kind()) {
quantifier* q1 = to_quantifier(t1.get());
quantifier* q2 = to_quantifier(t2.get());
for (unsigned i = 0; i < q1->get_num_decls(); ++i) {
@ -734,9 +734,10 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
is_forall = true;
}
if (is_quantifier(e)) {
q = to_quantifier(e);
SASSERT(!is_lambda(e));
q = to_quantifier(e);
// TBD check that quantifier is properly instantiated
return is_forall == q->is_forall();
return is_forall == ::is_forall(q);
}
}
UNREACHABLE();
@ -784,7 +785,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
// SASSERT(to_quantifier(premise)->get_num_decls() == sub.size());
premise = to_quantifier(premise)->get_expr();
}
vs(premise, sub.size(), sub.c_ptr(), premise);
premise = vs(premise, sub.size(), sub.c_ptr());
}
fmls.push_back(premise.get());
TRACE("proof_checker",
@ -974,7 +975,7 @@ bool proof_checker::match_app(expr const* e, func_decl_ref& d, expr_ref_vector&
bool proof_checker::match_quantifier(expr const* e, bool& is_univ, sort_ref_vector& sorts, expr_ref& body) const {
if (is_quantifier(e)) {
quantifier const* q = to_quantifier(e);
is_univ = q->is_forall();
is_univ = is_forall(q);
body = q->get_expr();
for (unsigned i = 0; i < q->get_num_decls(); ++i) {
sorts.push_back(q->get_decl_sort(i));

View file

@ -975,9 +975,7 @@ private:
void compose(expr_ref_vector& sub, expr_ref_vector const& s0) {
for (unsigned i = 0; i < sub.size(); ++i) {
expr_ref e(m);
var_subst(m, false)(sub[i].get(), s0.size(), s0.c_ptr(), e);
sub[i] = e;
sub[i] = var_subst(m, false)(sub[i].get(), s0.size(), s0.c_ptr());
}
}
@ -995,7 +993,7 @@ private:
tout << sub.size() << "\n";);
return;
}
var_subst(m, false)(q->get_expr(), sub.size(), sub.c_ptr(), fml);
fml = var_subst(m, false)(q->get_expr(), sub.size(), sub.c_ptr());
}
};

View file

@ -20,6 +20,7 @@ Notes:
#include "ast/rewriter/array_rewriter_params.hpp"
#include "ast/ast_lt.h"
#include "ast/ast_pp.h"
#include "ast/rewriter/var_subst.h"
void array_rewriter::updt_params(params_ref const & _p) {
array_rewriter_params p(_p);
@ -196,6 +197,17 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args,
return BR_DONE;
}
if (is_lambda(args[0])) {
// anywhere lambda reduction as opposed to whnf
// select(lambda(X) M, N) -> M[N/X]
quantifier* q = to_quantifier(args[0]);
SASSERT(q->get_num_decls() == num_args - 1);
var_subst subst(m());
result = subst(q->get_expr(), num_args - 1, args + 1);
return BR_REWRITE_FULL;
}
if (m_util.is_as_array(args[0])) {
// select(as-array[f], I) --> f(I)
func_decl * f = m_util.get_as_array_func_decl(to_app(args[0]));

View file

@ -636,7 +636,7 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend);
new_decl_names.push_back(n);
}
}
result = m().mk_quantifier(old_q->is_forall(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(),
result = m().mk_quantifier(old_q->get_kind(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(),
new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(),
old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns);
result_pr = nullptr;

View file

@ -588,58 +588,39 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result)
VERIFY(m().is_ite(ite, cond, t, e));
SASSERT(m().is_value(val));
if (m().is_value(t) && m().is_value(e)) {
if (t != val && e != val) {
TRACE("try_ite_value", tout << mk_ismt2_pp(t, m()) << " " << mk_ismt2_pp(e, m()) << " " << mk_ismt2_pp(val, m()) << "\n";
tout << t << " " << e << " " << val << "\n";);
result = m().mk_false();
}
else if (t == val && e == val) {
if (m().are_distinct(val, e)) {
result = m().mk_and(m().mk_eq(t, val), cond);
return BR_REWRITE2;
}
if (m().are_distinct(val, t)) {
result = m().mk_and(m().mk_eq(e, val), m().mk_not(cond));
return BR_REWRITE2;
}
if (m().are_equal(val, t)) {
if (m().are_equal(val, e)) {
result = m().mk_true();
}
else if (t == val) {
result = cond;
return BR_DONE;
}
else {
SASSERT(e == val);
mk_not(cond, result);
result = m().mk_or(m().mk_eq(e, val), cond);
}
return BR_DONE;
return BR_REWRITE2;
}
if (m_ite_extra_rules) {
if (m().is_value(t)) {
if (val == t) {
result = m().mk_or(cond, m().mk_eq(val, e));
}
else {
mk_not(cond, result);
result = m().mk_and(result, m().mk_eq(val, e));
}
return BR_REWRITE2;
}
if (m().is_value(e)) {
if (val == e) {
mk_not(cond, result);
result = m().mk_or(result, m().mk_eq(val, t));
}
else {
result = m().mk_and(cond, m().mk_eq(val, t));
}
return BR_REWRITE2;
}
if (m().are_equal(val, e)) {
result = m().mk_or(m().mk_eq(t, val), m().mk_not(cond));
return BR_REWRITE2;
}
{
expr* cond2, *t2, *e2;
if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
try_ite_value(to_app(t), val, result);
result = m().mk_ite(cond, result, m().mk_eq(e, val));
return BR_REWRITE2;
}
if (m().is_ite(e, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
try_ite_value(to_app(e), val, result);
result = m().mk_ite(cond, m().mk_eq(t, val), result);
return BR_REWRITE2;
}
expr* cond2 = nullptr, *t2 = nullptr, *e2 = nullptr;
if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
try_ite_value(to_app(t), val, result);
result = m().mk_ite(cond, result, m().mk_eq(e, val));
return BR_REWRITE2;
}
if (m().is_ite(e, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
try_ite_value(to_app(e), val, result);
result = m().mk_ite(cond, m().mk_eq(t, val), result);
return BR_REWRITE2;
}
return BR_FAILED;

View file

@ -87,20 +87,16 @@ bool bv_elim_cfg::reduce_quantifier(quantifier * q,
expr* const* sub = subst_map.c_ptr();
unsigned sub_size = subst_map.size();
subst(old_body, sub_size, sub, new_body);
new_body = subst(old_body, sub_size, sub);
for (unsigned j = 0; j < q->get_num_patterns(); j++) {
expr_ref pat(m);
subst(new_patterns[j], sub_size, sub, pat);
pats.push_back(pat);
pats.push_back(subst(new_patterns[j], sub_size, sub));
}
for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
expr_ref nopat(m);
subst(new_no_patterns[j], sub_size, sub, nopat);
no_pats.push_back(nopat);
no_pats.push_back(subst(new_no_patterns[j], sub_size, sub));
}
result = m.mk_quantifier(true,
result = m.mk_quantifier(forall_k,
names.size(),
sorts.c_ptr(),
names.c_ptr(),

View file

@ -133,7 +133,7 @@ void der::operator()(quantifier * q, expr_ref & r, proof_ref & pr) {
// Eliminate variables that have become unused
if (reduced && is_forall(r)) {
quantifier * q = to_quantifier(r);
elim_unused_vars(m_manager, q, params_ref(), r);
r = elim_unused_vars(m_manager, q, params_ref());
if (m_manager.proofs_enabled()) {
proof * p1 = m_manager.mk_elim_unused_vars(q, r);
pr = m_manager.mk_transitivity(pr, p1);
@ -343,8 +343,7 @@ void der::create_substitution(unsigned sz) {
expr_ref cur(m_map[m_order[i]], m_manager);
// do all the previous substitutions before inserting
expr_ref r(m_manager);
m_subst(cur, m_subst_map.size(), m_subst_map.c_ptr(), r);
expr_ref r = m_subst(cur, m_subst_map.size(), m_subst_map.c_ptr());
unsigned inx = sz - m_order[i]- 1;
SASSERT(m_subst_map[inx]==0);
@ -369,21 +368,18 @@ void der::apply_substitution(quantifier * q, expr_ref & r) {
unsigned sz = m_new_args.size();
expr_ref t(m_manager);
t = (sz == 1) ? m_new_args[0] : m_manager.mk_or(sz, m_new_args.c_ptr());
expr_ref new_e(m_manager);
m_subst(t, m_subst_map.size(), m_subst_map.c_ptr(), new_e);
expr_ref new_e = m_subst(t, m_subst_map.size(), m_subst_map.c_ptr());
// don't forget to update the quantifier patterns
expr_ref_buffer new_patterns(m_manager);
expr_ref_buffer new_no_patterns(m_manager);
for (unsigned j = 0; j < q->get_num_patterns(); j++) {
expr_ref new_pat(m_manager);
m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_pat);
expr_ref new_pat = m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
new_patterns.push_back(new_pat);
}
for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
expr_ref new_nopat(m_manager);
m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_nopat);
expr_ref new_nopat = m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
new_no_patterns.push_back(new_nopat);
}

View file

@ -100,7 +100,7 @@ void distribute_forall::reduce1_app(app * a) {
void distribute_forall::reduce1_quantifier(quantifier * q) {
// This transformation is applied after skolemization/quantifier elimination. So, all quantifiers are universal.
SASSERT(q->is_forall());
SASSERT(q->get_kind() == forall_k);
// This transformation is applied after basic pre-processing steps.
// So, we can assume that
@ -126,8 +126,7 @@ void distribute_forall::reduce1_quantifier(quantifier * q) {
br.mk_not(arg, not_arg);
quantifier_ref tmp_q(m_manager);
tmp_q = m_manager.update_quantifier(q, not_arg);
expr_ref new_q(m_manager);
elim_unused_vars(m_manager, tmp_q, params_ref(), new_q);
expr_ref new_q = elim_unused_vars(m_manager, tmp_q, params_ref());
new_args.push_back(new_q);
}
expr_ref result(m_manager);

View file

@ -114,7 +114,7 @@ bool elim_bounds_cfg::reduce_quantifier(quantifier * q,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
if (!q->is_forall()) {
if (!is_forall(q)) {
return false;
}
unsigned num_vars = q->get_num_decls();
@ -194,7 +194,7 @@ bool elim_bounds_cfg::reduce_quantifier(quantifier * q,
}
quantifier_ref new_q(m);
new_q = m.update_quantifier(q, new_body);
elim_unused_vars(m, new_q, params_ref(), result);
result = elim_unused_vars(m, new_q, params_ref());
result_pr = m.mk_rewrite(q, result);
TRACE("elim_bounds", tout << mk_pp(q, m) << "\n" << result << "\n";);
return true;

View file

@ -159,6 +159,8 @@ struct enum2bv_rewriter::imp {
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
if (q->get_kind() == lambda_k) return false;
m_sorts.reset();
expr_ref_vector bounds(m);
bool found = false;
@ -182,15 +184,20 @@ struct enum2bv_rewriter::imp {
}
expr_ref new_body_ref(old_body, m), tmp(m);
if (!bounds.empty()) {
if (q->is_forall()) {
switch (q->get_kind()) {
case forall_k:
new_body_ref = m.mk_implies(mk_and(bounds), new_body_ref);
}
else {
break;
case exists_k:
bounds.push_back(new_body_ref);
new_body_ref = mk_and(bounds);
break;
case lambda_k:
UNREACHABLE();
break;
}
}
result = m.mk_quantifier(q->is_forall(), q->get_num_decls(), m_sorts.c_ptr(), q->get_decl_names(), new_body_ref,
result = m.mk_quantifier(q->get_kind(), q->get_num_decls(), m_sorts.c_ptr(), q->get_decl_names(), new_body_ref,
q->get_weight(), q->get_qid(), q->get_skid(),
q->get_num_patterns(), new_patterns,
q->get_num_no_patterns(), new_no_patterns);

View file

@ -32,7 +32,7 @@ bool simplify_inj_axiom(ast_manager & m, quantifier * q, expr_ref & result) {
expr* arg1 = nullptr, * arg2 = nullptr, *narg = nullptr;
expr* app1 = nullptr, * app2 = nullptr;
expr* var1 = nullptr, * var2 = nullptr;
if (q->is_forall() && m.is_or(n, arg1, arg2)) {
if (is_forall(q) && m.is_or(n, arg1, arg2)) {
if (m.is_not(arg2))
std::swap(arg1, arg2);
if (m.is_not(arg1, narg) &&

View file

@ -79,12 +79,12 @@ public:
vars.push_back(a);
}
expr * const * exprs = (expr* const*) (vars.c_ptr() + vars.size()- nd);
instantiate(m, q, exprs, result);
result = instantiate(m, q, exprs);
}
unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector<sort>* sorts, svector<symbol>* names, bool use_fresh, bool rewrite_ok) {
unsigned pull_quantifier(bool _is_forall, expr_ref& fml, ptr_vector<sort>* sorts, svector<symbol>* names, bool use_fresh, bool rewrite_ok) {
unsigned index = var_counter().get_next_var(fml);
while (is_quantifier(fml) && (is_forall == to_quantifier(fml)->is_forall())) {
while (is_quantifier(fml) && _is_forall == is_forall(fml)) {
quantifier* q = to_quantifier(fml);
index += q->get_num_decls();
if (names) {
@ -99,7 +99,7 @@ public:
return index;
}
app_ref_vector vars(m);
pull_quantifier(is_forall, fml, vars, use_fresh, rewrite_ok);
pull_quantifier(_is_forall, fml, vars, use_fresh, rewrite_ok);
if (vars.empty()) {
return index;
}
@ -277,12 +277,16 @@ private:
}
case AST_QUANTIFIER: {
quantifier* q = to_quantifier(fml);
expr_ref tmp(m);
if (!is_compatible(qt, q->is_forall())) {
if (is_lambda(q)) {
result = fml;
break;
}
set_quantifier_type(qt, q->is_forall());
expr_ref tmp(m);
if (!is_compatible(qt, is_forall(q))) {
result = fml;
break;
}
set_quantifier_type(qt, is_forall(q));
extract_quantifier(q, vars, tmp, use_fresh);
pull_quantifier(tmp, qt, vars, result, use_fresh, rewrite_ok);
break;

View file

@ -208,12 +208,10 @@ void rewriter_core::cleanup() {
#ifdef _TRACE
void rewriter_core::display_stack(std::ostream & out, unsigned pp_depth) {
svector<frame>::iterator it = m_frame_stack.begin();
svector<frame>::iterator end = m_frame_stack.end();
for (; it != end; ++it) {
out << mk_bounded_pp(it->m_curr, m(), pp_depth) << "\n";
out << "state: " << it->m_state << "\n";
out << "cache: " << it->m_cache_result << ", new_child: " << it->m_new_child << ", max-depth: " << it->m_max_depth << ", i: " << it->m_i << "\n";
for (frame& f : m_frame_stack) {
out << mk_bounded_pp(f.m_curr, m(), pp_depth) << "\n";
out << "state: " << f.m_state << "\n";
out << "cache: " << f.m_cache_result << ", new_child: " << f.m_new_child << ", max-depth: " << f.m_max_depth << ", i: " << f.m_i << "\n";
out << "------------------\n";
}
}

View file

@ -350,11 +350,13 @@ public:
void update_inv_binding_at(unsigned i, expr* binding);
void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
void operator()(expr * t, expr_ref & result) { operator()(t, result, m_pr); }
void operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result) {
expr_ref operator()(expr * n, unsigned num_bindings, expr * const * bindings) {
expr_ref result(m());
SASSERT(!m_proof_gen);
reset();
set_inv_bindings(num_bindings, bindings);
operator()(n, result);
return result;
}
void resume(expr_ref & result, proof_ref & result_pr);

View file

@ -542,7 +542,7 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
}
result_stack().shrink(fr.m_spos);
result_stack().push_back(m_r.get());
SASSERT(m().is_bool(m_r));
SASSERT(m().get_sort(q) == m().get_sort(m_r));
if (!ProofGen) {
SASSERT(num_decls <= m_bindings.size());
m_bindings.shrink(m_bindings.size() - num_decls);

View file

@ -36,7 +36,7 @@ expr_ref sym_expr::accept(expr* e) {
switch (m_ty) {
case t_pred: {
var_subst subst(m);
subst(m_t, 1, &e, result);
result = subst(m_t, 1, &e);
break;
}
case t_char:

View file

@ -16,6 +16,7 @@ Author:
Notes:
--*/
#include "util/cooperate.h"
#include "ast/rewriter/th_rewriter.h"
#include "ast/rewriter/rewriter_params.hpp"
#include "ast/rewriter/bool_rewriter.h"
@ -28,10 +29,9 @@ Notes:
#include "ast/rewriter/pb_rewriter.h"
#include "ast/rewriter/seq_rewriter.h"
#include "ast/rewriter/rewriter_def.h"
#include "ast/rewriter/var_subst.h"
#include "ast/expr_substitution.h"
#include "ast/ast_smt2_pp.h"
#include "util/cooperate.h"
#include "ast/rewriter/var_subst.h"
#include "ast/ast_util.h"
#include "ast/well_sorted.h"
@ -606,7 +606,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
quantifier_ref q1(m());
proof * p1 = nullptr;
if (is_quantifier(new_body) &&
to_quantifier(new_body)->is_forall() == old_q->is_forall() &&
to_quantifier(new_body)->get_kind() == old_q->get_kind() &&
to_quantifier(new_body)->get_kind() != lambda_k &&
!old_q->has_patterns() &&
!to_quantifier(new_body)->has_patterns()) {
@ -619,7 +620,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
sorts.append(nested_q->get_num_decls(), nested_q->get_decl_sorts());
names.append(nested_q->get_num_decls(), nested_q->get_decl_names());
q1 = m().mk_quantifier(old_q->is_forall(),
q1 = m().mk_quantifier(old_q->get_kind(),
sorts.size(),
sorts.c_ptr(),
names.c_ptr(),
@ -653,17 +654,19 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
SASSERT(is_well_sorted(m(), q1));
}
elim_unused_vars(m(), q1, params_ref(), result);
SASSERT(m().get_sort(old_q) == m().get_sort(q1));
result = elim_unused_vars(m(), q1, params_ref());
TRACE("reduce_quantifier", tout << "after elim_unused_vars:\n" << mk_ismt2_pp(result, m()) << "\n";);
TRACE("reduce_quantifier", tout << "after elim_unused_vars:\n" << result << "\n";);
result_pr = nullptr;
if (m().proofs_enabled()) {
proof * p2 = nullptr;
if (q1.get() != result.get())
if (q1.get() != result.get() && q1->get_kind() != lambda_k)
p2 = m().mk_elim_unused_vars(q1, result);
result_pr = m().mk_transitivity(p1, p2);
}
SASSERT(m().get_sort(old_q) == m().get_sort(result));
return true;
}
@ -784,8 +787,8 @@ void th_rewriter::operator()(expr * t, expr_ref & result, proof_ref & result_pr)
m_imp->operator()(t, result, result_pr);
}
void th_rewriter::operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result) {
m_imp->operator()(n, num_bindings, bindings, result);
expr_ref th_rewriter::operator()(expr * n, unsigned num_bindings, expr * const * bindings) {
return m_imp->operator()(n, num_bindings, bindings);
}
void th_rewriter::set_substitution(expr_substitution * s) {

View file

@ -45,7 +45,7 @@ public:
void operator()(expr_ref& term);
void operator()(expr * t, expr_ref & result);
void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
void operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result);
expr_ref operator()(expr * n, unsigned num_bindings, expr * const * bindings);
expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args);

View file

@ -23,10 +23,11 @@ Notes:
#include "ast/well_sorted.h"
#include "ast/for_each_expr.h"
void var_subst::operator()(expr * n, unsigned num_args, expr * const * args, expr_ref & result) {
expr_ref var_subst::operator()(expr * n, unsigned num_args, expr * const * args) {
expr_ref result(m_reducer.m());
if (is_ground(n)) {
result = n;
return;
return result;
}
SASSERT(is_well_sorted(result.m(), n));
m_reducer.reset();
@ -41,6 +42,7 @@ void var_subst::operator()(expr * n, unsigned num_args, expr * const * args, exp
for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m_reducer.m()) << "\n";
tout << "\n------>\n";
tout << mk_ismt2_pp(result, m_reducer.m()) << "\n";);
return result;
}
unused_vars_eliminator::unused_vars_eliminator(ast_manager & m, params_ref const & params) :
@ -49,16 +51,22 @@ unused_vars_eliminator::unused_vars_eliminator(ast_manager & m, params_ref const
m_ignore_patterns_on_ground_qbody = m_params.get_bool("ignore_patterns_on_ground_qbody", true);
}
void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
expr_ref unused_vars_eliminator::operator()(quantifier* q) {
expr_ref result(m);
SASSERT(is_well_sorted(m, q));
TRACE("elim_unused_vars", tout << expr_ref(q, m) << "\n";);
if (is_lambda(q)) {
result = q;
return result;
}
if (m_ignore_patterns_on_ground_qbody && is_ground(q->get_expr())) {
// Ignore patterns if the body is a ground formula.
result = q->get_expr();
return;
return result;
}
if (!q->may_have_unused_vars()) {
result = q;
return;
return result;
}
m_used.reset();
m_used.process(q->get_expr());
@ -73,7 +81,7 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
if (m_used.uses_all_vars(num_decls)) {
q->set_no_unused_vars();
result = q;
return;
return result;
}
ptr_buffer<sort> used_decl_sorts;
@ -120,11 +128,11 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
expr_ref new_expr(m);
m_subst(q->get_expr(), var_mapping.size(), var_mapping.c_ptr(), new_expr);
new_expr = m_subst(q->get_expr(), var_mapping.size(), var_mapping.c_ptr());
if (num_removed == num_decls) {
result = new_expr;
return;
return result;
}
expr_ref tmp(m);
@ -132,15 +140,15 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
expr_ref_buffer new_no_patterns(m);
for (unsigned i = 0; i < num_patterns; i++) {
m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
tmp = m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr());
new_patterns.push_back(tmp);
}
for (unsigned i = 0; i < num_no_patterns; i++) {
m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
tmp = m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr());
new_no_patterns.push_back(tmp);
}
result = m.mk_quantifier(q->is_forall(),
result = m.mk_quantifier(q->get_kind(),
used_decl_sorts.size(),
used_decl_sorts.c_ptr(),
used_decl_names.c_ptr(),
@ -154,24 +162,28 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
new_no_patterns.c_ptr());
to_quantifier(result)->set_no_unused_vars();
SASSERT(is_well_sorted(m, result));
return result;
}
void elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params, expr_ref & result) {
expr_ref elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params) {
unused_vars_eliminator el(m, params);
el(q, result);
expr_ref result = el(q);
TRACE("elim_unused_vars", tout << expr_ref(q, m) << " -> " << result << "\n";);
return result;
}
void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref & result) {
expr_ref instantiate(ast_manager & m, quantifier * q, expr * const * exprs) {
var_subst subst(m);
expr_ref new_expr(m);
subst(q->get_expr(), q->get_num_decls(), exprs, new_expr);
TRACE("var_subst", tout << mk_pp(q, m) << "\n" << mk_pp(new_expr, m) << "\n";);
expr_ref new_expr(m), result(m);
new_expr = subst(q->get_expr(), q->get_num_decls(), exprs);
TRACE("var_subst", tout << mk_pp(q, m) << "\n" << new_expr << "\n";);
inv_var_shifter shift(m);
shift(new_expr, q->get_num_decls(), result);
SASSERT(is_well_sorted(m, result));
TRACE("instantiate_bug", tout << mk_ismt2_pp(q, m) << "\nusing\n";
for (unsigned i = 0; i < q->get_num_decls(); i++) tout << mk_ismt2_pp(exprs[i], m) << "\n";
tout << "\n----->\n" << mk_ismt2_pp(result, m) << "\n";);
return result;
}
static void get_free_vars_offset(expr_sparse_mark& mark, ptr_vector<expr>& todo, unsigned offset, expr* e, ptr_vector<sort>& sorts) {

View file

@ -48,7 +48,7 @@ public:
Otherwise, (VAR 0) is stored in the first position, (VAR 1) in the second, and so on.
*/
void operator()(expr * n, unsigned num_args, expr * const * args, expr_ref & result);
expr_ref operator()(expr * n, unsigned num_args, expr * const * args);
void reset() { m_reducer.reset(); }
};
@ -63,10 +63,10 @@ class unused_vars_eliminator {
bool m_ignore_patterns_on_ground_qbody;
public:
unused_vars_eliminator(ast_manager & m, params_ref const & params);
void operator()(quantifier* q, expr_ref& r);
expr_ref operator()(quantifier* q);
};
void elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params, expr_ref & r);
expr_ref elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params);
/**
\brief Instantiate quantifier q using the given exprs.
@ -77,7 +77,7 @@ void elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params
...
(VAR (q->get_num_decls() - 1)) is stored in the first position of the array.
*/
void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref & result);
expr_ref instantiate(ast_manager & m, quantifier * q, expr * const * exprs);
/**
\brief Enumerate set of free variables in expression.

View file

@ -35,9 +35,10 @@ struct well_sorted_proc {
void operator()(quantifier * n) {
expr const * e = n->get_expr();
if (!m_manager.is_bool(e)) {
if (!is_lambda(n) && !m_manager.is_bool(e)) {
warning_msg("quantifier's body must be a boolean.");
m_error = true;
UNREACHABLE();
}
}

View file

@ -1070,7 +1070,7 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg
tout << "body:\n" << mk_ismt2_pp(_t, m()) << "\n";
tout << "args:\n"; for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m()) << "\n" << mk_pp(m().get_sort(args[i]), m()) << "\n";);
var_subst subst(m());
subst(_t, num_args, args, result);
result = subst(_t, num_args, args);
if (well_sorted_check_enabled() && !is_well_sorted(m(), result))
throw cmd_exception("invalid macro application, sort mismatch ", s);
return;
@ -1625,6 +1625,7 @@ void cmd_context::display_dimacs() {
void cmd_context::display_model(model_ref& mdl) {
if (mdl) {
if (m_mc0) (*m_mc0)(mdl);
if (m_params.m_model_compress) mdl->compress();
model_params p;
if (p.v1() || p.v2()) {
std::ostringstream buffer;

View file

@ -34,6 +34,7 @@ context_params::context_params() {
m_debug_ref_count = false;
m_smtlib2_compliant = false;
m_well_sorted_check = false;
m_model_compress = true;
m_timeout = UINT_MAX;
m_rlimit = 0;
updt_params();
@ -102,6 +103,9 @@ void context_params::set(char const * param, char const * value) {
else if (p == "model_validate") {
set_bool(m_model_validate, param, value);
}
else if (p == "model_compress") {
set_bool(m_model_compress, param, value);
}
else if (p == "dump_models") {
set_bool(m_dump_models, param, value);
}
@ -146,6 +150,7 @@ void context_params::updt_params(params_ref const & p) {
m_proof = p.get_bool("proof", m_proof);
m_model = p.get_bool("model", m_model);
m_model_validate = p.get_bool("model_validate", m_model_validate);
m_model_compress = p.get_bool("model_compress", m_model_compress);
m_dump_models = p.get_bool("dump_models", m_dump_models);
m_trace = p.get_bool("trace", m_trace);
m_trace_file_name = p.get_str("trace_file_name", "z3.log");
@ -162,6 +167,7 @@ void context_params::collect_param_descrs(param_descrs & d) {
d.insert("type_check", CPK_BOOL, "type checker (alias for well_sorted_check)", "true");
d.insert("auto_config", CPK_BOOL, "use heuristics to automatically select solver and configure it", "true");
d.insert("model_validate", CPK_BOOL, "validate models produced by solvers", "false");
d.insert("model_compress", CPK_BOOL, "compress models for easier consumption", "true");
d.insert("dump_models", CPK_BOOL, "dump models whenever check-sat returns sat", "false");
d.insert("trace", CPK_BOOL, "trace generation for VCC", "false");
d.insert("trace_file_name", CPK_STRING, "trace out file name (see option 'trace')", "z3.log");

View file

@ -40,6 +40,7 @@ public:
bool m_well_sorted_check;
bool m_model;
bool m_model_validate;
bool m_model_compress;
bool m_dump_models;
bool m_unsat_core;
bool m_smtlib2_compliant; // it must be here because it enable/disable the use of coercions in the ast_manager.

View file

@ -135,9 +135,8 @@ public:
m_idx++;
}
void execute(cmd_context & ctx) override {
expr_ref r(ctx.m());
beta_reducer p(ctx.m());
p(m_source, m_subst.size(), m_subst.c_ptr(), r);
expr_ref r = p(m_source, m_subst.size(), m_subst.c_ptr());
store_expr_ref(ctx, m_target, r.get());
}
};
@ -274,8 +273,7 @@ UNARY_CMD(elim_unused_vars_cmd, "dbg-elim-unused-vars", "<expr>", "eliminate unu
ctx.display(ctx.regular_stream(), arg);
return;
}
expr_ref r(ctx.m());
elim_unused_vars(ctx.m(), to_quantifier(arg), gparams::get_ref(), r);
expr_ref r = elim_unused_vars(ctx.m(), to_quantifier(arg), gparams::get_ref());
SASSERT(!is_quantifier(r) || !to_quantifier(r)->may_have_unused_vars());
ctx.display(ctx.regular_stream(), r);
ctx.regular_stream() << std::endl;
@ -307,8 +305,7 @@ public:
if (num != m_q->get_num_decls())
throw cmd_exception("invalid command, mismatch between the number of quantified variables and the number of arguments.");
unsigned i = num;
while (i > 0) {
--i;
while (i-- > 0) {
sort * s = ctx.m().get_sort(ts[i]);
if (s != m_q->get_decl_sort(i)) {
std::ostringstream buffer;
@ -320,8 +317,7 @@ public:
}
void execute(cmd_context & ctx) override {
expr_ref r(ctx.m());
instantiate(ctx.m(), m_q, m_args.c_ptr(), r);
expr_ref r = instantiate(ctx.m(), m_q, m_args.c_ptr());
ctx.display(ctx.regular_stream(), r);
ctx.regular_stream() << std::endl;
}

View file

@ -15,11 +15,12 @@ Author:
Revision History:
--*/
#include "model/func_interp.h"
#include "ast/rewriter/var_subst.h"
#include "util/obj_hashtable.h"
#include "ast/rewriter/var_subst.h"
#include "ast/ast_pp.h"
#include "ast/ast_smt2_pp.h"
#include "ast/ast_util.h"
#include "model/func_interp.h"
func_entry::func_entry(ast_manager & m, unsigned arity, expr * const * args, expr * result):
m_args_are_values(true),
@ -77,10 +78,7 @@ func_interp::func_interp(ast_manager & m, unsigned arity):
}
func_interp::~func_interp() {
ptr_vector<func_entry>::iterator it = m_entries.begin();
ptr_vector<func_entry>::iterator end = m_entries.end();
for (; it != end; ++it) {
func_entry * curr = *it;
for (func_entry* curr : m_entries) {
curr->deallocate(m_manager, m_arity);
}
m_manager.dec_ref(m_else);
@ -90,10 +88,7 @@ func_interp::~func_interp() {
func_interp * func_interp::copy() const {
func_interp * new_fi = alloc(func_interp, m_manager, m_arity);
ptr_vector<func_entry>::const_iterator it = m_entries.begin();
ptr_vector<func_entry>::const_iterator end = m_entries.end();
for (; it != end; ++it) {
func_entry * curr = *it;
for (func_entry * curr : m_entries) {
new_fi->insert_new_entry(curr->get_args(), curr->get_result());
}
new_fi->set_else(m_else);
@ -141,9 +136,11 @@ void func_interp::set_else(expr * e) {
return;
reset_interp_cache();
TRACE("func_interp", tout << "set_else: " << expr_ref(e, m()) << "\n";);
ptr_vector<expr> args;
while (e && is_fi_entry_expr(e, args)) {
TRACE("func_interp", tout << "fi entry expr: " << mk_ismt2_pp(e, m()) << std::endl;);
insert_entry(args.c_ptr(), to_app(e)->get_arg(1));
e = to_app(e)->get_arg(2);
}
@ -161,10 +158,7 @@ bool func_interp::is_constant() const {
return false;
if (!is_ground(m_else))
return false;
ptr_vector<func_entry>::const_iterator it = m_entries.begin();
ptr_vector<func_entry>::const_iterator end = m_entries.end();
for (; it != end; ++it) {
func_entry * curr = *it;
for (func_entry* curr : m_entries) {
if (curr->get_result() != m_else)
return false;
}
@ -177,10 +171,7 @@ bool func_interp::is_constant() const {
args_are_values to true if for all entries e e.args_are_values() is true.
*/
func_entry * func_interp::get_entry(expr * const * args) const {
ptr_vector<func_entry>::const_iterator it = m_entries.begin();
ptr_vector<func_entry>::const_iterator end = m_entries.end();
for (; it != end; ++it) {
func_entry * curr = *it;
for (func_entry* curr : m_entries) {
if (curr->eq_args(m(), m_arity, args))
return curr;
}
@ -224,7 +215,7 @@ bool func_interp::eval_else(expr * const * args, expr_ref & result) const {
return false;
var_subst s(m_manager, false);
SASSERT(!s.std_order()); // (VAR 0) <- args[0], (VAR 1) <- args[1], ...
s(m_else, m_arity, args, result);
result = s(m_else, m_arity, args);
return true;
}
@ -237,10 +228,7 @@ expr * func_interp::get_max_occ_result() const {
obj_map<expr, unsigned> num_occs;
expr * r_max = nullptr;
unsigned max = 0;
ptr_vector<func_entry>::const_iterator it = m_entries.begin();
ptr_vector<func_entry>::const_iterator end = m_entries.end();
for (; it != end; ++it) {
func_entry * curr = *it;
for (func_entry * curr : m_entries) {
expr * r = curr->get_result();
unsigned occs = 0;
num_occs.find(r, occs);
@ -262,15 +250,11 @@ void func_interp::compress() {
return; // nothing to be done
if (!is_ground(m_else))
return; // forall entries e in m_entries e.get_result() is ground
unsigned i = 0;
unsigned j = 0;
unsigned sz = m_entries.size();
m_args_are_values = true;
for (; i < sz; i++) {
func_entry * curr = m_entries[i];
for (func_entry * curr : m_entries) {
if (curr->get_result() != m_else) {
m_entries[j] = curr;
j++;
m_entries[j++] = curr;
if (!curr->args_are_values())
m_args_are_values = false;
}
@ -278,10 +262,58 @@ void func_interp::compress() {
curr->deallocate(m_manager, m_arity);
}
}
if (j < sz) {
if (j < m_entries.size()) {
reset_interp_cache();
m_entries.shrink(j);
}
// other compression, if else is a default branch.
// or function encode identity.
if (m_manager.is_false(m_else)) {
expr_ref new_else(get_interp(), m_manager);
for (func_entry * curr : m_entries) {
curr->deallocate(m_manager, m_arity);
}
m_entries.reset();
reset_interp_cache();
m_manager.inc_ref(new_else);
m_manager.dec_ref(m_else);
m_else = new_else;
}
else if (!m_entries.empty() && is_identity()) {
for (func_entry * curr : m_entries) {
curr->deallocate(m_manager, m_arity);
}
m_entries.reset();
reset_interp_cache();
expr_ref new_else(m_manager.mk_var(0, m_manager.get_sort(m_else)), m_manager);
m_manager.inc_ref(new_else);
m_manager.dec_ref(m_else);
m_else = new_else;
}
}
/**
* \brief check if function is identity
*/
bool func_interp::is_identity() const {
if (m_arity != 1) return false;
if (m_else == nullptr) return false;
// all entries map a value to itself
for (func_entry * curr : m_entries) {
if (curr->get_arg(0) != curr->get_result()) return false;
if (curr->get_result() == m_else) return false;
}
if (is_var(m_else)) return true;
if (!m_manager.is_value(m_else)) return false;
sort_size const& sz = m_manager.get_sort(m_else)->get_num_elements();
if (!sz.is_finite()) return false;
//
// the else entry is a value not covered by other entries
// it, together with the entries covers the entire domain.
//
return (sz.size() == m_entries.size() + 1);
}
expr * func_interp::get_interp_core() const {
@ -289,10 +321,10 @@ expr * func_interp::get_interp_core() const {
return nullptr;
expr * r = m_else;
ptr_buffer<expr> vars;
ptr_vector<func_entry>::const_iterator it = m_entries.begin();
ptr_vector<func_entry>::const_iterator end = m_entries.end();
for (; it != end; ++it) {
func_entry * curr = *it;
for (func_entry * curr : m_entries) {
if (m_else == curr->get_result()) {
continue;
}
if (vars.empty()) {
for (unsigned i = 0; i < m_arity; i++) {
vars.push_back(m_manager.mk_var(i, m_manager.get_sort(curr->get_arg(i))));
@ -303,12 +335,17 @@ expr * func_interp::get_interp_core() const {
eqs.push_back(m_manager.mk_eq(vars[i], curr->get_arg(i)));
}
SASSERT(eqs.size() == m_arity);
expr * cond;
if (m_arity == 1)
cond = eqs.get(0);
else
cond = m_manager.mk_and(eqs.size(), eqs.c_ptr());
r = m_manager.mk_ite(cond, curr->get_result(), r);
expr * cond = mk_and(m_manager, eqs.size(), eqs.c_ptr());
expr * th = curr->get_result();
if (m_manager.is_true(th)) {
r = m_manager.mk_or(cond, r);
}
else if (m_manager.is_false(th)) {
r = m_manager.mk_and(m_manager.mk_not(cond), r);
}
else {
r = m_manager.mk_ite(cond, th, r);
}
}
return r;
}
@ -327,12 +364,9 @@ expr * func_interp::get_interp() const {
func_interp * func_interp::translate(ast_translation & translator) const {
func_interp * new_fi = alloc(func_interp, translator.to(), m_arity);
ptr_vector<func_entry>::const_iterator it = m_entries.begin();
ptr_vector<func_entry>::const_iterator end = m_entries.end();
for (; it != end; ++it) {
func_entry * curr = *it;
for (func_entry * curr : m_entries) {
ptr_buffer<expr> new_args;
for (unsigned i=0; i<m_arity; i++)
for (unsigned i = 0; i < m_arity; i++)
new_args.push_back(translator(curr->get_arg(i)));
new_fi->insert_new_entry(new_args.c_ptr(), translator(curr->get_result()));
}

View file

@ -57,6 +57,7 @@ public:
expr * get_result() const { return m_result; }
expr * get_arg(unsigned idx) const { return m_args[idx]; }
expr * const * get_args() const { return m_args; }
/**
\brief Return true if m.are_equal(m_args[i], args[i]) for all i in [0, arity)
*/
@ -101,6 +102,8 @@ public:
func_entry * get_entry(expr * const * args) const;
bool eval_else(expr * const * args, expr_ref & result) const;
unsigned num_entries() const { return m_entries.size(); }
ptr_vector<func_entry>::const_iterator begin() const { return m_entries.begin(); }
ptr_vector<func_entry>::const_iterator end() const { return m_entries.end(); }
func_entry const * const * get_entries() const { return m_entries.c_ptr(); }
func_entry const * get_entry(unsigned idx) const { return m_entries[idx]; }
@ -113,6 +116,7 @@ public:
private:
bool is_fi_entry_expr(expr * e, ptr_vector<expr> & args);
bool is_identity() const;
};
#endif

View file

@ -16,34 +16,36 @@ Author:
Revision History:
--*/
#include "model/model.h"
#include "util/top_sort.h"
#include "ast/ast_pp.h"
#include "ast/ast_ll_pp.h"
#include "ast/rewriter/var_subst.h"
#include "ast/rewriter/th_rewriter.h"
#include "ast/array_decl_plugin.h"
#include "ast/well_sorted.h"
#include "ast/used_symbols.h"
#include "ast/for_each_expr.h"
#include "ast/for_each_ast.h"
#include "model/model.h"
#include "model/model_evaluator.h"
model::model(ast_manager & m):
model_core(m),
m_mev(*this) {
m_mev(*this),
m_cleaned(false) {
}
model::~model() {
for (auto & kv : m_usort2universe) {
m_manager.dec_ref(kv.m_key);
m_manager.dec_array_ref(kv.m_value->size(), kv.m_value->c_ptr());
m.dec_ref(kv.m_key);
m.dec_array_ref(kv.m_value->size(), kv.m_value->c_ptr());
dealloc(kv.m_value);
}
}
void model::copy_const_interps(model const & source) {
for (auto const& kv : source.m_interp) {
for (auto const& kv : source.m_interp)
register_decl(kv.m_key, kv.m_value);
}
}
void model::copy_func_interps(model const & source) {
@ -57,13 +59,11 @@ void model::copy_usort_interps(model const & source) {
}
model * model::copy() const {
model * m = alloc(model, m_manager);
m->copy_const_interps(*this);
m->copy_func_interps(*this);
m->copy_usort_interps(*this);
return m;
model * mdl = alloc(model, m);
mdl->copy_const_interps(*this);
mdl->copy_func_interps(*this);
mdl->copy_usort_interps(*this);
return mdl;
}
bool model::eval_expr(expr * e, expr_ref & result, bool model_completion) {
@ -94,13 +94,13 @@ struct model::value_proc : public some_value_proc {
expr * model::get_some_value(sort * s) {
value_proc p(*this);
return m_manager.get_some_value(s, &p);
return m.get_some_value(s, &p);
}
ptr_vector<expr> const & model::get_universe(sort * s) const {
ptr_vector<expr> * u = nullptr;
m_usort2universe.find(s, u);
SASSERT(u != 0);
SASSERT(u != nullptr);
return *u;
}
@ -120,11 +120,11 @@ sort * model::get_uninterpreted_sort(unsigned idx) const {
void model::register_usort(sort * s, unsigned usize, expr * const * universe) {
sort2universe::obj_map_entry * entry = m_usort2universe.insert_if_not_there2(s, 0);
m_manager.inc_array_ref(usize, universe);
m.inc_array_ref(usize, universe);
if (entry->get_data().m_value == 0) {
// new entry
m_usorts.push_back(s);
m_manager.inc_ref(s);
m.inc_ref(s);
ptr_vector<expr> * new_u = alloc(ptr_vector<expr>);
new_u->append(usize, universe);
entry->get_data().m_value = new_u;
@ -133,7 +133,7 @@ void model::register_usort(sort * s, unsigned usize, expr * const * universe) {
// updating
ptr_vector<expr> * u = entry->get_data().m_value;
SASSERT(u);
m_manager.dec_array_ref(u->size(), u->c_ptr());
m.dec_array_ref(u->size(), u->c_ptr());
u->append(usize, universe);
}
}
@ -154,8 +154,8 @@ model * model::translate(ast_translation & translator) const {
// Translate usort interps
for (auto const& kv : m_usort2universe) {
ptr_vector<expr> new_universe;
for (unsigned i=0; i < kv.m_value->size(); i++)
new_universe.push_back(translator(kv.m_value->get(i)));
for (expr* e : *kv.m_value)
new_universe.push_back(translator(e));
res->register_usort(translator(kv.m_key),
new_universe.size(),
new_universe.c_ptr());
@ -164,22 +164,322 @@ model * model::translate(ast_translation & translator) const {
return res;
}
struct model::top_sort : public ::top_sort<func_decl> {
th_rewriter m_rewrite;
obj_map<func_decl, unsigned> m_occur_count;
top_sort(ast_manager& m):
m_rewrite(m)
{}
void add_occurs(func_decl* f) {
m_occur_count.insert(f, occur_count(f) + 1);
}
unsigned occur_count(func_decl* f) const {
unsigned count = 0;
m_occur_count.find(f, count);
return count;
}
~top_sort() override {}
};
void model::compress() {
if (m_cleaned) return;
// stratify m_finterp and m_decls in a topological sort
// such that functions f1 < f2 then f1 does not use f2.
// then for each function in order clean-up the interpretations
// by substituting in auxiliary definitions that can be eliminated.
func_decl_ref_vector pinned(m);
while (true) {
top_sort ts(m);
collect_deps(ts);
ts.topological_sort();
for (func_decl * f : ts.top_sorted()) {
cleanup_interp(ts, f);
}
func_decl_set removed;
ts.m_occur_count.reset();
for (func_decl * f : ts.top_sorted()) {
collect_occs(ts, f);
}
// remove auxiliary declarations that are not used.
for (func_decl * f : ts.top_sorted()) {
if (f->is_skolem() && ts.occur_count(f) == 0) {
pinned.push_back(f);
unregister_decl(f);
removed.insert(f);
}
}
if (removed.empty()) break;
remove_decls(m_decls, removed);
remove_decls(m_func_decls, removed);
remove_decls(m_const_decls, removed);
}
m_cleaned = true;
reset_eval_cache();
}
void model::collect_deps(top_sort& ts) {
for (auto const& kv : m_finterp) {
ts.insert(kv.m_key, collect_deps(ts, kv.m_value));
}
for (auto const& kv : m_interp) {
ts.insert(kv.m_key, collect_deps(ts, kv.m_value));
}
}
struct model::deps_collector {
model& m;
top_sort& ts;
func_decl_set& s;
array_util autil;
deps_collector(model& m, top_sort& ts, func_decl_set& s): m(m), ts(ts), s(s), autil(m.get_manager()) {}
void operator()(app* a) {
func_decl* f = a->get_decl();
if (autil.is_as_array(f)) {
f = autil.get_as_array_func_decl(a);
}
if (m.has_interpretation(f)) {
s.insert(f);
ts.add_occurs(f);
}
}
void operator()(expr* ) {}
};
struct model::occs_collector {
top_sort& ts;
occs_collector(top_sort& ts): ts(ts) {}
void operator()(func_decl* f) {
ts.add_occurs(f);
}
void operator()(ast* ) {}
};
model::func_decl_set* model::collect_deps(top_sort& ts, expr * e) {
func_decl_set* s = alloc(func_decl_set);
deps_collector collector(*this, ts, *s);
if (e) for_each_expr(collector, e);
return s;
}
model::func_decl_set* model::collect_deps(top_sort& ts, func_interp * fi) {
func_decl_set* s = alloc(func_decl_set);
deps_collector collector(*this, ts, *s);
fi->compress();
expr* e = fi->get_else();
if (e) for_each_expr(collector, e);
return s;
}
/**
\brief Inline interpretations of skolem functions
*/
void model::cleanup_interp(top_sort& ts, func_decl* f) {
unsigned pid = ts.partition_id(f);
expr * e1 = get_const_interp(f);
if (e1) {
expr_ref e2 = cleanup_expr(ts, e1, pid);
if (e2 != e1)
register_decl(f, e2);
return;
}
func_interp* fi = get_func_interp(f);
if (fi) {
e1 = fi->get_else();
expr_ref e2 = cleanup_expr(ts, e1, pid);
if (e1 != e2)
fi->set_else(e2);
}
}
void model::collect_occs(top_sort& ts, func_decl* f) {
expr * e = get_const_interp(f);
if (e) {
collect_occs(ts, e);
}
else {
func_interp* fi = get_func_interp(f);
if (fi) {
e = fi->get_else();
collect_occs(ts, e);
}
}
}
void model::collect_occs(top_sort& ts, expr* e) {
occs_collector collector(ts);
for_each_ast(collector, e);
}
bool model::can_inline_def(top_sort& ts, func_decl* f) {
if (ts.occur_count(f) <= 1) return true;
func_interp* fi = get_func_interp(f);
if (!fi) return false;
if (fi->get_else() == nullptr) return false;
expr* e = fi->get_else();
obj_hashtable<expr> subs;
ptr_buffer<expr> todo;
todo.push_back(e);
while (!todo.empty()) {
if (fi->num_entries() + subs.size() > 8) return false;
expr* e = todo.back();
todo.pop_back();
if (subs.contains(e)) continue;
subs.insert(e);
if (is_app(e)) {
for (expr* arg : *to_app(e)) {
todo.push_back(arg);
}
}
else if (is_quantifier(e)) {
todo.push_back(to_quantifier(e)->get_expr());
}
}
return true;
}
expr_ref model::cleanup_expr(top_sort& ts, expr* e, unsigned current_partition) {
if (!e) return expr_ref(0, m);
TRACE("model", tout << "cleaning up:\n" << mk_pp(e, m) << "\n";);
obj_map<expr, expr*> cache;
expr_ref_vector trail(m);
ptr_buffer<expr, 128> todo;
ptr_buffer<expr> args;
todo.push_back(e);
array_util autil(m);
func_interp* fi = nullptr;
unsigned pid = 0;
expr_ref new_t(m);
while (!todo.empty()) {
expr* a = todo.back();
switch(a->get_kind()) {
case AST_APP: {
app * t = to_app(a);
func_decl* f = t->get_decl();
bool visited = true;
args.reset();
for (expr* t_arg : *t) {
expr * arg = nullptr;
if (!cache.find(t_arg, arg)) {
visited = false;
todo.push_back(t_arg);
}
else {
args.push_back(arg);
}
}
if (!visited) {
continue;
}
fi = nullptr;
if (autil.is_as_array(a)) {
func_decl* f = autil.get_as_array_func_decl(a);
// only expand auxiliary definitions that occur once.
if (can_inline_def(ts, f)) {
fi = get_func_interp(f);
}
}
if (fi && fi->get_interp()) {
f = autil.get_as_array_func_decl(a);
expr_ref_vector sargs(m);
sort_ref_vector vars(m);
svector<symbol> var_names;
for (unsigned i = 0; i < f->get_arity(); ++i) {
var_names.push_back(symbol(i));
vars.push_back(f->get_domain(f->get_arity() - i - 1));
}
new_t = m.mk_lambda(vars.size(), vars.c_ptr(), var_names.c_ptr(), fi->get_interp());
}
else if (f->is_skolem() && can_inline_def(ts, f) && (fi = get_func_interp(f)) &&
fi->get_interp() && (!ts.partition_ids().find(f, pid) || pid != current_partition)) {
var_subst vs(m);
// ? TBD args.reverse();
new_t = vs(fi->get_interp(), args.size(), args.c_ptr());
}
#if 0
else if (is_uninterp_const(a) && !get_const_interp(f)) {
new_t = get_some_value(f->get_range());
register_decl(f, new_t);
}
#endif
else {
new_t = ts.m_rewrite.mk_app(f, args.size(), args.c_ptr());
}
if (t != new_t.get()) trail.push_back(new_t);
todo.pop_back();
cache.insert(t, new_t);
break;
}
default:
SASSERT(a != nullptr);
cache.insert(a, a);
todo.pop_back();
break;
}
}
ts.m_rewrite(cache[e], new_t);
return new_t;
}
void model::remove_decls(ptr_vector<func_decl> & decls, func_decl_set const & s) {
unsigned j = 0;
for (func_decl* f : decls) {
if (!s.contains(f)) {
decls[j++] = f;
}
}
decls.shrink(j);
}
expr_ref model::get_inlined_const_interp(func_decl* f) {
expr* v = get_const_interp(f);
if (!v) return expr_ref(0, m);
top_sort st(m);
expr_ref result1(v, m);
expr_ref result2 = cleanup_expr(st, v, UINT_MAX);
while (result1 != result2) {
result1 = result2;
result2 = cleanup_expr(st, result1, UINT_MAX);
}
return result2;
}
expr_ref model::operator()(expr* t) {
return m_mev(t);
}
expr_ref_vector model::operator()(expr_ref_vector const& ts) {
expr_ref_vector rs(m());
expr_ref_vector rs(m);
for (expr* t : ts) rs.push_back((*this)(t));
return rs;
}
bool model::is_true(expr* t) {
return m().is_true((*this)(t));
return m.is_true((*this)(t));
}
bool model::is_false(expr* t) {
return m().is_false((*this)(t));
return m.is_false((*this)(t));
}
bool model::is_true(expr_ref_vector const& ts) {

View file

@ -30,12 +30,28 @@ typedef ref<model> model_ref;
class model : public model_core {
protected:
typedef obj_map<sort, ptr_vector<expr>*> sort2universe;
typedef obj_hashtable<func_decl> func_decl_set;
ptr_vector<sort> m_usorts;
sort2universe m_usort2universe;
model_evaluator m_mev;
bool m_cleaned;
struct value_proc;
struct deps_collector;
struct occs_collector;
struct top_sort;
func_decl_set* collect_deps(top_sort& ts, expr * e);
func_decl_set* collect_deps(top_sort& ts, func_interp* fi);
void collect_deps(top_sort& ts);
void collect_occs(top_sort& ts, func_decl* f);
void collect_occs(top_sort& ts, expr* e);
void cleanup_interp(top_sort& ts, func_decl * f);
expr_ref cleanup_expr(top_sort& ts, expr* e, unsigned current_partition);
void remove_decls(ptr_vector<func_decl> & decls, func_decl_set const & s);
bool can_inline_def(top_sort& ts, func_decl* f);
public:
model(ast_manager & m);
~model() override;
@ -54,6 +70,8 @@ public:
sort * get_uninterpreted_sort(unsigned idx) const override;
bool has_uninterpreted_sort(sort * s) const;
expr_ref get_inlined_const_interp(func_decl* f);
//
// Primitives for building models
//
@ -63,6 +81,8 @@ public:
//
model * translate(ast_translation & translator) const;
void compress();
void set_model_completion(bool f) { m_mev.set_model_completion(f); }
void updt_params(params_ref const & p) { m_mev.updt_params(p); }
@ -94,7 +114,5 @@ public:
};
};
std::ostream& operator<<(std::ostream& out, model_core const& m);
#endif /* MODEL_H_ */

View file

@ -147,7 +147,7 @@ void model2expr(model& md, expr_ref& result) {
}
if (f->get_arity() > 0) {
var_subst vs(m, false);
vs(tmp, rev_vars.size(), rev_vars.c_ptr(), tmp);
tmp = vs(tmp, rev_vars.size(), rev_vars.c_ptr());
tmp = m.mk_forall(sorts.size(), sorts.c_ptr(), names.c_ptr(), tmp);
}
conjs.push_back(tmp);

View file

@ -20,12 +20,12 @@ Revision History:
model_core::~model_core() {
for (auto & kv : m_interp) {
m_manager.dec_ref(kv.m_key);
m_manager.dec_ref(kv.m_value);
m.dec_ref(kv.m_key);
m.dec_ref(kv.m_value);
}
for (auto & kv : m_finterp) {
m_manager.dec_ref(kv.m_key);
m.dec_ref(kv.m_key);
dealloc(kv.m_value);
}
}
@ -47,32 +47,33 @@ bool model_core::eval(func_decl* f, expr_ref & r) const {
void model_core::register_decl(func_decl * d, expr * v) {
SASSERT(d->get_arity() == 0);
TRACE("model", tout << "register " << d->get_name() << "\n";);
decl2expr::obj_map_entry * entry = m_interp.insert_if_not_there2(d, nullptr);
if (entry->get_data().m_value == nullptr) {
// new entry
m_decls.push_back(d);
m_const_decls.push_back(d);
m_manager.inc_ref(d);
m_manager.inc_ref(v);
m.inc_ref(d);
m.inc_ref(v);
entry->get_data().m_value = v;
}
else {
// replacing entry
m_manager.inc_ref(v);
m_manager.dec_ref(entry->get_data().m_value);
m.inc_ref(v);
m.dec_ref(entry->get_data().m_value);
entry->get_data().m_value = v;
}
}
void model_core::register_decl(func_decl * d, func_interp * fi) {
SASSERT(d->get_arity() > 0);
SASSERT(&fi->m() == &m_manager);
SASSERT(&fi->m() == &m);
decl2finterp::obj_map_entry * entry = m_finterp.insert_if_not_there2(d, nullptr);
if (entry->get_data().m_value == nullptr) {
// new entry
m_decls.push_back(d);
m_func_decls.push_back(d);
m_manager.inc_ref(d);
m.inc_ref(d);
entry->get_data().m_value = fi;
}
else {
@ -85,23 +86,23 @@ void model_core::register_decl(func_decl * d, func_interp * fi) {
void model_core::unregister_decl(func_decl * d) {
decl2expr::obj_map_entry * ec = m_interp.find_core(d);
if (ec && ec->get_data().m_value != 0) {
if (ec) {
auto k = ec->get_data().m_key;
auto v = ec->get_data().m_value;
m_interp.remove(d);
m_const_decls.erase(d);
m_manager.dec_ref(k);
m_manager.dec_ref(v);
m.dec_ref(k);
m.dec_ref(v);
return;
}
decl2finterp::obj_map_entry * ef = m_finterp.find_core(d);
if (ef && ef->get_data().m_value != 0) {
if (ef) {
auto k = ef->get_data().m_key;
auto v = ef->get_data().m_value;
m_finterp.remove(d);
m_func_decls.erase(d);
m_manager.dec_ref(k);
m.dec_ref(k);
dealloc(v);
}
}

View file

@ -27,7 +27,7 @@ class model_core {
protected:
typedef obj_map<func_decl, expr *> decl2expr;
typedef obj_map<func_decl, func_interp*> decl2finterp;
ast_manager & m_manager;
ast_manager & m;
unsigned m_ref_count;
decl2expr m_interp; //!< interpretation for uninterpreted constants
decl2finterp m_finterp; //!< interpretation for uninterpreted functions
@ -36,11 +36,10 @@ protected:
ptr_vector<func_decl> m_func_decls;
public:
model_core(ast_manager & m):m_manager(m), m_ref_count(0) { }
model_core(ast_manager & m):m(m), m_ref_count(0) { }
virtual ~model_core();
ast_manager & get_manager() const { return m_manager; }
ast_manager& m() const { return m_manager; }
ast_manager & get_manager() const { return m; }
unsigned get_num_decls() const { return m_decls.size(); }
func_decl * get_decl(unsigned i) const { return m_decls[i]; }
@ -65,6 +64,11 @@ public:
virtual expr * get_some_value(sort * s) = 0;
expr * get_some_const_interp(func_decl * d) {
expr * r = get_const_interp(d);
if (r) return r;
return get_some_value(d->get_range());
}
//
// Reference counting
//
@ -78,4 +82,7 @@ public:
};
std::ostream& operator<<(std::ostream& out, model_core const& m);
#endif

View file

@ -16,10 +16,12 @@ Author:
Revision History:
--*/
#include "util/cooperate.h"
#include "model/model.h"
#include "model/model_evaluator_params.hpp"
#include "ast/rewriter/rewriter_types.h"
#include "model/model_evaluator.h"
#include "model/model_v2_pp.h"
#include "ast/rewriter/rewriter_types.h"
#include "ast/rewriter/bool_rewriter.h"
#include "ast/rewriter/arith_rewriter.h"
#include "ast/rewriter/bv_rewriter.h"
@ -29,7 +31,6 @@ Revision History:
#include "ast/rewriter/array_rewriter.h"
#include "ast/rewriter/fpa_rewriter.h"
#include "ast/rewriter/rewriter_def.h"
#include "util/cooperate.h"
#include "ast/ast_pp.h"
#include "ast/ast_util.h"
#include "model/model_smt2_pp.h"
@ -274,7 +275,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
fi->set_else(m.get_some_value(f->get_range()));
var_subst vs(m, false);
vs(fi->get_interp(), num, args, result);
result = vs(fi->get_interp(), num, args);
return BR_REWRITE_FULL;
}

View file

@ -304,6 +304,6 @@ void model_smt2_pp(std::ostream & out, ast_manager & m, model_core const & md, u
}
std::ostream& operator<<(std::ostream& out, model_core const& m) {
model_smt2_pp(out, m.m(), m, 0);
model_smt2_pp(out, m.get_manager(), m, 0);
return out;
}

View file

@ -38,7 +38,7 @@ expr_ref bind_variables::operator()(expr* fml, bool is_forall) {
if (!m_names.empty()) {
m_bound.reverse();
m_names.reverse();
result = m.mk_quantifier(is_forall, m_bound.size(), m_bound.c_ptr(), m_names.c_ptr(), result);
result = m.mk_quantifier(is_forall ? forall_k : exists_k, m_bound.size(), m_bound.c_ptr(), m_names.c_ptr(), result);
}
m_pinned.reset();
m_cache.reset();

View file

@ -1044,7 +1044,7 @@ namespace datalog {
quantifier* q = to_quantifier(body);
expr* e = q->get_expr();
if (m.is_implies(e, body, e2)) {
fml = m.mk_quantifier(false, q->get_num_decls(),
fml = m.mk_quantifier(exists_k, q->get_num_decls(),
q->get_decl_sorts(), q->get_decl_names(),
body);
}
@ -1251,13 +1251,10 @@ namespace datalog {
obj_map<sort, unsigned> max_vars;
for (unsigned i = 0; i < rules.size(); ++i) {
expr* r = rules[i].get();
if (!is_quantifier(r)) {
if (!is_forall(r)) {
continue;
}
quantifier* q = to_quantifier(r);
if (!q->is_forall()) {
continue;
}
if (has_quantifiers(q->get_expr())) {
continue;
}
@ -1292,7 +1289,7 @@ namespace datalog {
subst.push_back(fresh_vars[vars[max_var]].get());
}
vsubst(q->get_expr(), subst.size(), subst.c_ptr(), res);
res = vsubst(q->get_expr(), subst.size(), subst.c_ptr());
rules[i] = res.get();
}
}

View file

@ -292,7 +292,7 @@ namespace datalog {
args.push_back(m.mk_var(0, m.mk_bool_sort()));
}
}
sub(q, args.size(), args.c_ptr(), q);
q = sub(q, args.size(), args.c_ptr());
vars.reset();
m_free_vars(q);
vars.append(m_free_vars.size(), m_free_vars.c_ptr());
@ -438,11 +438,7 @@ namespace datalog {
e = e2;
}
}
if (is_quantifier(e)) {
q = to_quantifier(e);
return q->is_forall();
}
return false;
return ::is_forall(e);
}
@ -745,7 +741,7 @@ namespace datalog {
expr_ref unbound_tail_pre_quant(m), fixed_tail(m), quant_tail(m);
var_subst vs(m, false);
vs(unbound_tail, subst.size(), subst.c_ptr(), unbound_tail_pre_quant);
unbound_tail_pre_quant = vs(unbound_tail, subst.size(), subst.c_ptr());
quant_tail = m.mk_exists(q_var_cnt, qsorts.c_ptr(), qnames.c_ptr(), unbound_tail_pre_quant);
@ -816,10 +812,10 @@ namespace datalog {
app_ref_vector new_tail(m);
svector<bool> tail_neg;
var_subst vs(m, false);
vs(r->get_head(), sz, es, tmp);
tmp = vs(r->get_head(), sz, es);
new_head = to_app(tmp);
for (unsigned i = 0; i < r->get_tail_size(); ++i) {
vs(r->get_tail(i), sz, es, tmp);
tmp = vs(r->get_tail(i), sz, es);
new_tail.push_back(to_app(tmp));
tail_neg.push_back(r->is_neg_tail(i));
}
@ -984,8 +980,7 @@ namespace datalog {
var_subst vs(m, false);
expr_ref new_head_e(m);
vs(m_head, subst_vals.size(), subst_vals.c_ptr(), new_head_e);
expr_ref new_head_e = vs(m_head, subst_vals.size(), subst_vals.c_ptr());
m.inc_ref(new_head_e);
m.dec_ref(m_head);
@ -993,8 +988,7 @@ namespace datalog {
for (unsigned i = 0; i < m_tail_size; i++) {
app * old_tail = get_tail(i);
expr_ref new_tail_e(m);
vs(old_tail, subst_vals.size(), subst_vals.c_ptr(), new_tail_e);
expr_ref new_tail_e = vs(old_tail, subst_vals.size(), subst_vals.c_ptr());
bool sign = is_neg_tail(i);
m.inc_ref(new_tail_e);
m.dec_ref(old_tail);

View file

@ -82,12 +82,10 @@ namespace datalog {
quantifier_finder_proc() : m_exist(false), m_univ(false) {}
void operator()(var * n) { }
void operator()(quantifier * n) {
if (n->is_forall()) {
m_univ = true;
}
else {
SASSERT(n->is_exists());
m_exist = true;
switch (n->get_kind()) {
case forall_k: m_univ = true; break;
case exists_k: m_exist = true; break;
case lambda_k: UNREACHABLE();
}
}
void operator()(app * n) { }

View file

@ -31,27 +31,20 @@ namespace datalog {
rule_dependencies::rule_dependencies(const rule_dependencies & o, bool reversed):
m_context(o.m_context) {
if (reversed) {
iterator oit = o.begin();
iterator oend = o.end();
for (; oit!=oend; ++oit) {
func_decl * pred = oit->m_key;
item_set & orig_items = *oit->get_value();
for (auto & kv : o) {
func_decl * pred = kv.m_key;
item_set & orig_items = *kv.get_value();
ensure_key(pred);
item_set::iterator dit = orig_items.begin();
item_set::iterator dend = orig_items.end();
for (; dit!=dend; ++dit) {
func_decl * master_pred = *dit;
for (func_decl * master_pred : orig_items) {
insert(master_pred, pred);
}
}
}
else {
iterator oit = o.begin();
iterator oend = o.end();
for (; oit!=oend; ++oit) {
func_decl * pred = oit->m_key;
item_set & orig_items = *oit->get_value();
for (auto & kv : o) {
func_decl * pred = kv.m_key;
item_set & orig_items = *kv.get_value();
m_data.insert(pred, alloc(item_set, orig_items));
}
}
@ -86,14 +79,10 @@ namespace datalog {
void rule_dependencies::populate(const rule_set & rules) {
SASSERT(m_data.empty());
rule_set::decl2rules::iterator it = rules.m_head2rules.begin();
rule_set::decl2rules::iterator end = rules.m_head2rules.end();
for (; it != end; ++it) {
ptr_vector<rule> * rules = it->m_value;
ptr_vector<rule>::iterator it2 = rules->begin();
ptr_vector<rule>::iterator end2 = rules->end();
for (; it2 != end2; ++it2) {
populate(*it2);
for (auto & kv : rules.m_head2rules) {
ptr_vector<rule> * rules = kv.m_value;
for (rule* r : *rules) {
populate(r);
}
}
}
@ -150,54 +139,41 @@ namespace datalog {
void rule_dependencies::restrict(const item_set & allowed) {
ptr_vector<func_decl> to_remove;
iterator pit = begin();
iterator pend = end();
for (; pit!=pend; ++pit) {
func_decl * pred = pit->m_key;
for (auto const& kv : *this) {
func_decl * pred = kv.m_key;
if (!allowed.contains(pred)) {
to_remove.insert(pred);
continue;
}
item_set& itms = *pit->get_value();
item_set& itms = *kv.get_value();
set_intersection(itms, allowed);
}
ptr_vector<func_decl>::iterator rit = to_remove.begin();
ptr_vector<func_decl>::iterator rend = to_remove.end();
for (; rit != rend; ++rit) {
remove_m_data_entry(*rit);
}
for (func_decl* f : to_remove)
remove_m_data_entry(f);
}
void rule_dependencies::remove(func_decl * itm) {
remove_m_data_entry(itm);
iterator pit = begin();
iterator pend = end();
for (; pit != pend; ++pit) {
item_set & itms = *pit->get_value();
for (auto const& kv : *this) {
item_set & itms = *kv.get_value();
itms.remove(itm);
}
}
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) {
remove_m_data_entry(*rit);
for (auto * item : to_remove) {
remove_m_data_entry(item);
}
iterator pit = begin();
iterator pend = end();
for (; pit!=pend; ++pit) {
item_set * itms = pit->get_value();
for (auto & kv : *this) {
item_set * itms = kv.get_value();
set_difference(*itms, to_remove);
}
}
unsigned rule_dependencies::out_degree(func_decl * f) const {
unsigned res = 0;
iterator pit = begin();
iterator pend = end();
for (; pit!=pend; ++pit) {
item_set & itms = *pit->get_value();
for (auto & kv : *this) {
item_set & itms = *kv.get_value();
if (itms.contains(f)) {
res++;
}
@ -333,19 +309,11 @@ namespace datalog {
void rule_set::inherit_predicates(rule_set const& other) {
m_refs.append(other.m_refs);
set_union(m_output_preds, other.m_output_preds);
{
obj_map<func_decl, func_decl*>::iterator it = other.m_orig2pred.begin();
obj_map<func_decl, func_decl*>::iterator end = other.m_orig2pred.end();
for (; it != end; ++it) {
m_orig2pred.insert(it->m_key, it->m_value);
}
for (auto & kv : other.m_orig2pred) {
m_orig2pred.insert(kv.m_key, kv.m_value);
}
{
obj_map<func_decl, func_decl*>::iterator it = other.m_pred2orig.begin();
obj_map<func_decl, func_decl*>::iterator end = other.m_pred2orig.end();
for (; it != end; ++it) {
m_pred2orig.insert(it->m_key, it->m_value);
}
for (auto & kv : other.m_pred2orig) {
m_pred2orig.insert(kv.m_key, kv.m_value);
}
}
@ -537,26 +505,19 @@ namespace datalog {
void rule_set::display_deps( std::ostream & out ) const
{
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) {
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) {
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) {
non_empty = true;
func_decl * dep = *dit;
out<<first->get_name()<<" -> "<<dep->get_name()<<"\n";
}
}
if (non_empty && sit!=send) {
bool non_empty = false;
for (func_decl_set* strat : strats) {
if (non_empty) {
out << "\n";
non_empty = false;
}
for (func_decl * first : *strat) {
const func_decl_set & deps = m_deps.get_deps(first);
for (func_decl * dep : deps) {
non_empty = true;
out<<first->get_name()<<" -> " <<dep->get_name()<<"\n";
}
}
}
}
@ -568,11 +529,8 @@ namespace datalog {
// -----------------------------------
rule_stratifier::~rule_stratifier() {
comp_vector::iterator it = m_strats.begin();
comp_vector::iterator end = m_strats.end();
for (; it!=end; ++it) {
SASSERT(*it);
dealloc(*it);
for (auto * t : m_strats) {
dealloc(t);
}
}
@ -617,10 +575,8 @@ namespace datalog {
m_stack_P.push_back(el);
const item_set & children = m_deps.get_deps(el);
item_set::iterator cit=children.begin();
item_set::iterator cend=children.end();
for (; cit!=cend; ++cit) {
traverse(*cit);
for (T* ch : children) {
traverse(ch);
}
if (el == m_stack_P.back()) {
@ -646,10 +602,8 @@ namespace datalog {
}
//detect strong components
rule_dependencies::iterator it = m_deps.begin();
rule_dependencies::iterator end = m_deps.end();
for (; it!=end; ++it) {
T * el = it->m_key;
for (auto const& kv : m_deps) {
T * el = kv.m_key;
//we take a note of the preorder number with which this sweep started
m_first_preorder = m_next_preorder;
traverse(el);
@ -662,19 +616,13 @@ namespace datalog {
in_degrees.resize(m_components.size());
//init in_degrees
it = m_deps.begin();
end = m_deps.end();
for (; it != end; ++it) {
T * el = it->m_key;
item_set * out_edges = it->m_value;
for (auto const& kv : m_deps) {
T * el = kv.m_key;
item_set * out_edges = kv.m_value;
unsigned el_comp = 0;
VERIFY( m_component_nums.find(el, el_comp) );
unsigned el_comp = m_component_nums[el];
item_set::iterator eit = out_edges->begin();
item_set::iterator eend = out_edges->end();
for (; eit!=eend; ++eit) {
T * tgt = *eit;
for (T * tgt : *out_edges) {
unsigned tgt_comp = m_component_nums.find(tgt);
@ -701,15 +649,9 @@ namespace datalog {
unsigned strats_index = 0;
while (strats_index < m_strats.size()) { //m_strats.size() changes inside the loop!
item_set * comp = m_strats[strats_index];
item_set::iterator cit=comp->begin();
item_set::iterator cend=comp->end();
for (; cit!=cend; ++cit) {
T * el = *cit;
for (T * el : *comp) {
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) {
T * tgt = *eit;
for (T * tgt : deps) {
unsigned tgt_comp = 0;
VERIFY( m_component_nums.find(tgt, tgt_comp) );
@ -724,7 +666,7 @@ namespace datalog {
m_components[tgt_comp] = 0;
}
}
traverse(*cit);
traverse(el);
}
}
strats_index++;
@ -738,12 +680,9 @@ namespace datalog {
SASSERT(m_pred_strat_nums.empty());
unsigned strat_cnt = m_strats.size();
for (unsigned strat_index=0; strat_index<strat_cnt; strat_index++) {
for (unsigned strat_index=0; strat_index < strat_cnt; strat_index++) {
item_set * comp = m_strats[strat_index];
item_set::iterator cit=comp->begin();
item_set::iterator cend=comp->end();
for (; cit != cend; ++cit) {
T * el = *cit;
for (T * el : *comp) {
m_pred_strat_nums.insert(el, strat_index);
}
}
@ -761,10 +700,8 @@ namespace datalog {
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() << " ";
for (auto * item : *m_strats[i]) {
out << item->get_name() << " ";
}
out << "\n";
}

View file

@ -115,8 +115,7 @@ namespace datalog {
expr_ref tmp(m);
for (unsigned i = 0; i < tgt.size(); ++i) {
if (tgt[i].get()) {
vs(tgt[i].get(), sub.size(), sub.c_ptr(), tmp);
tgt[i] = tmp;
tgt[i] = vs(tgt[i].get(), sub.size(), sub.c_ptr());
}
else {
tgt[i] = sub[i];

View file

@ -108,20 +108,20 @@ namespace datalog {
// apply substitution to body.
var_subst vs(m, false);
for (unsigned k = 0; k < p->get_arity(); ++k) {
vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr(), trm);
trm = vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr());
conjs.push_back(m.mk_eq(trm, mk_q_arg(p, k, true)));
}
for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
func_decl* q = r.get_decl(j);
for (unsigned k = 0; k < q->get_arity(); ++k) {
vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr(), trm);
trm = vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr());
conjs.push_back(m.mk_eq(trm, mk_q_arg(q, k, false)));
}
func_decl_ref qr = mk_q_func_decl(q);
conjs.push_back(m.mk_app(qr, m_bv.mk_bv_sub(var, mk_q_one())));
}
for (unsigned j = r.get_uninterpreted_tail_size(); j < r.get_tail_size(); ++j) {
vs(r.get_tail(j), sub.size(), sub.c_ptr(), trm);
trm = vs(r.get_tail(j), sub.size(), sub.c_ptr());
conjs.push_back(trm);
}
if (r.get_uninterpreted_tail_size() > 0) {
@ -238,7 +238,7 @@ namespace datalog {
var_subst vs(m, false);
num = mk_q_num(i);
expr* nums[1] = { num };
vs(t, 1, nums, tmp);
tmp = vs(t, 1, nums);
return (*model)(tmp);
}
@ -535,7 +535,7 @@ namespace datalog {
for (unsigned j = 0; j < sz; ++j) {
func_decl* head_j = r->get_decl(j);
app* body_j = r->get_tail(j);
vs(body_j, sub.size(), sub.c_ptr(), prop_body);
prop_body = vs(body_j, sub.size(), sub.c_ptr());
prs.push_back(get_proof(md, head_j, to_app(prop_body), level-1));
positions.push_back(std::make_pair(j+1,0));
substs.push_back(expr_ref_vector(m));
@ -609,11 +609,9 @@ namespace datalog {
}
expr_ref skolemize_vars(rule& r, expr_ref_vector const& args, ptr_vector<sort> const& vars, expr* e) {
expr_ref result(m);
expr_ref_vector binding = mk_skolem_binding(r, vars, args);
var_subst vs(m, false);
vs(e, binding.size(), binding.c_ptr(), result);
return result;
return vs(e, binding.size(), binding.c_ptr());
}
func_decl_ref mk_body_func(rule& r, ptr_vector<sort> const& args, unsigned index, sort* s) {
@ -646,8 +644,8 @@ namespace datalog {
return expr_ref(e, m);
}
var_subst vs(m, false);
vs(e, binding.size(), binding.c_ptr(), tmp);
vs(pat, binding.size(), binding.c_ptr(), head);
tmp = vs(e, binding.size(), binding.c_ptr());
head = vs(pat, binding.size(), binding.c_ptr());
patterns.push_back(m.mk_pattern(to_app(head)));
symbol qid, skid;
return expr_ref(m.mk_forall(sorts.size(), sorts.c_ptr(), names.c_ptr(), tmp, 1, qid, skid, 1, patterns.c_ptr()), m);
@ -892,7 +890,7 @@ namespace datalog {
// apply substitution to body.
var_subst vs(m, false);
for (unsigned k = 0; k < p->get_arity(); ++k) {
vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr(), tmp);
tmp = vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr());
expr_ref arg = mk_arg(p, k, path_var, trace_arg);
conjs.push_back(m.mk_eq(tmp, arg));
}
@ -906,7 +904,7 @@ namespace datalog {
}
func_decl* q = r.get_decl(j);
for (unsigned k = 0; k < q->get_arity(); ++k) {
vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr(), tmp);
tmp = vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr());
expr_ref arg = mk_arg(q, k, path_arg, vars[j].get());
conjs.push_back(m.mk_eq(tmp, arg));
}
@ -914,7 +912,7 @@ namespace datalog {
conjs.push_back(m.mk_app(q_pred, vars[j].get(), path_arg));
}
for (unsigned j = r.get_uninterpreted_tail_size(); j < r.get_tail_size(); ++j) {
vs(r.get_tail(j), sub.size(), sub.c_ptr(), tmp);
tmp = vs(r.get_tail(j), sub.size(), sub.c_ptr());
conjs.push_back(tmp);
}
bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), rule_body);
@ -1048,7 +1046,7 @@ namespace datalog {
expr_ref fml(m), head(m), tmp(m);
app_ref path1(m);
var_subst vs(m, false);
// var_subst vs(m, false);
mk_subst(*rules[i], path, trace, sub);
rm.to_formula(*rules[i], fml);
prs.push_back(rules[i]->get_proof());
@ -1399,20 +1397,20 @@ namespace datalog {
// apply substitution to body.
var_subst vs(m, false);
for (unsigned k = 0; k < p->get_arity(); ++k) {
vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr(), tmp);
tmp = vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr());
conjs.push_back(m.mk_eq(tmp, mk_level_arg(p, k, level)));
}
for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
SASSERT(level > 0);
func_decl* q = r.get_decl(j);
for (unsigned k = 0; k < q->get_arity(); ++k) {
vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr(), tmp);
tmp = vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr());
conjs.push_back(m.mk_eq(tmp, mk_level_arg(q, k, level-1)));
}
conjs.push_back(mk_level_predicate(q, level-1));
}
for (unsigned j = r.get_uninterpreted_tail_size(); j < r.get_tail_size(); ++j) {
vs(r.get_tail(j), sub.size(), sub.c_ptr(), tmp);
tmp = vs(r.get_tail(j), sub.size(), sub.c_ptr());
conjs.push_back(tmp);
}
bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), rule_body);

View file

@ -121,7 +121,7 @@ namespace datalog {
m_ground[i] = m.mk_fresh_const("c", fv[i]);
}
}
m_var_subst(e, m_ground.size(), m_ground.c_ptr(), e);
e = m_var_subst(e, m_ground.size(), m_ground.c_ptr());
}
static bool rule_sort_fn(const rule *r1, const rule *r2) {

View file

@ -59,9 +59,7 @@ namespace datalog {
for (unsigned i = 0; i < sig.size(); ++i) {
vars.push_back(m.mk_const(symbol(i), sig[i]));
}
expr_ref result(m);
sub(fml, vars.size(), vars.c_ptr(), result);
return result;
return sub(fml, vars.size(), vars.c_ptr());
}
void check_relation::add_fact(const relation_fact & f) {
@ -292,7 +290,7 @@ namespace datalog {
}
}
var_subst sub(m, false);
sub(fml, vars.size(), vars.c_ptr(), fml1);
fml1 = sub(fml, vars.size(), vars.c_ptr());
bound.reverse();
fml1 = m.mk_exists(bound.size(), bound.c_ptr(), names.c_ptr(), fml1);
return fml1;
@ -333,7 +331,7 @@ namespace datalog {
for (unsigned i = 0; i < sig2.size(); ++i) {
vars.push_back(m.mk_var(i + sig1.size(), sig2[i]));
}
sub(fml2, vars.size(), vars.c_ptr(), fml2);
fml2 = sub(fml2, vars.size(), vars.c_ptr());
fml1 = m.mk_and(fml1, fml2);
for (unsigned i = 0; i < cols1.size(); ++i) {
unsigned v1 = cols1[i];
@ -372,14 +370,14 @@ namespace datalog {
expr_ref fml1(m), fml2(m);
src.to_formula(fml1);
dst.to_formula(fml2);
subst(fml1, sub.size(), sub.c_ptr(), fml1);
fml1 = subst(fml1, sub.size(), sub.c_ptr());
expr_ref_vector vars(m);
for (unsigned i = 0; i < sig2.size(); ++i) {
vars.push_back(m.mk_const(symbol(i), sig2[i]));
}
subst(fml1, vars.size(), vars.c_ptr(), fml1);
subst(fml2, vars.size(), vars.c_ptr(), fml2);
fml1 = subst(fml1, vars.size(), vars.c_ptr());
fml2 = subst(fml2, vars.size(), vars.c_ptr());
check_equiv("permutation", fml1, fml2);
}
@ -405,8 +403,8 @@ namespace datalog {
strm << "x" << i;
vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i]));
}
sub(fml1, vars.size(), vars.c_ptr(), fml1);
sub(fml2, vars.size(), vars.c_ptr(), fml2);
fml1 = sub(fml1, vars.size(), vars.c_ptr());
fml2 = sub(fml2, vars.size(), vars.c_ptr());
check_equiv("filter", fml1, fml2);
}
@ -453,8 +451,8 @@ namespace datalog {
strm << "x" << i;
vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i]));
}
sub(fml1, vars.size(), vars.c_ptr(), fml1);
sub(fml2, vars.size(), vars.c_ptr(), fml2);
fml1 = sub(fml1, vars.size(), vars.c_ptr());
fml2 = sub(fml2, vars.size(), vars.c_ptr());
check_equiv("union", fml1, fml2);
@ -466,13 +464,13 @@ namespace datalog {
// dst \ dst0 == delta & dst & \ dst0
expr_ref fml4(m), fml5(m);
fml4 = m.mk_and(fml2, m.mk_not(dst0));
sub(fml4, vars.size(), vars.c_ptr(), fml4);
sub(d, vars.size(), vars.c_ptr(), d);
fml4 = sub(fml4, vars.size(), vars.c_ptr());
d = sub(d, vars.size(), vars.c_ptr());
check_contains("union_delta low", d, fml4);
//
// delta >= delta0
//
sub(delta0, vars.size(), vars.c_ptr(), d0);
d0 = sub(delta0, vars.size(), vars.c_ptr());
check_contains("union delta0", d, d0);
//
@ -480,8 +478,8 @@ namespace datalog {
//
fml4 = m.mk_or(fml2, delta0);
fml5 = m.mk_or(d, dst0);
sub(fml4, vars.size(), vars.c_ptr(), fml4);
sub(fml5, vars.size(), vars.c_ptr(), fml5);
fml4 = sub(fml4, vars.size(), vars.c_ptr());
fml5 = sub(fml5, vars.size(), vars.c_ptr());
check_equiv("union no overflow", fml4, fml5);
}
}

View file

@ -725,8 +725,7 @@ namespace datalog {
}
}
expr_ref renamed(m);
m_context.get_var_subst()(filter_cond, binding.size(), binding.c_ptr(), renamed);
expr_ref renamed = m_context.get_var_subst()(filter_cond, binding.size(), binding.c_ptr());
app_ref app_renamed(to_app(renamed), m);
if (remove_columns.empty()) {
if (!dealloc)

View file

@ -1311,8 +1311,7 @@ namespace datalog {
if(m_rel_cond_columns.empty()) {
expr_ref_vector renaming(m_manager);
get_renaming_args(r.m_sig2table, r.get_signature(), renaming);
expr_ref table_cond(m_manager);
m_subst(condition, renaming.size(), renaming.c_ptr(), table_cond);
expr_ref table_cond = m_subst(condition, renaming.size(), renaming.c_ptr());
m_table_filter = rmgr.mk_filter_interpreted_fn(r.get_table(), to_app(table_cond));
}
else {
@ -1361,9 +1360,7 @@ namespace datalog {
continue;
}
if(!m_rel_filter) {
expr_ref inner_cond(m_manager);
m_subst(m_cond, m_renaming_for_inner_rel.size(), m_renaming_for_inner_rel.c_ptr(),
inner_cond);
expr_ref inner_cond = m_subst(m_cond, m_renaming_for_inner_rel.size(), m_renaming_for_inner_rel.c_ptr());
m_rel_filter = rmgr.mk_filter_interpreted_fn(*inner, to_app(inner_cond));
}
(*m_rel_filter)(*inner);
@ -1411,11 +1408,10 @@ namespace datalog {
//create the condition with table values substituted in and relation values properly renamed
expr_ref inner_cond(m_manager);
m_subst(m_cond, m_renaming_for_inner_rel.size(), m_renaming_for_inner_rel.c_ptr(),
inner_cond);
inner_cond = m_subst(m_cond, m_renaming_for_inner_rel.size(), m_renaming_for_inner_rel.c_ptr());
relation_base * new_rel = old_rel.clone();
scoped_ptr<relation_mutator_fn> filter = rmgr.mk_filter_interpreted_fn(*new_rel, to_app(inner_cond));
(*filter)(*new_rel);

View file

@ -471,8 +471,7 @@ namespace datalog {
SASSERT(!r.is_undefined(i) || !contains_var(m_new_rule, i));
subst_arg[ofs-i] = r.m_data.get(i);
}
expr_ref res(m_manager);
m_subst(m_new_rule, subst_arg.size(), subst_arg.c_ptr(), res);
expr_ref res = m_subst(m_new_rule, subst_arg.size(), subst_arg.c_ptr());
r.m_data[m_col_idx] = to_app(res);
}
};

View file

@ -246,8 +246,8 @@ namespace datalog {
get_normalizer(t1, t2, norm_subst);
expr_ref t1n_ref(m);
expr_ref t2n_ref(m);
m_var_subst(t1, norm_subst.size(), norm_subst.c_ptr(), t1n_ref);
m_var_subst(t2, norm_subst.size(), norm_subst.c_ptr(), t2n_ref);
t1n_ref = m_var_subst(t1, norm_subst.size(), norm_subst.c_ptr());
t2n_ref = m_var_subst(t2, norm_subst.size(), norm_subst.c_ptr());
app * t1n = to_app(t1n_ref);
app * t2n = to_app(t2n_ref);
if (t1n->get_id() > t2n->get_id()) {
@ -531,7 +531,7 @@ namespace datalog {
expr_ref_vector denormalizer(m);
reverse_renaming(m, normalizer, denormalizer);
expr_ref new_transf(m);
m_var_subst(t_new, denormalizer.size(), denormalizer.c_ptr(), new_transf);
new_transf = m_var_subst(t_new, denormalizer.size(), denormalizer.c_ptr());
app * new_lit = to_app(new_transf);
m_pinned.push_back(new_lit);

View file

@ -1395,8 +1395,7 @@ namespace datalog {
args.push_back(m_decl_util.mk_numeral(el, m_free_vars[i]));
}
expr_ref ground(m_ast_manager);
m_vs(m_condition.get(), args.size(), args.c_ptr(), ground);
expr_ref ground = m_vs(m_condition.get(), args.size(), args.c_ptr());
m_simp(ground);
return m_ast_manager.is_false(ground);

View file

@ -85,7 +85,7 @@ namespace datalog {
s.push_back(m.mk_var(idx, sig[i]));
}
get_inner().to_formula(tmp);
get_plugin().get_context().get_var_subst()(tmp, sz, s.c_ptr(), fml);
fml = get_plugin().get_context().get_var_subst()(tmp, sz, s.c_ptr());
}
@ -584,8 +584,7 @@ namespace datalog {
}
subst_vect[subst_ofs-i] = m.mk_var(r.m_sig2inner[i], sig[i]);
}
expr_ref inner_cond(m);
get_context().get_var_subst()(condition, subst_vect.size(), subst_vect.c_ptr(), inner_cond);
expr_ref inner_cond = get_context().get_var_subst()(condition, subst_vect.size(), subst_vect.c_ptr());
relation_mutator_fn * inner_fun = get_manager().mk_filter_interpreted_fn(r.get_inner(), to_app(inner_cond));
if(!inner_fun) {

View file

@ -526,7 +526,7 @@ void lemma::mk_expr_core() {
sorts.push_back(get_sort(zks.get(i)));
names.push_back(zks.get(i)->get_decl()->get_name());
}
m_body = m.mk_quantifier(true, zks.size(),
m_body = m.mk_quantifier(forall_k, zks.size(),
sorts.c_ptr(),
names.c_ptr(),
m_body, 15, symbol(m_body->get_id()));
@ -633,7 +633,7 @@ void lemma::instantiate(expr * const * exprs, expr_ref &result, expr *e) {
expr *body = to_quantifier(lem)->get_expr();
unsigned num_decls = to_quantifier(lem)->get_num_decls();
var_subst vs(m, false);
vs(body, num_decls, exprs, result);
result = vs(body, num_decls, exprs);
}
void lemma::set_level (unsigned lvl) {
@ -1347,7 +1347,7 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core,
if (is_sat == l_true || is_sat == l_undef) {
if (core) { core->reset(); }
if (model && model->get()) {
if (model) {
r = find_rule(**model, is_concrete, reach_pred_used, num_reuse_reach);
TRACE ("spacer", tout << "reachable "
<< "is_concrete " << is_concrete << " rused: ";
@ -1621,9 +1621,7 @@ void pred_transformer::init_rule(decl2rel const& pts, datalog::rule const& rule)
ground_free_vars(trans, var_reprs, aux_vars, ut_size == 0);
SASSERT(is_all_non_null(var_reprs));
expr_ref tmp(m);
var_subst(m, false)(trans, var_reprs.size (),
(expr*const*)var_reprs.c_ptr(), tmp);
expr_ref tmp = var_subst(m, false)(trans, var_reprs.size (), (expr*const*)var_reprs.c_ptr());
flatten_and (tmp, side);
trans = mk_and(side);
side.reset ();

View file

@ -33,7 +33,7 @@ public:
bool is_h_marked(proof* p) {return m_h_mark.is_marked(p);}
bool is_b_pure (proof *p) {
return !is_h_marked(p) && !this->is_a_marked(p) && is_core_pure(m.get_fact(p));
return !is_h_marked (p) && !this->is_a_marked(p) && is_core_pure(m.get_fact (p));
}
void display_dot(std::ostream &out);

View file

@ -322,24 +322,6 @@ void iuc_solver::get_iuc(expr_ref_vector &core)
// -- new hypothesis reducer
else
{
#if 0
static unsigned bcnt = 0;
{
bcnt++;
TRACE("spacer", tout << "Dumping pf bcnt: " << bcnt << "\n";);
if (bcnt == 123) {
std::ofstream ofs;
ofs.open("/tmp/bpf_" + std::to_string(bcnt) + ".dot");
iuc_proof iuc_pf_before(m, res.get(), core_lits);
iuc_pf_before.display_dot(ofs);
ofs.close();
proof_checker pc(m);
expr_ref_vector side(m);
ENSURE(pc.check(res, side));
}
}
#endif
scoped_watch _t_ (m_hyp_reduce2_sw);
// pre-process proof for better iuc extraction
@ -374,22 +356,6 @@ void iuc_solver::get_iuc(expr_ref_vector &core)
iuc_proof iuc_pf(m, res, core_lits);
#if 0
static unsigned cnt = 0;
{
cnt++;
TRACE("spacer", tout << "Dumping pf cnt: " << cnt << "\n";);
if (cnt == 123) {
std::ofstream ofs;
ofs.open("/tmp/pf_" + std::to_string(cnt) + ".dot");
iuc_pf.display_dot(ofs);
ofs.close();
proof_checker pc(m);
expr_ref_vector side(m);
ENSURE(pc.check(res, side));
}
}
#endif
unsat_core_learner learner(m, iuc_pf);
unsat_core_plugin* plugin;

View file

@ -785,7 +785,7 @@ namespace {
void ground_expr(expr *e, expr_ref &out, app_ref_vector &vars) {
expr_free_vars fv;
ast_manager &m = out.get_manager();
ast_manager &m = out.m();
fv(e);
if (vars.size() < fv.size()) {
@ -795,7 +795,7 @@ namespace {
sort *s = fv[i] ? fv[i] : m.mk_bool_sort();
vars[i] = mk_zk_const(m, i, s);
var_subst vs(m, false);
vs(e, vars.size(),(expr * *) vars.c_ptr(), out);
out = vs(e, vars.size(),(expr * *) vars.c_ptr());
}
}

View file

@ -561,13 +561,13 @@ namespace tb {
}
vars.push_back(m.mk_const(symbol(i), sorts[i]));
}
vs(g.get_head(), vars.size(), vars.c_ptr(), fml);
fml = vs(g.get_head(), vars.size(), vars.c_ptr());
m_head = to_app(fml);
for (unsigned i = 0; i < g.get_num_predicates(); ++i) {
vs(g.get_predicate(i), vars.size(), vars.c_ptr(), fml);
fml = vs(g.get_predicate(i), vars.size(), vars.c_ptr());
m_preds.push_back(to_app(fml));
}
vs(g.get_constraint(), vars.size(), vars.c_ptr(), fml);
fml = vs(g.get_constraint(), vars.size(), vars.c_ptr());
fmls.push_back(fml);
m_precond = m.mk_and(fmls.size(), fmls.c_ptr());
IF_VERBOSE(2,
@ -1132,12 +1132,12 @@ namespace tb {
}
}
if (change) {
m_S2(result->get_constraint(), m_rename.size(), m_rename.c_ptr(), constraint);
constraint = m_S2(result->get_constraint(), m_rename.size(), m_rename.c_ptr());
for (unsigned i = 0; i < result->get_num_predicates(); ++i) {
m_S2(result->get_predicate(i), m_rename.size(), m_rename.c_ptr(), tmp);
tmp = m_S2(result->get_predicate(i), m_rename.size(), m_rename.c_ptr());
predicates[i] = to_app(tmp);
}
m_S2(result->get_head(), m_rename.size(), m_rename.c_ptr(), tmp);
tmp = m_S2(result->get_head(), m_rename.size(), m_rename.c_ptr());
head = to_app(tmp);
result->init(head, predicates, constraint);
}
@ -1168,7 +1168,7 @@ namespace tb {
if (vars[i]) {
v = m.mk_var(i, vars[i]);
m_S1.apply(2, delta, expr_offset(v, offset), tmp);
m_S2(tmp, m_rename.size(), m_rename.c_ptr(), tmp);
tmp = m_S2(tmp, m_rename.size(), m_rename.c_ptr());
insert_subst(offset, tmp);
}
else {
@ -1613,8 +1613,8 @@ namespace datalog {
}
expr_ref body = clause.get_body();
var_subst vs(m, false);
vs(body, subst.size(), subst.c_ptr(), body);
out << mk_pp(body, m) << "\n";
body = vs(body, subst.size(), subst.c_ptr());
out << body << "\n";
}
void resolve_rule(replace_proof_converter& pc, tb::clause const& r1, tb::clause const& r2,

View file

@ -98,7 +98,7 @@ namespace datalog {
}
var_subst vs(m, false);
for (unsigned i = r->get_uninterpreted_tail_size(); i < r->get_tail_size(); ++i) {
vs(r->get_tail(i), revsub.size(), revsub.c_ptr(), result);
result = vs(r->get_tail(i), revsub.size(), revsub.c_ptr());
conjs.push_back(result);
}
bwr.mk_and(conjs.size(), conjs.c_ptr(), result);

View file

@ -156,8 +156,7 @@ namespace datalog {
SASSERT(m_binding[i]);
});
m_binding.reverse();
expr_ref res(m);
instantiate(m, q, m_binding.c_ptr(), res);
expr_ref res = instantiate(m, q, m_binding.c_ptr());
m_binding.reverse();
m_cnst2var(res);
conjs.push_back(res);
@ -222,10 +221,7 @@ namespace datalog {
for (unsigned i = 0; i < qs.size(); ++i) {
instantiate_quantifier(qs[i].get(), conjs);
}
obj_map<func_decl, ptr_vector<expr>*>::iterator it = m_funs.begin(), end = m_funs.end();
for (; it != end; ++it) {
dealloc(it->m_value);
}
for (auto & kv : m_funs) dealloc(kv.m_value);
m_funs.reset();
fml = m.mk_and(conjs.size(), conjs.c_ptr());

View file

@ -69,7 +69,7 @@ namespace datalog {
// Hedge that we don't have to handle the general case for models produced
// by Horn clause solvers.
SASSERT(!new_fi->is_partial() && new_fi->num_entries() == 0);
vs(new_fi->get_else(), subst.size(), subst.c_ptr(), tmp);
tmp = vs(new_fi->get_else(), subst.size(), subst.c_ptr());
old_fi->set_else(tmp);
old_model->register_decl(old_p, old_fi);
}

View file

@ -352,7 +352,7 @@ namespace datalog {
}
if (!new_fi->is_partial()) {
TRACE("dl", tout << mk_pp(new_fi->get_else(), m) << "\n";);
vs(new_fi->get_else(), subst.size(), subst.c_ptr(), tmp);
tmp = vs(new_fi->get_else(), subst.size(), subst.c_ptr());
old_fi->set_else(tmp);
}
unsigned num_entries = new_fi->num_entries();
@ -362,7 +362,7 @@ namespace datalog {
func_entry const* e = new_fi->get_entry(j);
for (unsigned k = 0, l = 0; k < old_p->get_arity(); ++k) {
if (!is_sliced.get(k)) {
vs(e->get_arg(l++), subst.size(), subst.c_ptr(), tmp);
tmp = vs(e->get_arg(l++), subst.size(), subst.c_ptr());
args.push_back(tmp);
}
else {
@ -370,7 +370,7 @@ namespace datalog {
}
SASSERT(l <= new_p->get_arity());
}
vs(e->get_result(), subst.size(), subst.c_ptr(), res);
res = vs(e->get_result(), subst.size(), subst.c_ptr());
old_fi->insert_entry(args.c_ptr(), res.get());
}
old_model->register_decl(old_p, old_fi);

View file

@ -449,7 +449,6 @@ namespace opt {
}
lbool r = maxsmt();
if (r == l_true) {
ast_manager& m = m_solver->get_manager();
svector<symbol> labels;
maxsmt.get_model(m_model, labels);
// TBD: is m_fm applied or not?

View file

@ -78,6 +78,7 @@ namespace smt2 {
symbol m_bang;
symbol m_forall;
symbol m_exists;
symbol m_lambda;
symbol m_as;
symbol m_not;
symbol m_root_obj;
@ -161,7 +162,7 @@ namespace smt2 {
};
struct quant_frame : public expr_frame {
bool m_forall;
quantifier_kind m_kind;
symbol m_qid;
symbol m_skid;
unsigned m_weight;
@ -170,8 +171,8 @@ namespace smt2 {
unsigned m_sym_spos;
unsigned m_sort_spos;
unsigned m_expr_spos;
quant_frame(bool forall, unsigned pat_spos, unsigned nopat_spos, unsigned sym_spos, unsigned sort_spos, unsigned expr_spos):
expr_frame(EF_QUANT), m_forall(forall), m_weight(1),
quant_frame(quantifier_kind k, unsigned pat_spos, unsigned nopat_spos, unsigned sym_spos, unsigned sort_spos, unsigned expr_spos):
expr_frame(EF_QUANT), m_kind(k), m_weight(1),
m_pat_spos(pat_spos), m_nopat_spos(nopat_spos),
m_sym_spos(sym_spos), m_sort_spos(sort_spos),
m_expr_spos(expr_spos) {}
@ -407,6 +408,7 @@ namespace smt2 {
bool curr_id_is_match() const { SASSERT(curr_is_identifier()); return curr_id() == m_match; }
bool curr_id_is_forall() const { SASSERT(curr_is_identifier()); return curr_id() == m_forall; }
bool curr_id_is_exists() const { SASSERT(curr_is_identifier()); return curr_id() == m_exists; }
bool curr_id_is_lambda() const { SASSERT(curr_is_identifier()); return curr_id() == m_lambda; }
bool curr_id_is_bang() const { SASSERT(curr_is_identifier()); return curr_id() == m_bang; }
bool curr_id_is_let() const { SASSERT(curr_is_identifier()); return curr_id() == m_let; }
bool curr_id_is_root_obj() const { SASSERT(curr_is_identifier()); return curr_id() == m_root_obj; }
@ -1301,15 +1303,15 @@ namespace smt2 {
m_num_expr_frames++;
}
void push_quant_frame(bool is_forall) {
void push_quant_frame(quantifier_kind k) {
SASSERT(curr_is_identifier());
SASSERT(curr_id_is_forall() || curr_id_is_exists());
SASSERT(!is_forall || curr_id_is_forall());
SASSERT(is_forall || curr_id_is_exists());
SASSERT(curr_id_is_forall() || curr_id_is_exists() || curr_id_is_lambda());
SASSERT((k == forall_k) == curr_id_is_forall());
SASSERT((k == exists_k) == curr_id_is_exists());
SASSERT((k == lambda_k) == curr_id_is_lambda());
next();
void * mem = m_stack.allocate(sizeof(quant_frame));
new (mem) quant_frame(is_forall, pattern_stack().size(), nopattern_stack().size(), symbol_stack().size(),
new (mem) quant_frame(k, pattern_stack().size(), nopattern_stack().size(), symbol_stack().size(),
sort_stack().size(), expr_stack().size());
m_num_expr_frames++;
unsigned num_vars = parse_sorted_vars();
@ -1374,7 +1376,7 @@ namespace smt2 {
new_case = cases[i];
}
else {
sub(cases[i], subst.size(), subst.c_ptr(), new_case);
new_case = sub(cases[i], subst.size(), subst.c_ptr());
inv_var_shifter inv(m());
inv(new_case, subst.size(), new_case);
}
@ -1804,7 +1806,7 @@ namespace smt2 {
new (mem) app_frame(f, expr_spos, param_spos, has_as);
m_num_expr_frames++;
}
void push_expr_frame(expr_frame * curr) {
SASSERT(curr_is_lparen());
next();
@ -1815,10 +1817,13 @@ namespace smt2 {
push_let_frame();
}
else if (curr_id_is_forall()) {
push_quant_frame(true);
push_quant_frame(forall_k);
}
else if (curr_id_is_exists()) {
push_quant_frame(false);
push_quant_frame(exists_k);
}
else if (curr_id_is_lambda()) {
push_quant_frame(lambda_k);
}
else if (curr_id_is_bang()) {
push_bang_frame(curr);
@ -1915,6 +1920,7 @@ namespace smt2 {
SASSERT(expr_stack().size() >= fr->m_expr_spos);
unsigned num_decls = sort_stack().size() - fr->m_sort_spos;
if (expr_stack().size() - fr->m_expr_spos != num_decls /* variables */ + 1 /* result */)
//throw parser_exception("invalid quantified expression, syntax error: (forall|exists|lambda ((<symbol> <sort>)*) <expr>) expected");
throw parser_exception("invalid quantified expression, syntax error: (forall|exists ((<symbol> <sort>)*) <expr>) expected");
unsigned begin_pats = fr->m_pat_spos;
unsigned end_pats = pattern_stack().size();
@ -1938,19 +1944,19 @@ namespace smt2 {
TRACE("parse_quantifier", tout << "body:\n" << mk_pp(expr_stack().back(), m()) << "\n";);
if (fr->m_qid == symbol::null)
fr->m_qid = symbol(m_scanner.get_line());
if (!m().is_bool(expr_stack().back()))
if (fr->m_kind != lambda_k && !m().is_bool(expr_stack().back()))
throw parser_exception("quantifier body must be a Boolean expression");
quantifier * new_q = m().mk_quantifier(fr->m_forall,
num_decls,
sort_stack().c_ptr() + fr->m_sort_spos,
symbol_stack().c_ptr() + fr->m_sym_spos,
expr_stack().back(),
fr->m_weight,
fr->m_qid,
fr->m_skid,
num_pats, pattern_stack().c_ptr() + fr->m_pat_spos,
num_nopats, nopattern_stack().c_ptr() + fr->m_nopat_spos
);
quantifier* new_q = m().mk_quantifier(fr->m_kind,
num_decls,
sort_stack().c_ptr() + fr->m_sort_spos,
symbol_stack().c_ptr() + fr->m_sym_spos,
expr_stack().back(),
fr->m_weight,
fr->m_qid,
fr->m_skid,
num_pats, pattern_stack().c_ptr() + fr->m_pat_spos,
num_nopats, nopattern_stack().c_ptr() + fr->m_nopat_spos
);
TRACE("mk_quantifier", tout << "id: " << new_q->get_id() << "\n" << mk_ismt2_pp(new_q, m()) << "\n";);
TRACE("skid", tout << "new_q->skid: " << new_q->get_skid() << "\n";);
expr_stack().shrink(fr->m_expr_spos);
@ -2965,6 +2971,7 @@ namespace smt2 {
m_bang("!"),
m_forall("forall"),
m_exists("exists"),
m_lambda("lambda"),
m_as("as"),
m_not("not"),
m_root_obj("root-obj"),

View file

@ -2269,8 +2269,7 @@ namespace qe {
bound.push_back(m.mk_fresh_const("bound", fv[i]));
}
var_subst subst(m);
subst(fml, bound.size(), bound.c_ptr(), tmp);
fml = tmp;
fml = subst(fml, bound.size(), bound.c_ptr());
}
}
@ -2291,7 +2290,7 @@ namespace qe {
}
expr* const* exprs = (expr* const*)(vars.c_ptr());
var_subst subst(m);
subst(new_body, vars.size(), exprs, tmp);
tmp = subst(new_body, vars.size(), exprs);
inv_var_shifter shift(m);
shift(tmp, vars.size(), new_body);
}
@ -2337,13 +2336,18 @@ namespace qe {
case AST_QUANTIFIER: {
app_ref_vector vars(m);
quantifier* q = to_quantifier(e);
bool is_fa = q->is_forall();
tmp = q->get_expr();
extract_vars(q, tmp, vars);
elim(tmp);
init_qe();
m_qe->set_assumption(m_assumption);
m_qe->eliminate(is_fa, vars.size(), vars.c_ptr(), tmp);
if (is_lambda(q)) {
tmp = e;
}
else {
bool is_fa = is_forall(q);
tmp = q->get_expr();
extract_vars(q, tmp, vars);
elim(tmp);
init_qe();
m_qe->set_assumption(m_assumption);
m_qe->eliminate(is_fa, vars.size(), vars.c_ptr(), tmp);
}
m_trail.push_back(tmp);
m_visited.insert(e, tmp);
todo.pop_back();
@ -2593,6 +2597,9 @@ namespace qe {
)
{
if (is_lambda(old_q)) {
return false;
}
// bool is_forall = old_q->is_forall();
app_ref_vector vars(m);
TRACE("qe", tout << "simplifying" << mk_pp(new_body, m) << "\n";);
@ -2600,11 +2607,11 @@ namespace qe {
extract_vars(old_q, result, vars);
TRACE("qe", tout << "variables extracted" << mk_pp(result, m) << "\n";);
if (old_q->is_forall()) {
if (is_forall(old_q)) {
result = mk_not(m, result);
}
m_ctx.solve(result, vars);
if (old_q->is_forall()) {
if (is_forall(old_q)) {
expr* e = nullptr;
result = m.is_not(result, e)?e:mk_not(m, result);
}
@ -2619,7 +2626,7 @@ namespace qe {
names.push_back(vars[i]->get_decl()->get_name());
}
if (!vars.empty()) {
result = m.mk_quantifier(old_q->is_forall(), vars.size(), sorts.c_ptr(), names.c_ptr(), result, 1);
result = m.mk_quantifier(old_q->get_kind(), vars.size(), sorts.c_ptr(), names.c_ptr(), result, 1);
}
result_pr = nullptr;
return true;

View file

@ -327,8 +327,8 @@ namespace eq {
void flatten_args(quantifier* q, unsigned& num_args, expr*const*& args) {
expr * e = q->get_expr();
if ((q->is_forall() && m.is_or(e)) ||
(q->is_exists() && m.is_and(e))) {
if ((is_forall(q) && m.is_or(e)) ||
(is_exists(q) && m.is_and(e))) {
num_args = to_app(e)->get_num_args();
args = to_app(e)->get_args();
}
@ -356,27 +356,29 @@ namespace eq {
}
expr_ref t(m);
if (q->is_forall()) {
switch (q->get_kind()) {
case forall_k:
rw.mk_or(m_new_args.size(), m_new_args.c_ptr(), t);
}
else {
break;
case exists_k:
rw.mk_and(m_new_args.size(), m_new_args.c_ptr(), t);
break;
default:
t = e;
break;
}
expr_ref new_e(m);
m_subst(t, new_e);
expr_ref new_e = m_subst(t, m_subst_map.size(), m_subst_map.c_ptr());
// don't forget to update the quantifier patterns
expr_ref_buffer new_patterns(m);
expr_ref_buffer new_no_patterns(m);
for (unsigned j = 0; j < q->get_num_patterns(); j++) {
expr_ref new_pat(m);
m_subst(q->get_pattern(j), new_pat);
expr_ref new_pat = m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
new_patterns.push_back(new_pat);
}
for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
expr_ref new_nopat(m);
m_subst(q->get_no_pattern(j), new_nopat);
expr_ref new_nopat = m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
new_no_patterns.push_back(new_nopat);
}
@ -390,12 +392,17 @@ namespace eq {
set_is_variable_proc(is_v);
unsigned num_args = 1;
expr* const* args = &e;
if (is_lambda(q)) {
r = q;
pr = 0;
return;
}
flatten_args(q, num_args, args);
unsigned def_count = 0;
unsigned largest_vinx = 0;
find_definitions(num_args, args, q->is_exists(), def_count, largest_vinx);
find_definitions(num_args, args, is_exists(q), def_count, largest_vinx);
if (def_count > 0) {
get_elimination_order();
@ -423,7 +430,7 @@ namespace eq {
if (is_quantifier(r)) {
quantifier * q = to_quantifier(r);
::elim_unused_vars(m, q, m_params, r);
r = ::elim_unused_vars(m, q, m_params);
if (m.proofs_enabled()) {
proof * p1 = m.mk_elim_unused_vars(q, r);
pr = m.mk_transitivity(pr, p1);
@ -624,7 +631,7 @@ namespace eq {
expr_ref r(m), new_r(m);
r = m.mk_and(conjs.size(), conjs.c_ptr());
create_substitution(largest_vinx + 1);
m_subst(r, new_r);
new_r = m_subst(r, m_subst_map.size(), m_subst_map.c_ptr());
m_rewriter(new_r);
conjs.reset();
flatten_and(new_r, conjs);
@ -1756,16 +1763,12 @@ namespace fm {
// x_cost_lt is not a total order on variables
std::stable_sort(x_cost_vector.begin(), x_cost_vector.end(), x_cost_lt(m_is_int));
TRACE("qe_lite",
svector<x_cost>::iterator it2 = x_cost_vector.begin();
svector<x_cost>::iterator end2 = x_cost_vector.end();
for (; it2 != end2; ++it2) {
tout << "(" << mk_ismt2_pp(m_var2expr.get(it2->first), m) << " " << it2->second << ") ";
for (auto const& kv : x_cost_vector) {
tout << "(" << mk_ismt2_pp(m_var2expr.get(kv.first), m) << " " << kv.second << ") ";
}
tout << "\n";);
svector<x_cost>::iterator it2 = x_cost_vector.begin();
svector<x_cost>::iterator end2 = x_cost_vector.end();
for (; it2 != end2; ++it2) {
xs.push_back(it2->first);
for (auto const& kv : x_cost_vector) {
xs.push_back(kv.first);
}
}
@ -1802,11 +1805,9 @@ namespace fm {
void analyze(constraints const & cs, var x, bool & all_int, bool & unit_coeff) const {
all_int = true;
unit_coeff = true;
constraints::const_iterator it = cs.begin();
constraints::const_iterator end = cs.end();
for (; it != end; ++it) {
for (constraint const* c : cs) {
bool curr_unit_coeff;
analyze(*(*it), x, all_int, curr_unit_coeff);
analyze(*c, x, all_int, curr_unit_coeff);
if (!all_int)
return;
if (!curr_unit_coeff)
@ -1830,10 +1831,8 @@ namespace fm {
}
void copy_constraints(constraints const & s, clauses & t) {
constraints::const_iterator it = s.begin();
constraints::const_iterator end = s.end();
for (; it != end; ++it) {
app * c = to_expr(*(*it));
for (constraint const* cns : s) {
app * c = to_expr(*cns);
t.push_back(c);
}
}
@ -1842,10 +1841,8 @@ namespace fm {
void save_constraints(var x) { }
void mark_constraints_dead(constraints const & cs) {
constraints::const_iterator it = cs.begin();
constraints::const_iterator end = cs.end();
for (; it != end; ++it)
(*it)->m_dead = true;
for (constraint* c : cs)
c->m_dead = true;
}
void mark_constraints_dead(var x) {
@ -2094,14 +2091,8 @@ namespace fm {
}
void copy_remaining(vector<constraints> & v2cs) {
vector<constraints>::iterator it = v2cs.begin();
vector<constraints>::iterator end = v2cs.end();
for (; it != end; ++it) {
constraints & cs = *it;
constraints::iterator it2 = cs.begin();
constraints::iterator end2 = cs.end();
for (; it2 != end2; ++it2) {
constraint * c = *it2;
for (constraints& cs : v2cs) {
for (constraint* c : cs) {
if (!c->m_dead) {
c->m_dead = true;
expr * new_f = to_expr(*c);
@ -2170,11 +2161,8 @@ namespace fm {
}
void display_constraints(std::ostream & out, constraints const & cs) const {
constraints::const_iterator it = cs.begin();
constraints::const_iterator end = cs.end();
for (; it != end; ++it) {
out << " ";
display(out, *(*it));
for (constraint const* c : cs) {
display(out << " ", *c);
out << "\n";
}
}
@ -2215,7 +2203,9 @@ public:
for (unsigned i = 0; i < q->get_num_decls(); ++i) {
indices.insert(i);
}
m_imp(indices, true, result);
if (q->get_kind() != lambda_k) {
m_imp(indices, true, result);
}
if (is_forall(q)) {
result = push_not(result);
}
@ -2295,7 +2285,7 @@ public:
tmp = to_quantifier(tmp)->get_expr();
used.process(tmp);
var_subst vs(m, true);
vs(tmp, vars.size(), (expr*const*)vars.c_ptr(), fml);
fml = vs(tmp, vars.size(), (expr*const*)vars.c_ptr());
// collect set of variables that were used.
unsigned j = 0;
for (unsigned i = 0; i < vars.size(); ++i) {

View file

@ -31,6 +31,7 @@ Revision History:
#include "qe/qe_arrays.h"
#include "qe/qe_datatypes.h"
#include "qe/qe_lite.h"
#include "model/model_pp.h"
#include "model/model_evaluator.h"
@ -616,7 +617,7 @@ public:
qe::array_project_plugin ap(m);
ap(mdl, array_vars, fml, vars, m_reduce_all_selects);
SASSERT (array_vars.empty ());
m_rw(fml);
m_rw (fml);
SASSERT (!m.is_false (fml));
TRACE ("qe",
@ -650,9 +651,9 @@ public:
// substitute any remaining other vars
if (!m_dont_sub && !other_vars.empty ()) {
subst_vars (eval, other_vars, fml);
TRACE ("qe", tout << "After substituting remaining other vars:\n" << fml << "\n";);
// an extra round of simplification because subst_vars is not simplifying
m_rw(fml);
TRACE ("qe", tout << "After substituting remaining other vars:\n" << fml << "\n";);
other_vars.reset();
}

Some files were not shown because too many files have changed in this diff Show more