z3-src 503.2.1

Source distribution of the Z3 SMT solver, for use as a build dependency
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
/*++
Copyright (c) 2011 Microsoft Corporation

Module Name:

    rewriter.h

Abstract:

    Lean and mean rewriter

Author:

    Leonardo (leonardo) 2011-03-31

Notes:

--*/
#pragma once

#include "ast/ast.h"
#include "ast/rewriter/rewriter_types.h"
#include "ast/act_cache.h"
#include "util/obj_hashtable.h"

/**
   \brief Common infrastructure for AST rewriters.
*/
class rewriter_core {
protected:
    struct frame {
        expr *   m_curr;
        unsigned m_cache_result:1; // true if the result of rewriting m_expr must be cached.
        unsigned m_new_child:1;
        unsigned m_state:2;
        unsigned m_max_depth:2;     // bounded rewrite... if m_max_depth == 0, then children are not rewritten.
        unsigned m_i:26;
        unsigned m_spos;           // top of the result stack, when the frame was created.
        frame(expr * n, bool cache_res, unsigned st, unsigned max_depth, unsigned spos):
            m_curr(n), 
            m_cache_result(cache_res),
            m_new_child(false),
            m_state(st),
            m_max_depth(max_depth),
            m_i(0),
            m_spos(spos) {
        }
    };
    ast_manager &              m_manager;
    bool                       m_proof_gen; 
    bool                       m_cancel_check;
    typedef act_cache          cache;
    ptr_vector<cache>          m_cache_stack;
    cache *                    m_cache; // current cache.
    svector<frame>             m_frame_stack;
    expr_ref_vector            m_result_stack;

    // proof generation goodness ----
    ptr_vector<cache>          m_cache_pr_stack; 
    cache *                    m_cache_pr;
    proof_ref_vector           m_result_pr_stack;
    // --------------------------

    obj_hashtable<expr>        m_blocked;
    expr *                     m_root;
    unsigned                   m_num_qvars;
    struct scope {
        expr *   m_old_root;
        unsigned m_old_num_qvars;
        scope(expr * r, unsigned n):m_old_root(r), m_old_num_qvars(n) {}
    };
    svector<scope>             m_scopes;

    // Return true if the rewriting result of the given expression must be cached.
    bool must_cache(expr * t) const {
        return 
            t->get_ref_count() > 1 &&  // t must be a shared expression
            t != m_root && // t must not be the root expression
            ((is_app(t) && to_app(t)->get_num_args() > 0) || is_quantifier(t)); // t is a (non-constant) application or a quantifier.
    }

    void push_frame_core(expr * t, bool cache_res, unsigned st = 0, unsigned max_depth = RW_UNBOUNDED_DEPTH) {
        SASSERT(!m_proof_gen || m_result_stack.size() == m_result_pr_stack.size());
        m_frame_stack.push_back(frame(t, cache_res, st, max_depth, m_result_stack.size()));
    }

    void push_frame(expr * t, unsigned st = 0) {
        push_frame_core(t, must_cache(t), st);
    } 

    bool rewrites_to(expr* t, proof* p);
    bool rewrites_from(expr* t, proof* p);
    void init_cache_stack();
    void del_cache_stack();
    void reset_cache();
    void cache_result(expr * k, expr * v) { cache_shifted_result(k, 0, v); }
    void cache_shifted_result(expr * k, unsigned offset, expr * v);
    expr * get_cached(expr * k) const { return m_cache->find(k); } 
    expr * get_cached(expr* k, unsigned offset) const { return m_cache->find(k, offset); }

    void cache_result(expr * k, expr * v, proof * pr);
    proof * get_cached_pr(expr * k) const { return static_cast<proof*>(m_cache_pr->find(k)); } 

    void free_memory();
    void begin_scope();
    void end_scope();
    bool is_child_of_top_frame(expr * t) const;
    void set_new_child_flag(expr * old_t) {
        CTRACE(rewriter_bug, !is_child_of_top_frame(old_t), display_stack(tout, 3););
        SASSERT(is_child_of_top_frame(old_t));
        if (!m_frame_stack.empty())
            m_frame_stack.back().m_new_child = true;
    }
    void set_new_child_flag(expr * old_t, expr * new_t) { if (old_t != new_t) set_new_child_flag(old_t); }
    
    void elim_reflex_prs(unsigned spos);
    void block(expr* t) { m_blocked.insert(t); }
    bool is_blocked(expr* t) const { return m_blocked.contains(t); }
public:
    rewriter_core(ast_manager & m, bool proof_gen);
    virtual ~rewriter_core();
    ast_manager & m() const { return m_manager; }
    void reset();
    void cleanup();
    void set_cancel_check(bool f) { m_cancel_check = f; }
#ifdef _TRACE
    void display_stack(std::ostream & out, unsigned pp_depth);
#endif
    unsigned get_cache_size() const;
};

class var_shifter_core : public rewriter_core {
protected:
    bool visit(expr * t);
    void process_app(app * t, frame & fr);
    virtual void process_var(var * v) = 0;
    void process_quantifier(quantifier * q, frame & fr);
    void main_loop(expr * t, expr_ref & r);
public:
    var_shifter_core(ast_manager & m):rewriter_core(m, false) {}
};

/**
   \brief Functor used to shift the free variables of an AST by a given amount.
   This functor is used by the var_subst functor.

   This functor implements the following functions:
   1) shift(n, s) will return a new AST where all free variables (VAR i) in n,
   are replaced by (VAR (+ i s)).

   2) shift(n, b, s1, s2) is a variant of the previous function such that 
   for a each free variable (VAR i) is shifted to:
       - (VAR i + s1) if i >= b
       - (VAR i + s2) if i < b 
*/
class var_shifter : public var_shifter_core {
    unsigned  m_bound  { 0 };
    unsigned  m_shift1 { 0 };
    unsigned  m_shift2 { 0 };
    void process_var(var * v) override;
public:
    var_shifter(ast_manager & m):var_shifter_core(m) {}
    void operator()(expr * t, unsigned bound, unsigned shift1, unsigned shift2, expr_ref & r);
    void operator()(expr * t, unsigned s, expr_ref & r) {
        operator()(t, 0, s, 0, r);
    }
};

/**
   \brief Functor used to shift the free variables of an AST by a negative amount.

   Abstract implementation:

   inv_shift(f(c_1, ..., c_n), d, s) =
     f(inv_shift(c_1, d, s), ..., inv_shift(c_n, d, s))
   inv_shift(var(i), d, s) =
     if (i < d) 
       var(i)
     else
       assert(i - s >= d)
       var(i-s)
  inv_shift((forall (x) P), d, s) =
    (forall (x) inv_shift(P, d+1, s))
   
  This functor assumes that if we are shifting an expression F by N, then F
  does not contain free variables #0, ... #N-1 

  See assertion above.
*/
class inv_var_shifter : public var_shifter_core {
protected:
    unsigned m_shift = 0;
    void process_var(var * v) override;
public:
    inv_var_shifter(ast_manager & m):var_shifter_core(m) {}
    void operator()(expr * t, unsigned shift, expr_ref & r);
};

template<typename Config> 
class rewriter_tpl : public rewriter_core {
protected:
    // Rewriter maintains a stack of frames.
    // Each frame represents an expression that is being rewritten.
    // The resultant expressions are store on the Result stack.
    // Each frame is in a particular state.
    // Let f(t_0,...,t_n) be the expression is the frame Fr. Then Fr can be is one of the 
    // following states:
    //    PROCESS_CHILDREN(i) the children t_0, ..., t_{i-1} have already been rewritten, and the result is on the Result stack.
    //    REWRITE_BUILTIN All t_0, ..., t_n have been rewritten to t_0',...,t_n', and the builtin rewriter (or plugin) produced a new term t
    //                    that can be further rewritten.
    //    EXPAND_DEF      All t_0, ..., t_n have been rewritten to t_0',...,t_n'.
    //                    The function symbol f is a macro, and the body of the macro needs to be rewritten using the t_0',...,t_n' as bindings.
    //    REWRITE_RULE    All t_0, ..., t_n have been rewritten to t_0',...,t_n'.
    //                    There is rewrite rule lhs -> rhs s.t. f(t_0', ..., t_n') matches lhs with substitution delta.
    //                    rhs is then rewritten using delta.
    enum state {
        PROCESS_CHILDREN,
        REWRITE_BUILTIN,
        EXPAND_DEF,
        REWRITE_RULE
    };
    Config &                   m_cfg;
    unsigned                   m_num_steps;
    ptr_vector<expr>           m_bindings;
    var_shifter                m_shifter;
    inv_var_shifter            m_inv_shifter;
    expr_ref                   m_r;
    proof_ref                  m_pr;
    proof_ref                  m_pr2;
    unsigned_vector            m_shifts;

    svector<frame> & frame_stack() { return this->m_frame_stack; }
    svector<frame> const & frame_stack() const { return this->m_frame_stack; }
    expr_ref_vector & result_stack() { return this->m_result_stack; }
    expr_ref_vector const & result_stack() const { return this->m_result_stack; }
    proof_ref_vector & result_pr_stack() { return this->m_result_pr_stack; }
    proof_ref_vector const & result_pr_stack() const { return this->m_result_pr_stack; }

    void display_bindings(std::ostream& out);

    void set_new_child_flag(expr * old_t) {
        SASSERT(frame_stack().empty() || frame_stack().back().m_state != PROCESS_CHILDREN || this->is_child_of_top_frame(old_t));
        if (!frame_stack().empty())
            frame_stack().back().m_new_child = true;
    }
    void set_new_child_flag(expr * old_t, expr * new_t) { if (old_t != new_t) set_new_child_flag(old_t); }

    // cache the result of shared non atomic expressions.
    bool cache_results() const { return m_cfg.cache_results(); }
    // cache all results share and non shared expressions non atomic expressions.
    bool cache_all_results() const { return m_cfg.cache_all_results(); }
    // flat non shared AC terms
    bool flat_assoc(func_decl * f) const { return m_cfg.flat_assoc(f); }
    // rewrite patterns
    bool rewrite_patterns() const { return m_cfg.rewrite_patterns(); }
   
    // check maximum number of scopes
    void check_max_scopes() const { 
        if (m_cfg.max_scopes_exceeded(this->m_scopes.size()))
            throw rewriter_exception(Z3_MAX_SCOPES_MSG);
    }
    // check maximum size of the frame stack
    void check_max_frames() const { 
        if (m_cfg.max_frames_exceeded(frame_stack().size()))
            throw rewriter_exception(Z3_MAX_FRAMES_MSG);
    }
    // check maximum number of rewriting steps
    void check_max_steps() const { 
        if (m_cfg.max_steps_exceeded(m_num_steps))
            throw rewriter_exception(Z3_MAX_STEPS_MSG);
    }

    // If pre_visit returns false, then t children are not visited/rewritten.
    // This should be used with care, since it may produce incorrect results
    // when the rewriter is used to apply variable substitution.
    bool pre_visit(expr * t) {
        return m_cfg.pre_visit(t);
    }

    // Return true if the rewriting result of the given expression must be cached.
    bool must_cache(expr * t) const {
        if (cache_all_results())
            return t != this->m_root && ((is_app(t) && to_app(t)->get_num_args() > 0) || is_quantifier(t));
        if (cache_results())
            return rewriter_core::must_cache(t); 
        return false;
    }

    bool get_macro(func_decl * f, expr * & def, proof * & def_pr) {
        quantifier* q = nullptr;
        return m_cfg.get_macro(f, def, q, def_pr); 
    }

    void push_frame(expr * t, bool mcache, unsigned max_depth) {
        check_max_frames();
        push_frame_core(t, mcache, PROCESS_CHILDREN, max_depth);
    }

    void begin_scope() {
        check_max_scopes();
        rewriter_core::begin_scope();
    }
    
    template<bool ProofGen>
    void process_var(var * v);

    template<bool ProofGen>
    bool process_const(app * t);

    template<bool ProofGen>
    bool visit(expr * t, unsigned max_depth);

    template<bool ProofGen>
    void cache_result(expr * t, expr * new_t, proof * pr, bool c) {
        if (c) {
            if (!ProofGen)
                rewriter_core::cache_result(t, new_t);
            else
                rewriter_core::cache_result(t, new_t, pr);
        }
    }

    template<bool ProofGen>
    void process_app(app * t, frame & fr);

    bool constant_fold(app* t, frame& fr);

    template<bool ProofGen>
    void process_quantifier(quantifier * q, frame & fr);

    bool first_visit(frame & fr) const {
        return fr.m_state == PROCESS_CHILDREN && fr.m_i == 0;
    }

    bool not_rewriting() const;

    template<bool ProofGen>
    void main_loop(expr * t, expr_ref & result, proof_ref & result_pr);

    template<bool ProofGen>
    void resume_core(expr_ref & result, proof_ref & result_pr);

public:
    rewriter_tpl(ast_manager & m, bool proof_gen, Config & cfg);

    ast_manager & m() const { return this->m_manager; }
    Config & cfg() { return m_cfg; }
    Config const & cfg() const { return m_cfg; }
    
    void reset();
    void cleanup();
    
    void set_bindings(unsigned num_bindings, expr * const * bindings);
    void set_inv_bindings(unsigned num_bindings, expr * const * bindings);
    void update_binding_at(unsigned i, expr* binding);
    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); }
    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);
    void resume(expr_ref & result) { resume(result, m_pr); }

    // Return the number of steps performed by the rewriter in the last call to operator().
    unsigned get_num_steps() const { return m_num_steps; }
};

struct default_rewriter_cfg {
    bool cache_all_results() const { return false; }
    bool cache_results() const { return true; }
    bool flat_assoc(func_decl * f) const { return false; }
    bool rewrite_patterns() const { return true; }
    bool max_scopes_exceeded(unsigned num_scopes) const { return false; }
    bool max_frames_exceeded(unsigned num_frames) const { return false; }
    bool max_steps_exceeded(unsigned num_steps) const { return false; }
    bool pre_visit(expr * t) { return true; }
    br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { return BR_FAILED; }
    bool reduce_quantifier(quantifier * old_q, 
                           expr * new_body, 
                           expr * const * new_patterns, 
                           expr * const * new_no_patterns,
                           expr_ref & result,
                           proof_ref & result_pr) {
        return false;
    }
    bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr) { return false; }
    bool get_macro(func_decl * d, expr * & def, quantifier * & q, proof * & def_pr) { return false; }
    bool reduce_macro() { return false; }
    bool get_subst(expr * s, expr * & t, proof * & t_pr) { return false; }
    void reset() {}
    void cleanup() {}
};

struct beta_reducer_cfg : public default_rewriter_cfg {
    bool pre_visit(expr * t) { return !is_ground(t); }
};

class beta_reducer : public rewriter_tpl<beta_reducer_cfg>  {
    beta_reducer_cfg m_cfg;
public:
    beta_reducer(ast_manager & m):
        rewriter_tpl<beta_reducer_cfg>(m, false, m_cfg) {}
};