mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 01:25:31 +00:00
Z3 sources
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
3f9edad676
commit
e9eab22e5c
1186 changed files with 381859 additions and 0 deletions
215
lib/der.h
Normal file
215
lib/der.h
Normal file
|
@ -0,0 +1,215 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
der.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Destructive equality resolution.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-01-27.
|
||||
|
||||
Revision History:
|
||||
|
||||
Christoph Wintersteiger, 2010-03-30: Added Destr. Multi-Equality Resolution
|
||||
|
||||
--*/
|
||||
#ifndef _DER_H_
|
||||
#define _DER_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"var_subst.h"
|
||||
#include"assertion_set_strategy.h"
|
||||
|
||||
/*
|
||||
New DER: the class DER (above) eliminates variables one by one.
|
||||
This is inefficient, and we should implement a new version that
|
||||
can handle efficiently examples with hundreds of variables.
|
||||
|
||||
Suppose the target of the simplification is the quantifier
|
||||
(FORALL (x1 T1) (x2 T2) ... (xn Tn) (or ....))
|
||||
So, the variables x1 ... xn are the candidates for elimination.
|
||||
First, we build a mapping of candidate substitutions
|
||||
Since variables x1 ... xn have ids 0 ... n-1, we can
|
||||
use an array m_map to implement this mapping.
|
||||
|
||||
The idea is to traverse the children of the (or ...) looking
|
||||
for diseqs. The method is_var_diseq can be used for doing that.
|
||||
Given a child c, if is_var_diseq(c, num_decls, v, t) returns true,
|
||||
and m_map[v] is null, then we store t at m_map[v].
|
||||
For performance reasons, we also store a mapping from child position (in the OR) to variable ID.
|
||||
Thus, m_pos2var[pos] contains the variable that is defined by the diseq at position pos.
|
||||
m_pos2var[pos] = -1, if this position does not contain a diseq.
|
||||
|
||||
After doing that, m_map contains the variables that can
|
||||
be potentially eliminated using DER.
|
||||
We say m_map[v] is the definition of variable v.
|
||||
|
||||
The next step is to perform a topological sort on these
|
||||
variables. The result is an array (m_order) of integers (variable ids)
|
||||
such that i < j implies that m_map[m_order[i]] does not depend on variable m_order[j].
|
||||
For example, consider the case where m_map contains the following values
|
||||
|
||||
m_map[0] = (+ (VAR 2) 0)
|
||||
m_map[1] = null
|
||||
m_map[2] = (+ (VAR 3) 0)
|
||||
m_map[3] = (+ (VAR 1) 1)
|
||||
m_map[4] = (* (VAR 5) 2)
|
||||
m_map[5] = null
|
||||
|
||||
In this example, variable 0 depends on the definition of variable 2, which
|
||||
depends on the definition of variable 3, which depends on the definition of variable 0 (cycle).
|
||||
On the other hand, no cycle is found when starting at variable 4.
|
||||
Cycles can be broken by erasing entries from m_map. For example, the cycle above
|
||||
can be removed by setting m_map[0] = null.
|
||||
|
||||
m_map[0] = null
|
||||
m_map[1] = null
|
||||
m_map[2] = (+ (VAR 3) 0)
|
||||
m_map[3] = (+ (VAR 1) 1)
|
||||
m_map[4] = (* (VAR 5) 2)
|
||||
m_map[5] = null
|
||||
|
||||
The file asserted_formulas.cpp has a class top_sort for performing topological sort.
|
||||
This class cannot be used here, since it is meant for eliminating constants (instead of variables).
|
||||
We need to implement a new top_sort here, we do not need a separate class for doing that.
|
||||
Moreover, it is much simpler, since m_map is just an array.
|
||||
|
||||
In the example above (after setting m_map[0] to null), top_sort will produce the following order
|
||||
m_order = [3, 2, 4]
|
||||
|
||||
The next step is to use var_subst to update the definitions in var_subst.
|
||||
The idea is to process the variables in the order specified by m_order.
|
||||
When processing m_map[m_order[i]] we use the definitions of all variables in m_order[0 ... i-1].
|
||||
For example:
|
||||
The first variable is 3, since it is at m_order[0], nothing needs to be done.
|
||||
Next we have variable 2, we use m_map[3] since 3 is before 2 in m_order. So, the new
|
||||
definition for 2 is (+ (+ (VAR 1) 1) 0). That is, we update m_map[2] with (+ (+ (VAR 1) 1) 0)
|
||||
Next we have variable 4, we use m_map[3] and m_map[2] since 3 and 2 are before 4 in m_order.
|
||||
In this case, var_subst will not do anything since m_map[4] does not contain variables 3 or 2.
|
||||
So, the new m_map is:
|
||||
|
||||
m_map[0] = null
|
||||
m_map[1] = null
|
||||
m_map[2] = (+ (+ (VAR 1) 1) 0)
|
||||
m_map[3] = (+ (VAR 1) 1)
|
||||
m_map[4] = (* (VAR 5) 2)
|
||||
m_map[5] = null
|
||||
|
||||
Now, we update the body of the quantifier using var_subst and the mapping above.
|
||||
The idea is to create a new set of children for the OR.
|
||||
For each child at position i, we do
|
||||
if m_map[m_pos2var[i]] != -1
|
||||
skip this child, it is a diseq used during DER
|
||||
else
|
||||
apply var_subst using m_map to this child, and store the result in a new children array
|
||||
Create a new OR (new body of the quantifier) using the new children
|
||||
Then, we create a new quantifier using this new body, and use the function elim_unused_vars to
|
||||
eliminate the ununsed variables.
|
||||
|
||||
Remark: let us implement the new version inside the class der.
|
||||
Use #if 0 ... #endif to comment the old version.
|
||||
|
||||
Remark: after you are done, we can eliminate the call to occurs in is_var_diseq, since
|
||||
top_sort is already performing cycle detection.
|
||||
*/
|
||||
|
||||
/**
|
||||
\brief Functor for applying Destructive Multi-Equality Resolution.
|
||||
|
||||
(forall (X Y) (or X /= s C[X])) --> (forall (Y) C[Y])
|
||||
*/
|
||||
class der {
|
||||
ast_manager & m_manager;
|
||||
var_subst m_subst;
|
||||
expr_ref_buffer m_new_exprs;
|
||||
|
||||
ptr_vector<expr> m_map;
|
||||
int_vector m_pos2var;
|
||||
ptr_vector<var> m_inx2var;
|
||||
unsigned_vector m_order;
|
||||
expr_ref_vector m_subst_map;
|
||||
expr_ref_buffer m_new_args;
|
||||
|
||||
/**
|
||||
\brief Return true if e can be viewed as a variable disequality.
|
||||
Store the variable id in v and the definition in t.
|
||||
For example:
|
||||
|
||||
if e is (not (= (VAR 1) T)), then v assigned to 1, and t to T.
|
||||
if e is (iff (VAR 2) T), then v is assigned to 2, and t to (not T).
|
||||
(not T) is used because this formula is equivalent to (not (iff (VAR 2) (not T))),
|
||||
and can be viewed as a disequality.
|
||||
*/
|
||||
bool is_var_diseq(expr * e, unsigned num_decls, var *& v, expr_ref & t);
|
||||
|
||||
void get_elimination_order();
|
||||
void create_substitution(unsigned sz);
|
||||
void apply_substitution(quantifier * q, expr_ref & r);
|
||||
|
||||
void reduce1(quantifier * q, expr_ref & r, proof_ref & pr);
|
||||
|
||||
public:
|
||||
der(ast_manager & m):m_manager(m),m_subst(m),m_new_exprs(m),m_subst_map(m),m_new_args(m) {}
|
||||
ast_manager & m() const { return m_manager; }
|
||||
void operator()(quantifier * q, expr_ref & r, proof_ref & pr);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Functor for applying Destructive Multi-Equality Resolution in all
|
||||
universal quantifiers in an expression.
|
||||
*/
|
||||
class der_rewriter {
|
||||
protected:
|
||||
struct imp;
|
||||
imp * m_imp;
|
||||
public:
|
||||
der_rewriter(ast_manager & m);
|
||||
~der_rewriter();
|
||||
|
||||
ast_manager & m () const;
|
||||
|
||||
void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
|
||||
|
||||
void cancel() { set_cancel(true); }
|
||||
void reset_cancel() { set_cancel(false); }
|
||||
void set_cancel(bool f);
|
||||
void cleanup();
|
||||
void reset();
|
||||
};
|
||||
|
||||
typedef der_rewriter der_star;
|
||||
|
||||
// TODO: delete obsolete class
|
||||
class der_strategy : public assertion_set_strategy {
|
||||
struct imp;
|
||||
imp * m_imp;
|
||||
public:
|
||||
der_strategy(ast_manager & m);
|
||||
virtual ~der_strategy();
|
||||
|
||||
void operator()(assertion_set & s);
|
||||
|
||||
virtual void operator()(assertion_set & s, model_converter_ref & mc) {
|
||||
operator()(s);
|
||||
mc = 0;
|
||||
}
|
||||
|
||||
virtual void cleanup();
|
||||
virtual void set_cancel(bool f);
|
||||
};
|
||||
|
||||
inline as_st * mk_der(ast_manager & m) {
|
||||
return alloc(der_strategy, m);
|
||||
}
|
||||
|
||||
class tactic;
|
||||
|
||||
tactic * mk_der_tactic(ast_manager & m);
|
||||
|
||||
#endif /* _DER_H_ */
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue