GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/prop/minisat/simp/SimpSolver.cc Lines: 313 413 75.8 %
Date: 2021-11-05 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
10375
static BoolOption   opt_use_asymm        (_cat, "asymm",        "Shrink clauses by asymmetric branching.", false);
40
10375
static BoolOption   opt_use_rcheck       (_cat, "rcheck",       "Check if a clause is already implied. (costly)", false);
41
10375
static BoolOption   opt_use_elim         (_cat, "elim",         "Perform variable elimination.", true);
42
10375
static IntOption    opt_grow             (_cat, "grow",         "Allow a variable elimination step to grow by a number of clauses.", 0);
43
10375
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
10375
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
10375
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
15338
SimpSolver::SimpSolver(cvc5::prop::TheoryProxy* proxy,
52
                       cvc5::context::Context* context,
53
                       cvc5::context::UserContext* userContext,
54
                       ProofNodeManager* pnm,
55
15338
                       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
15338
      use_rcheck(opt_use_rcheck && !options::unsatCores() && !pnm),
64
15338
      use_elim(options::minisatUseElim() && !enableIncremental),
65
      merges(0),
66
      asymm_lits(0),
67
      eliminated_vars(0),
68
      elimorder(1),
69
17433
      use_simplification(!enableIncremental && !options::unsatCores()
70
16853
                         && !pnm)  // TODO: turn off simplifications if
71
                                   // proofs are on initially
72
      ,
73
30676
      occurs(ClauseDeleted(ca)),
74
30676
      elim_heap(ElimLt(n_occ)),
75
      bwdsub_assigns(0),
76
122704
      n_touched(0)
77
{
78
32720
    if(options::minisatUseElim() &&
79
15338
       Options::current().prop.minisatUseElimWasSetByUser &&
80
       enableIncremental) {
81
        WarningOnce() << "Incremental mode incompatible with --minisat-elim" << std::endl;
82
    }
83
84
30676
    vec<Lit> dummy(1,lit_Undef);
85
15338
    ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below.
86
15338
    bwdsub_tmpunit        = ca.alloc(0, dummy);
87
15338
    remove_satisfied      = false;
88
89
    // add the initialization for all the internal variables
90
46014
    for (int i = frozen.size(); i < vardata.size(); ++ i) {
91
30676
      frozen    .push(1);
92
30676
      eliminated.push(0);
93
30676
      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
15338
}
102
103
104
30666
SimpSolver::~SimpSolver()
105
{
106
30666
}
107
108
109
1319331
Var SimpSolver::newVar(bool sign, bool dvar, bool isTheoryAtom, bool preRegister, bool canErase) {
110
1319331
    Var v = Solver::newVar(sign, dvar, isTheoryAtom, preRegister, canErase);
111
112
1319331
    if (use_simplification){
113
138469
        frozen    .push((char)(!canErase));
114
138469
        eliminated.push((char)false);
115
138469
        n_occ     .push(0);
116
138469
        n_occ     .push(0);
117
138469
        occurs    .init(v);
118
138469
        touched   .push(0);
119
138469
        elim_heap .insert(v);
120
    }
121
1319331
    return v; }
122
123
124
125
20555
lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp)
126
{
127
20555
    if (options::minisatDumpDimacs()) {
128
      toDimacs();
129
      return l_Undef;
130
    }
131
20555
    Assert(decisionLevel() == 0);
132
133
41110
    vec<Var> extra_frozen;
134
20555
    lbool    result = l_True;
135
136
20555
    do_simp &= use_simplification;
137
138
20555
    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
20555
    if (result == l_True)
156
20265
        result = Solver::solve_();
157
290
    else if (verbosity >= 1)
158
1
        printf("===============================================================================\n");
159
160
20532
    if (result == l_True)
161
9674
        extendModel();
162
163
20532
    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
20532
    return result;
169
}
170
171
172
173
3712531
bool SimpSolver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id)
174
{
175
#ifdef CVC5_ASSERTIONS
176
3712531
  if (use_simplification)
177
  {
178
499272
    for (int i = 0; i < ps.size(); i++) Assert(!isEliminated(var(ps[i])));
179
  }
180
#endif
181
182
3712531
    int nclauses = clauses_persistent.size();
183
184
3712531
    if (use_rcheck && implied(ps))
185
        return true;
186
187
3712531
    if (!Solver::addClause_(ps, removable, id))
188
3449
        return false;
189
190
3709082
    if (use_simplification && clauses_persistent.size() == nclauses + 1){
191
244942
        CRef          cr = clauses_persistent.last();
192
244942
        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
244942
        subsumption_queue.insert(cr);
201
957440
        for (int i = 0; i < c.size(); i++){
202
712498
            occurs[var(c[i])].push(cr);
203
712498
            n_occ[toInt(c[i])]++;
204
712498
            touched[var(c[i])] = 1;
205
712498
            n_touched++;
206
712498
            if (elim_heap.inHeap(var(c[i])))
207
694926
                elim_heap.increase(var(c[i]));
208
        }
209
    }
210
211
3709082
    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
224262
    for (i = j = 0; i < subsumption_queue.size(); i++)
336
223707
        if (ca[subsumption_queue[i]].mark() == 0)
337
223707
            ca[subsumption_queue[i]].mark(2);
338
339
107789
    for (i = 0; i < touched.size(); i++)
340
107234
        if (touched[i]){
341
66126
            const vec<CRef>& cs = occurs.lookup(i);
342
793700
            for (j = 0; j < cs.size(); j++)
343
727574
                if (ca[cs[j]].mark() == 0){
344
37323
                    subsumption_queue.insert(cs[j]);
345
37323
                    ca[cs[j]].mark(2);
346
                }
347
66126
            touched[i] = 0;
348
        }
349
350
261585
    for (i = 0; i < subsumption_queue.size(); i++)
351
261030
        if (ca[subsumption_queue[i]].mark() == 2)
352
261030
            ca[subsumption_queue[i]].mark(0);
353
354
555
    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
738680
    while (subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()){
392
393
        // Empty subsumption queue and return immediately on user-interrupt:
394
365559
        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
365559
        if (subsumption_queue.size() == 0 && bwdsub_assigns < trail.size()){
401
24130
            Lit l = trail[bwdsub_assigns++];
402
24130
            ca[bwdsub_tmpunit][0] = l;
403
24130
            ca[bwdsub_tmpunit].calcAbstraction();
404
24130
            subsumption_queue.insert(bwdsub_tmpunit); }
405
406
365559
        CRef    cr = subsumption_queue.peek(); subsumption_queue.pop();
407
365559
        Clause& c  = ca[cr];
408
409
365559
        if (c.mark()) continue;
410
411
355058
        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
355058
        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
355058
        Var best = var(c[0]);
420
3961193
        for (int i = 1; i < c.size(); i++)
421
3606135
            if (occurs[var(c[i])].size() < occurs[best].size())
422
268620
                best = var(c[i]);
423
424
        // Search all candidates:
425
355058
        vec<CRef>& _cs = occurs.lookup(best);
426
355058
        CRef*       cs = (CRef*)_cs;
427
428
20011315
        for (int j = 0; j < _cs.size(); j++)
429
19656260
            if (c.mark())
430
                break;
431
19656260
            else if (!ca[cs[j]].mark() &&  cs[j] != cr && (subsumption_lim == -1 || ca[cs[j]].size() < subsumption_lim)){
432
19317113
                Lit l = c.subsumes(ca[cs[j]]);
433
434
19317113
                if (l == lit_Undef)
435
119316
                    subsumed++, removeClause(cs[j]);
436
19197797
                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
9674
void SimpSolver::extendModel()
635
{
636
    int i, j;
637
    Lit x;
638
639
19039
    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
9674
}
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
3170
        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
74365
        for (int cnt = 0; !elim_heap.empty(); cnt++){
682
73127
            Var elim = elim_heap.removeMin();
683
684
73127
            if (asynch_interrupt) break;
685
686
73127
            if (isEliminated(elim) || value(elim) != l_Undef) continue;
687
688
49062
            if (verbosity >= 2 && cnt % 100 == 0)
689
                printf("elimination left: %10d\r", elim_heap.size());
690
691
49062
            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
49062
            if (use_elim && value(elim) == l_Undef && !frozen[elim] && !eliminateVar(elim)){
702
1
                ok = false; goto cleanup; }
703
704
49061
            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
4197
void SimpSolver::cleanUpClauses()
743
{
744
4197
    occurs.cleanAll();
745
    int i,j;
746
2109999
    for (i = j = 0; i < clauses_persistent.size(); i++)
747
2105802
        if (ca[clauses_persistent[i]].mark() == 0)
748
1943934
            clauses_persistent[j++] = clauses_persistent[i];
749
4197
    clauses_persistent.shrink(i - j);
750
4197
}
751
752
//=================================================================================================
753
// Garbage Collection methods:
754
755
756
3019
void SimpSolver::relocAll(ClauseAllocator& to)
757
{
758
3019
    if (!use_simplification) return;
759
760
    // All occurs lists:
761
    //
762
422324
    for (int i = 0; i < nVars(); i++){
763
421412
        vec<CRef>& cs = occurs[i];
764
709811
        for (int j = 0; j < cs.size(); j++)
765
288399
            ca.reloc(cs[j], to);
766
    }
767
768
    // Subsumption queue:
769
    //
770
935
    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
912
    ca.reloc(bwdsub_tmpunit, to);
776
    // TODO reloc now takes the proof form the core solver
777
}
778
779
780
3019
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
6038
    ClauseAllocator to(ca.size() - ca.wasted());
785
786
3019
    cleanUpClauses();
787
3019
    to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields.
788
3019
    relocAll(to);
789
3019
    Solver::relocAll(to);
790
3019
    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
3019
    to.moveTo(ca);
796
    // TODO: proof.finalizeUpdateId();
797
34144
}