GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/decision/justification_strategy.cpp Lines: 274 280 97.9 %
Date: 2021-11-07 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
12754
JustificationStrategy::JustificationStrategy(Env& env)
27
    : DecisionEngine(env),
28
      d_assertions(
29
12754
          userContext(),
30
          context(),
31
12754
          options()
32
12754
              .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
12754
      d_useRlvOrder(options().decision.jhRlvOrder),
40
12754
      d_decisionStopOnly(options().decision.decisionMode
41
12754
                         == options::DecisionMode::STOPONLY),
42
12754
      d_jhSkMode(options().decision.jhSkolemMode),
43
76524
      d_jhSkRlvMode(options().decision.jhSkolemRlvMode)
44
{
45
12754
}
46
47
14708
void JustificationStrategy::presolve()
48
{
49
14708
  d_lastDecisionLit = Node::null();
50
14708
  d_currUnderStatus = Node::null();
51
14708
  d_currStatusDec = false;
52
  // reset the dynamic assertion list data
53
14708
  d_assertions.presolve();
54
14708
  d_skolemAssertions.presolve();
55
  // clear the stack
56
14708
  d_stack.clear();
57
14708
}
58
59
1410285
SatLiteral JustificationStrategy::getNextInternal(bool& stopSearch)
60
{
61
  // ensure we have an assertion
62
1410285
  if (!refreshCurrentAssertion())
63
  {
64
3790
    Trace("jh-process") << "getNext, already finished" << std::endl;
65
3790
    stopSearch = true;
66
3790
    return undefSatLiteral;
67
  }
68
1406495
  Assert(d_stack.hasCurrentAssertion());
69
  // temporary information in the loop below
70
  JustifyInfo* ji;
71
2812990
  JustifyNode next;
72
  // we start with the value implied by the last decision, if it exists
73
1406495
  SatValue lastChildVal = SAT_VALUE_UNKNOWN;
74
1406495
  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
1406495
  if (!d_lastDecisionLit.get().isNull())
83
  {
84
2735794
    Trace("jh-process") << "last decision = " << d_lastDecisionLit.get()
85
1367897
                        << std::endl;
86
1367897
    lastChildVal = lookupValue(d_lastDecisionLit.get());
87
1367897
    if (lastChildVal == SAT_VALUE_UNKNOWN)
88
    {
89
      // if the value is now unknown, we must reprocess the assertion, since
90
      // we have backtracked
91
212840
      TNode curr = d_stack.getCurrentAssertion();
92
106420
      d_stack.clear();
93
106420
      d_stack.reset(curr);
94
    }
95
  }
96
1406495
  d_lastDecisionLit = TNode::null();
97
  // while we are trying to satisfy assertions
98
17571706
  do
99
  {
100
18978201
    Assert(d_stack.getCurrent() != nullptr);
101
    // We get the next justify node, if it can be found.
102
12911272
    do
103
    {
104
      // get the current justify info, which should be ready
105
31889473
      ji = d_stack.getCurrent();
106
31889473
      if (ji == nullptr)
107
      {
108
9509273
        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
22380200
      next = getNextJustifyNode(ji, lastChildVal);
113
      // if the current node is finished, we pop the stack
114
22380200
      if (next.first.isNull())
115
      {
116
12911272
        d_stack.popStack();
117
      }
118
22380200
    } while (next.first.isNull());
119
120
18978201
    if (ji == nullptr)
121
    {
122
      // the assertion we just processed should have value true
123
9509273
      Assert(lastChildVal == SAT_VALUE_TRUE);
124
9509273
      if (!d_currUnderStatus.isNull())
125
      {
126
        // notify status if we are watching it
127
        DecisionStatus ds;
128
8877083
        if (d_currStatusDec)
129
        {
130
870799
          ds = DecisionStatus::DECISION;
131
870799
          ++(d_stats.d_numStatusDecision);
132
        }
133
        else
134
        {
135
8006284
          ds = DecisionStatus::NO_DECISION;
136
8006284
          ++(d_stats.d_numStatusNoDecision);
137
        }
138
8877083
        d_assertions.notifyStatus(d_currUnderStatus, ds);
139
      }
140
      // we did not find a next node for current, refresh current assertion
141
9509273
      d_stack.clear();
142
9509273
      refreshCurrentAssertion();
143
9509273
      lastChildVal = SAT_VALUE_UNKNOWN;
144
19018546
      Trace("jh-process") << "...exhausted assertion, now "
145
9509273
                          << d_stack.getCurrentAssertion() << std::endl;
146
    }
147
    else
148
    {
149
      // must have requested a next child to justify
150
9468928
      Assert(!next.first.isNull());
151
9468928
      Assert(next.second != SAT_VALUE_UNKNOWN);
152
      // Look up whether the next child already has a value
153
9468928
      lastChildVal = lookupValue(next.first);
154
9468928
      if (lastChildVal == SAT_VALUE_UNKNOWN)
155
      {
156
4915483
        bool nextPol = next.first.getKind() != kind::NOT;
157
8477683
        TNode nextAtom = nextPol ? next.first : next.first[0];
158
4915483
        if (isTheoryAtom(nextAtom))
159
        {
160
          // should be assigned a literal
161
1353283
          Assert(d_cnfStream->hasLiteral(nextAtom));
162
          // get the SAT literal
163
1353283
          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
1353283
          lastChildVal = nextPol ? next.second : invertValue(next.second);
168
          // (1) atom with unassigned value, return it as the decision, possibly
169
          // inverted
170
2706566
          Trace("jh-process")
171
1353283
              << "...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
1353283
          d_lastDecisionLit = next.first;
179
          // record that we made a decision
180
1353283
          d_currStatusDec = true;
181
1353283
          if (d_decisionStopOnly)
182
          {
183
            // only doing stop-only, return undefSatLiteral.
184
60664
            return undefSatLiteral;
185
          }
186
1292619
          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
3562200
          d_stack.pushToStack(next.first, next.second);
195
3562200
          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
9106890
        Trace("jh-debug") << "in main loop, " << next.first << " has value "
203
4553445
                          << 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
17624918
  } while (d_stack.hasCurrentAssertion());
209
  // we exhausted all assertions
210
53212
  Trace("jh-process") << "...exhausted all assertions" << std::endl;
211
53212
  stopSearch = true;
212
53212
  return undefSatLiteral;
213
}
214
215
22380200
JustifyNode JustificationStrategy::getNextJustifyNode(
216
    JustifyInfo* ji, prop::SatValue& lastChildVal)
217
{
218
  // get the node we are trying to justify and its desired value
219
44760400
  JustifyNode jc = ji->getNode();
220
22380200
  Assert(!jc.first.isNull());
221
22380200
  Assert(jc.second != SAT_VALUE_UNKNOWN);
222
  // extract the non-negated formula we are trying to justify
223
22380200
  bool currPol = jc.first.getKind() != NOT;
224
44760400
  TNode curr = currPol ? jc.first : jc.first[0];
225
22380200
  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
22380200
  Assert(!isTheoryAtom(curr));
229
22380200
  Assert(ck != NOT);
230
  // get the next child index to process
231
22380200
  size_t i = ji->getNextChildIndex();
232
44760400
  Trace("jh-debug") << "getNextJustifyNode " << curr << " / " << currPol
233
22380200
                    << ", index = " << i
234
22380200
                    << ", 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
22380200
  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
22380200
  SatValue currDesiredVal = currPol ? jc.second : invertValue(jc.second);
243
  // value is set to TRUE/FALSE if the value of curr can be determined.
244
22380200
  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
22380200
  SatValue desiredVal = SAT_VALUE_UNKNOWN;
249
22380200
  if (ck == AND || ck == OR)
250
  {
251
14714925
    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
9772377
      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
20437508
        for (const Node& c : curr)
260
        {
261
18423186
          SatValue v = lookupValue(c);
262
18423186
          if (v == currDesiredVal)
263
          {
264
6936136
            Trace("jh-debug") << "already forcing child " << c << std::endl;
265
6936136
            value = currDesiredVal;
266
6936136
            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
9772377
      desiredVal = currDesiredVal;
273
    }
274
7313542
    else if ((ck == AND && lastChildVal == SAT_VALUE_FALSE)
275
4685330
             || (ck == OR && lastChildVal == SAT_VALUE_TRUE)
276
7953020
             || i == curr.getNumChildren())
277
    {
278
2691367
      Trace("jh-debug") << "current is forcing child" << std::endl;
279
      // forcing or exhausted case
280
2691367
      value = lastChildVal;
281
    }
282
    else
283
    {
284
      // otherwise, no forced value, value of child should match the parent
285
2251181
      desiredVal = currDesiredVal;
286
14714925
    }
287
  }
288
7665275
  else if (ck == IMPLIES)
289
  {
290
3417663
    if (i == 0)
291
    {
292
      // lookahead to second child to determine if value already forced
293
1915133
      if (lookupValue(curr[1]) == SAT_VALUE_TRUE)
294
      {
295
780119
        value = SAT_VALUE_TRUE;
296
      }
297
      else
298
      {
299
        // otherwise, we request the opposite of what parent wants
300
1135014
        desiredVal = invertValue(currDesiredVal);
301
      }
302
    }
303
1502530
    else if (i == 1)
304
    {
305
      // forcing case
306
1125862
      if (lastChildVal == SAT_VALUE_FALSE)
307
      {
308
733585
        value = SAT_VALUE_TRUE;
309
      }
310
      else
311
      {
312
392277
        desiredVal = currDesiredVal;
313
      }
314
    }
315
    else
316
    {
317
      // exhausted case
318
376668
      value = lastChildVal;
319
    }
320
  }
321
4247612
  else if (ck == ITE)
322
  {
323
2255930
    if (i == 0)
324
    {
325
      // lookahead on branches
326
786078
      SatValue val1 = lookupValue(curr[1]);
327
786078
      SatValue val2 = lookupValue(curr[2]);
328
786078
      if (val1 == val2)
329
      {
330
        // branches have no difference, value is that of branches, which may
331
        // be unknown
332
295926
        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
786078
      desiredVal =
340
1367211
          (val1 == invertValue(currDesiredVal) || val2 == currDesiredVal)
341
1109069
              ? SAT_VALUE_FALSE
342
              : SAT_VALUE_TRUE;
343
    }
344
1469852
    else if (i == 1)
345
    {
346
735856
      Assert(lastChildVal != SAT_VALUE_UNKNOWN);
347
      // we just computed the value of the condition, check if the condition
348
      // was false
349
735856
      if (lastChildVal == SAT_VALUE_FALSE)
350
      {
351
        // this increments to the else branch
352
317953
        i = ji->getNextChildIndex();
353
      }
354
      // make the branch equal to the desired value
355
735856
      desiredVal = currDesiredVal;
356
    }
357
    else
358
    {
359
      // return the branch value
360
733996
      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
22380200
  if (value != SAT_VALUE_UNKNOWN)
421
  {
422
12911272
    Assert(!isTheoryAtom(curr));
423
    // add to justify if so
424
12911272
    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
12911272
    lastChildVal = currPol ? value : invertValue(value);
428
25822544
    Trace("jh-debug") << "getJustifyNode: return null with value "
429
12911272
                      << lastChildVal << std::endl;
430
    // return null, indicating there is nothing left to do for current
431
12911272
    return JustifyNode(TNode::null(), SAT_VALUE_UNKNOWN);
432
  }
433
18937856
  Trace("jh-debug") << "getJustifyNode: return " << curr[i]
434
9468928
                    << " 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
9468928
  Assert(i < curr.getNumChildren()) << curr.getKind() << " had no value";
438
  // should set a desired value
439
9468928
  Assert(desiredVal != SAT_VALUE_UNKNOWN)
440
      << "Child " << i << " of " << curr.getKind() << " had no desired value";
441
  // return the justify node
442
9468928
  return JustifyNode(curr[i], desiredVal);
443
}
444
445
44085418
prop::SatValue JustificationStrategy::lookupValue(TNode n)
446
{
447
44085418
  bool pol = n.getKind() != NOT;
448
88170836
  TNode atom = pol ? n : n[0];
449
44085418
  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
44085418
  auto jit = d_justified.find(atom);
454
44085418
  if (jit != d_justified.end())
455
  {
456
15772256
    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
28313162
  if (isTheoryAtom(atom))
464
  {
465
12325368
    SatLiteral nsl = d_cnfStream->getLiteral(atom);
466
12325368
    prop::SatValue val = d_satSolver->value(nsl);
467
12325368
    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
7426227
      d_justified.insert(atom, val);
474
7426227
      return pol ? val : invertValue(val);
475
    }
476
  }
477
20886935
  return SAT_VALUE_UNKNOWN;
478
}
479
480
51100
bool JustificationStrategy::isDone() { return !refreshCurrentAssertion(); }
481
482
325679
void JustificationStrategy::addAssertion(TNode assertion, bool isLemma)
483
{
484
325679
  Trace("jh-assert") << "addAssertion " << assertion << std::endl;
485
651358
  std::vector<TNode> toProcess;
486
325679
  toProcess.push_back(assertion);
487
325679
  insertToAssertionList(toProcess, false);
488
325679
}
489
490
22006
void JustificationStrategy::addSkolemDefinition(TNode lem,
491
                                                TNode skolem,
492
                                                bool isLemma)
493
{
494
44012
  Trace("jh-assert") << "addSkolemDefinition " << lem << " / " << skolem
495
22006
                     << std::endl;
496
22006
  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
22006
}
504
12754
bool JustificationStrategy::needsActiveSkolemDefs() const
505
{
506
12754
  return d_jhSkRlvMode == options::JutificationSkolemRlvMode::ASSERT;
507
}
508
509
7431374
void JustificationStrategy::notifyActiveSkolemDefs(std::vector<TNode>& defs)
510
{
511
7431374
  Assert(d_jhSkRlvMode == options::JutificationSkolemRlvMode::ASSERT);
512
  // assertion processed makes all skolems in assertion active,
513
  // which triggers their definitions to becoming relevant
514
7431374
  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
7431374
}
519
520
7757053
void JustificationStrategy::insertToAssertionList(std::vector<TNode>& toProcess,
521
                                                  bool useSkolemList)
522
{
523
7757053
  AssertionList& al = useSkolemList ? d_skolemAssertions : d_assertions;
524
7757053
  IntStat& sizeStat =
525
      useSkolemList ? d_stats.d_maxSkolemDefsSize : d_stats.d_maxAssertionsSize;
526
  // always miniscope AND and negated OR immediately
527
7757053
  size_t index = 0;
528
  // must keep some intermediate nodes below around for ref counting
529
15514106
  std::vector<Node> keep;
530
9480499
  while (index < toProcess.size())
531
  {
532
1723446
    TNode curr = toProcess[index];
533
861723
    bool pol = curr.getKind() != NOT;
534
1723446
    TNode currAtom = pol ? curr : curr[0];
535
861723
    index++;
536
861723
    Kind k = currAtom.getKind();
537
861723
    if (k == AND && pol)
538
    {
539
21162
      toProcess.insert(toProcess.begin() + index, curr.begin(), curr.end());
540
    }
541
840561
    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
840322
    else if (!isTheoryAtom(currAtom))
554
    {
555
629254
      al.addAssertion(curr);
556
      // take stats
557
629254
      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
7757053
  toProcess.clear();
569
7757053
}
570
571
10970658
bool JustificationStrategy::refreshCurrentAssertion()
572
{
573
10970658
  Trace("jh-process") << "refreshCurrentAssertion" << std::endl;
574
  // if we already have a current assertion, nothing to be done
575
21941316
  TNode curr = d_stack.getCurrentAssertion();
576
10970658
  if (!curr.isNull())
577
  {
578
1415111
    if (curr != d_currUnderStatus && !d_currUnderStatus.isNull())
579
    {
580
44173
      ++(d_stats.d_numStatusBacktrack);
581
44173
      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
44173
      d_currUnderStatus = Node::null();
585
      // NOTE: could reset the stack here to preserve other invariants,
586
      // currently we do not.
587
    }
588
1415111
    return true;
589
  }
590
9555547
  bool skFirst = (d_jhSkMode != options::JutificationSkolemMode::LAST);
591
  // use main assertions first
592
9555547
  if (refreshCurrentAssertionFromList(skFirst))
593
  {
594
559522
    return true;
595
  }
596
  // if satisfied all main assertions, use the skolem assertions, which may
597
  // fail
598
8996025
  return refreshCurrentAssertionFromList(!skFirst);
599
}
600
601
18551572
bool JustificationStrategy::refreshCurrentAssertionFromList(bool useSkolemList)
602
{
603
18551572
  AssertionList& al = useSkolemList ? d_skolemAssertions : d_assertions;
604
18551572
  bool doWatchStatus = !useSkolemList;
605
18551572
  d_currUnderStatus = Node::null();
606
37103144
  TNode curr = al.getNextAssertion();
607
  SatValue currValue;
608
19599948
  while (!curr.isNull())
609
  {
610
10010278
    Trace("jh-process") << "Check assertion " << curr << std::endl;
611
    // we never add theory literals to our assertions lists
612
10010278
    Assert(!isTheoryLiteral(curr));
613
10010278
    currValue = lookupValue(curr);
614
10010278
    if (currValue == SAT_VALUE_UNKNOWN)
615
    {
616
      // if not already justified, we reset the stack and push to it
617
9486090
      d_stack.reset(curr);
618
9486090
      d_lastDecisionLit = TNode::null();
619
      // for activity
620
9486090
      if (doWatchStatus)
621
      {
622
        // initially, mark that we have not found a decision in this
623
8926568
        d_currUnderStatus = d_stack.getCurrentAssertion();
624
8926568
        d_currStatusDec = false;
625
      }
626
9486090
      return true;
627
    }
628
    // assertions should all be satisfied, otherwise we are in conflict
629
524188
    Assert(currValue == SAT_VALUE_TRUE);
630
524188
    if (doWatchStatus)
631
    {
632
      // mark that we did not find a decision in it
633
523924
      ++(d_stats.d_numStatusNoDecision);
634
523924
      d_assertions.notifyStatus(curr, DecisionStatus::NO_DECISION);
635
    }
636
    // already justified, immediately skip
637
524188
    curr = al.getNextAssertion();
638
  }
639
9065482
  return false;
640
}
641
642
10010278
bool JustificationStrategy::isTheoryLiteral(TNode n)
643
{
644
10010278
  return isTheoryAtom(n.getKind() == NOT ? n[0] : n);
645
}
646
647
79370717
bool JustificationStrategy::isTheoryAtom(TNode n)
648
{
649
79370717
  Kind k = n.getKind();
650
79370717
  Assert(k != NOT);
651
65064646
  return k != AND && k != OR && k != IMPLIES && k != ITE && k != XOR
652
96792916
         && (k != EQUAL || !n[0].getType().isBoolean());
653
}
654
655
}  // namespace decision
656
31137
}  // namespace cvc5