GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/prop/minisat/simp/SimpSolver.cc Lines: 313 413 75.8 %
Date: 2021-11-07 Branches: 410 1048 39.1 %

Line Exec Source
1
/***********************************************************************************[SimpSolver.cc]
2
Copyright (c) 2006,      Niklas Een, Niklas Sorensson
3
Copyright (c) 2007-2010, Niklas Sorensson
4
5
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
6
associated documentation files (the "Software"), to deal in the Software without restriction,
7
including without limitation the rights to use, copy, modify, merge, publish, distribute,
8
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
9
furnished to do so, subject to the following conditions:
10
11
The above copyright notice and this permission notice shall be included in all copies or
12
substantial portions of the Software.
13
14
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
15
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
18
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19
**************************************************************************************************/
20
21
#include "prop/minisat/simp/SimpSolver.h"
22
23
#include "base/check.h"
24
#include "options/prop_options.h"
25
#include "options/smt_options.h"
26
#include "proof/clause_id.h"
27
#include "prop/minisat/mtl/Sort.h"
28
#include "prop/minisat/utils/System.h"
29
30
using namespace cvc5;
31
using namespace cvc5::Minisat;
32
33
//=================================================================================================
34
// Options:
35
36
37
static const char* _cat = "SIMP";
38
39
10379
static BoolOption   opt_use_asymm        (_cat, "asymm",        "Shrink clauses by asymmetric branching.", false);
40
10379
static BoolOption   opt_use_rcheck       (_cat, "rcheck",       "Check if a clause is already implied. (costly)", false);
41
10379
static BoolOption   opt_use_elim         (_cat, "elim",         "Perform variable elimination.", true);
42
10379
static IntOption    opt_grow             (_cat, "grow",         "Allow a variable elimination step to grow by a number of clauses.", 0);
43
10379
static IntOption    opt_clause_lim       (_cat, "cl-lim",       "Variables are not eliminated if it produces a resolvent with a length above this limit. -1 means no limit", 20,   IntRange(-1, INT32_MAX));
44
10379
static IntOption    opt_subsumption_lim  (_cat, "sub-lim",      "Do not check if subsumption against a clause larger than this. -1 means no limit.", 1000, IntRange(-1, INT32_MAX));
45
10379
static DoubleOption opt_simp_garbage_frac(_cat, "simp-gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered during simplification.",  0.5, DoubleRange(0, false, HUGE_VAL, false));
46
47
48
//=================================================================================================
49
// Constructor/Destructor:
50
51
15340
SimpSolver::SimpSolver(cvc5::prop::TheoryProxy* proxy,
52
                       cvc5::context::Context* context,
53
                       cvc5::context::UserContext* userContext,
54
                       ProofNodeManager* pnm,
55
15340
                       bool enableIncremental)
56
    : Solver(proxy, context, userContext, pnm, enableIncremental),
57
      grow(opt_grow),
58
      clause_lim(opt_clause_lim),
59
      subsumption_lim(opt_subsumption_lim),
60
      simp_garbage_frac(opt_simp_garbage_frac),
61
      use_asymm(opt_use_asymm),
62
      // make sure this is not enabled if unsat cores or proofs are on
63
15340
      use_rcheck(opt_use_rcheck && !options::unsatCores() && !pnm),
64
15340
      use_elim(options::minisatUseElim() && !enableIncremental),
65
      merges(0),
66
      asymm_lits(0),
67
      eliminated_vars(0),
68
      elimorder(1),
69
17437
      use_simplification(!enableIncremental && !options::unsatCores()
70
16855
                         && !pnm)  // TODO: turn off simplifications if
71
                                   // proofs are on initially
72
      ,
73
30680
      occurs(ClauseDeleted(ca)),
74
30680
      elim_heap(ElimLt(n_occ)),
75
      bwdsub_assigns(0),
76
122720
      n_touched(0)
77
{
78
32726
    if(options::minisatUseElim() &&
79
15340
       Options::current().prop.minisatUseElimWasSetByUser &&
80
       enableIncremental) {
81
        WarningOnce() << "Incremental mode incompatible with --minisat-elim" << std::endl;
82
    }
83
84
30680
    vec<Lit> dummy(1,lit_Undef);
85
15340
    ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below.
86
15340
    bwdsub_tmpunit        = ca.alloc(0, dummy);
87
15340
    remove_satisfied      = false;
88
89
    // add the initialization for all the internal variables
90
46020
    for (int i = frozen.size(); i < vardata.size(); ++ i) {
91
30680
      frozen    .push(1);
92
30680
      eliminated.push(0);
93
30680
      if (use_simplification){
94
3030
          n_occ     .push(0);
95
3030
          n_occ     .push(0);
96
3030
          occurs    .init(i);
97
3030
          touched   .push(0);
98
3030
          elim_heap .insert(i);
99
      }
100
    }
101
15340
}
102
103
104
30670
SimpSolver::~SimpSolver()
105
{
106
30670
}
107
108
109
1324882
Var SimpSolver::newVar(bool sign, bool dvar, bool isTheoryAtom, bool preRegister, bool canErase) {
110
1324882
    Var v = Solver::newVar(sign, dvar, isTheoryAtom, preRegister, canErase);
111
112
1324882
    if (use_simplification){
113
137513
        frozen    .push((char)(!canErase));
114
137513
        eliminated.push((char)false);
115
137513
        n_occ     .push(0);
116
137513
        n_occ     .push(0);
117
137513
        occurs    .init(v);
118
137513
        touched   .push(0);
119
137513
        elim_heap .insert(v);
120
    }
121
1324882
    return v; }
122
123
124
125
20557
lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp)
126
{
127
20557
    if (options::minisatDumpDimacs()) {
128
      toDimacs();
129
      return l_Undef;
130
    }
131
20557
    Assert(decisionLevel() == 0);
132
133
41114
    vec<Var> extra_frozen;
134
20557
    lbool    result = l_True;
135
136
20557
    do_simp &= use_simplification;
137
138
20557
    if (do_simp){
139
        // Assumptions must be temporarily frozen to run variable elimination:
140
1465
        for (int i = 0; i < assumptions.size(); i++){
141
            Var v = var(assumptions[i]);
142
143
            // If an assumption has been eliminated, remember it.
144
            Assert(!isEliminated(v));
145
146
            if (!frozen[v]){
147
                // Freeze and store.
148
                setFrozen(v, true);
149
                extra_frozen.push(v);
150
            } }
151
152
1465
        result = lbool(eliminate(turn_off_simp));
153
    }
154
155
20557
    if (result == l_True)
156
20267
        result = Solver::solve_();
157
290
    else if (verbosity >= 1)
158
1
        printf("===============================================================================\n");
159
160
20534
    if (result == l_True)
161
9677
        extendModel();
162
163
20534
    if (do_simp)
164
        // Unfreeze the assumptions that were frozen:
165
1453
        for (int i = 0; i < extra_frozen.size(); i++)
166
            setFrozen(extra_frozen[i], false);
167
168
20534
    return result;
169
}
170
171
172
173
3732729
bool SimpSolver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id)
174
{
175
#ifdef CVC5_ASSERTIONS
176
3732729
  if (use_simplification)
177
  {
178
496128
    for (int i = 0; i < ps.size(); i++) Assert(!isEliminated(var(ps[i])));
179
  }
180
#endif
181
182
3732729
    int nclauses = clauses_persistent.size();
183
184
3732729
    if (use_rcheck && implied(ps))
185
        return true;
186
187
3732729
    if (!Solver::addClause_(ps, removable, id))
188
3454
        return false;
189
190
3729275
    if (use_simplification && clauses_persistent.size() == nclauses + 1){
191
244892
        CRef          cr = clauses_persistent.last();
192
244892
        const Clause& c  = ca[cr];
193
194
        // NOTE: the clause is added to the queue immediately and then
195
        // again during 'gatherTouchedClauses()'. If nothing happens
196
        // in between, it will only be checked once. Otherwise, it may
197
        // be checked twice unnecessarily. This is an unfortunate
198
        // consequence of how backward subsumption is used to mimic
199
        // forward subsumption.
200
244892
        subsumption_queue.insert(cr);
201
957277
        for (int i = 0; i < c.size(); i++){
202
712385
            occurs[var(c[i])].push(cr);
203
712385
            n_occ[toInt(c[i])]++;
204
712385
            touched[var(c[i])] = 1;
205
712385
            n_touched++;
206
712385
            if (elim_heap.inHeap(var(c[i])))
207
694813
                elim_heap.increase(var(c[i]));
208
        }
209
    }
210
211
3729275
    return true;
212
}
213
214
215
161868
void SimpSolver::removeClause(CRef cr)
216
{
217
161868
    const Clause& c = ca[cr];
218
161868
    Debug("minisat") << "SimpSolver::removeClause(" << c << ")" << std::endl;
219
220
161868
    if (use_simplification)
221
590484
        for (int i = 0; i < c.size(); i++){
222
428616
            n_occ[toInt(c[i])]--;
223
428616
            updateElimHeap(var(c[i]));
224
428616
            occurs.smudge(var(c[i]));
225
        }
226
227
161868
    Solver::removeClause(cr);
228
161868
}
229
230
231
59256
bool SimpSolver::strengthenClause(CRef cr, Lit l)
232
{
233
59256
    Clause& c = ca[cr];
234
59256
    Assert(decisionLevel() == 0);
235
59256
    Assert(use_simplification);
236
237
    // FIX: this is too inefficient but would be nice to have (properly implemented)
238
    // if (!find(subsumption_queue, &c))
239
59256
    subsumption_queue.insert(cr);
240
241
59256
    if (c.size() == 2){
242
8379
        removeClause(cr);
243
8379
        c.strengthen(l);
244
    }else{
245
50877
        detachClause(cr, true);
246
50877
        c.strengthen(l);
247
50877
        attachClause(cr);
248
50877
        remove(occurs[var(l)], cr);
249
50877
        n_occ[toInt(l)]--;
250
50877
        updateElimHeap(var(l));
251
    }
252
253
59256
    return c.size() == 1 ? enqueue(c[0]) && propagate(CHECK_WITHOUT_THEORY) == CRef_Undef : true;
254
}
255
256
257
// Returns FALSE if clause is always satisfied ('out_clause' should not be used).
258
49510
bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause)
259
{
260
49510
    merges++;
261
49510
    out_clause.clear();
262
263
49510
    bool  ps_smallest = _ps.size() < _qs.size();
264
49510
    const Clause& ps  =  ps_smallest ? _qs : _ps;
265
49510
    const Clause& qs  =  ps_smallest ? _ps : _qs;
266
267
112845
    for (int i = 0; i < qs.size(); i++)
268
    {
269
91679
      if (var(qs[i]) != v)
270
      {
271
248443
        for (int j = 0; j < ps.size(); j++)
272
        {
273
218117
          if (var(ps[j]) == var(qs[i]))
274
          {
275
32858
            if (ps[j] == ~qs[i])
276
28344
              return false;
277
            else
278
4514
              goto next;
279
          }
280
        }
281
30326
        out_clause.push(qs[i]);
282
      }
283
91830
    next:;
284
    }
285
286
103902
    for (int i = 0; i < ps.size(); i++)
287
82736
        if (var(ps[i]) != v)
288
61570
            out_clause.push(ps[i]);
289
290
21166
    return true;
291
}
292
293
294
// Returns FALSE if clause is always satisfied.
295
196862
bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, int& size)
296
{
297
196862
    merges++;
298
299
196862
    bool  ps_smallest = _ps.size() < _qs.size();
300
196862
    const Clause& ps  =  ps_smallest ? _qs : _ps;
301
196862
    const Clause& qs  =  ps_smallest ? _ps : _qs;
302
196862
    const Lit*  __ps  = (const Lit*)ps;
303
196862
    const Lit*  __qs  = (const Lit*)qs;
304
305
196862
    size = ps.size()-1;
306
307
523590
    for (int i = 0; i < qs.size(); i++)
308
    {
309
411441
      if (var(__qs[i]) != v)
310
      {
311
1640059
        for (int j = 0; j < ps.size(); j++)
312
        {
313
1460371
          if (var(__ps[j]) == var(__qs[i]))
314
          {
315
101395
            if (__ps[j] == ~__qs[i])
316
84713
              return false;
317
            else
318
16682
              goto next;
319
          }
320
        }
321
179688
        size++;
322
      }
323
457086
    next:;
324
    }
325
326
112149
    return true;
327
}
328
329
330
1241
void SimpSolver::gatherTouchedClauses()
331
{
332
1241
    if (n_touched == 0) return;
333
334
    int i,j;
335
224211
    for (i = j = 0; i < subsumption_queue.size(); i++)
336
223657
        if (ca[subsumption_queue[i]].mark() == 0)
337
223657
            ca[subsumption_queue[i]].mark(2);
338
339
107732
    for (i = 0; i < touched.size(); i++)
340
107178
        if (touched[i]){
341
66084
            const vec<CRef>& cs = occurs.lookup(i);
342
793545
            for (j = 0; j < cs.size(); j++)
343
727461
                if (ca[cs[j]].mark() == 0){
344
37323
                    subsumption_queue.insert(cs[j]);
345
37323
                    ca[cs[j]].mark(2);
346
                }
347
66084
            touched[i] = 0;
348
        }
349
350
261534
    for (i = 0; i < subsumption_queue.size(); i++)
351
260980
        if (ca[subsumption_queue[i]].mark() == 2)
352
260980
            ca[subsumption_queue[i]].mark(0);
353
354
554
    n_touched = 0;
355
}
356
357
358
bool SimpSolver::implied(const vec<Lit>& c)
359
{
360
  Assert(decisionLevel() == 0);
361
362
  trail_lim.push(trail.size());
363
  for (int i = 0; i < c.size(); i++)
364
  {
365
    if (value(c[i]) == l_True)
366
    {
367
      cancelUntil(0);
368
      return false;
369
    }
370
    else if (value(c[i]) != l_False)
371
    {
372
      Assert(value(c[i]) == l_Undef);
373
      uncheckedEnqueue(~c[i]);
374
    }
375
  }
376
377
  bool result = propagate(CHECK_WITHOUT_THEORY) != CRef_Undef;
378
  cancelUntil(0);
379
  return result;
380
}
381
382
383
// Backward subsumption + backward subsumption resolution
384
7568
bool SimpSolver::backwardSubsumptionCheck(bool verbose)
385
{
386
7568
    int cnt = 0;
387
7568
    int subsumed = 0;
388
7568
    int deleted_literals = 0;
389
7568
    Assert(decisionLevel() == 0);
390
391
738558
    while (subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()){
392
393
        // Empty subsumption queue and return immediately on user-interrupt:
394
365498
        if (asynch_interrupt){
395
            subsumption_queue.clear();
396
            bwdsub_assigns = trail.size();
397
            break; }
398
399
        // Check top-level assignments by creating a dummy clause and placing it in the queue:
400
365498
        if (subsumption_queue.size() == 0 && bwdsub_assigns < trail.size()){
401
24119
            Lit l = trail[bwdsub_assigns++];
402
24119
            ca[bwdsub_tmpunit][0] = l;
403
24119
            ca[bwdsub_tmpunit].calcAbstraction();
404
24119
            subsumption_queue.insert(bwdsub_tmpunit); }
405
406
365498
        CRef    cr = subsumption_queue.peek(); subsumption_queue.pop();
407
365498
        Clause& c  = ca[cr];
408
409
365498
        if (c.mark()) continue;
410
411
354997
        if (verbose && verbosity >= 2 && cnt++ % 1000 == 0)
412
            printf("subsumption left: %10d (%10d subsumed, %10d deleted literals)\r", subsumption_queue.size(), subsumed, deleted_literals);
413
414
354997
        Assert(c.size() > 1
415
               || value(c[0]) == l_True);  // Unit-clauses should have been
416
                                           // propagated before this point.
417
418
        // Find best variable to scan:
419
354997
        Var best = var(c[0]);
420
3961069
        for (int i = 1; i < c.size(); i++)
421
3606072
            if (occurs[var(c[i])].size() < occurs[best].size())
422
268626
                best = var(c[i]);
423
424
        // Search all candidates:
425
354997
        vec<CRef>& _cs = occurs.lookup(best);
426
354997
        CRef*       cs = (CRef*)_cs;
427
428
20011133
        for (int j = 0; j < _cs.size(); j++)
429
19656139
            if (c.mark())
430
                break;
431
19656139
            else if (!ca[cs[j]].mark() &&  cs[j] != cr && (subsumption_lim == -1 || ca[cs[j]].size() < subsumption_lim)){
432
19317042
                Lit l = c.subsumes(ca[cs[j]]);
433
434
19317042
                if (l == lit_Undef)
435
119316
                    subsumed++, removeClause(cs[j]);
436
19197726
                else if (l != lit_Error){
437
59256
                    deleted_literals++;
438
439
59256
                    if (!strengthenClause(cs[j], ~l))
440
3
                        return false;
441
442
                    // Did current candidate get deleted from cs? Then check candidate at index j again:
443
59253
                    if (var(l) == best)
444
56439
                        j--;
445
                }
446
            }
447
    }
448
449
7565
    return true;
450
}
451
452
453
bool SimpSolver::asymm(Var v, CRef cr)
454
{
455
    Clause& c = ca[cr];
456
    Assert(decisionLevel() == 0);
457
458
    if (c.mark() || satisfied(c)) return true;
459
460
    trail_lim.push(trail.size());
461
    Lit l = lit_Undef;
462
    for (int i = 0; i < c.size(); i++)
463
        if (var(c[i]) != v && value(c[i]) != l_False)
464
            uncheckedEnqueue(~c[i]);
465
        else
466
            l = c[i];
467
468
    if (propagate(CHECK_WITHOUT_THEORY) != CRef_Undef){
469
        cancelUntil(0);
470
        asymm_lits++;
471
        if (!strengthenClause(cr, l))
472
            return false;
473
    }else
474
        cancelUntil(0);
475
476
    return true;
477
}
478
479
480
bool SimpSolver::asymmVar(Var v)
481
{
482
  Assert(use_simplification);
483
484
  const vec<CRef>& cls = occurs.lookup(v);
485
486
  if (value(v) != l_Undef || cls.size() == 0) return true;
487
488
  for (int i = 0; i < cls.size(); i++)
489
    if (!asymm(v, cls[i])) return false;
490
491
  return backwardSubsumptionCheck();
492
}
493
494
495
6329
static void mkElimClause(vec<uint32_t>& elimclauses, Lit x)
496
{
497
6329
    elimclauses.push(toInt(x));
498
6329
    elimclauses.push(1);
499
6329
}
500
501
502
12967
static void mkElimClause(vec<uint32_t>& elimclauses, Var v, Clause& c)
503
{
504
12967
    int first = elimclauses.size();
505
12967
    int v_pos = -1;
506
507
    // Copy clause to elimclauses-vector. Remember position where the
508
    // variable 'v' occurs:
509
57596
    for (int i = 0; i < c.size(); i++){
510
44629
        elimclauses.push(toInt(c[i]));
511
44629
        if (var(c[i]) == v)
512
12967
            v_pos = i + first;
513
    }
514
12967
    Assert(v_pos != -1);
515
516
    // Swap the first literal with the 'v' literal, so that the literal
517
    // containing 'v' will occur first in the clause:
518
12967
    uint32_t tmp = elimclauses[v_pos];
519
12967
    elimclauses[v_pos] = elimclauses[first];
520
12967
    elimclauses[first] = tmp;
521
522
    // Store the length of the clause last:
523
12967
    elimclauses.push(c.size());
524
12967
}
525
526
527
528
12671
bool SimpSolver::eliminateVar(Var v)
529
{
530
12671
  Assert(!frozen[v]);
531
12671
  Assert(!isEliminated(v));
532
12671
  Assert(value(v) == l_Undef);
533
534
  // Split the occurrences into positive and negative:
535
  //
536
12671
  const vec<CRef>& cls = occurs.lookup(v);
537
25342
  vec<CRef> pos, neg;
538
153324
  for (int i = 0; i < cls.size(); i++)
539
140653
    (find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]);
540
541
  // Check whether the increase in number of clauses stays within the allowed
542
  // ('grow'). Moreover, no clause must exceed the limit on the maximal clause
543
  // size (if it is set):
544
  //
545
12671
  int cnt = 0;
546
12671
  int clause_size = 0;
547
548
42621
  for (int i = 0; i < pos.size(); i++)
549
226812
    for (int j = 0; j < neg.size(); j++)
550
393724
      if (merge(ca[pos[i]], ca[neg[j]], v, clause_size)
551
203204
          && (++cnt > cls.size() + grow
552
107413
              || (clause_lim != -1 && clause_size > clause_lim)))
553
6342
        return true;
554
555
  // Delete and store old clauses:
556
6329
  eliminated[v] = true;
557
6329
  setDecisionVar(v, false);
558
6329
  eliminated_vars++;
559
560
6329
  if (pos.size() > neg.size())
561
  {
562
4625
    for (int i = 0; i < neg.size(); i++)
563
2945
      mkElimClause(elimclauses, v, ca[neg[i]]);
564
1680
    mkElimClause(elimclauses, mkLit(v));
565
  }
566
  else
567
  {
568
14671
    for (int i = 0; i < pos.size(); i++)
569
10022
      mkElimClause(elimclauses, v, ca[pos[i]]);
570
4649
    mkElimClause(elimclauses, ~mkLit(v));
571
  }
572
573
6329
    for (int i = 0; i < cls.size(); i++) removeClause(cls[i]);
574
575
6329
    ClauseId id = ClauseIdUndef;
576
    // Produce clauses in cross product:
577
6329
    vec<Lit>& resolvent = add_tmp;
578
22510
    for (int i = 0; i < pos.size(); i++)
579
65691
        for (int j = 0; j < neg.size(); j++) {
580
49510
            bool removable = ca[pos[i]].removable() && ca[pos[neg[j]]].removable();
581
70676
            if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) &&
582
21166
                !addClause_(resolvent, removable, id)) {
583
                return false;
584
            }
585
        }
586
587
    // Free occurs list for this variable:
588
6329
    occurs[v].clear(true);
589
590
    // Free watchers lists for this variable, if possible:
591
6329
    if (watches[ mkLit(v)].size() == 0) watches[ mkLit(v)].clear(true);
592
6329
    if (watches[~mkLit(v)].size() == 0) watches[~mkLit(v)].clear(true);
593
594
6329
    return backwardSubsumptionCheck();
595
}
596
597
598
bool SimpSolver::substitute(Var v, Lit x)
599
{
600
  Assert(!frozen[v]);
601
  Assert(!isEliminated(v));
602
  Assert(value(v) == l_Undef);
603
604
  if (!ok) return false;
605
606
  eliminated[v] = true;
607
  setDecisionVar(v, false);
608
  const vec<CRef>& cls = occurs.lookup(v);
609
610
  vec<Lit>& subst_clause = add_tmp;
611
  for (int i = 0; i < cls.size(); i++)
612
  {
613
    Clause& c = ca[cls[i]];
614
615
    subst_clause.clear();
616
    for (int j = 0; j < c.size(); j++)
617
    {
618
      Lit p = c[j];
619
      subst_clause.push(var(p) == v ? x ^ sign(p) : p);
620
    }
621
622
    removeClause(cls[i]);
623
    ClauseId id = ClauseIdUndef;
624
    if (!addClause_(subst_clause, c.removable(), id))
625
    {
626
      return ok = false;
627
    }
628
  }
629
630
    return true;
631
}
632
633
634
9677
void SimpSolver::extendModel()
635
{
636
    int i, j;
637
    Lit x;
638
639
19042
    for (i = elimclauses.size()-1; i > 0; i -= j){
640
14205
        for (j = elimclauses[i--]; j > 1; j--, i--)
641
9339
            if (modelValue(toLit(elimclauses[i])) != l_False)
642
4499
                goto next;
643
644
4866
        x = toLit(elimclauses[i]);
645
4866
        model[var(x)] = lbool(!sign(x));
646
9365
    next:;
647
    }
648
9677
}
649
650
651
1465
bool SimpSolver::eliminate(bool turn_off_elim)
652
{
653
1465
    if (!simplify())
654
287
        return false;
655
1178
    else if (!use_simplification)
656
        return true;
657
658
    // Main simplification loop:
659
    //
660
3654
    while (n_touched > 0 || bwdsub_assigns < trail.size() || elim_heap.size() > 0){
661
662
1241
        gatherTouchedClauses();
663
        // printf("  ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n", cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns);
664
3171
        if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size())
665
2480
            && !backwardSubsumptionCheck(true))
666
        {
667
2
          ok = false;
668
2
          goto cleanup;
669
        }
670
671
        // Empty elim_heap and return immediately on user-interrupt:
672
1239
        if (asynch_interrupt){
673
          Assert(bwdsub_assigns == trail.size());
674
          Assert(subsumption_queue.size() == 0);
675
          Assert(n_touched == 0);
676
          elim_heap.clear();
677
          goto cleanup;
678
        }
679
680
        // printf("  ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(), elim_heap.size());
681
74312
        for (int cnt = 0; !elim_heap.empty(); cnt++){
682
73074
            Var elim = elim_heap.removeMin();
683
684
73074
            if (asynch_interrupt) break;
685
686
73074
            if (isEliminated(elim) || value(elim) != l_Undef) continue;
687
688
49020
            if (verbosity >= 2 && cnt % 100 == 0)
689
                printf("elimination left: %10d\r", elim_heap.size());
690
691
49020
            if (use_asymm){
692
                // Temporarily freeze variable. Otherwise, it would immediately end up on the queue again:
693
                bool was_frozen = frozen[elim];
694
                frozen[elim] = true;
695
                if (!asymmVar(elim)){
696
                    ok = false; goto cleanup; }
697
                frozen[elim] = was_frozen; }
698
699
            // At this point, the variable may have been set by assymetric branching, so check it
700
            // again. Also, don't eliminate frozen variables:
701
49020
            if (use_elim && value(elim) == l_Undef && !frozen[elim] && !eliminateVar(elim)){
702
1
                ok = false; goto cleanup; }
703
704
49019
            checkGarbage(simp_garbage_frac);
705
        }
706
707
1238
        Assert(subsumption_queue.size() == 0);
708
    }
709
1175
 cleanup:
710
711
    // If no more simplification is needed, free all simplification-related data structures:
712
1178
    if (turn_off_elim){
713
        touched  .clear(true);
714
        occurs   .clear(true);
715
        n_occ    .clear(true);
716
        elim_heap.clear(true);
717
        subsumption_queue.clear(true);
718
719
        use_simplification    = false;
720
        remove_satisfied      = true;
721
        ca.extra_clause_field = false;
722
723
        // Force full cleanup (this is safe and desirable since it only happens once):
724
        rebuildOrderHeap();
725
        garbageCollect();
726
    }else{
727
        // Cheaper cleanup:
728
1178
        cleanUpClauses(); // TODO: can we make 'cleanUpClauses()' not be linear in the problem size somehow?
729
1178
        checkGarbage();
730
    }
731
732
1178
    if (verbosity >= 1 && elimclauses.size() > 0)
733
      printf(
734
          "|  Eliminated clauses:     %10.2f Mb                                "
735
          "      |\n",
736
          double(elimclauses.size() * sizeof(uint32_t)) / (1024 * 1024));
737
738
1178
    return ok;
739
}
740
741
742
4228
void SimpSolver::cleanUpClauses()
743
{
744
4228
    occurs.cleanAll();
745
    int i,j;
746
2102178
    for (i = j = 0; i < clauses_persistent.size(); i++)
747
2097950
        if (ca[clauses_persistent[i]].mark() == 0)
748
1936082
            clauses_persistent[j++] = clauses_persistent[i];
749
4228
    clauses_persistent.shrink(i - j);
750
4228
}
751
752
//=================================================================================================
753
// Garbage Collection methods:
754
755
756
3050
void SimpSolver::relocAll(ClauseAllocator& to)
757
{
758
3050
    if (!use_simplification) return;
759
760
    // All occurs lists:
761
    //
762
415294
    for (int i = 0; i < nVars(); i++){
763
414388
        vec<CRef>& cs = occurs[i];
764
702887
        for (int j = 0; j < cs.size(); j++)
765
288499
            ca.reloc(cs[j], to);
766
    }
767
768
    // Subsumption queue:
769
    //
770
929
    for (int i = 0; i < subsumption_queue.size(); i++)
771
23
        ca.reloc(subsumption_queue[i], to);
772
    // TODO reloc now takes the proof form the core solver
773
    // Temporary clause:
774
    //
775
906
    ca.reloc(bwdsub_tmpunit, to);
776
    // TODO reloc now takes the proof form the core solver
777
}
778
779
780
3050
void SimpSolver::garbageCollect()
781
{
782
    // Initialize the next region to a size corresponding to the estimated utilization degree. This
783
    // is not precise but should avoid some unnecessary reallocations for the new region:
784
6100
    ClauseAllocator to(ca.size() - ca.wasted());
785
786
3050
    cleanUpClauses();
787
3050
    to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields.
788
3050
    relocAll(to);
789
3050
    Solver::relocAll(to);
790
3050
    if (verbosity >= 2)
791
      printf(
792
          "|  Garbage collection:   %12d bytes => %12d bytes             |\n",
793
          ca.size() * ClauseAllocator::Unit_Size,
794
          to.size() * ClauseAllocator::Unit_Size);
795
3050
    to.moveTo(ca);
796
    // TODO: proof.finalizeUpdateId();
797
34187
}