z3-src 503.3.0

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
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
/*++
Copyright (c) 2017 Microsoft Corporation

Module Name:

    sat_lookahead.h

Abstract:
   
    Lookahead SAT solver in the style of March.
    Thanks also to the presentation in sat11.w.    

Author:

    Nikolaj Bjorner (nbjorner) 2017-2-11

Notes:

--*/
#pragma once


#include "util/small_object_allocator.h"
#include "sat/sat_elim_eqs.h"

namespace pb {
    class solver;
}

namespace sat {

    struct pp_prefix {
        uint64_t m_prefix;
        unsigned m_depth;
        pp_prefix(uint64_t p, unsigned d) : m_prefix(p), m_depth(d) {}
    };
    
    inline std::ostream& operator<<(std::ostream& out, pp_prefix const& p) {
        unsigned d = std::min(63u, p.m_depth);
        for (unsigned i = 0; i <= d; ++i) {
            if (0 != (p.m_prefix & (1ull << i))) out << "1"; else out << "0";
        }
        if (d < p.m_depth) {
            out << " d:" << p.m_depth;
        }
        return out;
    }

    enum class lookahead_mode {
        searching,         // normal search
        lookahead1,        // lookahead mode
        lookahead2         // double lookahead
    };

    inline std::ostream& operator<<(std::ostream& out, lookahead_mode m) {
        switch (m) {
        case lookahead_mode::searching:  return out << "searching";
        case lookahead_mode::lookahead1: return out << "lookahead1";
        case lookahead_mode::lookahead2: return out << "lookahead2";
        }
        return out;
    }

    const double dbl_max = 100000000.0;

    class lookahead {
        solver&    m_s;
        unsigned   m_num_vars;
        reslimit   m_rlimit;

        friend class ccc;
        friend class pb::solver;

        struct config {
            double   m_dl_success;
            double   m_alpha;
            double   m_max_score;
            unsigned m_max_hlevel; 
            unsigned m_min_cutoff;
            bool     m_preselect;
            unsigned m_level_cand;
            double   m_delta_rho;
            unsigned m_dl_max_iterations;
            unsigned m_tc1_limit;
            reward_t m_reward_type;
            cutoff_t m_cube_cutoff;
            unsigned m_cube_depth;
            double   m_cube_fraction;
            double   m_cube_freevars;
            double   m_cube_psat_var_exp;
            double   m_cube_psat_clause_base;
            double   m_cube_psat_trigger;

            config() {
                memset(this, 0, sizeof(*this));
                m_dl_success = 0.8;
                m_alpha = 3.5;
                m_max_score = 20.0;
                m_max_hlevel = 50;
                m_min_cutoff = 30;
                m_preselect = false;
                m_level_cand = 600;
                m_delta_rho = (double)0.7;
                m_dl_max_iterations = 2;
                m_tc1_limit = 10000000;
                m_reward_type = reward_t::ternary_reward;
                m_cube_cutoff = cutoff_t::adaptive_freevars_cutoff;
                m_cube_depth = 10;
                m_cube_fraction = 0.4;
                m_cube_freevars = 0.8;
                m_cube_psat_var_exp = 1.0;
                m_cube_psat_clause_base = 2.0;
                m_cube_psat_trigger = 5.0;
            }
        };

        struct prefix {
            unsigned m_prefix = 0;
            unsigned m_length = 0;
        };

        struct lit_info {
            double     m_lookahead_reward = 0;
            unsigned  m_double_lookahead = 0;
        };

        struct stats {
            unsigned m_propagations;
            unsigned m_bca;
            unsigned m_add_binary;
            unsigned m_del_binary;
            unsigned m_decisions;
            unsigned m_windfall_binaries;
            unsigned m_double_lookahead_propagations;
            unsigned m_double_lookahead_rounds;
            stats() { reset(); }
            void reset() { memset(this, 0, sizeof(*this)); }
        };

        struct binary {
            binary(literal u, literal v): m_u(u), m_v(v) {}
            literal m_u, m_v;
        };

        class nary {            
            unsigned m_size;         // number of non-false literals
            size_t   m_obj_size;     // object size (counting all literals)
            literal  m_head;         // head literal
            literal  m_literals[0];  // list of literals, put any true literal in head.
            size_t num_lits() const {
                return (m_obj_size - sizeof(nary)) / sizeof(literal);
            }
        public:
            static size_t get_obj_size(unsigned sz) { return sizeof(nary) + sz * sizeof(literal); }
            size_t obj_size() const { return m_obj_size; }
            nary(unsigned sz, literal const* lits):
                m_size(sz),
                m_obj_size(get_obj_size(sz)) {
                for (unsigned i = 0; i < sz; ++i) m_literals[i] = lits[i];
                m_head = lits[0];
            }
            unsigned size() const { return m_size; }
            unsigned dec_size() { SASSERT(m_size > 0); return --m_size; }
            void inc_size() { SASSERT(is_reduced()); ++m_size; }
            literal get_head() const { return m_head; }
            void set_head(literal l) { m_head = l; }
            bool is_reduced() const { return m_size < num_lits(); }

            literal operator[](unsigned i) { SASSERT(i < num_lits()); return m_literals[i]; }
            literal const* begin() const { return m_literals; }
            literal const* end() const { return m_literals + num_lits(); }
            // swap the true literal to the head.
            // void swap(unsigned i, unsigned j) { SASSERT(i < num_lits() && j < num_lits()); std::swap(m_literals[i], m_literals[j]); }
        };

        struct cube_state {
            bool           m_first;
            bool_vector  m_is_decision;
            literal_vector m_cube;
            double         m_freevars_threshold;
            double         m_psat_threshold;
            unsigned       m_conflicts;
            unsigned       m_cutoffs;
            unsigned       m_backtracks;
            cube_state() { reset(); }
            void reset() { 
                m_first = true;
                m_is_decision.reset(); 
                m_cube.reset(); 
                m_freevars_threshold = 0;
                m_psat_threshold = dbl_max;
                reset_stats();
            }
            void reset_stats() { m_conflicts = 0; m_cutoffs = 0; m_backtracks = 0;}
            void inc_conflict() { ++m_conflicts; }
            void inc_cutoff() { ++m_cutoffs; }
        };

        config                 m_config;
        double                 m_delta_trigger;
        double                 m_delta_decrease;
        double                 m_delta_fraction;

        literal_vector         m_assumptions;

        literal_vector         m_trail;         // trail of units
        unsigned_vector        m_trail_lim;
        vector<literal_vector> m_binary;        // literal: binary clauses
        unsigned_vector        m_binary_trail;  // trail of added binary clauses
        unsigned_vector        m_binary_trail_lim; 

        // specialized clause managemet uses ternary clauses and dedicated clause data-structure.
        // this replaces m_clauses below
        vector<svector<binary>> m_ternary;        // lit |-> vector of ternary clauses
        unsigned_vector         m_ternary_count;  // lit |-> current number of active ternary clauses for lit

        small_object_allocator    m_allocator;
        vector<ptr_vector<nary>>  m_nary;        // lit |-> vector of nary clauses
        ptr_vector<nary>          m_nary_clauses; // vector of all nary clauses
        unsigned_vector           m_nary_count;     // lit |-> number of valid clause_id in m_nary[lit]

        unsigned               m_num_tc1;
        unsigned_vector        m_num_tc1_lim;
        unsigned               m_qhead;         // propagation queue head
        unsigned_vector        m_qhead_lim;
        bool                   m_inconsistent;
        unsigned_vector        m_bstamp;        // literal: timestamp for binary implication
        vector<svector<double> >  m_H;           // literal: fitness score
        svector<double>*        m_heur;          // current fitness 
        svector<double>         m_rating;        // var:     pre-selection rating
        unsigned               m_bstamp_id;     // unique id for binary implication.
        unsigned               m_istamp_id;     // unique id for managing double lookaheads
        unsigned_vector        m_stamp;         // var: timestamp with truth value        
        unsigned               m_level;         // current level, = 2 * m_trail_lim.size() 
        const unsigned         c_fixed_truth = UINT_MAX - 1;
        vector<watch_list>     m_watches;       // literal: watch structure
        svector<lit_info>      m_lits;          // literal: attributes.
        double                 m_lookahead_reward; // metric associated with current lookahead1 literal.
        literal_vector         m_wstack;        // windofall stack that is populated in lookahead1 mode
        unsigned               m_last_prefix_length;
        uint64_t                 m_prefix;        // where we are in search tree
        svector<prefix>        m_vprefix;       // var:     prefix where variable participates in propagation
        unsigned               m_rating_throttle; // throttle to recompute rating
        indexed_uint_set       m_freevars;
        unsigned               m_init_freevars;
        lookahead_mode         m_search_mode;   // mode of search
        stats                  m_stats;
        model                  m_model; 
        cube_state             m_cube_state;
        unsigned               m_max_ops;       // cap number of operations used to compute lookahead reward.
        //scoped_ptr<extension>  m_ext;
 
        // ---------------------------------------
        // truth values


        inline bool is_fixed_at(literal l, unsigned level) const { return m_stamp[l.var()] >= level; }
        inline bool is_fixed(literal l) const { return is_fixed_at(l, m_level); }
        inline bool is_undef(literal l) const { return !is_fixed(l); }
        inline bool is_undef(bool_var v) const { return m_stamp[v] < m_level; }
        inline bool is_false_at(literal l, unsigned level) const {
            return is_fixed_at(l, level) && (bool)((m_stamp[l.var()] & 0x1) ^ l.sign());
        } // even iff l.sign()
        inline bool is_false(literal l)  const { return is_false_at(l, m_level); }
        inline bool is_true_at(literal l, unsigned level) const {
            return is_fixed_at(l, level) && !(bool)((m_stamp[l.var()] & 0x1) ^ l.sign());
        }
        inline bool is_true(literal l) const { return is_true_at(l, m_level); }
        inline void set_true(literal l) { m_stamp[l.var()] = m_level + l.sign(); }
        inline void set_undef(literal l) { m_stamp[l.var()] = 0; }
        inline unsigned get_level(literal l) const { return m_stamp[l.var()] & ~0x1; }
        void set_level(literal d, literal s) { m_stamp[d.var()] = get_level(s) + d.sign(); }
        lbool value(literal l) const { return is_undef(l) ? l_undef : is_true(l) ? l_true : l_false; }
        
        // set the level within a scope of the search.
        class scoped_level {
            lookahead& m_parent;
            unsigned   m_save;
        public:
            scoped_level(lookahead& p, unsigned l): 
                m_parent(p), m_save(p.m_level)  {
                p.m_level = l;
            }
            ~scoped_level() {
                m_parent.m_level = m_save;
            }
        };

        class scoped_ext {
            lookahead& p;
        public:
            scoped_ext(lookahead& p);
            ~scoped_ext();
        };

        class scoped_assumptions {
            lookahead& p;
            literal_vector lits;
        public:
            scoped_assumptions(lookahead& p, literal_vector const& lits);
            ~scoped_assumptions();
        };

        // -------------------------------------
        // prefix updates. I use low order bits.
        
        void flip_prefix();
        void prune_prefix();

        /**
           length < trail_lim.size:
           - mask m_prefix and p wrt length
           - update if different.
         */
        void update_prefix(literal l);

        bool active_prefix(bool_var x);

        // ----------------------------------------

        void add_binary(literal l1, literal l2);
        void del_binary(unsigned idx);
        void validate_binary(literal l1, literal l2);

        // -------------------------------------
        // track consequences of binary clauses
        // see also 72 - 79 in sat11.w

        void inc_bstamp(); 
        void inc_istamp();
        void set_bstamp(literal l) { m_bstamp[l.index()] = m_bstamp_id; }
        void set_bstamps(literal l);
        bool is_stamped(literal l) const { return m_bstamp[l.index()] == m_bstamp_id; }
        bool add_tc1(literal u, literal v);

        /**
           \brief main routine for adding a new binary clause dynamically.
         */
        void try_add_binary(literal u, literal v);

        // -------------------------------------
        // pre-selection
        // see also 91 - 102 sat11.w

        void pre_select();

        struct candidate {
            bool_var m_var;
            double    m_rating;
            candidate(bool_var v, double r): m_var(v), m_rating(r) {}
        };
        svector<candidate> m_candidates;
        tracked_uint_set   m_select_lookahead_vars;

        double get_rating(bool_var v) const { return m_rating[v]; }
        double get_rating(literal l) const { return get_rating(l.var()); }
        bool select(unsigned level);
        void heap_sort();
        void heapify();        
        void sift_down(unsigned j, unsigned sz);
        bool validate_heap_sort();
        double init_candidates(unsigned level, bool newbies);
        std::ostream& display_candidates(std::ostream& out) const;
        bool is_unsat() const;
        bool is_sat() const;
        bool missed_propagation() const;
        bool missed_conflict() const;
        void init_pre_selection(unsigned level);
        void ensure_H(unsigned level);
        void h_scores(svector<double>& h, svector<double>& hp);
        void heule_schur_scores();
        double heule_schur_score(literal l);
        void heule_unit_scores();
        double heule_unit_score(literal l);
        void march_cu_scores();
        double march_cu_score(literal l);
        double l_score(literal l, svector<double> const& h, double factor, double sqfactor, double afactor);

        // ------------------------------------       
        // Implication graph
        // Compute implication ordering and strongly connected components.
        // sat11.w 103 - 114.
        
        struct arcs : public literal_vector {}; 
        // Knuth uses a shared pool of fixed size for arcs.
        // Should it be useful we could use this approach too 
        // by changing the arcs abstraction and associated functions.

        struct dfs_info {
            unsigned m_rank;
            unsigned m_height;
            literal  m_parent;
            arcs     m_next;
            unsigned m_nextp;
            literal  m_link;
            literal  m_min;
            literal  m_vcomp;
            dfs_info() { reset(); }
            void reset() {
                m_rank = 0;
                m_height = 0;
                m_parent = null_literal;
                m_next.reset();
                m_link = null_literal;
                m_min = null_literal;
                m_vcomp = null_literal;
                m_nextp = 0;
            }
        };
        
        literal           m_active; 
        unsigned          m_rank; 
        unsigned          m_rank_max;
        literal           m_settled;
        vector<dfs_info>  m_dfs;
        
        void get_scc();
        void init_scc();
        void init_dfs_info(literal l);
        void init_arcs(literal l);
        void add_arc(literal u, literal v);
        bool has_arc(literal v) const { return m_dfs[v.index()].m_next.size() > m_dfs[v.index()].m_nextp; } 
        arcs get_arcs(literal v) const { return m_dfs[v.index()].m_next; }
        literal pop_arc(literal u) { return m_dfs[u.index()].m_next[m_dfs[u.index()].m_nextp++]; }
        unsigned num_next(literal u) const { return m_dfs[u.index()].m_next.size(); }
        literal get_next(literal u, unsigned i) const { return m_dfs[u.index()].m_next[i]; }
        literal get_min(literal v) const { return m_dfs[v.index()].m_min; }
        unsigned get_rank(literal v) const { return m_dfs[v.index()].m_rank; }
        bool     maxed_rank(literal v) const { return get_rank(v) >= m_rank_max; }
        unsigned get_height(literal v) const { return m_dfs[v.index()].m_height; }
        literal get_parent(literal u) const { return m_dfs[u.index()].m_parent; }
        literal get_link(literal u) const { return m_dfs[u.index()].m_link; }
        literal get_vcomp(literal u) const { return m_dfs[u.index()].m_vcomp; }
        void set_link(literal v, literal u) { m_dfs[v.index()].m_link = u; }
        void set_min(literal v, literal u) { m_dfs[v.index()].m_min = u; }
        void set_rank(literal v, unsigned r) { m_dfs[v.index()].m_rank = r; }
        void set_height(literal v, unsigned h) { m_dfs[v.index()].m_height = h; }
        void set_parent(literal v, literal p) { TRACE(scc, tout << v << " <- " << p << "\n";); m_dfs[v.index()].m_parent = p; }
        void set_vcomp(literal v, literal u) { m_dfs[v.index()].m_vcomp = u; }
        void get_scc(literal v);
        void activate_scc(literal l);
        void found_scc(literal v);
        std::ostream& display_dfs(std::ostream& out) const;
        std::ostream& display_dfs(std::ostream& out, literal l) const;
        std::ostream& display_scc(std::ostream& out) const;
        std::ostream& display_scc(std::ostream& out, literal l) const;


        // ------------------------------------
        // lookahead forest
        // sat11.w 115-121

        literal m_root_child;

        literal get_child(literal u) const;
        void set_child(literal v, literal u);
        void find_heights();
        std::ostream& display_forest(std::ostream& out, literal l);

        struct literal_offset {
            literal  m_lit;
            unsigned m_offset;
            literal_offset(literal l): m_lit(l), m_offset(0) {}
        };
        svector<literal_offset> m_lookahead;
        void set_offset(unsigned idx, unsigned offset) { m_lookahead[idx].m_offset = offset; }
        void set_lookahead(literal l) { m_lookahead.push_back(literal_offset(l)); }
        void construct_lookahead_table();

        // ------------------------------------
        // clause management

        watch_list& get_wlist(literal l) { return m_watches[l.index()]; }
        watch_list const& get_wlist(literal l) const { return m_watches[l.index()]; }

        // new clause management:
        void add_ternary(literal u, literal v, literal w);
        void propagate_ternary(literal l);
        lbool propagate_ternary(literal l1, literal l2);
        void remove_ternary(literal l, literal u, literal v);
        void restore_ternary(literal l);

        void propagate_external(literal l);
        void add_clause(clause const& c);
        void propagate_clauses_searching(literal l);
        void propagate_clauses_lookahead(literal l);
        void restore_clauses(literal l);
        void remove_clause(literal l, nary& n);
        void remove_clause_at(literal l, nary& n);
        // ------------------------------------
        // initialization
        
        void init_var(bool_var v);
        void init(bool learned);
        void copy_clauses(clause_vector const& clauses, bool learned);
        nary * copy_clause(clause const& c);

        // ------------------------------------
        // search
        
        void push(literal lit, unsigned level);
        void pop();
        bool push_lookahead2(literal lit, unsigned level);
        unsigned push_lookahead1(literal lit, unsigned level);
        void pop_lookahead1(literal lit, unsigned num_units);
        void lookahead_backtrack();
        double mix_diff(double l, double r) const;
        clause const& get_clause(watch_list::iterator it) const;
        bool is_nary_propagation(clause const& c, literal l) const;
        void propagate_clauses(literal l);
        void propagate_binary(literal l);
        void propagate();
        literal choose();
        literal choose_base();
        void compute_lookahead_reward();
        literal select_literal();
        void update_binary_clause_reward(literal l1, literal l2);
        void update_nary_clause_reward(clause const& c);
 
        void set_lookahead_reward(literal l, double f) { m_lits[l.index()].m_lookahead_reward = f; }
        void inc_lookahead_reward(literal l, double f) { m_lits[l.index()].m_lookahead_reward += f; }
        double get_lookahead_reward(literal l) const { return m_lits[l.index()].m_lookahead_reward; }
            
        void reset_lookahead_reward(literal l);
        void update_lookahead_reward(literal l, unsigned level);
        bool dl_enabled(literal l) const { return m_lits[l.index()].m_double_lookahead != m_istamp_id; }
        void dl_disable(literal l) { m_lits[l.index()].m_double_lookahead = m_istamp_id; }
        bool dl_no_overflow(unsigned base) const { return base + static_cast < uint64_t>(2 * m_lookahead.size()) * static_cast <uint64_t>(m_config.m_dl_max_iterations + 1) < c_fixed_truth; }

        unsigned do_double(literal l, unsigned& base);
        unsigned double_look(literal l, unsigned& base);
        void set_conflict() { TRACE(sat, tout << "conflict\n";); m_inconsistent = true; }
        bool inconsistent() const { return m_inconsistent; }

        unsigned scope_lvl() const { return m_trail_lim.size(); }

        bool in_reduced_clause(literal l);
        bool in_reduced_clause(bool_var v);
        void validate_assign(literal l);
        void assign(literal l);
        void propagated(literal l);
        bool backtrack(literal_vector& trail);
        bool backtrack(literal_vector& trail, bool_vector & is_decision);
        lbool search();
        void init_model();
        std::ostream& display_binary(std::ostream& out) const;
        std::ostream& display_clauses(std::ostream& out) const;
        std::ostream& display_values(std::ostream& out) const;
        std::ostream& display_lookahead(std::ostream& out) const;
        std::ostream& display_cube(std::ostream& out, literal_vector const& cube) const;
        void display_search_string();

        void init_search();
        void checkpoint();

        void init_config();

        void normalize_parents();

        void add_hyper_binary();

        double psat_heur();

        bool should_cutoff(unsigned depth);

    public:
        lookahead(solver& s) : 
            m_s(s),
            m_num_vars(s.num_vars()),
            m_num_tc1(0),
            m_level(2),
            m_last_prefix_length(0),
            m_prefix(0),
            m_rating_throttle(0) {
            m_s.rlimit().push_child(&m_rlimit);
            init_config();
        }

        ~lookahead() {
            m_s.rlimit().pop_child();
            for (nary* n : m_nary_clauses) { 
                m_allocator.deallocate(n->obj_size(), n);
            }
        }
        

        lbool check() {
            init_search();
            return search();
        }

        /**
           \brief create cubes to std-out in DIMACS form.
           The cubes are controlled using cut-depth and cut-fraction parameters.
           If cut-depth != 0, then it is used to control thedepth of cuts.
           Otherwise, cut-fraction gives an adaptive threshold for creating cuts.
        */

        lbool cube(bool_var_vector& vars, literal_vector& lits, unsigned backtrack_level);

        void update_cube_statistics(statistics& st);

        /**
           \brief simplify set of clauses by extracting units from a lookahead at base level.
         */
        void simplify(bool learned);

        std::ostream& display(std::ostream& out) const;
        std::ostream& display_summary(std::ostream& out) const;

        /**
           \brief display lookahead scores as a sequence of:
           <variable_id:uint> <true_branch_score:double> <false_branch_score:double>\n
        */
        void display_lookahead_scores(std::ostream& out);

        model const& get_model();

        void collect_statistics(statistics& st) const;

        double literal_occs(literal l);
        double literal_big_occs(literal l);

        /**
           \brief retrieve clauses as one vector of literals.
           clauses are separated by null-literal
        */
        void get_clauses(literal_vector& clauses, unsigned max_clause_size);

        sat::config const& get_config() const { return m_s.get_config(); }
              
    };
}