GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/prop/bvminisat/simp/SimpSolver.cc Lines: 293 406 72.2 %
Date: 2021-09-29 Branches: 349 964 36.2 %

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/bvminisat/simp/SimpSolver.h"
22
23
#include "base/check.h"
24
#include "options/bv_options.h"
25
#include "options/smt_options.h"
26
#include "proof/clause_id.h"
27
#include "prop/bvminisat/mtl/Sort.h"
28
#include "prop/bvminisat/utils/System.h"
29
30
namespace cvc5 {
31
namespace BVMinisat {
32
33
//=================================================================================================
34
// Options:
35
36
37
static const char* _cat = "SIMP";
38
39
7582
static BoolOption   opt_use_asymm        (_cat, "asymm",        "Shrink clauses by asymmetric branching.", false);
40
7582
static BoolOption   opt_use_rcheck       (_cat, "rcheck",       "Check if a clause is already implied. (costly)", false);
41
7582
static BoolOption   opt_use_elim         (_cat, "elim",         "Perform variable elimination.", true);
42
7582
static IntOption    opt_grow             (_cat, "grow",         "Allow a variable elimination step to grow by a number of clauses.", 0);
43
7582
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
7582
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
7582
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
3
SimpSolver::SimpSolver(cvc5::context::Context* context)
52
    : Solver(context),
53
      grow(opt_grow),
54
      clause_lim(opt_clause_lim),
55
      subsumption_lim(opt_subsumption_lim),
56
      simp_garbage_frac(opt_simp_garbage_frac),
57
      use_asymm(opt_use_asymm),
58
      use_rcheck(opt_use_rcheck),
59
      use_elim(opt_use_elim
60
3
               && cvc5::options::bitblastMode()
61
3
                      == cvc5::options::BitblastMode::EAGER
62
5
               && !cvc5::options::produceModels()),
63
      merges(0),
64
      asymm_lits(0),
65
      eliminated_vars(0),
66
      elimorder(1),
67
      use_simplification(true),
68
6
      occurs(ClauseDeleted(ca)),
69
6
      elim_heap(ElimLt(n_occ)),
70
      bwdsub_assigns(0),
71
18
      n_touched(0)
72
{
73
74
6
    vec<Lit> dummy(1,lit_Undef);
75
3
    ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below.
76
3
    bwdsub_tmpunit        = ca.alloc(dummy);
77
3
    remove_satisfied      = false;
78
79
    // add the initialization for all the internal variables
80
9
    for (int i = frozen.size(); i < vardata.size(); ++ i) {
81
6
      frozen    .push(1);
82
6
      eliminated.push(0);
83
6
      if (use_simplification){
84
6
          n_occ     .push(0);
85
6
          n_occ     .push(0);
86
6
          occurs    .init(i);
87
6
          touched   .push(0);
88
6
          elim_heap .insert(i);
89
      }
90
    }
91
92
3
}
93
94
95
6
SimpSolver::~SimpSolver()
96
{
97
  //  cvc5::StatisticsRegistry::unregisterStat(&total_eliminate_time);
98
6
}
99
100
101
282
Var SimpSolver::newVar(bool sign, bool dvar, bool freeze) {
102
282
    Var v = Solver::newVar(sign, dvar);
103
104
282
    frozen    .push((char)false);
105
282
    eliminated.push((char)false);
106
107
282
    if (use_simplification){
108
282
        n_occ     .push(0);
109
282
        n_occ     .push(0);
110
282
        occurs    .init(v);
111
282
        touched   .push(0);
112
282
        elim_heap .insert(v);
113
282
        if (freeze) {
114
68
          setFrozen(v, true);
115
        }
116
    }
117
282
    return v;
118
}
119
120
121
122
2
lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp)
123
{
124
2
    only_bcp = false;
125
126
4
    vec<Var> extra_frozen;
127
2
    lbool    result = l_True;
128
129
2
    do_simp &= use_simplification;
130
131
2
    if (do_simp) {
132
        // Assumptions must be temporarily frozen to run variable elimination:
133
2
        for (int i = 0; i < assumptions.size(); i++){
134
            Var v = var(assumptions[i]);
135
136
            // If an assumption has been eliminated, remember it.
137
            Assert(!isEliminated(v));
138
139
            if (!frozen[v]){
140
                // Freeze and store.
141
                setFrozen(v, true);
142
                extra_frozen.push(v);
143
            } }
144
145
2
        if (do_simp && clause_added) {
146
2
          cancelUntil(0);
147
2
          result = lbool(eliminate(turn_off_simp));
148
2
          clause_added = false;
149
        }
150
    }
151
152
2
    if (result == l_True)
153
2
        result = Solver::solve_();
154
    else if (verbosity >= 1)
155
        printf("===============================================================================\n");
156
157
2
    if (do_simp)
158
        // Unfreeze the assumptions that were frozen:
159
2
        for (int i = 0; i < extra_frozen.size(); i++)
160
            setFrozen(extra_frozen[i], false);
161
162
4
    return result;
163
}
164
165
166
167
1238
bool SimpSolver::addClause_(vec<Lit>& ps, ClauseId& id)
168
{
169
#ifdef CVC5_ASSERTIONS
170
1238
  for (int i = 0; i < ps.size(); i++) Assert(!isEliminated(var(ps[i])));
171
#endif
172
173
1238
    int nclauses = clauses.size();
174
175
1238
    if (use_rcheck && implied(ps))
176
        return true;
177
178
1238
    if (!Solver::addClause_(ps, id))
179
        return false;
180
181
1238
    if (use_simplification && clauses.size() == nclauses + 1){
182
1234
        CRef          cr = clauses.last();
183
1234
        const Clause& clause = ca[cr];
184
185
        // NOTE: the clause is added to the queue immediately and then
186
        // again during 'gatherTouchedClauses()'. If nothing happens
187
        // in between, it will only be checked once. Otherwise, it may
188
        // be checked twice unnecessarily. This is an unfortunate
189
        // consequence of how backward subsumption is used to mimic
190
        // forward subsumption.
191
1234
        subsumption_queue.insert(cr);
192
5164
        for (int i = 0; i < clause.size(); i++)
193
        {
194
3930
          occurs[var(clause[i])].push(cr);
195
3930
          n_occ[toInt(clause[i])]++;
196
3930
          touched[var(clause[i])] = 1;
197
3930
          n_touched++;
198
3930
          if (elim_heap.inHeap(var(clause[i])))
199
3930
            elim_heap.increase(var(clause[i]));
200
        }
201
    }
202
203
1238
    return true;
204
}
205
206
207
704
void SimpSolver::removeClause(CRef cr)
208
{
209
704
  const Clause& clause = ca[cr];
210
211
704
  if (use_simplification)
212
  {
213
2718
    for (int i = 0; i < clause.size(); i++)
214
    {
215
2014
      n_occ[toInt(clause[i])]--;
216
2014
      updateElimHeap(var(clause[i]));
217
2014
      occurs.smudge(var(clause[i]));
218
    }
219
  }
220
704
  Solver::removeClause(cr);
221
704
}
222
223
224
114
bool SimpSolver::strengthenClause(CRef cr, Lit l)
225
{
226
114
  Clause& clause = ca[cr];
227
114
  Assert(decisionLevel() == 0);
228
114
  Assert(use_simplification);
229
230
  // FIX: this is too inefficient but would be nice to have (properly
231
  // implemented) if (!find(subsumption_queue, &clause))
232
114
  subsumption_queue.insert(cr);
233
234
114
  if (clause.size() == 2)
235
  {
236
36
    removeClause(cr);
237
36
    clause.strengthen(l);
238
  }
239
  else
240
  {
241
78
    detachClause(cr, true);
242
78
    clause.strengthen(l);
243
78
    attachClause(cr);
244
78
    remove(occurs[var(l)], cr);
245
78
    n_occ[toInt(l)]--;
246
78
    updateElimHeap(var(l));
247
  }
248
249
114
  return clause.size() == 1 ? enqueue(clause[0]) && propagate() == CRef_Undef
250
114
                            : true;
251
}
252
253
254
// Returns FALSE if clause is always satisfied ('out_clause' should not be used).
255
788
bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause)
256
{
257
788
    merges++;
258
788
    out_clause.clear();
259
260
788
    bool  ps_smallest = _ps.size() < _qs.size();
261
788
    const Clause& ps  =  ps_smallest ? _qs : _ps;
262
788
    const Clause& qs  =  ps_smallest ? _ps : _qs;
263
264
1800
    for (int i = 0; i < qs.size(); i++)
265
    {
266
1398
      if (var(qs[i]) != v)
267
      {
268
3240
        for (int j = 0; j < ps.size(); j++)
269
        {
270
2800
          if (var(ps[j]) == var(qs[i]))
271
          {
272
468
            if (ps[j] == ~qs[i])
273
386
              return false;
274
            else
275
82
              goto next;
276
          }
277
        }
278
440
        out_clause.push(qs[i]);
279
      }
280
1502
    next:;
281
    }
282
283
1986
    for (int i = 0; i < ps.size(); i++)
284
1584
        if (var(ps[i]) != v)
285
1182
            out_clause.push(ps[i]);
286
287
402
    return true;
288
}
289
290
291
// Returns FALSE if clause is always satisfied.
292
2630
bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, int& size)
293
{
294
2630
    merges++;
295
296
2630
    bool  ps_smallest = _ps.size() < _qs.size();
297
2630
    const Clause& ps  =  ps_smallest ? _qs : _ps;
298
2630
    const Clause& qs  =  ps_smallest ? _ps : _qs;
299
2630
    const Lit*  __ps  = (const Lit*)ps;
300
2630
    const Lit*  __qs  = (const Lit*)qs;
301
302
2630
    size = ps.size()-1;
303
304
7354
    for (int i = 0; i < qs.size(); i++)
305
    {
306
5852
      if (var(__qs[i]) != v)
307
      {
308
23712
        for (int j = 0; j < ps.size(); j++)
309
        {
310
21106
          if (var(__ps[j]) == var(__qs[i]))
311
          {
312
1554
            if (__ps[j] == ~__qs[i])
313
1128
              return false;
314
            else
315
426
              goto next;
316
          }
317
        }
318
2606
        size++;
319
      }
320
6416
    next:;
321
    }
322
323
1502
    return true;
324
}
325
326
327
4
void SimpSolver::gatherTouchedClauses()
328
{
329
4
    if (n_touched == 0) return;
330
331
    int i,j;
332
836
    for (i = j = 0; i < subsumption_queue.size(); i++)
333
832
        if (ca[subsumption_queue[i]].mark() == 0)
334
832
            ca[subsumption_queue[i]].mark(2);
335
336
576
    for (i = 0; i < touched.size(); i++)
337
572
        if (touched[i]){
338
464
            const vec<CRef>& cs = occurs.lookup(i);
339
4616
            for (j = 0; j < cs.size(); j++)
340
4152
                if (ca[cs[j]].mark() == 0){
341
532
                    subsumption_queue.insert(cs[j]);
342
532
                    ca[cs[j]].mark(2);
343
                }
344
464
            touched[i] = 0;
345
        }
346
347
1368
    for (i = 0; i < subsumption_queue.size(); i++)
348
1364
        if (ca[subsumption_queue[i]].mark() == 2)
349
1364
            ca[subsumption_queue[i]].mark(0);
350
351
4
    n_touched = 0;
352
}
353
354
bool SimpSolver::implied(const vec<Lit>& clause)
355
{
356
  Assert(decisionLevel() == 0);
357
358
  trail_lim.push(trail.size());
359
  for (int i = 0; i < clause.size(); i++)
360
  {
361
    if (value(clause[i]) == l_True)
362
    {
363
      cancelUntil(0);
364
      return false;
365
    }
366
    else if (value(clause[i]) != l_False)
367
    {
368
      Assert(value(clause[i]) == l_Undef);
369
      uncheckedEnqueue(~clause[i]);
370
    }
371
  }
372
373
  bool result = propagate() != CRef_Undef;
374
  cancelUntil(0);
375
  return result;
376
}
377
378
379
// Backward subsumption + backward subsumption resolution
380
100
bool SimpSolver::backwardSubsumptionCheck(bool verbose)
381
{
382
100
    int cnt = 0;
383
100
    int subsumed = 0;
384
100
    int deleted_literals = 0;
385
100
    Assert(decisionLevel() == 0);
386
387
3948
    while (subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()){
388
389
        // Empty subsumption queue and return immediately on user-interrupt:
390
1924
        if (asynch_interrupt){
391
            subsumption_queue.clear();
392
            bwdsub_assigns = trail.size();
393
            break; }
394
395
        // Check top-level assignments by creating a dummy clause and placing it in the queue:
396
1924
        if (subsumption_queue.size() == 0 && bwdsub_assigns < trail.size()){
397
44
            Lit l = trail[bwdsub_assigns++];
398
44
            ca[bwdsub_tmpunit][0] = l;
399
44
            ca[bwdsub_tmpunit].calcAbstraction();
400
44
            subsumption_queue.insert(bwdsub_tmpunit); }
401
402
1924
        CRef    cr = subsumption_queue.peek(); subsumption_queue.pop();
403
1924
        Clause& clause = ca[cr];
404
405
1924
        if (clause.mark()) continue;
406
407
1880
        if (verbose && verbosity >= 2 && cnt++ % 1000 == 0)
408
            printf("subsumption left: %10d (%10d subsumed, %10d deleted literals)\r", subsumption_queue.size(), subsumed, deleted_literals);
409
410
1880
        Assert(clause.size() > 1
411
               || value(clause[0]) == l_True);  // Unit-clauses should have been
412
                                                // propagated before this point.
413
414
        // Find best variable to scan:
415
1880
        Var best = var(clause[0]);
416
5980
        for (int i = 1; i < clause.size(); i++)
417
4100
          if (occurs[var(clause[i])].size() < occurs[best].size())
418
1928
            best = var(clause[i]);
419
420
        // Search all candidates:
421
1880
        vec<CRef>& _cs = occurs.lookup(best);
422
1880
        CRef*       cs = (CRef*)_cs;
423
424
17794
        for (int j = 0; j < _cs.size(); j++)
425
15914
          if (clause.mark())
426
            break;
427
47706
          else if (!ca[cs[j]].mark() && cs[j] != cr
428
43998
                   && (subsumption_lim == -1
429
14042
                       || ca[cs[j]].size() < subsumption_lim))
430
          {
431
14042
            Lit l = clause.subsumes(ca[cs[j]]);
432
433
14042
            if (l == lit_Undef)
434
116
              subsumed++, removeClause(cs[j]);
435
13926
            else if (l != lit_Error)
436
            {
437
114
              deleted_literals++;
438
439
114
              if (!strengthenClause(cs[j], ~l)) return false;
440
441
              // Did current candidate get deleted from cs? Then check candidate
442
              // at index j again:
443
114
              if (var(l) == best) j--;
444
            }
445
          }
446
    }
447
448
100
    return true;
449
}
450
451
452
bool SimpSolver::asymm(Var v, CRef cr)
453
{
454
  Clause& clause = ca[cr];
455
  Assert(decisionLevel() == 0);
456
457
  if (clause.mark() || satisfied(clause)) return true;
458
459
  trail_lim.push(trail.size());
460
  Lit l = lit_Undef;
461
  for (int i = 0; i < clause.size(); i++)
462
    if (var(clause[i]) != v && value(clause[i]) != l_False)
463
      uncheckedEnqueue(~clause[i]);
464
    else
465
      l = clause[i];
466
467
  if (propagate() != CRef_Undef)
468
  {
469
    cancelUntil(0);
470
    asymm_lits++;
471
    if (!strengthenClause(cr, l)) return false;
472
  }
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
96
static void mkElimClause(vec<uint32_t>& elimclauses, Lit x)
496
{
497
96
    elimclauses.push(toInt(x));
498
96
    elimclauses.push(1);
499
96
}
500
501
252
static void mkElimClause(vec<uint32_t>& elimclauses, Var v, Clause& clause)
502
{
503
252
    int first = elimclauses.size();
504
252
    int v_pos = -1;
505
506
    // Copy clause to elimclauses-vector. Remember position where the
507
    // variable 'v' occurs:
508
1002
    for (int i = 0; i < clause.size(); i++)
509
    {
510
750
      elimclauses.push(toInt(clause[i]));
511
750
      if (var(clause[i]) == v) v_pos = i + first;
512
    }
513
252
    Assert(v_pos != -1);
514
515
    // Swap the first literal with the 'v' literal, so that the literal
516
    // containing 'v' will occur first in the clause:
517
252
    uint32_t tmp = elimclauses[v_pos];
518
252
    elimclauses[v_pos] = elimclauses[first];
519
252
    elimclauses[first] = tmp;
520
521
    // Store the length of the clause last:
522
252
    elimclauses.push(clause.size());
523
252
}
524
525
526
527
182
bool SimpSolver::eliminateVar(Var v)
528
{
529
182
  Assert(!frozen[v]);
530
182
  Assert(!isEliminated(v));
531
182
  Assert(value(v) == l_Undef);
532
533
  // Split the occurrences into positive and negative:
534
  //
535
182
  const vec<CRef>& cls = occurs.lookup(v);
536
364
  vec<CRef> pos, neg;
537
1748
  for (int i = 0; i < cls.size(); i++)
538
1566
    (find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]);
539
540
  // Check whether the increase in number of clauses stays within the allowed
541
  // ('grow'). Moreover, no clause must exceed the limit on the maximal clause
542
  // size (if it is set):
543
  //
544
182
  int cnt = 0;
545
182
  int clause_size = 0;
546
547
668
  for (int i = 0; i < pos.size(); i++)
548
3116
    for (int j = 0; j < neg.size(); j++)
549
5260
      if (merge(ca[pos[i]], ca[neg[j]], v, clause_size)
550
2716
          && (++cnt > cls.size() + grow
551
1416
              || (clause_lim != -1 && clause_size > clause_lim)))
552
86
        return true;
553
554
  // Delete and store old clauses:
555
96
  eliminated[v] = true;
556
96
  setDecisionVar(v, false);
557
96
  eliminated_vars++;
558
559
96
  if (pos.size() > neg.size())
560
  {
561
4
    for (int i = 0; i < neg.size(); i++)
562
2
      mkElimClause(elimclauses, v, ca[neg[i]]);
563
2
    mkElimClause(elimclauses, mkLit(v));
564
  }
565
  else
566
  {
567
344
    for (int i = 0; i < pos.size(); i++)
568
250
      mkElimClause(elimclauses, v, ca[pos[i]]);
569
94
    mkElimClause(elimclauses, ~mkLit(v));
570
  }
571
572
96
    for (int i = 0; i < cls.size(); i++) removeClause(cls[i]);
573
574
    // Produce clauses in cross product:
575
96
    vec<Lit>& resolvent = add_tmp;
576
350
    for (int i = 0; i < pos.size(); i++)
577
1042
      for (int j = 0; j < neg.size(); j++) {
578
788
        ClauseId id = -1;
579
1190
        if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) &&
580
402
            !addClause_(resolvent, id))
581
          return false;
582
      }
583
584
    // Free occurs list for this variable:
585
96
    occurs[v].clear(true);
586
587
    // Free watchers lists for this variable, if possible:
588
96
    if (watches[ mkLit(v)].size() == 0) watches[ mkLit(v)].clear(true);
589
96
    if (watches[~mkLit(v)].size() == 0) watches[~mkLit(v)].clear(true);
590
591
96
    return backwardSubsumptionCheck();
592
}
593
594
595
bool SimpSolver::substitute(Var v, Lit x)
596
{
597
  Assert(!frozen[v]);
598
  Assert(!isEliminated(v));
599
  Assert(value(v) == l_Undef);
600
601
  if (!ok) return false;
602
603
  eliminated[v] = true;
604
  setDecisionVar(v, false);
605
  const vec<CRef>& cls = occurs.lookup(v);
606
607
  vec<Lit>& subst_clause = add_tmp;
608
  for (int i = 0; i < cls.size(); i++)
609
  {
610
    Clause& clause = ca[cls[i]];
611
612
    subst_clause.clear();
613
    for (int j = 0; j < clause.size(); j++)
614
    {
615
      Lit p = clause[j];
616
      subst_clause.push(var(p) == v ? x ^ sign(p) : p);
617
    }
618
619
    removeClause(cls[i]);
620
    ClauseId id;
621
    if (!addClause_(subst_clause, id)) return ok = false;
622
  }
623
624
    return true;
625
}
626
627
628
void SimpSolver::extendModel()
629
{
630
    int i, j;
631
    Lit x;
632
633
    for (i = elimclauses.size()-1; i > 0; i -= j){
634
        for (j = elimclauses[i--]; j > 1; j--, i--)
635
            if (modelValue(toLit(elimclauses[i])) != l_False)
636
                goto next;
637
638
        x = toLit(elimclauses[i]);
639
        model[var(x)] = lbool(!sign(x));
640
    next:;
641
    }
642
}
643
644
645
2
bool SimpSolver::eliminate(bool turn_off_elim)
646
{
647
  //  cvc5::TimerStat::CodeTimer codeTimer(total_eliminate_time);
648
649
2
  if (!simplify())
650
    return false;
651
2
  else if (!use_simplification)
652
    return true;
653
654
  // Main simplification loop:
655
  //
656
10
  while (n_touched > 0 || bwdsub_assigns < trail.size() || elim_heap.size() > 0)
657
  {
658
4
    gatherTouchedClauses();
659
    // printf("  ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n",
660
    // cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns);
661
8
    if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size())
662
8
        && !backwardSubsumptionCheck(true))
663
    {
664
      ok = false;
665
      goto cleanup;
666
    }
667
668
    // Empty elim_heap and return immediately on user-interrupt:
669
4
    if (asynch_interrupt)
670
    {
671
      Assert(bwdsub_assigns == trail.size());
672
      Assert(subsumption_queue.size() == 0);
673
      Assert(n_touched == 0);
674
      elim_heap.clear();
675
      goto cleanup;
676
    }
677
678
    // printf("  ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(),
679
    // elim_heap.size());
680
294
    for (int cnt = 0; !elim_heap.empty(); cnt++)
681
    {
682
290
      Var elim = elim_heap.removeMin();
683
684
290
      if (asynch_interrupt) break;
685
686
290
      if (isEliminated(elim) || value(elim) != l_Undef) continue;
687
688
246
      if (verbosity >= 2 && cnt % 100 == 0)
689
        printf("elimination left: %10d\r", elim_heap.size());
690
691
246
      if (use_asymm)
692
      {
693
        // Temporarily freeze variable. Otherwise, it would immediately end up
694
        // on the queue again:
695
        bool was_frozen = frozen[elim];
696
        frozen[elim] = true;
697
        if (!asymmVar(elim))
698
        {
699
          ok = false;
700
          goto cleanup;
701
        }
702
        frozen[elim] = was_frozen;
703
      }
704
705
      // At this point, the variable may have been set by assymetric branching,
706
      // so check it again. Also, don't eliminate frozen variables:
707
738
      if (use_elim && value(elim) == l_Undef && !frozen[elim]
708
428
          && !eliminateVar(elim))
709
      {
710
        ok = false;
711
        goto cleanup;
712
      }
713
714
246
      checkGarbage(simp_garbage_frac);
715
    }
716
717
4
    Assert(subsumption_queue.size() == 0);
718
    }
719
2
 cleanup:
720
721
    // If no more simplification is needed, free all simplification-related data structures:
722
2
    if (turn_off_elim){
723
        touched  .clear(true);
724
        occurs   .clear(true);
725
        n_occ    .clear(true);
726
        elim_heap.clear(true);
727
        subsumption_queue.clear(true);
728
729
        use_simplification    = false;
730
        remove_satisfied      = true;
731
        ca.extra_clause_field = false;
732
733
        // Force full cleanup (this is safe and desirable since it only happens once):
734
        rebuildOrderHeap();
735
        garbageCollect();
736
    }else{
737
        // Cheaper cleanup:
738
2
        cleanUpClauses(); // TODO: can we make 'cleanUpClauses()' not be linear in the problem size somehow?
739
2
        checkGarbage();
740
    }
741
742
2
    if (verbosity >= 1 && elimclauses.size() > 0)
743
      printf(
744
          "|  Eliminated clauses:     %10.2f Mb                                "
745
          "      |\n",
746
          double(elimclauses.size() * sizeof(uint32_t)) / (1024 * 1024));
747
748
2
    return ok;
749
750
751
752
}
753
754
755
4
void SimpSolver::cleanUpClauses()
756
{
757
4
    occurs.cleanAll();
758
    int i,j;
759
1784
    for (i = j = 0; i < clauses.size(); i++)
760
1780
        if (ca[clauses[i]].mark() == 0)
761
1076
            clauses[j++] = clauses[i];
762
4
    clauses.shrink(i - j);
763
4
}
764
765
766
//=================================================================================================
767
// Garbage Collection methods:
768
769
770
2
void SimpSolver::relocAll(ClauseAllocator& to)
771
{
772
2
    if (!use_simplification) return;
773
774
    // All occurs lists:
775
    //
776
288
    for (int i = 0; i < nVars(); i++){
777
286
        vec<CRef>& cs = occurs[i];
778
2014
        for (int j = 0; j < cs.size(); j++)
779
1728
            ca.reloc(cs[j], to);
780
    }
781
782
    // Subsumption queue:
783
    //
784
2
    for (int i = 0; i < subsumption_queue.size(); i++)
785
        ca.reloc(subsumption_queue[i], to);
786
787
    // Temporary clause:
788
    //
789
2
    ca.reloc(bwdsub_tmpunit, to);
790
}
791
792
793
2
void SimpSolver::garbageCollect()
794
{
795
    // Initialize the next region to a size corresponding to the estimated utilization degree. This
796
    // is not precise but should avoid some unnecessary reallocations for the new region:
797
4
    ClauseAllocator to(ca.size() - ca.wasted());
798
799
2
    cleanUpClauses();
800
2
    to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields.
801
2
    relocAll(to);
802
2
    Solver::relocAll(to);
803
2
    if (verbosity >= 2)
804
      printf(
805
          "|  Garbage collection:   %12d bytes => %12d bytes             |\n",
806
          ca.size() * ClauseAllocator::Unit_Size,
807
          to.size() * ClauseAllocator::Unit_Size);
808
2
    to.moveTo(ca);
809
2
}
810
811
}  // namespace BVMinisat
812
22746
}  // namespace cvc5