GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/decision/justification_strategy.cpp Lines: 273 279 97.8 %
Date: 2021-08-03 Branches: 502 1148 43.7 %

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
7728
JustificationStrategy::JustificationStrategy(context::Context* c,
27
                                             context::UserContext* u,
28
                                             prop::SkolemDefManager* skdm,
29
7728
                                             ResourceManager* rm)
30
    : DecisionEngine(c, rm),
31
      d_skdm(skdm),
32
      d_assertions(
33
          u,
34
          c,
35
23184
          options::jhRlvOrder()),  // assertions are user-context dependent
36
      d_skolemAssertions(c, c),  // skolem assertions are SAT-context dependent
37
      d_justified(c),
38
      d_stack(c),
39
      d_lastDecisionLit(c),
40
      d_currStatusDec(false),
41
7728
      d_useRlvOrder(options::jhRlvOrder()),
42
7728
      d_decisionStopOnly(options::decisionMode()
43
7728
                         == options::DecisionMode::STOPONLY),
44
15456
      d_jhSkMode(options::jhSkolemMode()),
45
46368
      d_jhSkRlvMode(options::jhSkolemRlvMode())
46
{
47
7728
}
48
49
9715
void JustificationStrategy::presolve()
50
{
51
9715
  d_lastDecisionLit = Node::null();
52
9715
  d_currUnderStatus = Node::null();
53
9715
  d_currStatusDec = false;
54
  // reset the dynamic assertion list data
55
9715
  d_assertions.presolve();
56
9715
  d_skolemAssertions.presolve();
57
  // clear the stack
58
9715
  d_stack.clear();
59
9715
}
60
61
1241365
SatLiteral JustificationStrategy::getNextInternal(bool& stopSearch)
62
{
63
  // ensure we have an assertion
64
1241365
  if (!refreshCurrentAssertion())
65
  {
66
2930
    Trace("jh-process") << "getNext, already finished" << std::endl;
67
2930
    stopSearch = true;
68
2930
    return undefSatLiteral;
69
  }
70
1238435
  Assert(d_stack.hasCurrentAssertion());
71
  // temporary information in the loop below
72
  JustifyInfo* ji;
73
2476870
  JustifyNode next;
74
  // we start with the value implied by the last decision, if it exists
75
1238435
  SatValue lastChildVal = SAT_VALUE_UNKNOWN;
76
1238435
  Trace("jh-process") << "getNext" << std::endl;
77
  // If we had just sent a decision, then we lookup its value here. This may
78
  // correspond to a context where the decision was carried out, or
79
  // alternatively it may correspond to a case where we have backtracked and
80
  // propagated that literal with opposite polarity. Thus, we do not assume we
81
  // know the value of d_lastDecisionLit and look it up again here. The value
82
  // of lastChildVal will be used to update the justify info in the current
83
  // stack below.
84
1238435
  if (!d_lastDecisionLit.get().isNull())
85
  {
86
2409430
    Trace("jh-process") << "last decision = " << d_lastDecisionLit.get()
87
1204715
                        << std::endl;
88
1204715
    lastChildVal = lookupValue(d_lastDecisionLit.get());
89
1204715
    if (lastChildVal == SAT_VALUE_UNKNOWN)
90
    {
91
      // if the value is now unknown, we must reprocess the assertion, since
92
      // we have backtracked
93
198712
      TNode curr = d_stack.getCurrentAssertion();
94
99356
      d_stack.clear();
95
99356
      d_stack.reset(curr);
96
    }
97
  }
98
1238435
  d_lastDecisionLit = TNode::null();
99
  // while we are trying to satisfy assertions
100
13117510
  do
101
  {
102
14355945
    Assert(d_stack.getCurrent() != nullptr);
103
    // We get the next justify node, if it can be found.
104
9102231
    do
105
    {
106
      // get the current justify info, which should be ready
107
23458176
      ji = d_stack.getCurrent();
108
23458176
      if (ji == nullptr)
109
      {
110
6653012
        break;
111
      }
112
      // get the next child to process from the current justification info
113
      // based on the fact that its last child processed had value lastChildVal.
114
16805164
      next = getNextJustifyNode(ji, lastChildVal);
115
      // if the current node is finished, we pop the stack
116
16805164
      if (next.first.isNull())
117
      {
118
9102231
        d_stack.popStack();
119
      }
120
16805164
    } while (next.first.isNull());
121
122
14355945
    if (ji == nullptr)
123
    {
124
      // the assertion we just processed should have value true
125
6653012
      Assert(lastChildVal == SAT_VALUE_TRUE);
126
6653012
      if (!d_currUnderStatus.isNull())
127
      {
128
        // notify status if we are watching it
129
        DecisionStatus ds;
130
6049709
        if (d_currStatusDec)
131
        {
132
727802
          ds = DecisionStatus::DECISION;
133
727802
          ++(d_stats.d_numStatusDecision);
134
        }
135
        else
136
        {
137
5321907
          ds = DecisionStatus::NO_DECISION;
138
5321907
          ++(d_stats.d_numStatusNoDecision);
139
        }
140
6049709
        d_assertions.notifyStatus(d_currUnderStatus, ds);
141
      }
142
      // we did not find a next node for current, refresh current assertion
143
6653012
      d_stack.clear();
144
6653012
      refreshCurrentAssertion();
145
6653012
      lastChildVal = SAT_VALUE_UNKNOWN;
146
13306024
      Trace("jh-process") << "...exhausted assertion, now "
147
6653012
                          << d_stack.getCurrentAssertion() << std::endl;
148
    }
149
    else
150
    {
151
      // must have requested a next child to justify
152
7702933
      Assert(!next.first.isNull());
153
7702933
      Assert(next.second != SAT_VALUE_UNKNOWN);
154
      // Look up whether the next child already has a value
155
7702933
      lastChildVal = lookupValue(next.first);
156
7702933
      if (lastChildVal == SAT_VALUE_UNKNOWN)
157
      {
158
3803346
        bool nextPol = next.first.getKind() != kind::NOT;
159
6415719
        TNode nextAtom = nextPol ? next.first : next.first[0];
160
3803346
        if (isTheoryAtom(nextAtom))
161
        {
162
          // should be assigned a literal
163
1190973
          Assert(d_cnfStream->hasLiteral(nextAtom));
164
          // get the SAT literal
165
1190973
          SatLiteral nsl = d_cnfStream->getLiteral(nextAtom);
166
          // flip if the atom was negated
167
          // store the last decision value here, which will be used at the
168
          // starting value on the next call to this method
169
1190973
          lastChildVal = nextPol ? next.second : invertValue(next.second);
170
          // (1) atom with unassigned value, return it as the decision, possibly
171
          // inverted
172
2381946
          Trace("jh-process")
173
1190973
              << "...return " << nextAtom << " " << lastChildVal << std::endl;
174
          // Note that the last child of the current node we looked at does
175
          // *not* yet have a value. Although we are returning it as a decision,
176
          // we cannot set its value in d_justified, because we have yet to
177
          // push a decision level. Thus, we remember the literal we decided
178
          // on. The value of d_lastDecisionLit will be processed at the
179
          // beginning of the next call to getNext above.
180
1190973
          d_lastDecisionLit = next.first;
181
          // record that we made a decision
182
1190973
          d_currStatusDec = true;
183
1190973
          if (d_decisionStopOnly)
184
          {
185
            // only doing stop-only, return undefSatLiteral.
186
60237
            return undefSatLiteral;
187
          }
188
1130736
          return lastChildVal == SAT_VALUE_FALSE ? ~nsl : nsl;
189
        }
190
        else
191
        {
192
          // NOTE: it may be the case that we have yet to justify this node,
193
          // as indicated by the return of lookupValue. We may have a value
194
          // assigned to next.first by the SAT solver, but we ignore it here.
195
          // (2) unprocessed non-atom, push to the stack
196
2612373
          d_stack.pushToStack(next.first, next.second);
197
2612373
          d_stats.d_maxStackSize.maxAssign(d_stack.size());
198
          // we have yet to process children for the next node, so lastChildVal
199
          // remains set to SAT_VALUE_UNKNOWN.
200
        }
201
      }
202
      else
203
      {
204
7799174
        Trace("jh-debug") << "in main loop, " << next.first << " has value "
205
3899587
                          << lastChildVal << std::endl;
206
      }
207
      // (3) otherwise, next already has a value lastChildVal which will be
208
      // processed in the next iteration of the loop.
209
    }
210
13164972
  } while (d_stack.hasCurrentAssertion());
211
  // we exhausted all assertions
212
47462
  Trace("jh-process") << "...exhausted all assertions" << std::endl;
213
47462
  stopSearch = true;
214
47462
  return undefSatLiteral;
215
}
216
217
16805164
JustifyNode JustificationStrategy::getNextJustifyNode(
218
    JustifyInfo* ji, prop::SatValue& lastChildVal)
219
{
220
  // get the node we are trying to justify and its desired value
221
33610328
  JustifyNode jc = ji->getNode();
222
16805164
  Assert(!jc.first.isNull());
223
16805164
  Assert(jc.second != SAT_VALUE_UNKNOWN);
224
  // extract the non-negated formula we are trying to justify
225
16805164
  bool currPol = jc.first.getKind() != NOT;
226
33610328
  TNode curr = currPol ? jc.first : jc.first[0];
227
16805164
  Kind ck = curr.getKind();
228
  // the current node should be a non-theory literal and not have double
229
  // negation, due to our invariants of what is pushed onto the stack
230
16805164
  Assert(!isTheoryAtom(curr));
231
16805164
  Assert(ck != NOT);
232
  // get the next child index to process
233
16805164
  size_t i = ji->getNextChildIndex();
234
33610328
  Trace("jh-debug") << "getNextJustifyNode " << curr << " / " << currPol
235
16805164
                    << ", index = " << i
236
16805164
                    << ", last child value = " << lastChildVal << std::endl;
237
  // NOTE: if i>0, we just computed the value of the (i-1)^th child
238
  // i.e. i == 0 || lastChildVal != SAT_VALUE_UNKNOWN,
239
  // however this does not hold when backtracking has occurred.
240
  // if i=0, we shouldn't have a last child value
241
16805164
  Assert(i > 0 || lastChildVal == SAT_VALUE_UNKNOWN)
242
      << "in getNextJustifyNode, value given for non-existent last child";
243
  // we are trying to make the value of curr equal to currDesiredVal
244
16805164
  SatValue currDesiredVal = currPol ? jc.second : invertValue(jc.second);
245
  // value is set to TRUE/FALSE if the value of curr can be determined.
246
16805164
  SatValue value = SAT_VALUE_UNKNOWN;
247
  // if we require processing the next child of curr, we set desiredVal to
248
  // value which we want that child to be to make curr's value equal to
249
  // currDesiredVal.
250
16805164
  SatValue desiredVal = SAT_VALUE_UNKNOWN;
251
16805164
  if (ck == AND || ck == OR)
252
  {
253
10624847
    if (i == 0)
254
    {
255
      // See if a single child with currDesiredVal forces value, which is the
256
      // case if ck / currDesiredVal in { and / false, or / true }.
257
6762741
      if ((ck == AND) == (currDesiredVal == SAT_VALUE_FALSE))
258
      {
259
        // lookahead to determine if already satisfied
260
        // we scan only once, when processing the first child
261
13535598
        for (const Node& c : curr)
262
        {
263
12099661
          SatValue v = lookupValue(c);
264
12099661
          if (v == currDesiredVal)
265
          {
266
4609946
            Trace("jh-debug") << "already forcing child " << c << std::endl;
267
4609946
            value = currDesiredVal;
268
4609946
            break;
269
          }
270
          // NOTE: if v == SAT_VALUE_UNKNOWN, then we can add this to a watch
271
          // list and short circuit processing in the children of this node.
272
        }
273
      }
274
6762741
      desiredVal = currDesiredVal;
275
    }
276
5741381
    else if ((ck == AND && lastChildVal == SAT_VALUE_FALSE)
277
3648075
             || (ck == OR && lastChildVal == SAT_VALUE_TRUE)
278
6318387
             || i == curr.getNumChildren())
279
    {
280
2012509
      Trace("jh-debug") << "current is forcing child" << std::endl;
281
      // forcing or exhausted case
282
2012509
      value = lastChildVal;
283
    }
284
    else
285
    {
286
      // otherwise, no forced value, value of child should match the parent
287
1849597
      desiredVal = currDesiredVal;
288
10624847
    }
289
  }
290
6180317
  else if (ck == IMPLIES)
291
  {
292
2199309
    if (i == 0)
293
    {
294
      // lookahead to second child to determine if value already forced
295
1206313
      if (lookupValue(curr[1]) == SAT_VALUE_TRUE)
296
      {
297
543119
        value = SAT_VALUE_TRUE;
298
      }
299
      else
300
      {
301
        // otherwise, we request the opposite of what parent wants
302
663194
        desiredVal = invertValue(currDesiredVal);
303
      }
304
    }
305
992996
    else if (i == 1)
306
    {
307
      // forcing case
308
655278
      if (lastChildVal == SAT_VALUE_FALSE)
309
      {
310
301944
        value = SAT_VALUE_TRUE;
311
      }
312
      else
313
      {
314
353334
        desiredVal = currDesiredVal;
315
      }
316
    }
317
    else
318
    {
319
      // exhausted case
320
337718
      value = lastChildVal;
321
    }
322
  }
323
3981008
  else if (ck == ITE)
324
  {
325
2047418
    if (i == 0)
326
    {
327
      // lookahead on branches
328
710305
      SatValue val1 = lookupValue(curr[1]);
329
710305
      SatValue val2 = lookupValue(curr[2]);
330
710305
      if (val1 == val2)
331
      {
332
        // branches have no difference, value is that of branches, which may
333
        // be unknown
334
252852
        value = val1;
335
      }
336
      // if first branch is already wrong or second branch is already correct,
337
      // try to make condition false. Note that we arbitrarily choose true here
338
      // if both children are unknown. If both children have the same value
339
      // and that value is not unknown, desiredVal will be ignored, since
340
      // value is set above.
341
710305
      desiredVal =
342
1222150
          (val1 == invertValue(currDesiredVal) || val2 == currDesiredVal)
343
1006893
              ? SAT_VALUE_FALSE
344
              : SAT_VALUE_TRUE;
345
    }
346
1337113
    else if (i == 1)
347
    {
348
669504
      Assert(lastChildVal != SAT_VALUE_UNKNOWN);
349
      // we just computed the value of the condition, check if the condition
350
      // was false
351
669504
      if (lastChildVal == SAT_VALUE_FALSE)
352
      {
353
        // this increments to the else branch
354
292602
        i = ji->getNextChildIndex();
355
      }
356
      // make the branch equal to the desired value
357
669504
      desiredVal = currDesiredVal;
358
    }
359
    else
360
    {
361
      // return the branch value
362
667609
      value = lastChildVal;
363
    }
364
  }
365
1933590
  else if (ck == XOR || ck == EQUAL)
366
  {
367
1933590
    Assert(curr[0].getType().isBoolean());
368
1933590
    if (i == 0)
369
    {
370
      // check if the rhs forces a value
371
671640
      SatValue val1 = lookupValue(curr[1]);
372
671640
      if (val1 == SAT_VALUE_UNKNOWN)
373
      {
374
        // not forced, arbitrarily choose true
375
464708
        desiredVal = SAT_VALUE_TRUE;
376
      }
377
      else
378
      {
379
        // if the RHS of the XOR/EQUAL already had a value val1, then:
380
        // ck    / currDesiredVal
381
        // equal / true             ... LHS should have same value as RHS
382
        // equal / false            ... LHS should have opposite value as RHS
383
        // xor   / true             ... LHS should have opposite value as RHS
384
        // xor   / false            ... LHS should have same value as RHS
385
413864
        desiredVal = ((ck == EQUAL) == (currDesiredVal == SAT_VALUE_TRUE))
386
206932
                         ? val1
387
                         : invertValue(val1);
388
      }
389
    }
390
1261950
    else if (i == 1)
391
    {
392
644507
      Assert(lastChildVal != SAT_VALUE_UNKNOWN);
393
      // same as above, choosing a value for RHS based on the value of LHS,
394
      // which is stored in lastChildVal.
395
1289014
      desiredVal = ((ck == EQUAL) == (currDesiredVal == SAT_VALUE_TRUE))
396
923470
                       ? lastChildVal
397
278963
                       : invertValue(lastChildVal);
398
    }
399
    else
400
    {
401
      // recompute the value of the first child
402
617443
      SatValue val0 = lookupValue(curr[0]);
403
617443
      Assert(val0 != SAT_VALUE_UNKNOWN);
404
617443
      Assert(lastChildVal != SAT_VALUE_UNKNOWN);
405
      // compute the value of the equal/xor. The values for LHS/RHS are
406
      // stored in val0 and lastChildVal.
407
      // (val0 == lastChildVal) / ck
408
      // true                  / equal ... value of curr is true
409
      // true                  / xor   ... value of curr is false
410
      // false                 / equal ... value of curr is false
411
      // false                 / xor   ... value of curr is true
412
617443
      value = ((val0 == lastChildVal) == (ck == EQUAL)) ? SAT_VALUE_TRUE
413
                                                        : SAT_VALUE_FALSE;
414
1933590
    }
415
  }
416
  else
417
  {
418
    // curr should not be an atom
419
    Assert(false);
420
  }
421
  // we return null if we have determined the value of the current node
422
16805164
  if (value != SAT_VALUE_UNKNOWN)
423
  {
424
9102231
    Assert(!isTheoryAtom(curr));
425
    // add to justify if so
426
9102231
    d_justified.insert(curr, value);
427
    // update the last child value, which will be used by the parent of the
428
    // current node, if it exists.
429
9102231
    lastChildVal = currPol ? value : invertValue(value);
430
18204462
    Trace("jh-debug") << "getJustifyNode: return null with value "
431
9102231
                      << lastChildVal << std::endl;
432
    // return null, indicating there is nothing left to do for current
433
9102231
    return JustifyNode(TNode::null(), SAT_VALUE_UNKNOWN);
434
  }
435
15405866
  Trace("jh-debug") << "getJustifyNode: return " << curr[i]
436
7702933
                    << " with desired value " << desiredVal << std::endl;
437
  // The next child should be a valid argument in curr. Otherwise, we did not
438
  // recognize when its value could be inferred above.
439
7702933
  Assert(i < curr.getNumChildren()) << curr.getKind() << " had no value";
440
  // should set a desired value
441
7702933
  Assert(desiredVal != SAT_VALUE_UNKNOWN)
442
      << "Child " << i << " of " << curr.getKind() << " had no desired value";
443
  // return the justify node
444
7702933
  return JustifyNode(curr[i], desiredVal);
445
}
446
447
32590597
prop::SatValue JustificationStrategy::lookupValue(TNode n)
448
{
449
32590597
  bool pol = n.getKind() != NOT;
450
65181194
  TNode atom = pol ? n : n[0];
451
32590597
  Assert(atom.getKind() != NOT);
452
  // check if we have already determined the value
453
  // notice that d_justified may contain nodes that are not assigned SAT values,
454
  // since this class infers when the value of nodes can be determined.
455
32590597
  auto jit = d_justified.find(atom);
456
32590597
  if (jit != d_justified.end())
457
  {
458
11007067
    return pol ? jit->second : invertValue(jit->second);
459
  }
460
  // Notice that looking up values for non-theory atoms may lead to
461
  // an incomplete strategy where a formula is asserted but not justified
462
  // via its theory literal subterms. This is the case because the justification
463
  // heuristic is not the only source of decisions, as the theory may request
464
  // them.
465
21583530
  if (isTheoryAtom(atom))
466
  {
467
10082242
    SatLiteral nsl = d_cnfStream->getLiteral(atom);
468
10082242
    prop::SatValue val = d_satSolver->value(nsl);
469
10082242
    if (val != SAT_VALUE_UNKNOWN)
470
    {
471
      // this is the moment where we realize a skolem definition is relevant,
472
      // add now.
473
      // NOTE: if we enable skolems when they are justified, we could call
474
      // a method notifyJustified(atom) here
475
6042156
      d_justified.insert(atom, val);
476
6042156
      return pol ? val : invertValue(val);
477
    }
478
  }
479
15541374
  return SAT_VALUE_UNKNOWN;
480
}
481
482
45480
bool JustificationStrategy::isDone() { return !refreshCurrentAssertion(); }
483
484
290243
void JustificationStrategy::addAssertion(TNode assertion)
485
{
486
290243
  Trace("jh-assert") << "addAssertion " << assertion << std::endl;
487
580486
  std::vector<TNode> toProcess;
488
290243
  toProcess.push_back(assertion);
489
290243
  insertToAssertionList(toProcess, false);
490
290243
}
491
492
22262
void JustificationStrategy::addSkolemDefinition(TNode lem, TNode skolem)
493
{
494
44524
  Trace("jh-assert") << "addSkolemDefinition " << lem << " / " << skolem
495
22262
                     << std::endl;
496
22262
  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
22262
}
504
505
5934600
void JustificationStrategy::notifyAsserted(TNode n)
506
{
507
5934600
  if (d_jhSkRlvMode == options::JutificationSkolemRlvMode::ASSERT)
508
  {
509
    // assertion processed makes all skolems in assertion active,
510
    // which triggers their definitions to becoming relevant
511
11869200
    std::vector<TNode> defs;
512
5934600
    d_skdm->notifyAsserted(n, defs, true);
513
5934600
    insertToAssertionList(defs, true);
514
  }
515
  // NOTE: can update tracking triggers, pop stack to where a child implied
516
  // that a node on the current stack is justified.
517
5934600
}
518
519
6224843
void JustificationStrategy::insertToAssertionList(std::vector<TNode>& toProcess,
520
                                                  bool useSkolemList)
521
{
522
6224843
  AssertionList& al = useSkolemList ? d_skolemAssertions : d_assertions;
523
6224843
  IntStat& sizeStat =
524
      useSkolemList ? d_stats.d_maxSkolemDefsSize : d_stats.d_maxAssertionsSize;
525
  // always miniscope AND and negated OR immediately
526
6224843
  size_t index = 0;
527
  // must keep some intermediate nodes below around for ref counting
528
12449686
  std::vector<Node> keep;
529
7777845
  while (index < toProcess.size())
530
  {
531
1553002
    TNode curr = toProcess[index];
532
776501
    bool pol = curr.getKind() != NOT;
533
1553002
    TNode currAtom = pol ? curr : curr[0];
534
776501
    index++;
535
776501
    Kind k = currAtom.getKind();
536
776501
    if (k == AND && pol)
537
    {
538
17091
      toProcess.insert(toProcess.begin() + index, curr.begin(), curr.end());
539
    }
540
759410
    else if (k == OR && !pol)
541
    {
542
576
      std::vector<Node> negc;
543
3639
      for (TNode c : currAtom)
544
      {
545
6702
        Node cneg = c.negate();
546
3351
        negc.push_back(cneg);
547
        // ensure ref counted
548
3351
        keep.push_back(cneg);
549
      }
550
576
      toProcess.insert(toProcess.begin() + index, negc.begin(), negc.end());
551
    }
552
759122
    else if (!isTheoryAtom(currAtom))
553
    {
554
589011
      al.addAssertion(curr);
555
      // take stats
556
589011
      sizeStat.maxAssign(al.size());
557
    }
558
    else
559
    {
560
      // we skip (top-level) theory literals, since these are always propagated
561
      // NOTE: skolem definitions that are always relevant should be added to
562
      // assertions, for uniformity via a method notifyJustified(currAtom)
563
    }
564
  }
565
  // clear since toProcess may contain nodes with 0 ref count after returning
566
  // otherwise
567
6224843
  toProcess.clear();
568
6224843
}
569
570
7939857
bool JustificationStrategy::refreshCurrentAssertion()
571
{
572
7939857
  Trace("jh-process") << "refreshCurrentAssertion" << std::endl;
573
  // if we already have a current assertion, nothing to be done
574
15879714
  TNode curr = d_stack.getCurrentAssertion();
575
7939857
  if (!curr.isNull())
576
  {
577
1247428
    if (curr != d_currUnderStatus && !d_currUnderStatus.isNull())
578
    {
579
39985
      ++(d_stats.d_numStatusBacktrack);
580
39985
      d_assertions.notifyStatus(d_currUnderStatus, DecisionStatus::BACKTRACK);
581
      // we've backtracked to another assertion which may be partially
582
      // processed. don't track its status?
583
39985
      d_currUnderStatus = Node::null();
584
      // NOTE: could reset the stack here to preserve other invariants,
585
      // currently we do not.
586
    }
587
1247428
    return true;
588
  }
589
6692429
  bool skFirst = (d_jhSkMode != options::JutificationSkolemMode::LAST);
590
  // use main assertions first
591
6692429
  if (refreshCurrentAssertionFromList(skFirst))
592
  {
593
537226
    return true;
594
  }
595
  // if satisfied all main assertions, use the skolem assertions, which may
596
  // fail
597
6155203
  return refreshCurrentAssertionFromList(!skFirst);
598
}
599
600
12847632
bool JustificationStrategy::refreshCurrentAssertionFromList(bool useSkolemList)
601
{
602
12847632
  AssertionList& al = useSkolemList ? d_skolemAssertions : d_assertions;
603
12847632
  bool doWatchStatus = !useSkolemList;
604
12847632
  d_currUnderStatus = Node::null();
605
25695264
  TNode curr = al.getNextAssertion();
606
  SatValue currValue;
607
14918820
  while (!curr.isNull())
608
  {
609
7667282
    Trace("jh-process") << "Check assertion " << curr << std::endl;
610
    // we never add theory literals to our assertions lists
611
7667282
    Assert(!isTheoryLiteral(curr));
612
7667282
    currValue = lookupValue(curr);
613
7667282
    if (currValue == SAT_VALUE_UNKNOWN)
614
    {
615
      // if not already justified, we reset the stack and push to it
616
6631688
      d_stack.reset(curr);
617
6631688
      d_lastDecisionLit = TNode::null();
618
      // for activity
619
6631688
      if (doWatchStatus)
620
      {
621
        // initially, mark that we have not found a decision in this
622
6094462
        d_currUnderStatus = d_stack.getCurrentAssertion();
623
6094462
        d_currStatusDec = false;
624
      }
625
6631688
      return true;
626
    }
627
    // assertions should all be satisfied, otherwise we are in conflict
628
1035594
    Assert(currValue == SAT_VALUE_TRUE);
629
1035594
    if (doWatchStatus)
630
    {
631
      // mark that we did not find a decision in it
632
1035330
      ++(d_stats.d_numStatusNoDecision);
633
1035330
      d_assertions.notifyStatus(curr, DecisionStatus::NO_DECISION);
634
    }
635
    // already justified, immediately skip
636
1035594
    curr = al.getNextAssertion();
637
  }
638
6215944
  return false;
639
}
640
641
7667282
bool JustificationStrategy::isTheoryLiteral(TNode n)
642
{
643
7667282
  return isTheoryAtom(n.getKind() == NOT ? n[0] : n);
644
}
645
646
59720675
bool JustificationStrategy::isTheoryAtom(TNode n)
647
{
648
59720675
  Kind k = n.getKind();
649
59720675
  Assert(k != NOT);
650
50724840
  return k != AND && k != OR && k != IMPLIES && k != ITE && k != XOR
651
74531532
         && (k != EQUAL || !n[0].getType().isBoolean());
652
}
653
654
}  // namespace decision
655
60198
}  // namespace cvc5