z3-src 415.4.3

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
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
/*++
Copyright (c) 2020 Microsoft Corporation

Module Name:

    arith_solver.h

Abstract:

    Theory plugin for arithmetic

Author:

    Nikolaj Bjorner (nbjorner) 2020-09-08

--*/
#pragma once

#include "util/obj_pair_set.h"
#include "ast/ast_trail.h"
#include "ast/arith_decl_plugin.h"

#include "math/lp/indexed_value.h"
#include "math/lp/lar_solver.h"
#include "math/lp/nla_solver.h"
#include "math/lp/lp_types.h"
#include "math/lp/lp_api.h"
#include "math/polynomial/algebraic_numbers.h"
#include "math/polynomial/polynomial.h"
#include "sat/smt/sat_th.h"

namespace euf {
    class solver;
}

namespace arith {

    typedef ptr_vector<lp_api::bound<sat::literal>> lp_bounds;
    typedef lp::lpvar lpvar;
    typedef euf::theory_var theory_var;
    typedef euf::theory_id theory_id;
    typedef euf::enode enode;
    typedef euf::enode_pair enode_pair;
    typedef sat::literal literal;
    typedef sat::bool_var bool_var;
    typedef sat::literal_vector literal_vector;
    typedef lp_api::bound<sat::literal> api_bound;

    enum class hint_type {
        farkas_h,
        bound_h,
        cut_h,
        implied_eq_h,
        nla_h
    };

    struct arith_proof_hint : public euf::th_proof_hint {
        hint_type m_ty;
        unsigned  m_lit_head, m_lit_tail, m_eq_head, m_eq_tail;
        arith_proof_hint(hint_type t, unsigned lh, unsigned lt, unsigned eh, unsigned et):
            m_ty(t), m_lit_head(lh), m_lit_tail(lt), m_eq_head(eh), m_eq_tail(et) {}
        expr* get_hint(euf::solver& s) const override;
    };

    class arith_proof_hint_builder {
        vector<std::pair<rational, literal>>   m_literals;
        svector<std::tuple<euf::enode*,euf::enode*,bool>> m_eqs;
        hint_type                              m_ty;
        unsigned                               m_lit_head = 0, m_lit_tail = 0, m_eq_head = 0, m_eq_tail = 0;
        void reset() { m_lit_head = m_lit_tail; m_eq_head = m_eq_tail; }
        void add(euf::enode* a, euf::enode* b, bool is_eq) {
            if (m_eq_tail < m_eqs.size())
                m_eqs[m_eq_tail] = { a, b, is_eq };
            else
                m_eqs.push_back({a, b, is_eq });
            m_eq_tail++; 
        }
    public:
        void set_type(euf::solver& ctx, hint_type ty);
        void add_eq(euf::enode* a, euf::enode* b) { add(a, b, true); }
        void add_diseq(euf::enode* a, euf::enode* b) { add(a, b, false); }
        void add_lit(rational const& coeff, literal lit) { 
            if (m_lit_tail < m_literals.size())
                m_literals[m_lit_tail] = {coeff, lit};
            else
                m_literals.push_back({coeff, lit}); 
            m_lit_tail++;
        }
        std::pair<rational, literal> const& lit(unsigned i) const { return m_literals[i]; }
        std::tuple<enode*, enode*, bool> const& eq(unsigned i) const { return m_eqs[i]; }
        arith_proof_hint* mk(euf::solver& s);
    };

    class solver : public euf::th_euf_solver {

        friend struct arith_proof_hint;
        friend class sls;

        struct scope {
            unsigned m_bounds_lim;
            unsigned m_asserted_qhead;
            unsigned m_asserted_lim;
        };

        class resource_limit : public lp::lp_resource_limit {
            solver& m_imp;
        public:
            resource_limit(solver& i) : m_imp(i) { }
            bool get_cancel_flag() override { return !m_imp.m.inc(); }
        };

        struct var_value_eq {
            solver& m_th;
            var_value_eq(solver& th) :m_th(th) {}
            bool operator()(theory_var v1, theory_var v2) const {
                if (m_th.is_int(v1) != m_th.is_int(v2)) {
                    return false;
                }
                return m_th.is_eq(v1, v2);
            }
        };

        struct var_value_hash {
            solver& m_th;
            var_value_hash(solver& th) :m_th(th) {}
            unsigned operator()(theory_var v) const {
                if (m_th.use_nra_model()) {
                    return m_th.is_int(v);
                }
                else {
                    return (unsigned)std::hash<lp::impq>()(m_th.get_ivalue(v));
                }
            }
        };
        int_hashtable<var_value_hash, var_value_eq>   m_model_eqs;

        bool                m_new_eq = false;


        // temporary values kept during internalization
        struct internalize_state {
            expr_ref_vector     m_terms;
            vector<rational>    m_coeffs;
            svector<theory_var> m_vars;
            ptr_vector<expr>    m_to_ensure_enode, m_to_ensure_var;
            internalize_state(ast_manager& m) : m_terms(m) {}
            void reset() {
                m_terms.reset();
                m_coeffs.reset();
                m_vars.reset();
                m_to_ensure_enode.reset();
                m_to_ensure_var.reset();
            }
        };
        scoped_ptr_vector<internalize_state> m_internalize_states;
        unsigned                      m_internalize_head = 0;

        class scoped_internalize_state {
            solver& m_imp;
            internalize_state& m_st;

            internalize_state& push_internalize(solver& i) {
                if (i.m_internalize_head == i.m_internalize_states.size()) {
                    i.m_internalize_states.push_back(alloc(internalize_state, i.m));
                }
                internalize_state& st = *i.m_internalize_states[i.m_internalize_head++];
                st.reset();
                return st;
            }
        public:
            scoped_internalize_state(solver& i) : m_imp(i), m_st(push_internalize(i)) {}
            ~scoped_internalize_state() { --m_imp.m_internalize_head; }
            expr_ref_vector& terms() { return m_st.m_terms; }
            vector<rational>& coeffs() { return m_st.m_coeffs; }
            svector<theory_var>& vars() { return m_st.m_vars; }
            ptr_vector<expr>& to_ensure_enode() { return m_st.m_to_ensure_enode; }
            ptr_vector<expr>& to_ensure_var() { return m_st.m_to_ensure_var; }
            void push(expr* e, rational c) { m_st.m_terms.push_back(e); m_st.m_coeffs.push_back(c); }
            void set_back(unsigned i) {
                if (terms().size() == i + 1) return;
                terms()[i] = terms().back();
                coeffs()[i] = coeffs().back();
                terms().pop_back();
                coeffs().pop_back();
            }
        };

        typedef vector<std::pair<rational, lpvar>> var_coeffs;
        vector<rational>         m_columns;
        var_coeffs               m_left_side;              // constraint left side

        lpvar m_one_var   = UINT_MAX;
        lpvar m_zero_var  = UINT_MAX;
        lpvar m_rone_var  = UINT_MAX;
        lpvar m_rzero_var = UINT_MAX;

        enum constraint_source {
            inequality_source,
            equality_source,
            definition_source,
            null_source
        };
        svector<constraint_source>                    m_constraint_sources;
        svector<literal>                              m_inequalities;    // asserted rows corresponding to inequality literals.
        svector<euf::enode_pair>                      m_equalities;      // asserted rows corresponding to equalities.
        svector<theory_var>                           m_definitions;     // asserted rows corresponding to definitions
        svector<std::pair<euf::th_eq, bool>>          m_delayed_eqs;

        literal_vector  m_asserted;
        expr* m_not_handled = nullptr;
        ptr_vector<app>        m_underspecified;
        ptr_vector<expr>       m_idiv_terms;
        ptr_vector<app>        m_bv_terms;
        vector<ptr_vector<api_bound> > m_use_list;        // bounds where variables are used.

        // attributes for incremental version:
        u_map<api_bound*>      m_bool_var2bound;
        vector<lp_bounds>      m_bounds;
        unsigned_vector        m_unassigned_bounds;
        unsigned_vector        m_bounds_trail;
        unsigned               m_asserted_qhead = 0;

        svector<std::pair<theory_var, theory_var> >       m_assume_eq_candidates;
        unsigned                                          m_assume_eq_head = 0;
        indexed_uint_set                                         m_tmp_var_set;

        unsigned                                          m_num_conflicts = 0;
        lp_api::stats                                     m_stats;
        svector<scope>                                    m_scopes;

        // non-linear arithmetic
        scoped_ptr<nla::solver>  m_nla;
        bool m_use_nra_model = false;

        // integer arithmetic
        scoped_ptr<lp::int_solver>   m_lia;


        scoped_ptr<lp::lar_solver>   m_solver;
        resource_limit               m_resource_limit;
        lp_bounds                    m_new_bounds;
        symbol                       m_farkas;
        std_vector<lp::implied_bound> m_implied_bounds;
        lp::lp_bound_propagator<solver> m_bp;
        mutable vector<std::pair<lp::lpvar, rational>> m_todo_terms;

        // lemmas
        lp::explanation     m_explanation;
        literal_vector      m_core, m_core2;
        vector<rational>    m_coeffs;
        svector<enode_pair> m_eqs;
        vector<parameter>   m_params;
        nla::lemma          m_lemma;
        arith_util          a;

        bool is_int(theory_var v) const { return is_int(var2enode(v)); }
        bool is_int(euf::enode* n) const { return a.is_int(n->get_expr()); }
        bool is_real(theory_var v) const { return is_real(var2enode(v)); }
        bool is_real(euf::enode* n) const { return a.is_real(n->get_expr()); }
        bool is_bool(theory_var v) const { return is_bool(var2enode(v)); }
        bool is_bool(euf::enode* n) const { return m.is_bool(n->get_expr()); }
        

        // internalize
        bool m_internalize_initialized { false };
        void init_internalize();
        lpvar add_const(int c, lpvar& var, bool is_int);
        lpvar get_one(bool is_int);
        lpvar get_zero(bool is_int);
        void ensure_nla();
        void found_unsupported(expr* n);
        void found_underspecified(expr* n);

        void linearize_term(expr* term, scoped_internalize_state& st);
        void linearize_ineq(expr* lhs, expr* rhs, scoped_internalize_state& st);
        void linearize(scoped_internalize_state& st);

        void add_eq_constraint(lp::constraint_index index, enode* n1, enode* n2);
        void add_ineq_constraint(lp::constraint_index index, literal lit);
        void add_def_constraint(lp::constraint_index index);
        void add_def_constraint(lp::constraint_index index, theory_var v);
        void add_def_constraint_and_equality(lpvar vi, lp::lconstraint_kind kind, const rational& bound);
        void internalize_args(app* t, bool force = false);
        void ensure_arg_vars(app* t);
        theory_var internalize_power(app* t, app* n, unsigned p);
        theory_var internalize_mul(app* t);
        theory_var internalize_numeral(app* t, rational const& v);
        theory_var internalize_def(expr* term);
        theory_var internalize_def(expr* term, scoped_internalize_state& st);
        theory_var internalize_linearized_def(expr* term, scoped_internalize_state& st);
        void init_left_side(scoped_internalize_state& st);
        bool internalize_term(expr* term);
        bool internalize_atom(expr* atom);        
        bool is_unit_var(scoped_internalize_state& st);
        bool is_one(scoped_internalize_state& st);
        bool is_zero(scoped_internalize_state& st);
        expr* mk_sub(expr* a, expr* b);
        enode* mk_enode(expr* e);

        lpvar register_theory_var_in_lar_solver(theory_var v);
        theory_var mk_evar(expr* e);
        bool has_var(expr* e);
        bool reflect(expr* n) const;

        lpvar get_lpvar(theory_var v) const;
        lp::lpvar get_column(theory_var v) const;

        // axioms
        void mk_div_axiom(expr* p, expr* q);
        void mk_to_int_axiom(app* n);
        void mk_abs_axiom(app* n);
        void mk_is_int_axiom(expr* n);
        void mk_idiv_mod_axioms(expr* p, expr* q);
        void mk_rem_axiom(expr* dividend, expr* divisor);
        void mk_power_axiom(expr* t, expr* n, expr* p);
        void mk_bound_axioms(api_bound& b);
        void mk_bound_axiom(api_bound& b1, api_bound& b2);
        void mk_power0_axioms(app* t, app* n);
        void mk_bv_axiom(app* n);
        void flush_bound_axioms();
        void add_farkas_clause(sat::literal l1, sat::literal l2);

        // bounds
        struct compare_bounds {
            bool operator()(api_bound* a1, api_bound* a2) const { return a1->get_value() < a2->get_value(); }
        };

        typedef lp_bounds::iterator iterator;

        lp_bounds::iterator first(
            lp_api::bound_kind kind,
            iterator it,
            iterator end);

        lp_bounds::iterator next_inf(
            api_bound* a1,
            lp_api::bound_kind kind,
            iterator it,
            iterator end,
            bool& found_compatible);

        lp_bounds::iterator next_sup(
            api_bound* a1,
            lp_api::bound_kind kind,
            iterator it,
            iterator end,
            bool& found_compatible);

        void propagate_eqs(lp::lpvar t, lp::constraint_index ci, lp::lconstraint_kind k, api_bound& b, rational const& value);
        void propagate_basic_bounds(unsigned qhead);
        void propagate_bounds_with_lp_solver();
        void propagate_bound(literal lit, api_bound& b);
        void propagate_lp_solver_bound(const lp::implied_bound& be);
        void refine_bound(theory_var v, const lp::implied_bound& be);
        literal is_bound_implied(lp::lconstraint_kind k, rational const& value, api_bound const& b) const;
        void assert_bound(bool is_true, api_bound& b);
        void mk_eq_axiom(bool is_eq, euf::th_eq const& eq);
        void mk_diseq_axiom(theory_var v1, theory_var v2);
        void assert_idiv_mod_axioms(theory_var u, theory_var v, theory_var w, rational const& r);
        api_bound* mk_var_bound(sat::literal lit, theory_var v, lp_api::bound_kind bk, rational const& bound);
        lp::lconstraint_kind bound2constraint_kind(bool is_int, lp_api::bound_kind bk, bool is_true);
        void fixed_var_eh(theory_var v1, u_dependency* dep, rational const& bound);
        bool set_upper_bound(lp::lpvar t, lp::constraint_index ci, rational const& v) { return set_bound(t, ci, v, false); }
        bool set_lower_bound(lp::lpvar t, lp::constraint_index ci, rational const& v) { return set_bound(t, ci, v, true); }
        bool set_bound(lp::lpvar tv, lp::constraint_index ci, rational const& v, bool is_lower);

        typedef std::pair<lp::constraint_index, rational> constraint_bound;
        vector<constraint_bound>        m_lower_terms;
        vector<constraint_bound>        m_upper_terms;
        vector<constraint_bound>        m_history;

        bool can_get_value(theory_var v) const {
            return is_registered_var(v) && m_model_is_initialized;
        }

        vector<rational>     m_fixed_values;
        map<rational, theory_var, rational::hash_proc, rational::eq_proc> m_value2var;
        struct undo_value;
        void register_fixed_var(theory_var v, rational const& value);

        // solving
        void report_equality_of_fixed_vars(unsigned vi1, unsigned vi2);
        void reserve_bounds(theory_var v);

        void updt_unassigned_bounds(theory_var v, int inc);

        void pop_core(unsigned n) override;
        void push_core() override;
        void del_bounds(unsigned old_size);

        bool all_zeros(vector<rational> const& v) const;

        bound_prop_mode propagation_mode() const;

        bool is_registered_var(theory_var v) const;
        void ensure_column(theory_var v);
        lp::impq get_ivalue(theory_var v) const;
        rational get_value(theory_var v) const;

        void random_update();
        bool assume_eqs();
        bool delayed_assume_eqs();
        bool is_eq(theory_var v1, theory_var v2);
        bool use_nra_model();
        bool include_func_interp(enode* n) const;

        lbool make_feasible();
        bool  check_delayed_eqs();
        lbool check_lia();
        lbool check_nla(unsigned level);
        bool check_bv_terms();
        bool check_bv_term(app* n);
        void add_lemmas();
        void propagate_nla();
        void add_equality(lpvar v, rational const& k, lp::explanation const& exp);
        bool is_infeasible() const;

        nlsat::anum const& nl_value(theory_var v, scoped_anum& r) const;


        bool has_bound(lpvar vi, u_dependency*& ci, rational const& bound, bool is_lower);
        bool has_lower_bound(lpvar vi, u_dependency*& ci, rational const& bound);
        bool has_upper_bound(lpvar vi, u_dependency*& ci, rational const& bound);

        /*
         * Facility to put a small box around integer variables used in branch and bounds.
         */

        unsigned                  m_bounded_range_idx;  // current size of bounded range.
        literal                   m_bounded_range_lit;  // current bounded range literal
        expr_ref_vector           m_bound_terms; // predicates used for bounds
        expr_ref                  m_bound_predicate;

        bool                      m_model_is_initialized = false;

        unsigned small_lemma_size() const { return get_config().m_arith_small_lemma_size; }
        bool propagate_eqs() const { return get_config().m_arith_propagate_eqs && m_num_conflicts < get_config().m_arith_propagation_threshold; }
        bool should_propagate() const { return bound_prop_mode::BP_NONE != propagation_mode(); }
        bool should_refine_bounds() const { return bound_prop_mode::BP_REFINE == propagation_mode() && s().at_search_lvl(); }

        unsigned init_range() const { return 5; }
        unsigned max_range() const { return 20; }

        void reset_evidence();
        bool check_idiv_bounds();
        bool is_bounded(expr* n);

        app_ref mk_bound(lp::lar_term const& term, rational const& k, bool lower_bound);
        app_ref mk_bound(lp::lar_term const& term, rational const& k, bool lower_bound, rational& offset, expr_ref& t);
        literal mk_eq(lp::lar_term const& term, rational const& offset);

        rational gcd_reduce(u_map<rational>& coeffs);
        app_ref mk_term(lp::lar_term const& term, bool is_int);
        app_ref coeffs2app(u_map<rational> const& coeffs, rational const& offset, bool is_int);
        void term2coeffs(lp::lar_term const& term, u_map<rational>& coeffs, rational const& coeff);
        void term2coeffs(lp::lar_term const& term, u_map<rational>& coeffs);

        void get_infeasibility_explanation_and_set_conflict();
        void set_conflict(hint_type ty);
        void set_conflict_or_lemma(hint_type ty, literal_vector const& core, bool is_conflict);
        void set_evidence(lp::constraint_index idx);
        void assign(literal lit, literal_vector const& core, svector<enode_pair> const& eqs, euf::th_proof_hint const* pma);

        sat::literal mk_ineq_literal(nla::ineq const& ineq);
        void false_case_of_check_nla(const nla::lemma& l);        
        void dbg_finalize_model(model& mdl);

        arith_proof_hint_builder m_arith_hint;

        arith_proof_hint const* explain(hint_type ty, sat::literal lit = sat::null_literal);
        arith_proof_hint const* explain_implied_eq(lp::explanation const& e, euf::enode* a, euf::enode* b);
        arith_proof_hint const* explain_trichotomy(sat::literal le, sat::literal ge, sat::literal eq);
        arith_proof_hint const* explain_conflict(hint_type ty, sat::literal_vector const& core, euf::enode_pair_vector const& eqs);
        void explain_assumptions(lp::explanation const& e);

        bool validate_conflict();

        

    public:
        solver(euf::solver& ctx, theory_id id);
        ~solver() override;
        bool is_external(bool_var v) override { return false; }
        void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) override;
        void asserted(literal l) override;
        sat::check_result check() override;
        void simplify() override {}
        void init_search() override {}

        std::ostream& display(std::ostream& out) const override;
        std::ostream& display_justification(std::ostream& out, sat::ext_justification_idx idx) const override;
        std::ostream& display_constraint(std::ostream& out, sat::ext_constraint_idx idx) const override;
        void collect_statistics(statistics& st) const override;
        euf::th_solver* clone(euf::solver& ctx) override;
        bool use_diseqs() const override { return true; }
        void new_eq_eh(euf::th_eq const& eq) override;
        void new_diseq_eh(euf::th_eq const& de) override;
        bool unit_propagate() override;
        void init_model() override;
        void finalize_model(model& mdl) override { DEBUG_CODE(dbg_finalize_model(mdl);); }
        void add_value(euf::enode* n, model& mdl, expr_ref_vector& values) override;
        bool add_dep(euf::enode* n, top_sort<euf::enode>& dep) override;
        sat::literal internalize(expr* e, bool sign, bool root) override;
        void internalize(expr* e) override;
        void eq_internalized(euf::enode* n) override;
        void apply_sort_cnstr(euf::enode* n, sort* s) override {}
        void initialize_value(expr* var, expr* value) override;
        bool is_shared(theory_var v) const override;
        lbool get_phase(bool_var v) override;
        bool include_func_interp(func_decl* f) const override;
        bool enable_ackerman_axioms(euf::enode* n) const override { return !a.is_add(n->get_expr()); }
        bool has_unhandled() const override { return m_not_handled != nullptr; }

        // bounds and equality propagation callbacks
        lp::lar_solver& lp() { return *m_solver; }
        lp::lar_solver const& lp() const { return *m_solver; }
        bool is_equal(theory_var x, theory_var y) const;
        bool add_eq(lpvar u, lpvar v, lp::explanation const& e, bool is_fixed);
        void consume(rational const& v, lp::constraint_index j);
        bool bound_is_interesting(unsigned vi, lp::lconstraint_kind kind, const rational& bval) const;

        bool get_value(euf::enode* n, expr_ref& val);
    };



}