GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/decision/justification_strategy.cpp Lines: 274 280 97.9 %
Date: 2021-11-06 Branches: 499 1148 43.5 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds
4
 *
5
 * This file is part of the cvc5 project.
6
 *
7
 * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8
 * in the top-level source directory and their institutional affiliations.
9
 * All rights reserved.  See the file COPYING in the top-level source
10
 * directory for licensing information.
11
 * ****************************************************************************
12
 *
13
 * Implementation of the justification SAT decision strategy
14
 */
15
16
#include "decision/justification_strategy.h"
17
18
#include "prop/skolem_def_manager.h"
19
20
using namespace cvc5::kind;
21
using namespace cvc5::prop;
22
23
namespace cvc5 {
24
namespace decision {
25
26
12755
JustificationStrategy::JustificationStrategy(Env& env)
27
    : DecisionEngine(env),
28
      d_assertions(
29
12755
          userContext(),
30
          context(),
31
12755
          options()
32
12755
              .decision.jhRlvOrder),  // assertions are user-context dependent
33
      d_skolemAssertions(
34
          context(), context()),  // skolem assertions are SAT-context dependent
35
      d_justified(context()),
36
      d_stack(context()),
37
      d_lastDecisionLit(context()),
38
      d_currStatusDec(false),
39
12755
      d_useRlvOrder(options().decision.jhRlvOrder),
40
12755
      d_decisionStopOnly(options().decision.decisionMode
41
12755
                         == options::DecisionMode::STOPONLY),
42
12755
      d_jhSkMode(options().decision.jhSkolemMode),
43
76530
      d_jhSkRlvMode(options().decision.jhSkolemRlvMode)
44
{
45
12755
}
46
47
14712
void JustificationStrategy::presolve()
48
{
49
14712
  d_lastDecisionLit = Node::null();
50
14712
  d_currUnderStatus = Node::null();
51
14712
  d_currStatusDec = false;
52
  // reset the dynamic assertion list data
53
14712
  d_assertions.presolve();
54
14712
  d_skolemAssertions.presolve();
55
  // clear the stack
56
14712
  d_stack.clear();
57
14712
}
58
59
1439064
SatLiteral JustificationStrategy::getNextInternal(bool& stopSearch)
60
{
61
  // ensure we have an assertion
62
1439064
  if (!refreshCurrentAssertion())
63
  {
64
3790
    Trace("jh-process") << "getNext, already finished" << std::endl;
65
3790
    stopSearch = true;
66
3790
    return undefSatLiteral;
67
  }
68
1435274
  Assert(d_stack.hasCurrentAssertion());
69
  // temporary information in the loop below
70
  JustifyInfo* ji;
71
2870548
  JustifyNode next;
72
  // we start with the value implied by the last decision, if it exists
73
1435274
  SatValue lastChildVal = SAT_VALUE_UNKNOWN;
74
1435274
  Trace("jh-process") << "getNext" << std::endl;
75
  // If we had just sent a decision, then we lookup its value here. This may
76
  // correspond to a context where the decision was carried out, or
77
  // alternatively it may correspond to a case where we have backtracked and
78
  // propagated that literal with opposite polarity. Thus, we do not assume we
79
  // know the value of d_lastDecisionLit and look it up again here. The value
80
  // of lastChildVal will be used to update the justify info in the current
81
  // stack below.
82
1435274
  if (!d_lastDecisionLit.get().isNull())
83
  {
84
2792180
    Trace("jh-process") << "last decision = " << d_lastDecisionLit.get()
85
1396090
                        << std::endl;
86
1396090
    lastChildVal = lookupValue(d_lastDecisionLit.get());
87
1396090
    if (lastChildVal == SAT_VALUE_UNKNOWN)
88
    {
89
      // if the value is now unknown, we must reprocess the assertion, since
90
      // we have backtracked
91
213416
      TNode curr = d_stack.getCurrentAssertion();
92
106708
      d_stack.clear();
93
106708
      d_stack.reset(curr);
94
    }
95
  }
96
1435274
  d_lastDecisionLit = TNode::null();
97
  // while we are trying to satisfy assertions
98
18025589
  do
99
  {
100
19460863
    Assert(d_stack.getCurrent() != nullptr);
101
    // We get the next justify node, if it can be found.
102
13263318
    do
103
    {
104
      // get the current justify info, which should be ready
105
32724181
      ji = d_stack.getCurrent();
106
32724181
      if (ji == nullptr)
107
      {
108
9759396
        break;
109
      }
110
      // get the next child to process from the current justification info
111
      // based on the fact that its last child processed had value lastChildVal.
112
22964785
      next = getNextJustifyNode(ji, lastChildVal);
113
      // if the current node is finished, we pop the stack
114
22964785
      if (next.first.isNull())
115
      {
116
13263318
        d_stack.popStack();
117
      }
118
22964785
    } while (next.first.isNull());
119
120
19460863
    if (ji == nullptr)
121
    {
122
      // the assertion we just processed should have value true
123
9759396
      Assert(lastChildVal == SAT_VALUE_TRUE);
124
9759396
      if (!d_currUnderStatus.isNull())
125
      {
126
        // notify status if we are watching it
127
        DecisionStatus ds;
128
9125249
        if (d_currStatusDec)
129
        {
130
898405
          ds = DecisionStatus::DECISION;
131
898405
          ++(d_stats.d_numStatusDecision);
132
        }
133
        else
134
        {
135
8226844
          ds = DecisionStatus::NO_DECISION;
136
8226844
          ++(d_stats.d_numStatusNoDecision);
137
        }
138
9125249
        d_assertions.notifyStatus(d_currUnderStatus, ds);
139
      }
140
      // we did not find a next node for current, refresh current assertion
141
9759396
      d_stack.clear();
142
9759396
      refreshCurrentAssertion();
143
9759396
      lastChildVal = SAT_VALUE_UNKNOWN;
144
19518792
      Trace("jh-process") << "...exhausted assertion, now "
145
9759396
                          << d_stack.getCurrentAssertion() << std::endl;
146
    }
147
    else
148
    {
149
      // must have requested a next child to justify
150
9701467
      Assert(!next.first.isNull());
151
9701467
      Assert(next.second != SAT_VALUE_UNKNOWN);
152
      // Look up whether the next child already has a value
153
9701467
      lastChildVal = lookupValue(next.first);
154
9701467
      if (lastChildVal == SAT_VALUE_UNKNOWN)
155
      {
156
5046005
        bool nextPol = next.first.getKind() != kind::NOT;
157
8710348
        TNode nextAtom = nextPol ? next.first : next.first[0];
158
5046005
        if (isTheoryAtom(nextAtom))
159
        {
160
          // should be assigned a literal
161
1381662
          Assert(d_cnfStream->hasLiteral(nextAtom));
162
          // get the SAT literal
163
1381662
          SatLiteral nsl = d_cnfStream->getLiteral(nextAtom);
164
          // flip if the atom was negated
165
          // store the last decision value here, which will be used at the
166
          // starting value on the next call to this method
167
1381662
          lastChildVal = nextPol ? next.second : invertValue(next.second);
168
          // (1) atom with unassigned value, return it as the decision, possibly
169
          // inverted
170
2763324
          Trace("jh-process")
171
1381662
              << "...return " << nextAtom << " " << lastChildVal << std::endl;
172
          // Note that the last child of the current node we looked at does
173
          // *not* yet have a value. Although we are returning it as a decision,
174
          // we cannot set its value in d_justified, because we have yet to
175
          // push a decision level. Thus, we remember the literal we decided
176
          // on. The value of d_lastDecisionLit will be processed at the
177
          // beginning of the next call to getNext above.
178
1381662
          d_lastDecisionLit = next.first;
179
          // record that we made a decision
180
1381662
          d_currStatusDec = true;
181
1381662
          if (d_decisionStopOnly)
182
          {
183
            // only doing stop-only, return undefSatLiteral.
184
60664
            return undefSatLiteral;
185
          }
186
1320998
          return lastChildVal == SAT_VALUE_FALSE ? ~nsl : nsl;
187
        }
188
        else
189
        {
190
          // NOTE: it may be the case that we have yet to justify this node,
191
          // as indicated by the return of lookupValue. We may have a value
192
          // assigned to next.first by the SAT solver, but we ignore it here.
193
          // (2) unprocessed non-atom, push to the stack
194
3664343
          d_stack.pushToStack(next.first, next.second);
195
3664343
          d_stats.d_maxStackSize.maxAssign(d_stack.size());
196
          // we have yet to process children for the next node, so lastChildVal
197
          // remains set to SAT_VALUE_UNKNOWN.
198
        }
199
      }
200
      else
201
      {
202
9310924
        Trace("jh-debug") << "in main loop, " << next.first << " has value "
203
4655462
                          << lastChildVal << std::endl;
204
      }
205
      // (3) otherwise, next already has a value lastChildVal which will be
206
      // processed in the next iteration of the loop.
207
    }
208
18079201
  } while (d_stack.hasCurrentAssertion());
209
  // we exhausted all assertions
210
53612
  Trace("jh-process") << "...exhausted all assertions" << std::endl;
211
53612
  stopSearch = true;
212
53612
  return undefSatLiteral;
213
}
214
215
22964785
JustifyNode JustificationStrategy::getNextJustifyNode(
216
    JustifyInfo* ji, prop::SatValue& lastChildVal)
217
{
218
  // get the node we are trying to justify and its desired value
219
45929570
  JustifyNode jc = ji->getNode();
220
22964785
  Assert(!jc.first.isNull());
221
22964785
  Assert(jc.second != SAT_VALUE_UNKNOWN);
222
  // extract the non-negated formula we are trying to justify
223
22964785
  bool currPol = jc.first.getKind() != NOT;
224
45929570
  TNode curr = currPol ? jc.first : jc.first[0];
225
22964785
  Kind ck = curr.getKind();
226
  // the current node should be a non-theory literal and not have double
227
  // negation, due to our invariants of what is pushed onto the stack
228
22964785
  Assert(!isTheoryAtom(curr));
229
22964785
  Assert(ck != NOT);
230
  // get the next child index to process
231
22964785
  size_t i = ji->getNextChildIndex();
232
45929570
  Trace("jh-debug") << "getNextJustifyNode " << curr << " / " << currPol
233
22964785
                    << ", index = " << i
234
22964785
                    << ", last child value = " << lastChildVal << std::endl;
235
  // NOTE: if i>0, we just computed the value of the (i-1)^th child
236
  // i.e. i == 0 || lastChildVal != SAT_VALUE_UNKNOWN,
237
  // however this does not hold when backtracking has occurred.
238
  // if i=0, we shouldn't have a last child value
239
22964785
  Assert(i > 0 || lastChildVal == SAT_VALUE_UNKNOWN)
240
      << "in getNextJustifyNode, value given for non-existent last child";
241
  // we are trying to make the value of curr equal to currDesiredVal
242
22964785
  SatValue currDesiredVal = currPol ? jc.second : invertValue(jc.second);
243
  // value is set to TRUE/FALSE if the value of curr can be determined.
244
22964785
  SatValue value = SAT_VALUE_UNKNOWN;
245
  // if we require processing the next child of curr, we set desiredVal to
246
  // value which we want that child to be to make curr's value equal to
247
  // currDesiredVal.
248
22964785
  SatValue desiredVal = SAT_VALUE_UNKNOWN;
249
22964785
  if (ck == AND || ck == OR)
250
  {
251
15129048
    if (i == 0)
252
    {
253
      // See if a single child with currDesiredVal forces value, which is the
254
      // case if ck / currDesiredVal in { and / false, or / true }.
255
10033213
      if ((ck == AND) == (currDesiredVal == SAT_VALUE_FALSE))
256
      {
257
        // lookahead to determine if already satisfied
258
        // we scan only once, when processing the first child
259
21059846
        for (const Node& c : curr)
260
        {
261
19010010
          SatValue v = lookupValue(c);
262
19010010
          if (v == currDesiredVal)
263
          {
264
7122103
            Trace("jh-debug") << "already forcing child " << c << std::endl;
265
7122103
            value = currDesiredVal;
266
7122103
            break;
267
          }
268
          // NOTE: if v == SAT_VALUE_UNKNOWN, then we can add this to a watch
269
          // list and short circuit processing in the children of this node.
270
        }
271
      }
272
10033213
      desiredVal = currDesiredVal;
273
    }
274
7581431
    else if ((ck == AND && lastChildVal == SAT_VALUE_FALSE)
275
4836194
             || (ck == OR && lastChildVal == SAT_VALUE_TRUE)
276
8226459
             || i == curr.getNumChildren())
277
    {
278
2765562
      Trace("jh-debug") << "current is forcing child" << std::endl;
279
      // forcing or exhausted case
280
2765562
      value = lastChildVal;
281
    }
282
    else
283
    {
284
      // otherwise, no forced value, value of child should match the parent
285
2330273
      desiredVal = currDesiredVal;
286
15129048
    }
287
  }
288
7835737
  else if (ck == IMPLIES)
289
  {
290
3563263
    if (i == 0)
291
    {
292
      // lookahead to second child to determine if value already forced
293
1998747
      if (lookupValue(curr[1]) == SAT_VALUE_TRUE)
294
      {
295
807018
        value = SAT_VALUE_TRUE;
296
      }
297
      else
298
      {
299
        // otherwise, we request the opposite of what parent wants
300
1191729
        desiredVal = invertValue(currDesiredVal);
301
      }
302
    }
303
1564516
    else if (i == 1)
304
    {
305
      // forcing case
306
1182573
      if (lastChildVal == SAT_VALUE_FALSE)
307
      {
308
785009
        value = SAT_VALUE_TRUE;
309
      }
310
      else
311
      {
312
397564
        desiredVal = currDesiredVal;
313
      }
314
    }
315
    else
316
    {
317
      // exhausted case
318
381943
      value = lastChildVal;
319
    }
320
  }
321
4272474
  else if (ck == ITE)
322
  {
323
2280792
    if (i == 0)
324
    {
325
      // lookahead on branches
326
794368
      SatValue val1 = lookupValue(curr[1]);
327
794368
      SatValue val2 = lookupValue(curr[2]);
328
794368
      if (val1 == val2)
329
      {
330
        // branches have no difference, value is that of branches, which may
331
        // be unknown
332
296498
        value = val1;
333
      }
334
      // if first branch is already wrong or second branch is already correct,
335
      // try to make condition false. Note that we arbitrarily choose true here
336
      // if both children are unknown. If both children have the same value
337
      // and that value is not unknown, desiredVal will be ignored, since
338
      // value is set above.
339
794368
      desiredVal =
340
1382584
          (val1 == invertValue(currDesiredVal) || val2 == currDesiredVal)
341
1120261
              ? SAT_VALUE_FALSE
342
              : SAT_VALUE_TRUE;
343
    }
344
1486424
    else if (i == 1)
345
    {
346
744142
      Assert(lastChildVal != SAT_VALUE_UNKNOWN);
347
      // we just computed the value of the condition, check if the condition
348
      // was false
349
744142
      if (lastChildVal == SAT_VALUE_FALSE)
350
      {
351
        // this increments to the else branch
352
320851
        i = ji->getNextChildIndex();
353
      }
354
      // make the branch equal to the desired value
355
744142
      desiredVal = currDesiredVal;
356
    }
357
    else
358
    {
359
      // return the branch value
360
742282
      value = lastChildVal;
361
    }
362
  }
363
1991682
  else if (ck == XOR || ck == EQUAL)
364
  {
365
1991682
    Assert(curr[0].getType().isBoolean());
366
1991682
    if (i == 0)
367
    {
368
      // check if the rhs forces a value
369
689691
      SatValue val1 = lookupValue(curr[1]);
370
689691
      if (val1 == SAT_VALUE_UNKNOWN)
371
      {
372
        // not forced, arbitrarily choose true
373
467529
        desiredVal = SAT_VALUE_TRUE;
374
      }
375
      else
376
      {
377
        // if the RHS of the XOR/EQUAL already had a value val1, then:
378
        // ck    / currDesiredVal
379
        // equal / true             ... LHS should have same value as RHS
380
        // equal / false            ... LHS should have opposite value as RHS
381
        // xor   / true             ... LHS should have opposite value as RHS
382
        // xor   / false            ... LHS should have same value as RHS
383
444324
        desiredVal = ((ck == EQUAL) == (currDesiredVal == SAT_VALUE_TRUE))
384
222162
                         ? val1
385
                         : invertValue(val1);
386
      }
387
    }
388
1301991
    else if (i == 1)
389
    {
390
663842
      Assert(lastChildVal != SAT_VALUE_UNKNOWN);
391
      // same as above, choosing a value for RHS based on the value of LHS,
392
      // which is stored in lastChildVal.
393
1327684
      desiredVal = ((ck == EQUAL) == (currDesiredVal == SAT_VALUE_TRUE))
394
941568
                       ? lastChildVal
395
277726
                       : invertValue(lastChildVal);
396
    }
397
    else
398
    {
399
      // recompute the value of the first child
400
638149
      SatValue val0 = lookupValue(curr[0]);
401
638149
      Assert(val0 != SAT_VALUE_UNKNOWN);
402
638149
      Assert(lastChildVal != SAT_VALUE_UNKNOWN);
403
      // compute the value of the equal/xor. The values for LHS/RHS are
404
      // stored in val0 and lastChildVal.
405
      // (val0 == lastChildVal) / ck
406
      // true                  / equal ... value of curr is true
407
      // true                  / xor   ... value of curr is false
408
      // false                 / equal ... value of curr is false
409
      // false                 / xor   ... value of curr is true
410
638149
      value = ((val0 == lastChildVal) == (ck == EQUAL)) ? SAT_VALUE_TRUE
411
                                                        : SAT_VALUE_FALSE;
412
1991682
    }
413
  }
414
  else
415
  {
416
    // curr should not be an atom
417
    Assert(false);
418
  }
419
  // we return null if we have determined the value of the current node
420
22964785
  if (value != SAT_VALUE_UNKNOWN)
421
  {
422
13263318
    Assert(!isTheoryAtom(curr));
423
    // add to justify if so
424
13263318
    d_justified.insert(curr, value);
425
    // update the last child value, which will be used by the parent of the
426
    // current node, if it exists.
427
13263318
    lastChildVal = currPol ? value : invertValue(value);
428
26526636
    Trace("jh-debug") << "getJustifyNode: return null with value "
429
13263318
                      << lastChildVal << std::endl;
430
    // return null, indicating there is nothing left to do for current
431
13263318
    return JustifyNode(TNode::null(), SAT_VALUE_UNKNOWN);
432
  }
433
19402934
  Trace("jh-debug") << "getJustifyNode: return " << curr[i]
434
9701467
                    << " with desired value " << desiredVal << std::endl;
435
  // The next child should be a valid argument in curr. Otherwise, we did not
436
  // recognize when its value could be inferred above.
437
9701467
  Assert(i < curr.getNumChildren()) << curr.getKind() << " had no value";
438
  // should set a desired value
439
9701467
  Assert(desiredVal != SAT_VALUE_UNKNOWN)
440
      << "Child " << i << " of " << curr.getKind() << " had no desired value";
441
  // return the justify node
442
9701467
  return JustifyNode(curr[i], desiredVal);
443
}
444
445
45323614
prop::SatValue JustificationStrategy::lookupValue(TNode n)
446
{
447
45323614
  bool pol = n.getKind() != NOT;
448
90647228
  TNode atom = pol ? n : n[0];
449
45323614
  Assert(atom.getKind() != NOT);
450
  // check if we have already determined the value
451
  // notice that d_justified may contain nodes that are not assigned SAT values,
452
  // since this class infers when the value of nodes can be determined.
453
45323614
  auto jit = d_justified.find(atom);
454
45323614
  if (jit != d_justified.end())
455
  {
456
16195826
    return pol ? jit->second : invertValue(jit->second);
457
  }
458
  // Notice that looking up values for non-theory atoms may lead to
459
  // an incomplete strategy where a formula is asserted but not justified
460
  // via its theory literal subterms. This is the case because the justification
461
  // heuristic is not the only source of decisions, as the theory may request
462
  // them.
463
29127788
  if (isTheoryAtom(atom))
464
  {
465
12717832
    SatLiteral nsl = d_cnfStream->getLiteral(atom);
466
12717832
    prop::SatValue val = d_satSolver->value(nsl);
467
12717832
    if (val != SAT_VALUE_UNKNOWN)
468
    {
469
      // this is the moment where we realize a skolem definition is relevant,
470
      // add now.
471
      // NOTE: if we enable skolems when they are justified, we could call
472
      // a method notifyJustified(atom) here
473
7721725
      d_justified.insert(atom, val);
474
7721725
      return pol ? val : invertValue(val);
475
    }
476
  }
477
21406063
  return SAT_VALUE_UNKNOWN;
478
}
479
480
51500
bool JustificationStrategy::isDone() { return !refreshCurrentAssertion(); }
481
482
327248
void JustificationStrategy::addAssertion(TNode assertion, bool isLemma)
483
{
484
327248
  Trace("jh-assert") << "addAssertion " << assertion << std::endl;
485
654496
  std::vector<TNode> toProcess;
486
327248
  toProcess.push_back(assertion);
487
327248
  insertToAssertionList(toProcess, false);
488
327248
}
489
490
22010
void JustificationStrategy::addSkolemDefinition(TNode lem,
491
                                                TNode skolem,
492
                                                bool isLemma)
493
{
494
44020
  Trace("jh-assert") << "addSkolemDefinition " << lem << " / " << skolem
495
22010
                     << std::endl;
496
22010
  if (d_jhSkRlvMode == options::JutificationSkolemRlvMode::ALWAYS)
497
  {
498
    // just add to main assertions list
499
    std::vector<TNode> toProcess;
500
    toProcess.push_back(lem);
501
    insertToAssertionList(toProcess, false);
502
  }
503
22010
}
504
12755
bool JustificationStrategy::needsActiveSkolemDefs() const
505
{
506
12755
  return d_jhSkRlvMode == options::JutificationSkolemRlvMode::ASSERT;
507
}
508
509
7662981
void JustificationStrategy::notifyActiveSkolemDefs(std::vector<TNode>& defs)
510
{
511
7662981
  Assert(d_jhSkRlvMode == options::JutificationSkolemRlvMode::ASSERT);
512
  // assertion processed makes all skolems in assertion active,
513
  // which triggers their definitions to becoming relevant
514
7662981
  insertToAssertionList(defs, true);
515
  // NOTE: if we had a notifyAsserted callback, we could update tracking
516
  // triggers, pop stack to where a child implied that a node on the current
517
  // stack is justified.
518
7662981
}
519
520
7990229
void JustificationStrategy::insertToAssertionList(std::vector<TNode>& toProcess,
521
                                                  bool useSkolemList)
522
{
523
7990229
  AssertionList& al = useSkolemList ? d_skolemAssertions : d_assertions;
524
7990229
  IntStat& sizeStat =
525
      useSkolemList ? d_stats.d_maxSkolemDefsSize : d_stats.d_maxAssertionsSize;
526
  // always miniscope AND and negated OR immediately
527
7990229
  size_t index = 0;
528
  // must keep some intermediate nodes below around for ref counting
529
15980458
  std::vector<Node> keep;
530
9718005
  while (index < toProcess.size())
531
  {
532
1727776
    TNode curr = toProcess[index];
533
863888
    bool pol = curr.getKind() != NOT;
534
1727776
    TNode currAtom = pol ? curr : curr[0];
535
863888
    index++;
536
863888
    Kind k = currAtom.getKind();
537
863888
    if (k == AND && pol)
538
    {
539
21458
      toProcess.insert(toProcess.begin() + index, curr.begin(), curr.end());
540
    }
541
842430
    else if (k == OR && !pol)
542
    {
543
478
      std::vector<Node> negc;
544
3143
      for (TNode c : currAtom)
545
      {
546
5808
        Node cneg = c.negate();
547
2904
        negc.push_back(cneg);
548
        // ensure ref counted
549
2904
        keep.push_back(cneg);
550
      }
551
478
      toProcess.insert(toProcess.begin() + index, negc.begin(), negc.end());
552
    }
553
842191
    else if (!isTheoryAtom(currAtom))
554
    {
555
630537
      al.addAssertion(curr);
556
      // take stats
557
630537
      sizeStat.maxAssign(al.size());
558
    }
559
    else
560
    {
561
      // we skip (top-level) theory literals, since these are always propagated
562
      // NOTE: skolem definitions that are always relevant should be added to
563
      // assertions, for uniformity via a method notifyJustified(currAtom)
564
    }
565
  }
566
  // clear since toProcess may contain nodes with 0 ref count after returning
567
  // otherwise
568
7990229
  toProcess.clear();
569
7990229
}
570
571
11249960
bool JustificationStrategy::refreshCurrentAssertion()
572
{
573
11249960
  Trace("jh-process") << "refreshCurrentAssertion" << std::endl;
574
  // if we already have a current assertion, nothing to be done
575
22499920
  TNode curr = d_stack.getCurrentAssertion();
576
11249960
  if (!curr.isNull())
577
  {
578
1444165
    if (curr != d_currUnderStatus && !d_currUnderStatus.isNull())
579
    {
580
44660
      ++(d_stats.d_numStatusBacktrack);
581
44660
      d_assertions.notifyStatus(d_currUnderStatus, DecisionStatus::BACKTRACK);
582
      // we've backtracked to another assertion which may be partially
583
      // processed. don't track its status?
584
44660
      d_currUnderStatus = Node::null();
585
      // NOTE: could reset the stack here to preserve other invariants,
586
      // currently we do not.
587
    }
588
1444165
    return true;
589
  }
590
9805795
  bool skFirst = (d_jhSkMode != options::JutificationSkolemMode::LAST);
591
  // use main assertions first
592
9805795
  if (refreshCurrentAssertionFromList(skFirst))
593
  {
594
560705
    return true;
595
  }
596
  // if satisfied all main assertions, use the skolem assertions, which may
597
  // fail
598
9245090
  return refreshCurrentAssertionFromList(!skFirst);
599
}
600
601
19050885
bool JustificationStrategy::refreshCurrentAssertionFromList(bool useSkolemList)
602
{
603
19050885
  AssertionList& al = useSkolemList ? d_skolemAssertions : d_assertions;
604
19050885
  bool doWatchStatus = !useSkolemList;
605
19050885
  d_currUnderStatus = Node::null();
606
38101770
  TNode curr = al.getNextAssertion();
607
  SatValue currValue;
608
20180477
  while (!curr.isNull())
609
  {
610
10300724
    Trace("jh-process") << "Check assertion " << curr << std::endl;
611
    // we never add theory literals to our assertions lists
612
10300724
    Assert(!isTheoryLiteral(curr));
613
10300724
    currValue = lookupValue(curr);
614
10300724
    if (currValue == SAT_VALUE_UNKNOWN)
615
    {
616
      // if not already justified, we reset the stack and push to it
617
9735928
      d_stack.reset(curr);
618
9735928
      d_lastDecisionLit = TNode::null();
619
      // for activity
620
9735928
      if (doWatchStatus)
621
      {
622
        // initially, mark that we have not found a decision in this
623
9175223
        d_currUnderStatus = d_stack.getCurrentAssertion();
624
9175223
        d_currStatusDec = false;
625
      }
626
9735928
      return true;
627
    }
628
    // assertions should all be satisfied, otherwise we are in conflict
629
564796
    Assert(currValue == SAT_VALUE_TRUE);
630
564796
    if (doWatchStatus)
631
    {
632
      // mark that we did not find a decision in it
633
564532
      ++(d_stats.d_numStatusNoDecision);
634
564532
      d_assertions.notifyStatus(curr, DecisionStatus::NO_DECISION);
635
    }
636
    // already justified, immediately skip
637
564796
    curr = al.getNextAssertion();
638
  }
639
9314957
  return false;
640
}
641
642
10300724
bool JustificationStrategy::isTheoryLiteral(TNode n)
643
{
644
10300724
  return isTheoryAtom(n.getKind() == NOT ? n[0] : n);
645
}
646
647
81544811
bool JustificationStrategy::isTheoryAtom(TNode n)
648
{
649
81544811
  Kind k = n.getKind();
650
81544811
  Assert(k != NOT);
651
66694467
  return k != AND && k != OR && k != IMPLIES && k != ITE && k != XOR
652
99388439
         && (k != EQUAL || !n[0].getType().isBoolean());
653
}
654
655
}  // namespace decision
656
31137
}  // namespace cvc5