GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/prop/bvminisat/simp/SimpSolver.cc Lines: 297 406 73.2 %
Date: 2021-05-21 Branches: 366 974 37.6 %

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
9245
static BoolOption   opt_use_asymm        (_cat, "asymm",        "Shrink clauses by asymmetric branching.", false);
40
9245
static BoolOption   opt_use_rcheck       (_cat, "rcheck",       "Check if a clause is already implied. (costly)", false);
41
9245
static BoolOption   opt_use_elim         (_cat, "elim",         "Perform variable elimination.", true);
42
9245
static IntOption    opt_grow             (_cat, "grow",         "Allow a variable elimination step to grow by a number of clauses.", 0);
43
9245
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
9245
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
9245
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
8927
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
1621451
               && cvc5::options::bitblastMode()
61
8927
                      == cvc5::options::BitblastMode::EAGER
62
8942
               && !cvc5::options::produceModels()),
63
      merges(0),
64
      asymm_lits(0),
65
      eliminated_vars(0),
66
      elimorder(1),
67
      use_simplification(true),
68
17854
      occurs(ClauseDeleted(ca)),
69
17854
      elim_heap(ElimLt(n_occ)),
70
      bwdsub_assigns(0),
71
53562
      n_touched(0)
72
{
73
74
17854
    vec<Lit> dummy(1,lit_Undef);
75
8927
    ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below.
76
8927
    bwdsub_tmpunit        = ca.alloc(dummy);
77
8927
    remove_satisfied      = false;
78
79
    // add the initialization for all the internal variables
80
26781
    for (int i = frozen.size(); i < vardata.size(); ++ i) {
81
17854
      frozen    .push(1);
82
17854
      eliminated.push(0);
83
17854
      if (use_simplification){
84
17854
          n_occ     .push(0);
85
17854
          n_occ     .push(0);
86
17854
          occurs    .init(i);
87
17854
          touched   .push(0);
88
17854
          elim_heap .insert(i);
89
      }
90
    }
91
92
8927
}
93
94
95
17854
SimpSolver::~SimpSolver()
96
{
97
  //  cvc5::StatisticsRegistry::unregisterStat(&total_eliminate_time);
98
17854
}
99
100
101
1978747
Var SimpSolver::newVar(bool sign, bool dvar, bool freeze) {
102
1978747
    Var v = Solver::newVar(sign, dvar);
103
104
1978747
    frozen    .push((char)false);
105
1978747
    eliminated.push((char)false);
106
107
1978747
    if (use_simplification){
108
1978747
        n_occ     .push(0);
109
1978747
        n_occ     .push(0);
110
1978747
        occurs    .init(v);
111
1978747
        touched   .push(0);
112
1978747
        elim_heap .insert(v);
113
1978747
        if (freeze) {
114
268193
          setFrozen(v, true);
115
        }
116
    }
117
1978747
    return v;
118
}
119
120
121
122
9917
lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp)
123
{
124
9917
    only_bcp = false;
125
126
19834
    vec<Var> extra_frozen;
127
9917
    lbool    result = l_True;
128
129
9917
    do_simp &= use_simplification;
130
131
9917
    if (do_simp) {
132
        // Assumptions must be temporarily frozen to run variable elimination:
133
785132
        for (int i = 0; i < assumptions.size(); i++){
134
775215
            Var v = var(assumptions[i]);
135
136
            // If an assumption has been eliminated, remember it.
137
775215
            Assert(!isEliminated(v));
138
139
775215
            if (!frozen[v]){
140
                // Freeze and store.
141
                setFrozen(v, true);
142
                extra_frozen.push(v);
143
            } }
144
145
9917
        if (do_simp && clause_added) {
146
5945
          cancelUntil(0);
147
5945
          result = lbool(eliminate(turn_off_simp));
148
5945
          clause_added = false;
149
        }
150
    }
151
152
9917
    if (result == l_True)
153
9917
        result = Solver::solve_();
154
    else if (verbosity >= 1)
155
        printf("===============================================================================\n");
156
157
9917
    if (do_simp)
158
        // Unfreeze the assumptions that were frozen:
159
9917
        for (int i = 0; i < extra_frozen.size(); i++)
160
            setFrozen(extra_frozen[i], false);
161
162
19834
    return result;
163
}
164
165
166
167
7607263
bool SimpSolver::addClause_(vec<Lit>& ps, ClauseId& id)
168
{
169
#ifdef CVC5_ASSERTIONS
170
7607263
  for (int i = 0; i < ps.size(); i++) Assert(!isEliminated(var(ps[i])));
171
#endif
172
173
7607263
    int nclauses = clauses.size();
174
175
7607263
    if (use_rcheck && implied(ps))
176
        return true;
177
178
7607263
    if (!Solver::addClause_(ps, id))
179
        return false;
180
181
7607263
    if (use_simplification && clauses.size() == nclauses + 1){
182
7595842
        CRef          cr = clauses.last();
183
7595842
        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
7595842
        subsumption_queue.insert(cr);
192
28260569
        for (int i = 0; i < clause.size(); i++)
193
        {
194
20664727
          occurs[var(clause[i])].push(cr);
195
20664727
          n_occ[toInt(clause[i])]++;
196
20664727
          touched[var(clause[i])] = 1;
197
20664727
          n_touched++;
198
20664727
          if (elim_heap.inHeap(var(clause[i])))
199
19462056
            elim_heap.increase(var(clause[i]));
200
        }
201
    }
202
203
7607263
    return true;
204
}
205
206
207
53346
void SimpSolver::removeClause(CRef cr)
208
{
209
53346
  const Clause& clause = ca[cr];
210
211
53346
  if (use_simplification)
212
  {
213
218556
    for (int i = 0; i < clause.size(); i++)
214
    {
215
165210
      n_occ[toInt(clause[i])]--;
216
165210
      updateElimHeap(var(clause[i]));
217
165210
      occurs.smudge(var(clause[i]));
218
    }
219
  }
220
53346
  Solver::removeClause(cr);
221
53346
}
222
223
224
44137
bool SimpSolver::strengthenClause(CRef cr, Lit l)
225
{
226
44137
  Clause& clause = ca[cr];
227
44137
  Assert(decisionLevel() == 0);
228
44137
  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
44137
  subsumption_queue.insert(cr);
233
234
44137
  if (clause.size() == 2)
235
  {
236
3481
    removeClause(cr);
237
3481
    clause.strengthen(l);
238
  }
239
  else
240
  {
241
40656
    detachClause(cr, true);
242
40656
    clause.strengthen(l);
243
40656
    attachClause(cr);
244
40656
    remove(occurs[var(l)], cr);
245
40656
    n_occ[toInt(l)]--;
246
40656
    updateElimHeap(var(l));
247
  }
248
249
44137
  return clause.size() == 1 ? enqueue(clause[0]) && propagate() == CRef_Undef
250
44137
                            : true;
251
}
252
253
254
// Returns FALSE if clause is always satisfied ('out_clause' should not be used).
255
28059
bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause)
256
{
257
28059
    merges++;
258
28059
    out_clause.clear();
259
260
28059
    bool  ps_smallest = _ps.size() < _qs.size();
261
28059
    const Clause& ps  =  ps_smallest ? _qs : _ps;
262
28059
    const Clause& qs  =  ps_smallest ? _ps : _qs;
263
264
58929
    for (int i = 0; i < qs.size(); i++)
265
    {
266
47675
      if (var(qs[i]) != v)
267
      {
268
139521
        for (int j = 0; j < ps.size(); j++)
269
        {
270
125484
          if (var(ps[j]) == var(qs[i]))
271
          {
272
20470
            if (ps[j] == ~qs[i])
273
16805
              return false;
274
            else
275
3665
              goto next;
276
          }
277
        }
278
14037
        out_clause.push(qs[i]);
279
      }
280
44038
    next:;
281
    }
282
283
57606
    for (int i = 0; i < ps.size(); i++)
284
46352
        if (var(ps[i]) != v)
285
35098
            out_clause.push(ps[i]);
286
287
11254
    return true;
288
}
289
290
291
// Returns FALSE if clause is always satisfied.
292
57407
bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, int& size)
293
{
294
57407
    merges++;
295
296
57407
    bool  ps_smallest = _ps.size() < _qs.size();
297
57407
    const Clause& ps  =  ps_smallest ? _qs : _ps;
298
57407
    const Clause& qs  =  ps_smallest ? _ps : _qs;
299
57407
    const Lit*  __ps  = (const Lit*)ps;
300
57407
    const Lit*  __qs  = (const Lit*)qs;
301
302
57407
    size = ps.size()-1;
303
304
148391
    for (int i = 0; i < qs.size(); i++)
305
    {
306
116469
      if (var(__qs[i]) != v)
307
      {
308
395641
        for (int j = 0; j < ps.size(); j++)
309
        {
310
347652
          if (var(__ps[j]) == var(__qs[i]))
311
          {
312
33100
            if (__ps[j] == ~__qs[i])
313
25485
              return false;
314
            else
315
7615
              goto next;
316
          }
317
        }
318
47989
        size++;
319
      }
320
126364
    next:;
321
    }
322
323
31922
    return true;
324
}
325
326
327
5956
void SimpSolver::gatherTouchedClauses()
328
{
329
5956
    if (n_touched == 0) return;
330
331
    int i,j;
332
6291873
    for (i = j = 0; i < subsumption_queue.size(); i++)
333
6285919
        if (ca[subsumption_queue[i]].mark() == 0)
334
6285919
            ca[subsumption_queue[i]].mark(2);
335
336
19349928
    for (i = 0; i < touched.size(); i++)
337
19343974
        if (touched[i]){
338
1791671
            const vec<CRef>& cs = occurs.lookup(i);
339
29723196
            for (j = 0; j < cs.size(); j++)
340
27931525
                if (ca[cs[j]].mark() == 0){
341
8217514
                    subsumption_queue.insert(cs[j]);
342
8217514
                    ca[cs[j]].mark(2);
343
                }
344
1791671
            touched[i] = 0;
345
        }
346
347
14509387
    for (i = 0; i < subsumption_queue.size(); i++)
348
14503433
        if (ca[subsumption_queue[i]].mark() == 2)
349
14503433
            ca[subsumption_queue[i]].mark(0);
350
351
5954
    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
8476
bool SimpSolver::backwardSubsumptionCheck(bool verbose)
381
{
382
8476
    int cnt = 0;
383
8476
    int subsumed = 0;
384
8476
    int deleted_literals = 0;
385
8476
    Assert(decisionLevel() == 0);
386
387
29139046
    while (subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()){
388
389
        // Empty subsumption queue and return immediately on user-interrupt:
390
14565285
        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
14565285
        if (subsumption_queue.size() == 0 && bwdsub_assigns < trail.size()){
397
6461
            Lit l = trail[bwdsub_assigns++];
398
6461
            ca[bwdsub_tmpunit][0] = l;
399
6461
            ca[bwdsub_tmpunit].calcAbstraction();
400
6461
            subsumption_queue.insert(bwdsub_tmpunit); }
401
402
14565285
        CRef    cr = subsumption_queue.peek(); subsumption_queue.pop();
403
14565285
        Clause& clause = ca[cr];
404
405
14565285
        if (clause.mark()) continue;
406
407
14540160
        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
14540160
        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
14540160
        Var best = var(clause[0]);
416
42210171
        for (int i = 1; i < clause.size(); i++)
417
27670011
          if (occurs[var(clause[i])].size() < occurs[best].size())
418
12825980
            best = var(clause[i]);
419
420
        // Search all candidates:
421
14540160
        vec<CRef>& _cs = occurs.lookup(best);
422
14540160
        CRef*       cs = (CRef*)_cs;
423
424
162866454
        for (int j = 0; j < _cs.size(); j++)
425
148326294
          if (clause.mark())
426
            break;
427
444977668
          else if (!ca[cs[j]].mark() && cs[j] != cr
428
415909056
                   && (subsumption_lim == -1
429
133791381
                       || ca[cs[j]].size() < subsumption_lim))
430
          {
431
133791381
            Lit l = clause.subsumes(ca[cs[j]]);
432
433
133791381
            if (l == lit_Undef)
434
33577
              subsumed++, removeClause(cs[j]);
435
133757804
            else if (l != lit_Error)
436
            {
437
44137
              deleted_literals++;
438
439
44137
              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
44137
              if (var(l) == best) j--;
444
            }
445
          }
446
    }
447
448
8476
    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
2520
static void mkElimClause(vec<uint32_t>& elimclauses, Lit x)
496
{
497
2520
    elimclauses.push(toInt(x));
498
2520
    elimclauses.push(1);
499
2520
}
500
501
6220
static void mkElimClause(vec<uint32_t>& elimclauses, Var v, Clause& clause)
502
{
503
6220
    int first = elimclauses.size();
504
6220
    int v_pos = -1;
505
506
    // Copy clause to elimclauses-vector. Remember position where the
507
    // variable 'v' occurs:
508
29061
    for (int i = 0; i < clause.size(); i++)
509
    {
510
22841
      elimclauses.push(toInt(clause[i]));
511
22841
      if (var(clause[i]) == v) v_pos = i + first;
512
    }
513
6220
    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
6220
    uint32_t tmp = elimclauses[v_pos];
518
6220
    elimclauses[v_pos] = elimclauses[first];
519
6220
    elimclauses[first] = tmp;
520
521
    // Store the length of the clause last:
522
6220
    elimclauses.push(clause.size());
523
6220
}
524
525
526
527
4028
bool SimpSolver::eliminateVar(Var v)
528
{
529
4028
  Assert(!frozen[v]);
530
4028
  Assert(!isEliminated(v));
531
4028
  Assert(value(v) == l_Undef);
532
533
  // Split the occurrences into positive and negative:
534
  //
535
4028
  const vec<CRef>& cls = occurs.lookup(v);
536
8056
  vec<CRef> pos, neg;
537
39476
  for (int i = 0; i < cls.size(); i++)
538
35448
    (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
4028
  int cnt = 0;
545
4028
  int clause_size = 0;
546
547
14005
  for (int i = 0; i < pos.size(); i++)
548
67384
    for (int j = 0; j < neg.size(); j++)
549
114814
      if (merge(ca[pos[i]], ca[neg[j]], v, clause_size)
550
58915
          && (++cnt > cls.size() + grow
551
30414
              || (clause_lim != -1 && clause_size > clause_lim)))
552
1508
        return true;
553
554
  // Delete and store old clauses:
555
2520
  eliminated[v] = true;
556
2520
  setDecisionVar(v, false);
557
2520
  eliminated_vars++;
558
559
2520
  if (pos.size() > neg.size())
560
  {
561
734
    for (int i = 0; i < neg.size(); i++)
562
496
      mkElimClause(elimclauses, v, ca[neg[i]]);
563
238
    mkElimClause(elimclauses, mkLit(v));
564
  }
565
  else
566
  {
567
8006
    for (int i = 0; i < pos.size(); i++)
568
5724
      mkElimClause(elimclauses, v, ca[pos[i]]);
569
2282
    mkElimClause(elimclauses, ~mkLit(v));
570
  }
571
572
2520
    for (int i = 0; i < cls.size(); i++) removeClause(cls[i]);
573
574
    // Produce clauses in cross product:
575
2520
    vec<Lit>& resolvent = add_tmp;
576
8987
    for (int i = 0; i < pos.size(); i++)
577
34526
      for (int j = 0; j < neg.size(); j++) {
578
28059
        ClauseId id = -1;
579
39313
        if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) &&
580
11254
            !addClause_(resolvent, id))
581
          return false;
582
      }
583
584
    // Free occurs list for this variable:
585
2520
    occurs[v].clear(true);
586
587
    // Free watchers lists for this variable, if possible:
588
2520
    if (watches[ mkLit(v)].size() == 0) watches[ mkLit(v)].clear(true);
589
2520
    if (watches[~mkLit(v)].size() == 0) watches[~mkLit(v)].clear(true);
590
591
2520
    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
5945
bool SimpSolver::eliminate(bool turn_off_elim)
646
{
647
  //  cvc5::TimerStat::CodeTimer codeTimer(total_eliminate_time);
648
649
5945
  if (!simplify())
650
    return false;
651
5945
  else if (!use_simplification)
652
    return true;
653
654
  // Main simplification loop:
655
  //
656
17857
  while (n_touched > 0 || bwdsub_assigns < trail.size() || elim_heap.size() > 0)
657
  {
658
5956
    gatherTouchedClauses();
659
    // printf("  ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n",
660
    // cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns);
661
11914
    if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size())
662
11912
        && !backwardSubsumptionCheck(true))
663
    {
664
      ok = false;
665
      goto cleanup;
666
    }
667
668
    // Empty elim_heap and return immediately on user-interrupt:
669
5956
    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
1643570
    for (int cnt = 0; !elim_heap.empty(); cnt++)
681
    {
682
1637614
      Var elim = elim_heap.removeMin();
683
684
1637614
      if (asynch_interrupt) break;
685
686
1637614
      if (isEliminated(elim) || value(elim) != l_Undef) continue;
687
688
1631184
      if (verbosity >= 2 && cnt % 100 == 0)
689
        printf("elimination left: %10d\r", elim_heap.size());
690
691
1631184
      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
3268335
      if (use_elim && value(elim) == l_Undef && !frozen[elim]
708
1635212
          && !eliminateVar(elim))
709
      {
710
        ok = false;
711
        goto cleanup;
712
      }
713
714
1631184
      checkGarbage(simp_garbage_frac);
715
    }
716
717
5956
    Assert(subsumption_queue.size() == 0);
718
    }
719
5945
 cleanup:
720
721
    // If no more simplification is needed, free all simplification-related data structures:
722
5945
    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
5945
        cleanUpClauses(); // TODO: can we make 'cleanUpClauses()' not be linear in the problem size somehow?
739
5945
        checkGarbage();
740
    }
741
742
5945
    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
5945
    return ok;
749
750
751
752
}
753
754
755
6005
void SimpSolver::cleanUpClauses()
756
{
757
6005
    occurs.cleanAll();
758
    int i,j;
759
95610297
    for (i = j = 0; i < clauses.size(); i++)
760
95604292
        if (ca[clauses[i]].mark() == 0)
761
95550946
            clauses[j++] = clauses[i];
762
6005
    clauses.shrink(i - j);
763
6005
}
764
765
766
//=================================================================================================
767
// Garbage Collection methods:
768
769
770
60
void SimpSolver::relocAll(ClauseAllocator& to)
771
{
772
60
    if (!use_simplification) return;
773
774
    // All occurs lists:
775
    //
776
44543
    for (int i = 0; i < nVars(); i++){
777
44483
        vec<CRef>& cs = occurs[i];
778
434754
        for (int j = 0; j < cs.size(); j++)
779
390271
            ca.reloc(cs[j], to);
780
    }
781
782
    // Subsumption queue:
783
    //
784
300
    for (int i = 0; i < subsumption_queue.size(); i++)
785
240
        ca.reloc(subsumption_queue[i], to);
786
787
    // Temporary clause:
788
    //
789
60
    ca.reloc(bwdsub_tmpunit, to);
790
}
791
792
793
60
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
120
    ClauseAllocator to(ca.size() - ca.wasted());
798
799
60
    cleanUpClauses();
800
60
    to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields.
801
60
    relocAll(to);
802
60
    Solver::relocAll(to);
803
60
    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
60
    to.moveTo(ca);
809
60
}
810
811
}  // namespace BVMinisat
812
1640259
}  // namespace cvc5