GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/theory_engine.cpp Lines: 715 851 84.0 %
Date: 2021-11-05 Branches: 1802 4362 41.3 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Dejan Jovanovic, Morgan Deters
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
 * The theory engine.
14
 */
15
16
#include "theory/theory_engine.h"
17
18
#include <sstream>
19
20
#include "base/map_util.h"
21
#include "decision/decision_engine.h"
22
#include "expr/attribute.h"
23
#include "expr/node_builder.h"
24
#include "expr/node_visitor.h"
25
#include "options/quantifiers_options.h"
26
#include "options/smt_options.h"
27
#include "options/theory_options.h"
28
#include "printer/printer.h"
29
#include "proof/lazy_proof.h"
30
#include "proof/proof_checker.h"
31
#include "proof/proof_ensure_closed.h"
32
#include "prop/prop_engine.h"
33
#include "smt/env.h"
34
#include "smt/logic_exception.h"
35
#include "theory/combination_care_graph.h"
36
#include "theory/decision_manager.h"
37
#include "theory/quantifiers/first_order_model.h"
38
#include "theory/quantifiers_engine.h"
39
#include "theory/relevance_manager.h"
40
#include "theory/rewriter.h"
41
#include "theory/shared_solver.h"
42
#include "theory/theory.h"
43
#include "theory/theory_engine_proof_generator.h"
44
#include "theory/theory_id.h"
45
#include "theory/theory_model.h"
46
#include "theory/theory_traits.h"
47
#include "theory/uf/equality_engine.h"
48
#include "util/resource_manager.h"
49
50
using namespace std;
51
52
using namespace cvc5::theory;
53
54
namespace cvc5 {
55
56
/* -------------------------------------------------------------------------- */
57
58
namespace theory {
59
60
/**
61
 * IMPORTANT: The order of the theories is important. For example, strings
62
 *            depends on arith, quantifiers needs to come as the very last.
63
 *            Do not change this order.
64
 */
65
66
#define CVC5_FOR_EACH_THEORY                                     \
67
  CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_BUILTIN)   \
68
  CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_BOOL)      \
69
  CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_UF)        \
70
  CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_ARITH)     \
71
  CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_BV)        \
72
  CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_FP)        \
73
  CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_ARRAYS)    \
74
  CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_DATATYPES) \
75
  CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_SEP)       \
76
  CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_SETS)      \
77
  CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_BAGS)      \
78
  CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_STRINGS)   \
79
  CVC5_FOR_EACH_THEORY_STATEMENT(cvc5::theory::THEORY_QUANTIFIERS)
80
81
}  // namespace theory
82
83
/* -------------------------------------------------------------------------- */
84
85
inline void flattenAnd(Node n, std::vector<TNode>& out){
86
  Assert(n.getKind() == kind::AND);
87
  for(Node::iterator i=n.begin(), i_end=n.end(); i != i_end; ++i){
88
    Node curr = *i;
89
    if(curr.getKind() == kind::AND){
90
      flattenAnd(curr, out);
91
    }else{
92
      out.push_back(curr);
93
    }
94
  }
95
}
96
97
inline Node flattenAnd(Node n){
98
  std::vector<TNode> out;
99
  flattenAnd(n, out);
100
  return NodeManager::currentNM()->mkNode(kind::AND, out);
101
}
102
103
/**
104
 * Compute the string for a given theory id. In this module, we use
105
 * THEORY_SAT_SOLVER as an id, which is not a normal id but maps to
106
 * THEORY_LAST. Thus, we need our own string conversion here.
107
 *
108
 * @param id The theory id
109
 * @return The string corresponding to the theory id
110
 */
111
2080022
std::string getTheoryString(theory::TheoryId id)
112
{
113
2080022
  if (id == theory::THEORY_SAT_SOLVER)
114
  {
115
1457862
    return "THEORY_SAT_SOLVER";
116
  }
117
  else
118
  {
119
1244320
    std::stringstream ss;
120
622160
    ss << id;
121
622160
    return ss.str();
122
  }
123
}
124
125
15271
void TheoryEngine::finishInit()
126
{
127
15271
  Trace("theory") << "Begin TheoryEngine::finishInit" << std::endl;
128
  // NOTE: This seems to be required since
129
  // theory::TheoryTraits<THEORY>::isParametric cannot be accessed without
130
  // using the CVC5_FOR_EACH_THEORY_STATEMENT macro. -AJR
131
30542
  std::vector<theory::Theory*> paraTheories;
132
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT
133
#undef CVC5_FOR_EACH_THEORY_STATEMENT
134
#endif
135
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY)   \
136
  if (theory::TheoryTraits<THEORY>::isParametric \
137
      && d_logicInfo.isTheoryEnabled(THEORY))    \
138
  {                                              \
139
    paraTheories.push_back(theoryOf(THEORY));    \
140
  }
141
  // Collect the parametric theories, which are given to the theory combination
142
  // manager below
143
15271
  CVC5_FOR_EACH_THEORY;
144
145
  // Initialize the theory combination architecture
146
15271
  if (options().theory.tcMode == options::TcMode::CARE_GRAPH)
147
  {
148
15271
    d_tc.reset(new CombinationCareGraph(d_env, *this, paraTheories));
149
  }
150
  else
151
  {
152
    Unimplemented() << "TheoryEngine::finishInit: theory combination mode "
153
                    << options().theory.tcMode << " not supported";
154
  }
155
  // create the relevance filter if any option requires it
156
15271
  if (options().theory.relevanceFilter || options().smt.produceDifficulty)
157
  {
158
23
    d_relManager.reset(new RelevanceManager(userContext(), Valuation(this)));
159
  }
160
161
  // initialize the quantifiers engine
162
15271
  if (d_logicInfo.isQuantified())
163
  {
164
    // get the quantifiers engine, which is initialized by the quantifiers
165
    // theory
166
12153
    d_quantEngine = d_theoryTable[THEORY_QUANTIFIERS]->getQuantifiersEngine();
167
12153
    Assert(d_quantEngine != nullptr);
168
  }
169
  // finish initializing the quantifiers engine, which must come before
170
  // initializing theory combination, since quantifiers engine may have a
171
  // special model builder object
172
15271
  if (d_logicInfo.isQuantified())
173
  {
174
12153
    d_quantEngine->finishInit(this);
175
  }
176
  // initialize the theory combination manager, which decides and allocates the
177
  // equality engines to use for all theories.
178
15271
  d_tc->finishInit();
179
  // get pointer to the shared solver
180
15271
  d_sharedSolver = d_tc->getSharedSolver();
181
182
  // finish initializing the theories by linking them with the appropriate
183
  // utilities and then calling their finishInit method.
184
213794
  for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) {
185
198523
    Theory* t = d_theoryTable[theoryId];
186
198523
    if (t == nullptr)
187
    {
188
      continue;
189
    }
190
    // setup the pointers to the utilities
191
198523
    const EeTheoryInfo* eeti = d_tc->getEeTheoryInfo(theoryId);
192
198523
    Assert(eeti != nullptr);
193
    // the theory's official equality engine is the one specified by the
194
    // equality engine manager
195
198523
    t->setEqualityEngine(eeti->d_usedEe);
196
    // set the quantifiers engine
197
198523
    t->setQuantifiersEngine(d_quantEngine);
198
    // set the decision manager for the theory
199
198523
    t->setDecisionManager(d_decManager.get());
200
    // finish initializing the theory
201
198523
    t->finishInit();
202
  }
203
15271
  Trace("theory") << "End TheoryEngine::finishInit" << std::endl;
204
15271
}
205
206
15271
TheoryEngine::TheoryEngine(Env& env)
207
    : EnvObj(env),
208
      d_propEngine(nullptr),
209
15271
      d_logicInfo(env.getLogicInfo()),
210
15271
      d_pnm(d_env.isTheoryProofProducing() ? d_env.getProofNodeManager()
211
                                           : nullptr),
212
      d_lazyProof(
213
15271
          d_pnm != nullptr ? new LazyCDProof(
214
10744
              d_pnm, nullptr, userContext(), "TheoryEngine::LazyCDProof")
215
                           : nullptr),
216
15271
      d_tepg(new TheoryEngineProofGenerator(d_pnm, userContext())),
217
      d_tc(nullptr),
218
      d_sharedSolver(nullptr),
219
      d_quantEngine(nullptr),
220
15271
      d_decManager(new DecisionManager(userContext())),
221
      d_relManager(nullptr),
222
      d_inConflict(context(), false),
223
      d_inSatMode(false),
224
      d_hasShutDown(false),
225
      d_incomplete(context(), false),
226
      d_incompleteTheory(context(), THEORY_BUILTIN),
227
      d_incompleteId(context(), IncompleteId::UNKNOWN),
228
      d_propagationMap(context()),
229
      d_propagationMapTimestamp(context(), 0),
230
      d_propagatedLiterals(context()),
231
      d_propagatedLiteralsIndex(context(), 0),
232
      d_atomRequests(context()),
233
15271
      d_combineTheoriesTime(statisticsRegistry().registerTimer(
234
30542
          "TheoryEngine::combineTheoriesTime")),
235
      d_true(),
236
      d_false(),
237
      d_interrupted(false),
238
      d_inPreregister(false),
239
132912
      d_factsAsserted(context(), false)
240
{
241
213794
  for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST;
242
      ++ theoryId)
243
  {
244
198523
    d_theoryTable[theoryId] = NULL;
245
198523
    d_theoryOut[theoryId] = NULL;
246
  }
247
248
15271
  if (options().smt.sortInference)
249
  {
250
20
    d_sortInfer.reset(new SortInference(env));
251
  }
252
253
15271
  d_true = NodeManager::currentNM()->mkConst<bool>(true);
254
15271
  d_false = NodeManager::currentNM()->mkConst<bool>(false);
255
15271
}
256
257
45798
TheoryEngine::~TheoryEngine() {
258
15266
  Assert(d_hasShutDown);
259
260
213724
  for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) {
261
198458
    if(d_theoryTable[theoryId] != NULL) {
262
198410
      delete d_theoryTable[theoryId];
263
198410
      delete d_theoryOut[theoryId];
264
    }
265
  }
266
30532
}
267
268
void TheoryEngine::interrupt() { d_interrupted = true; }
269
1215197
void TheoryEngine::preRegister(TNode preprocessed) {
270
2430394
  Debug("theory") << "TheoryEngine::preRegister( " << preprocessed << ")"
271
1215197
                  << std::endl;
272
1215197
  d_preregisterQueue.push(preprocessed);
273
274
1215197
  if (!d_inPreregister) {
275
    // We're in pre-register
276
1138082
    d_inPreregister = true;
277
278
    // Process the pre-registration queue
279
3568468
    while (!d_preregisterQueue.empty()) {
280
      // Get the next atom to pre-register
281
1215197
      preprocessed = d_preregisterQueue.front();
282
1215197
      d_preregisterQueue.pop();
283
284
      // the atom should not have free variables
285
2430394
      Debug("theory") << "TheoryEngine::preRegister: " << preprocessed
286
1215197
                      << std::endl;
287
1215197
      if (Configuration::isAssertionBuild())
288
      {
289
2430394
        std::unordered_set<Node> fvs;
290
1215197
        expr::getFreeVariables(preprocessed, fvs);
291
1215197
        if (!fvs.empty())
292
        {
293
          Unhandled() << "Preregistered term with free variable: "
294
                      << preprocessed << ", fv=" << *fvs.begin();
295
        }
296
      }
297
      // should not have witness
298
1215197
      Assert(!expr::hasSubtermKind(kind::WITNESS, preprocessed));
299
300
      // pre-register with the shared solver, which handles
301
      // calling prepregister on individual theories, adding shared terms,
302
      // and setting up equalities to propagate in the shared term database.
303
1215197
      Assert(d_sharedSolver != nullptr);
304
1215201
      d_sharedSolver->preRegister(preprocessed);
305
    }
306
307
    // Leaving pre-register
308
1138078
    d_inPreregister = false;
309
  }
310
1215193
}
311
312
void TheoryEngine::printAssertions(const char* tag) {
313
  if (Trace.isOn(tag)) {
314
315
    for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) {
316
      Theory* theory = d_theoryTable[theoryId];
317
      if (theory && d_logicInfo.isTheoryEnabled(theoryId)) {
318
        Trace(tag) << "--------------------------------------------" << endl;
319
        Trace(tag) << "Assertions of " << theory->getId() << ": " << endl;
320
        {
321
          context::CDList<Assertion>::const_iterator it = theory->facts_begin(),
322
                                                     it_end =
323
                                                         theory->facts_end();
324
          for (unsigned i = 0; it != it_end; ++it, ++i)
325
          {
326
            if ((*it).d_isPreregistered)
327
            {
328
              Trace(tag) << "[" << i << "]: ";
329
            }
330
            else
331
            {
332
              Trace(tag) << "(" << i << "): ";
333
            }
334
            Trace(tag) << (*it).d_assertion << endl;
335
          }
336
        }
337
338
        if (d_logicInfo.isSharingEnabled()) {
339
          Trace(tag) << "Shared terms of " << theory->getId() << ": " << endl;
340
          context::CDList<TNode>::const_iterator it = theory->shared_terms_begin(), it_end = theory->shared_terms_end();
341
          for (unsigned i = 0; it != it_end; ++ it, ++i) {
342
              Trace(tag) << "[" << i << "]: " << (*it) << endl;
343
          }
344
        }
345
      }
346
    }
347
  }
348
}
349
350
/**
351
 * Check all (currently-active) theories for conflicts.
352
 * @param effort the effort level to use
353
 */
354
5151605
void TheoryEngine::check(Theory::Effort effort) {
355
  // spendResource();
356
357
  // Reset the interrupt flag
358
5151605
  d_interrupted = false;
359
360
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT
361
#undef CVC5_FOR_EACH_THEORY_STATEMENT
362
#endif
363
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY)                      \
364
  if (theory::TheoryTraits<THEORY>::hasCheck                        \
365
      && d_logicInfo.isTheoryEnabled(THEORY))                       \
366
  {                                                                 \
367
    theoryOf(THEORY)->check(effort);                                \
368
    if (d_inConflict)                                               \
369
    {                                                               \
370
      Debug("conflict") << THEORY << " in conflict. " << std::endl; \
371
      break;                                                        \
372
    }                                                               \
373
  }
374
375
  // Do the checking
376
  try {
377
378
    // Mark the output channel unused (if this is FULL_EFFORT, and nothing
379
    // is done by the theories, no additional check will be needed)
380
5151605
    d_outputChannelUsed = false;
381
382
    // Mark the lemmas flag (no lemmas added)
383
5151605
    d_lemmasAdded = false;
384
385
5151605
    Debug("theory") << "TheoryEngine::check(" << effort << "): d_factsAsserted = " << (d_factsAsserted ? "true" : "false") << endl;
386
387
    // If in full effort, we have a fake new assertion just to jumpstart the checking
388
5151605
    if (Theory::fullEffort(effort)) {
389
88696
      d_factsAsserted = true;
390
      // Reset round for the relevance manager, which notice only sets a flag
391
      // to indicate that its information must be recomputed.
392
88696
      if (d_relManager != nullptr)
393
      {
394
141
        d_relManager->resetRound();
395
      }
396
88696
      d_tc->resetRound();
397
    }
398
399
    // Check until done
400
14611109
    while (d_factsAsserted && !d_inConflict && !d_lemmasAdded) {
401
402
4890033
      Debug("theory") << "TheoryEngine::check(" << effort << "): running check" << endl;
403
404
4890033
      Trace("theory::assertions") << endl;
405
4890033
      if (Trace.isOn("theory::assertions")) {
406
        printAssertions("theory::assertions");
407
      }
408
409
4890033
      if(Theory::fullEffort(effort)) {
410
95406
        Trace("theory::assertions::fulleffort") << endl;
411
95406
        if (Trace.isOn("theory::assertions::fulleffort")) {
412
          printAssertions("theory::assertions::fulleffort");
413
        }
414
      }
415
416
      // Note that we've discharged all the facts
417
4890033
      d_factsAsserted = false;
418
419
      // Do the checking
420
4890033
      CVC5_FOR_EACH_THEORY;
421
422
4729752
      Debug("theory") << "TheoryEngine::check(" << effort << "): running propagation after the initial check" << endl;
423
424
      // We are still satisfiable, propagate as much as possible
425
4729752
      propagate(effort);
426
427
      // We do combination if all has been processed and we are in fullcheck
428
9529100
      if (Theory::fullEffort(effort) && d_logicInfo.isSharingEnabled()
429
4792584
          && !d_factsAsserted && !needCheck() && !d_inConflict)
430
      {
431
        // Do the combination
432
30599
        Debug("theory") << "TheoryEngine::check(" << effort << "): running combination" << endl;
433
        {
434
61198
          TimerStat::CodeTimer combineTheoriesTimer(d_combineTheoriesTime);
435
30599
          d_tc->combineTheories();
436
        }
437
30599
        if(d_logicInfo.isQuantified()){
438
22097
          d_quantEngine->notifyCombineTheories();
439
        }
440
      }
441
    }
442
443
    // Must consult quantifiers theory for last call to ensure sat, or otherwise add a lemma
444
5151601
    if( Theory::fullEffort(effort) && ! d_inConflict && ! needCheck() ) {
445
29638
      Trace("theory::assertions-model") << endl;
446
29638
      if (Trace.isOn("theory::assertions-model")) {
447
        printAssertions("theory::assertions-model");
448
      }
449
      // reset the model in the combination engine
450
29638
      d_tc->resetModel();
451
      //checks for theories requiring the model go at last call
452
414932
      for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) {
453
385294
        if( theoryId!=THEORY_QUANTIFIERS ){
454
355656
          Theory* theory = d_theoryTable[theoryId];
455
355656
          if (theory && d_logicInfo.isTheoryEnabled(theoryId)) {
456
192188
            if( theory->needsCheckLastEffort() ){
457
16064
              if (!d_tc->buildModel())
458
              {
459
                break;
460
              }
461
16064
              theory->check(Theory::EFFORT_LAST_CALL);
462
            }
463
          }
464
        }
465
      }
466
29638
      if (!d_inConflict)
467
      {
468
29638
        if(d_logicInfo.isQuantified()) {
469
          // quantifiers engine must check at last call effort
470
23378
          d_quantEngine->check(Theory::EFFORT_LAST_CALL);
471
        }
472
      }
473
      // notify the relevant manager
474
29623
      if (d_relManager != nullptr)
475
      {
476
120
        d_relManager->notifyCandidateModel(getModel());
477
      }
478
29623
      if (!d_inConflict && !needCheck())
479
      {
480
        // We only mark that we are in "SAT mode". We build the model later only
481
        // if the user asks for it via getBuiltModel.
482
9676
        d_inSatMode = true;
483
      }
484
    }
485
486
5151586
    Debug("theory") << "TheoryEngine::check(" << effort << "): done, we are " << (d_inConflict ? "unsat" : "sat") << (d_lemmasAdded ? " with new lemmas" : " with no new lemmas");
487
5151586
    Debug("theory") << ", need check = " << (needCheck() ? "YES" : "NO") << endl;
488
489
5151586
    if( Theory::fullEffort(effort) && !d_inConflict && !needCheck()) {
490
      // Do post-processing of model from the theories (e.g. used for THEORY_SEP
491
      // to construct heap model)
492
9676
      d_tc->postProcessModel(d_incomplete.get());
493
    }
494
  } catch(const theory::Interrupted&) {
495
    Trace("theory") << "TheoryEngine::check() => interrupted" << endl;
496
  }
497
5151586
}
498
499
4729752
void TheoryEngine::propagate(Theory::Effort effort)
500
{
501
  // Reset the interrupt flag
502
4729752
  d_interrupted = false;
503
504
  // Definition of the statement that is to be run by every theory
505
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT
506
#undef CVC5_FOR_EACH_THEORY_STATEMENT
507
#endif
508
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY)   \
509
  if (theory::TheoryTraits<THEORY>::hasPropagate \
510
      && d_logicInfo.isTheoryEnabled(THEORY))    \
511
  {                                              \
512
    theoryOf(THEORY)->propagate(effort);         \
513
  }
514
515
  // Reset the interrupt flag
516
4729752
  d_interrupted = false;
517
518
  // Propagate for each theory using the statement above
519
4729752
  CVC5_FOR_EACH_THEORY;
520
4729752
}
521
522
3476398
Node TheoryEngine::getNextDecisionRequest()
523
{
524
3476398
  return d_decManager->getNextDecisionRequest();
525
}
526
527
145144
bool TheoryEngine::properConflict(TNode conflict) const {
528
  bool value;
529
145144
  if (conflict.getKind() == kind::AND) {
530
1733043
    for (unsigned i = 0; i < conflict.getNumChildren(); ++ i) {
531
1588515
      if (! getPropEngine()->hasValue(conflict[i], value)) {
532
        Debug("properConflict") << "Bad conflict is due to unassigned atom: "
533
                                << conflict[i] << endl;
534
        return false;
535
      }
536
1588515
      if (! value) {
537
        Debug("properConflict") << "Bad conflict is due to false atom: "
538
                                << conflict[i] << endl;
539
        return false;
540
      }
541
1588515
      if (conflict[i] != Rewriter::rewrite(conflict[i])) {
542
        Debug("properConflict") << "Bad conflict is due to atom not in normal form: "
543
                                << conflict[i] << " vs " << Rewriter::rewrite(conflict[i]) << endl;
544
        return false;
545
      }
546
    }
547
  } else {
548
616
    if (! getPropEngine()->hasValue(conflict, value)) {
549
      Debug("properConflict") << "Bad conflict is due to unassigned atom: "
550
                              << conflict << endl;
551
      return false;
552
    }
553
616
    if(! value) {
554
      Debug("properConflict") << "Bad conflict is due to false atom: "
555
                              << conflict << endl;
556
      return false;
557
    }
558
616
    if (conflict != Rewriter::rewrite(conflict)) {
559
      Debug("properConflict") << "Bad conflict is due to atom not in normal form: "
560
                              << conflict << " vs " << Rewriter::rewrite(conflict) << endl;
561
      return false;
562
    }
563
  }
564
145144
  return true;
565
}
566
567
17326198
TheoryModel* TheoryEngine::getModel()
568
{
569
17326198
  Assert(d_tc != nullptr);
570
17326198
  TheoryModel* m = d_tc->getModel();
571
17326198
  Assert(m != nullptr);
572
17326198
  return m;
573
}
574
575
12702
TheoryModel* TheoryEngine::getBuiltModel()
576
{
577
12702
  Assert(d_tc != nullptr);
578
  // If this method was called, we should be in SAT mode, and produceModels
579
  // should be true.
580
12702
  AlwaysAssert(options().smt.produceModels);
581
12702
  if (!d_inSatMode)
582
  {
583
    // not available, perhaps due to interuption.
584
    return nullptr;
585
  }
586
  // must build model at this point
587
12702
  if (!d_tc->buildModel())
588
  {
589
    return nullptr;
590
  }
591
12701
  return d_tc->getModel();
592
}
593
594
16522
bool TheoryEngine::buildModel()
595
{
596
16522
  Assert(d_tc != nullptr);
597
16522
  return d_tc->buildModel();
598
}
599
600
20558
bool TheoryEngine::presolve() {
601
  // Reset the interrupt flag
602
20558
  d_interrupted = false;
603
604
  // Reset the decision manager. This clears its decision strategies that are
605
  // no longer valid in this user context.
606
20558
  d_decManager->presolve();
607
608
  try {
609
    // Definition of the statement that is to be run by every theory
610
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT
611
#undef CVC5_FOR_EACH_THEORY_STATEMENT
612
#endif
613
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY)   \
614
  if (theory::TheoryTraits<THEORY>::hasPresolve) \
615
  {                                              \
616
    theoryOf(THEORY)->presolve();                \
617
    if (d_inConflict)                            \
618
    {                                            \
619
      return true;                               \
620
    }                                            \
621
  }
622
623
    // Presolve for each theory using the statement above
624
20558
    CVC5_FOR_EACH_THEORY;
625
  } catch(const theory::Interrupted&) {
626
    Trace("theory") << "TheoryEngine::presolve() => interrupted" << endl;
627
  }
628
  // return whether we have a conflict
629
20558
  return false;
630
}/* TheoryEngine::presolve() */
631
632
20535
void TheoryEngine::postsolve() {
633
  // no longer in SAT mode
634
20535
  d_inSatMode = false;
635
  // Reset the interrupt flag
636
20535
  d_interrupted = false;
637
20535
  CVC5_UNUSED bool wasInConflict = d_inConflict;
638
639
  try {
640
    // Definition of the statement that is to be run by every theory
641
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT
642
#undef CVC5_FOR_EACH_THEORY_STATEMENT
643
#endif
644
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY)    \
645
  if (theory::TheoryTraits<THEORY>::hasPostsolve) \
646
  {                                               \
647
    theoryOf(THEORY)->postsolve();                \
648
    Assert(!d_inConflict || wasInConflict)        \
649
        << "conflict raised during postsolve()";  \
650
  }
651
652
    // Postsolve for each theory using the statement above
653
    CVC5_FOR_EACH_THEORY;
654
  } catch(const theory::Interrupted&) {
655
    Trace("theory") << "TheoryEngine::postsolve() => interrupted" << endl;
656
  }
657
20535
}/* TheoryEngine::postsolve() */
658
659
660
2631
void TheoryEngine::notifyRestart() {
661
  // Reset the interrupt flag
662
2631
  d_interrupted = false;
663
664
  // Definition of the statement that is to be run by every theory
665
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT
666
#undef CVC5_FOR_EACH_THEORY_STATEMENT
667
#endif
668
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY)       \
669
  if (theory::TheoryTraits<THEORY>::hasNotifyRestart \
670
      && d_logicInfo.isTheoryEnabled(THEORY))        \
671
  {                                                  \
672
    theoryOf(THEORY)->notifyRestart();               \
673
  }
674
675
  // notify each theory using the statement above
676
2631
  CVC5_FOR_EACH_THEORY;
677
2631
}
678
679
250915
void TheoryEngine::ppStaticLearn(TNode in, NodeBuilder& learned)
680
{
681
  // Reset the interrupt flag
682
250915
  d_interrupted = false;
683
684
  // Definition of the statement that is to be run by every theory
685
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT
686
#undef CVC5_FOR_EACH_THEORY_STATEMENT
687
#endif
688
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY)        \
689
  if (theory::TheoryTraits<THEORY>::hasPpStaticLearn) \
690
  {                                                   \
691
    theoryOf(THEORY)->ppStaticLearn(in, learned);     \
692
  }
693
694
  // static learning for each theory using the statement above
695
250915
  CVC5_FOR_EACH_THEORY;
696
250915
}
697
698
113077
bool TheoryEngine::isRelevant(Node lit) const
699
{
700
113077
  if (d_relManager != nullptr)
701
  {
702
2482
    return d_relManager->isRelevant(lit);
703
  }
704
  // otherwise must assume its relevant
705
110595
  return true;
706
}
707
708
15266
void TheoryEngine::shutdown() {
709
  // Set this first; if a Theory shutdown() throws an exception,
710
  // at least the destruction of the TheoryEngine won't confound
711
  // matters.
712
15266
  d_hasShutDown = true;
713
714
  // Shutdown all the theories
715
213724
  for(TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; ++theoryId) {
716
198458
    if(d_theoryTable[theoryId]) {
717
198410
      theoryOf(theoryId)->shutdown();
718
    }
719
  }
720
15266
}
721
722
97445
theory::Theory::PPAssertStatus TheoryEngine::solve(
723
    TrustNode tliteral, TrustSubstitutionMap& substitutionOut)
724
{
725
  // Reset the interrupt flag
726
97445
  d_interrupted = false;
727
728
194890
  TNode literal = tliteral.getNode();
729
194890
  TNode atom = literal.getKind() == kind::NOT ? literal[0] : literal;
730
97445
  Trace("theory::solve") << "TheoryEngine::solve(" << literal << "): solving with " << theoryOf(atom)->getId() << endl;
731
732
194890
  if(! d_logicInfo.isTheoryEnabled(Theory::theoryOf(atom)) &&
733
97445
     Theory::theoryOf(atom) != THEORY_SAT_SOLVER) {
734
    stringstream ss;
735
    ss << "The logic was specified as " << d_logicInfo.getLogicString()
736
       << ", which doesn't include " << Theory::theoryOf(atom)
737
       << ", but got a preprocessing-time fact for that theory." << endl
738
       << "The fact:" << endl
739
       << literal;
740
    throw LogicException(ss.str());
741
  }
742
743
  Theory::PPAssertStatus solveStatus =
744
97445
      theoryOf(atom)->ppAssert(tliteral, substitutionOut);
745
97445
  Trace("theory::solve") << "TheoryEngine::solve(" << literal << ") => " << solveStatus << endl;
746
194890
  return solveStatus;
747
}
748
749
228078
TrustNode TheoryEngine::ppRewriteEquality(TNode eq)
750
{
751
228078
  Assert(eq.getKind() == kind::EQUAL);
752
456156
  std::vector<SkolemLemma> lems;
753
228078
  TrustNode trn = theoryOf(eq)->ppRewrite(eq, lems);
754
  // should never introduce a skolem to eliminate an equality
755
228078
  Assert(lems.empty());
756
456156
  return trn;
757
}
758
759
19093
void TheoryEngine::notifyPreprocessedAssertions(
760
    const std::vector<Node>& assertions) {
761
  // call all the theories
762
267302
  for (TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST;
763
       ++theoryId) {
764
248209
    if (d_theoryTable[theoryId]) {
765
248209
      theoryOf(theoryId)->ppNotifyAssertions(assertions);
766
    }
767
  }
768
19093
  if (d_relManager != nullptr)
769
  {
770
19
    d_relManager->notifyPreprocessedAssertions(assertions);
771
  }
772
19093
}
773
774
45478111
bool TheoryEngine::markPropagation(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) {
775
  // What and where we are asserting
776
90956222
  NodeTheoryPair toAssert(assertion, toTheoryId, d_propagationMapTimestamp);
777
  // What and where it came from
778
90956222
  NodeTheoryPair toExplain(originalAssertion, fromTheoryId, d_propagationMapTimestamp);
779
780
  // See if the theory already got this literal
781
45478111
  PropagationMap::const_iterator find = d_propagationMap.find(toAssert);
782
45478111
  if (find != d_propagationMap.end()) {
783
    // The theory already knows this
784
13393484
    Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): already there" << endl;
785
13393484
    return false;
786
  }
787
788
32084627
  Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): marking [" << d_propagationMapTimestamp << "] " << assertion << ", " << toTheoryId << " from " << originalAssertion << ", " << fromTheoryId << endl;
789
790
  // Mark the propagation
791
32084627
  d_propagationMap[toAssert] = toExplain;
792
32084627
  d_propagationMapTimestamp = d_propagationMapTimestamp + 1;
793
794
32084627
  return true;
795
}
796
797
798
51216971
void TheoryEngine::assertToTheory(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) {
799
51216971
  Trace("theory::assertToTheory") << "TheoryEngine::assertToTheory(" << assertion << ", " << originalAssertion << "," << toTheoryId << ", " << fromTheoryId << ")" << endl;
800
801
51216971
  Assert(toTheoryId != fromTheoryId);
802
85801160
  if(toTheoryId != THEORY_SAT_SOLVER &&
803
34584189
     ! d_logicInfo.isTheoryEnabled(toTheoryId)) {
804
    stringstream ss;
805
    ss << "The logic was specified as " << d_logicInfo.getLogicString()
806
       << ", which doesn't include " << toTheoryId
807
       << ", but got an asserted fact to that theory." << endl
808
       << "The fact:" << endl
809
       << assertion;
810
    throw LogicException(ss.str());
811
  }
812
813
51216971
  if (d_inConflict) {
814
90549
    return;
815
  }
816
817
  // If sharing is disabled, things are easy
818
51126422
  if (!d_logicInfo.isSharingEnabled()) {
819
5648311
    Assert(assertion == originalAssertion);
820
5648311
    if (fromTheoryId == THEORY_SAT_SOLVER) {
821
      // Send to the apropriate theory
822
4082183
      theory::Theory* toTheory = theoryOf(toTheoryId);
823
      // We assert it, and we know it's preregistereed
824
4082183
      toTheory->assertFact(assertion, true);
825
      // Mark that we have more information
826
4082183
      d_factsAsserted = true;
827
    } else {
828
1566128
      Assert(toTheoryId == THEORY_SAT_SOLVER);
829
      // Check for propositional conflict
830
      bool value;
831
1566128
      if (d_propEngine->hasValue(assertion, value)) {
832
1015149
        if (!value) {
833
25701
          Trace("theory::propagate") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << "): conflict (no sharing)" << endl;
834
51402
          Trace("dtview::conflict")
835
25701
              << ":THEORY-CONFLICT: " << assertion << std::endl;
836
25701
          markInConflict();
837
        } else {
838
989448
          return;
839
        }
840
      }
841
576680
      d_propagatedLiterals.push_back(assertion);
842
    }
843
4658863
    return;
844
  }
845
846
  // determine the actual theory that will process/explain the fact, which is
847
  // THEORY_BUILTIN if the theory uses the central equality engine
848
45478111
  TheoryId toTheoryIdProp = (Theory::expUsingCentralEqualityEngine(toTheoryId))
849
45478111
                                ? THEORY_BUILTIN
850
45478111
                                : toTheoryId;
851
  // If sending to the shared solver, it's also simple
852
45478111
  if (toTheoryId == THEORY_BUILTIN) {
853
14214713
    if (markPropagation(
854
            assertion, originalAssertion, toTheoryIdProp, fromTheoryId))
855
    {
856
      // assert to the shared solver
857
7607232
      bool polarity = assertion.getKind() != kind::NOT;
858
15214464
      TNode atom = polarity ? assertion : assertion[0];
859
7607232
      d_sharedSolver->assertShared(atom, polarity, assertion);
860
    }
861
14214713
    return;
862
  }
863
864
  // Things from the SAT solver are already normalized, so they go
865
  // directly to the apropriate theory
866
31263398
  if (fromTheoryId == THEORY_SAT_SOLVER) {
867
    // We know that this is normalized, so just send it off to the theory
868
11412861
    if (markPropagation(
869
            assertion, originalAssertion, toTheoryIdProp, fromTheoryId))
870
    {
871
      // Is it preregistered
872
11277648
      bool preregistered = d_propEngine->isSatLiteral(assertion) && Theory::theoryOf(assertion) == toTheoryId;
873
      // We assert it
874
11277648
      theoryOf(toTheoryId)->assertFact(assertion, preregistered);
875
      // Mark that we have more information
876
11277648
      d_factsAsserted = true;
877
    }
878
11412861
    return;
879
  }
880
881
  // Propagations to the SAT solver are just enqueued for pickup by
882
  // the SAT solver later
883
19850537
  if (toTheoryId == THEORY_SAT_SOLVER) {
884
15005421
    Assert(toTheoryIdProp == toTheoryId);
885
15005421
    if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) {
886
      // Enqueue for propagation to the SAT solver
887
9140041
      d_propagatedLiterals.push_back(assertion);
888
      // Check for propositional conflicts
889
      bool value;
890
9140041
      if (d_propEngine->hasValue(assertion, value) && !value) {
891
86090
        Trace("theory::propagate")
892
43045
            << "TheoryEngine::assertToTheory(" << assertion << ", "
893
43045
            << toTheoryId << ", " << fromTheoryId << "): conflict (sharing)"
894
43045
            << endl;
895
86090
        Trace("dtview::conflict")
896
43045
            << ":THEORY-CONFLICT: " << assertion << std::endl;
897
43045
        markInConflict();
898
      }
899
    }
900
15005421
    return;
901
  }
902
903
4845116
  Assert(assertion.getKind() == kind::EQUAL
904
         || (assertion.getKind() == kind::NOT
905
             && assertion[0].getKind() == kind::EQUAL));
906
907
  // Normalize
908
9690232
  Node normalizedLiteral = Rewriter::rewrite(assertion);
909
910
  // See if it rewrites false directly -> conflict
911
4845116
  if (normalizedLiteral.isConst()) {
912
21341
    if (!normalizedLiteral.getConst<bool>()) {
913
      // Mark the propagation for explanations
914
415
      if (markPropagation(normalizedLiteral,
915
                          originalAssertion,
916
                          toTheoryIdProp,
917
                          fromTheoryId))
918
      {
919
        // special case, trust node has no proof generator
920
830
        TrustNode trnn = TrustNode::mkTrustConflict(normalizedLiteral);
921
        // Get the explanation (conflict will figure out where it came from)
922
415
        conflict(trnn, toTheoryId);
923
      } else {
924
        Unreachable();
925
      }
926
415
      return;
927
    }
928
  }
929
930
  // Try and assert (note that we assert the non-normalized one)
931
4844701
  if (markPropagation(
932
          assertion, originalAssertion, toTheoryIdProp, fromTheoryId))
933
  {
934
    // Check if has been pre-registered with the theory
935
4059291
    bool preregistered = d_propEngine->isSatLiteral(assertion) && Theory::theoryOf(assertion) == toTheoryId;
936
    // Assert away
937
4059291
    theoryOf(toTheoryId)->assertFact(assertion, preregistered);
938
4059291
    d_factsAsserted = true;
939
  }
940
941
4844701
  return;
942
}
943
944
15487146
void TheoryEngine::assertFact(TNode literal)
945
{
946
15487146
  Trace("theory") << "TheoryEngine::assertFact(" << literal << ")" << endl;
947
948
  // spendResource();
949
950
  // If we're in conflict, nothing to do
951
15487146
  if (d_inConflict) {
952
36047
    return;
953
  }
954
955
  // Get the atom
956
15451099
  bool polarity = literal.getKind() != kind::NOT;
957
30902198
  TNode atom = polarity ? literal : literal[0];
958
959
15451099
  if (d_logicInfo.isSharingEnabled()) {
960
    // If any shared terms, it's time to do sharing work
961
11368916
    d_sharedSolver->preNotifySharedFact(atom);
962
963
    // If it's an equality, assert it to the shared term manager, even though the terms are not
964
    // yet shared. As the terms become shared later, the shared terms manager will then add them
965
    // to the assert the equality to the interested theories
966
11368916
    if (atom.getKind() == kind::EQUAL) {
967
      // Assert it to the the owning theory
968
5718779
      assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
969
      // Shared terms manager will assert to interested theories directly, as
970
      // the terms become shared
971
5718779
      assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ THEORY_SAT_SOLVER);
972
973
      // Now, let's check for any atom triggers from lemmas
974
5718779
      AtomRequests::atom_iterator it = d_atomRequests.getAtomIterator(atom);
975
5760361
      while (!it.done()) {
976
20791
        const AtomRequests::Request& request = it.get();
977
        Node toAssert =
978
41582
            polarity ? (Node)request.d_atom : request.d_atom.notNode();
979
41582
        Debug("theory::atoms") << "TheoryEngine::assertFact(" << literal
980
20791
                               << "): sending requested " << toAssert << endl;
981
20791
        assertToTheory(
982
20791
            toAssert, literal, request.d_toTheory, THEORY_SAT_SOLVER);
983
20791
        it.next();
984
      }
985
986
    } else {
987
      // Not an equality, just assert to the appropriate theory
988
5650137
      assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
989
    }
990
  } else {
991
    // Assert the fact to the appropriate theory directly
992
4082183
    assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
993
  }
994
}
995
996
19267349
bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) {
997
38534698
  Debug("theory::propagate")
998
19267349
      << "TheoryEngine::propagate(" << literal << ", " << theory << ")" << endl;
999
1000
38534698
  Trace("dtview::prop") << std::string(context()->getLevel(), ' ')
1001
19267349
                        << ":THEORY-PROP: " << literal << endl;
1002
1003
  // spendResource();
1004
1005
  // Get the atom
1006
19267349
  bool polarity = literal.getKind() != kind::NOT;
1007
38534698
  TNode atom = polarity ? literal : literal[0];
1008
1009
19267349
  if (d_logicInfo.isSharingEnabled() && atom.getKind() == kind::EQUAL) {
1010
14554895
    if (d_propEngine->isSatLiteral(literal)) {
1011
      // We propagate SAT literals to SAT
1012
11920328
      assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
1013
    }
1014
14554895
    if (theory != THEORY_BUILTIN) {
1015
      // Assert to the shared terms database
1016
8520997
      assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ theory);
1017
    }
1018
  } else {
1019
    // Just send off to the SAT solver
1020
4712454
    Assert(d_propEngine->isSatLiteral(literal));
1021
4712454
    assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
1022
  }
1023
1024
38534698
  return !d_inConflict;
1025
}
1026
1027
15308
const LogicInfo& TheoryEngine::getLogicInfo() const { return d_logicInfo; }
1028
1029
1437
bool TheoryEngine::getSepHeapTypes(TypeNode& locType, TypeNode& dataType) const
1030
{
1031
1437
  if (d_sepLocType.isNull())
1032
  {
1033
1415
    return false;
1034
  }
1035
22
  locType = d_sepLocType;
1036
22
  dataType = d_sepDataType;
1037
22
  return true;
1038
}
1039
1040
120
void TheoryEngine::declareSepHeap(TypeNode locT, TypeNode dataT)
1041
{
1042
120
  Theory* tsep = theoryOf(THEORY_SEP);
1043
120
  if (tsep == nullptr)
1044
  {
1045
    Assert(false) << "TheoryEngine::declareSepHeap called without the "
1046
                     "separation logic theory enabled";
1047
    return;
1048
  }
1049
1050
  // Definition of the statement that is to be run by every theory
1051
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT
1052
#undef CVC5_FOR_EACH_THEORY_STATEMENT
1053
#endif
1054
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \
1055
  theoryOf(THEORY)->declareSepHeap(locT, dataT);
1056
1057
  // notify each theory using the statement above
1058
120
  CVC5_FOR_EACH_THEORY;
1059
1060
  // remember the types we have set
1061
118
  d_sepLocType = locT;
1062
118
  d_sepDataType = dataT;
1063
}
1064
1065
1204234
theory::EqualityStatus TheoryEngine::getEqualityStatus(TNode a, TNode b) {
1066
1204234
  Assert(a.getType().isComparableTo(b.getType()));
1067
1204234
  return d_sharedSolver->getEqualityStatus(a, b);
1068
}
1069
1070
const std::unordered_set<TNode>& TheoryEngine::getRelevantAssertions(
1071
    bool& success)
1072
{
1073
  // if we are not in SAT mode, or there is no relevance manager, we fail
1074
  if (!d_inSatMode || d_relManager == nullptr)
1075
  {
1076
    success = false;
1077
    return d_emptyRelevantSet;
1078
  }
1079
  return d_relManager->getRelevantAssertions(success);
1080
}
1081
1082
4
void TheoryEngine::getDifficultyMap(std::map<Node, Node>& dmap)
1083
{
1084
4
  Assert(d_relManager != nullptr);
1085
4
  d_relManager->getDifficultyMap(dmap);
1086
4
}
1087
1088
4589
Node TheoryEngine::getModelValue(TNode var) {
1089
4589
  if (var.isConst())
1090
  {
1091
    // the model value of a constant must be itself
1092
    return var;
1093
  }
1094
4589
  Assert(d_sharedSolver->isShared(var));
1095
4589
  return theoryOf(Theory::theoryOf(var.getType()))->getModelValue(var);
1096
}
1097
1098
116943
TrustNode TheoryEngine::getExplanation(TNode node)
1099
{
1100
233886
  Debug("theory::explain") << "TheoryEngine::getExplanation(" << node
1101
116943
                           << "): current propagation index = "
1102
116943
                           << d_propagationMapTimestamp << endl;
1103
116943
  bool polarity = node.getKind() != kind::NOT;
1104
233886
  TNode atom = polarity ? node : node[0];
1105
1106
  // If we're not in shared mode, explanations are simple
1107
116943
  if (!d_logicInfo.isSharingEnabled())
1108
  {
1109
68468
    Debug("theory::explain")
1110
34234
        << "TheoryEngine::getExplanation: sharing is NOT enabled. "
1111
34234
        << " Responsible theory is: " << theoryOf(atom)->getId() << std::endl;
1112
1113
68468
    TrustNode texplanation = theoryOf(atom)->explain(node);
1114
68468
    Node explanation = texplanation.getNode();
1115
68468
    Debug("theory::explain") << "TheoryEngine::getExplanation(" << node
1116
34234
                             << ") => " << explanation << endl;
1117
34234
    if (isProofEnabled())
1118
    {
1119
9571
      texplanation.debugCheckClosed(
1120
          "te-proof-exp", "texplanation no share", false);
1121
      // check if no generator, if so, add THEORY_LEMMA
1122
9571
      if (texplanation.getGenerator() == nullptr)
1123
      {
1124
        Node proven = texplanation.getProven();
1125
        TheoryId tid = theoryOf(atom)->getId();
1126
        Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(tid);
1127
        d_lazyProof->addStep(proven, PfRule::THEORY_LEMMA, {}, {proven, tidn});
1128
        texplanation =
1129
            TrustNode::mkTrustPropExp(node, explanation, d_lazyProof.get());
1130
      }
1131
    }
1132
34234
    return texplanation;
1133
  }
1134
1135
165418
  Debug("theory::explain") << "TheoryEngine::getExplanation: sharing IS enabled"
1136
82709
                           << std::endl;
1137
1138
  // Initial thing to explain
1139
165418
  NodeTheoryPair toExplain(node, THEORY_SAT_SOLVER, d_propagationMapTimestamp);
1140
82709
  Assert(d_propagationMap.find(toExplain) != d_propagationMap.end());
1141
1142
165418
  NodeTheoryPair nodeExplainerPair = d_propagationMap[toExplain];
1143
165418
  Debug("theory::explain")
1144
82709
      << "TheoryEngine::getExplanation: explainer for node "
1145
82709
      << nodeExplainerPair.d_node
1146
82709
      << " is theory: " << nodeExplainerPair.d_theory << std::endl;
1147
1148
  // Create the workplace for explanations
1149
165418
  std::vector<NodeTheoryPair> vec{d_propagationMap[toExplain]};
1150
  // Process the explanation
1151
165418
  TrustNode texplanation = getExplanation(vec);
1152
165418
  Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => "
1153
82709
                           << texplanation.getNode() << endl;
1154
82709
  return texplanation;
1155
}
1156
1157
65000
struct AtomsCollect {
1158
1159
  std::vector<TNode> d_atoms;
1160
  std::unordered_set<TNode> d_visited;
1161
1162
 public:
1163
  typedef void return_type;
1164
1165
408130
  bool alreadyVisited(TNode current, TNode parent) {
1166
    // Check if already visited
1167
408130
    if (d_visited.find(current) != d_visited.end()) return true;
1168
    // Don't visit non-boolean
1169
377257
    if (!current.getType().isBoolean()) return true;
1170
    // New node
1171
306911
    return false;
1172
  }
1173
1174
102846
  void visit(TNode current, TNode parent) {
1175
102846
    if (Theory::theoryOf(current) != theory::THEORY_BOOL) {
1176
39473
      d_atoms.push_back(current);
1177
    }
1178
102846
    d_visited.insert(current);
1179
102846
  }
1180
1181
32500
  void start(TNode node) {}
1182
32500
  void done(TNode node) {}
1183
1184
32500
  std::vector<TNode> getAtoms() const {
1185
32500
    return d_atoms;
1186
  }
1187
};
1188
1189
32500
void TheoryEngine::ensureLemmaAtoms(TNode n, theory::TheoryId atomsTo)
1190
{
1191
32500
  Assert(atomsTo != THEORY_LAST);
1192
65000
  Debug("theory::atoms") << "TheoryEngine::ensureLemmaAtoms(" << n << ", "
1193
32500
                         << atomsTo << ")" << endl;
1194
65000
  AtomsCollect collectAtoms;
1195
32500
  NodeVisitor<AtomsCollect>::run(collectAtoms, n);
1196
32500
  ensureLemmaAtoms(collectAtoms.getAtoms(), atomsTo);
1197
32500
}
1198
1199
32500
void TheoryEngine::ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::TheoryId atomsTo) {
1200
71973
  for (unsigned i = 0; i < atoms.size(); ++ i) {
1201
1202
    // Non-equality atoms are either owned by theory or they don't make sense
1203
39473
    if (atoms[i].getKind() != kind::EQUAL) {
1204
42021
      continue;
1205
    }
1206
1207
    // The equality
1208
36925
    Node eq = atoms[i];
1209
    // Simple normalization to not repeat stuff
1210
30873
    if (eq[0] > eq[1]) {
1211
      eq = eq[1].eqNode(eq[0]);
1212
    }
1213
1214
    // Rewrite the equality
1215
36925
    Node eqNormalized = Rewriter::rewrite(atoms[i]);
1216
1217
61746
    Debug("theory::atoms") << "TheoryEngine::ensureLemmaAtoms(): " << eq
1218
30873
                           << " with nf " << eqNormalized << endl;
1219
1220
    // If the equality is a boolean constant, we send immediately
1221
30877
    if (eqNormalized.isConst()) {
1222
4
      if (eqNormalized.getConst<bool>()) {
1223
        assertToTheory(eq, eqNormalized, /** to */ atomsTo, /** Sat solver */ theory::THEORY_SAT_SOLVER);
1224
      } else {
1225
4
        assertToTheory(eq.notNode(), eqNormalized.notNode(), /** to */ atomsTo, /** Sat solver */ theory::THEORY_SAT_SOLVER);
1226
      }
1227
4
      continue;
1228
30869
    }else if( eqNormalized.getKind() != kind::EQUAL){
1229
      Assert(eqNormalized.getKind() == kind::BOOLEAN_TERM_VARIABLE
1230
             || (eqNormalized.getKind() == kind::NOT
1231
                 && eqNormalized[0].getKind() == kind::BOOLEAN_TERM_VARIABLE));
1232
      // this happens for Boolean term equalities V = true that are rewritten to V, we should skip
1233
      //  TODO : revisit this
1234
      continue;
1235
    }
1236
1237
    // If the normalization did the just flips, keep the flip
1238
30869
    if (eqNormalized[0] == eq[1] && eqNormalized[1] == eq[0]) {
1239
1714
      eq = eqNormalized;
1240
    }
1241
1242
    // Check if the equality is already known by the sat solver
1243
30869
    if (d_propEngine->isSatLiteral(eqNormalized)) {
1244
      bool value;
1245
25508
      if (d_propEngine->hasValue(eqNormalized, value)) {
1246
49634
        if (value) {
1247
24779
          assertToTheory(eq, eqNormalized, atomsTo, theory::THEORY_SAT_SOLVER);
1248
49596
          continue;
1249
        } else {
1250
38
          assertToTheory(eq.notNode(), eqNormalized.notNode(), atomsTo, theory::THEORY_SAT_SOLVER);
1251
38
          continue;
1252
        }
1253
      }
1254
    }
1255
1256
    // If the theory is asking about a different form, or the form is ok but if will go to a different theory
1257
    // then we must figure it out
1258
6052
    if (eqNormalized != eq || Theory::theoryOf(eq) != atomsTo) {
1259
      // If you get eqNormalized, send atoms[i] to atomsTo
1260
5040
      d_atomRequests.add(eqNormalized, eq, atomsTo);
1261
    }
1262
  }
1263
32500
}
1264
1265
509538
void TheoryEngine::lemma(TrustNode tlemma,
1266
                         theory::LemmaProperty p,
1267
                         theory::TheoryId from)
1268
{
1269
  // For resource-limiting (also does a time check).
1270
  // spendResource();
1271
509538
  Assert(tlemma.getKind() == TrustNodeKind::LEMMA
1272
         || tlemma.getKind() == TrustNodeKind::CONFLICT);
1273
  // get the node
1274
1019076
  Node node = tlemma.getNode();
1275
1019076
  Node lemma = tlemma.getProven();
1276
1277
509538
  Assert(!expr::hasFreeVar(lemma));
1278
1279
  // when proofs are enabled, we ensure the trust node has a generator by
1280
  // adding a trust step to the lazy proof maintained by this class
1281
509538
  if (isProofEnabled())
1282
  {
1283
    // ensure proof: set THEORY_LEMMA if no generator is provided
1284
69972
    if (tlemma.getGenerator() == nullptr)
1285
    {
1286
      // internal lemmas should have generators
1287
6611
      Assert(from != THEORY_LAST);
1288
      // add theory lemma step to proof
1289
13222
      Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(from);
1290
6611
      d_lazyProof->addStep(lemma, PfRule::THEORY_LEMMA, {}, {lemma, tidn});
1291
      // update the trust node
1292
6611
      tlemma = TrustNode::mkTrustLemma(lemma, d_lazyProof.get());
1293
    }
1294
    // ensure closed
1295
69972
    tlemma.debugCheckClosed("te-proof-debug", "TheoryEngine::lemma_initial");
1296
  }
1297
1298
  // assert the lemma
1299
509540
  d_propEngine->assertLemma(tlemma, p);
1300
1301
  // If specified, we must add this lemma to the set of those that need to be
1302
  // justified, where note we pass all auxiliary lemmas in skAsserts as well,
1303
  // since these by extension must be justified as well.
1304
509536
  if (d_relManager != nullptr)
1305
  {
1306
1134
    std::vector<Node> skAsserts;
1307
1134
    std::vector<Node> sks;
1308
    Node retLemma =
1309
1134
        d_propEngine->getPreprocessedTerm(tlemma.getProven(), skAsserts, sks);
1310
567
    if (isLemmaPropertyNeedsJustify(p))
1311
    {
1312
      d_relManager->notifyPreprocessedAssertion(retLemma);
1313
      d_relManager->notifyPreprocessedAssertions(skAsserts);
1314
    }
1315
567
    d_relManager->notifyLemma(retLemma);
1316
  }
1317
1318
  // Mark that we added some lemmas
1319
509536
  d_lemmasAdded = true;
1320
509536
}
1321
1322
213890
void TheoryEngine::markInConflict()
1323
{
1324
#ifdef CVC5_FOR_EACH_THEORY_STATEMENT
1325
#undef CVC5_FOR_EACH_THEORY_STATEMENT
1326
#endif
1327
#define CVC5_FOR_EACH_THEORY_STATEMENT(THEORY) \
1328
  theoryOf(THEORY)->notifyInConflict();
1329
213890
  CVC5_FOR_EACH_THEORY;
1330
213890
  d_inConflict = true;
1331
213890
}
1332
1333
145144
void TheoryEngine::conflict(TrustNode tconflict, TheoryId theoryId)
1334
{
1335
145144
  Assert(tconflict.getKind() == TrustNodeKind::CONFLICT);
1336
1337
290288
  TNode conflict = tconflict.getNode();
1338
290288
  Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", "
1339
145144
                            << theoryId << ")" << endl;
1340
145144
  Trace("te-proof-debug") << "Check closed conflict" << std::endl;
1341
  // doesn't require proof generator, yet, since THEORY_LEMMA is added below
1342
145144
  tconflict.debugCheckClosed(
1343
      "te-proof-debug", "TheoryEngine::conflict_initial", false);
1344
1345
145144
  Trace("dtview::conflict") << ":THEORY-CONFLICT: " << conflict << std::endl;
1346
1347
  // Mark that we are in conflict
1348
145144
  markInConflict();
1349
1350
  // In the multiple-theories case, we need to reconstruct the conflict
1351
145144
  if (d_logicInfo.isSharingEnabled()) {
1352
    // Create the workplace for explanations
1353
247524
    std::vector<NodeTheoryPair> vec;
1354
123762
    vec.push_back(
1355
247524
        NodeTheoryPair(conflict, theoryId, d_propagationMapTimestamp));
1356
1357
    // Process the explanation
1358
247524
    TrustNode tncExp = getExplanation(vec);
1359
247524
    Node fullConflict = tncExp.getNode();
1360
1361
123762
    if (isProofEnabled())
1362
    {
1363
28940
      Trace("te-proof-debug")
1364
14470
          << "Check closed conflict explained with sharing" << std::endl;
1365
14470
      tncExp.debugCheckClosed("te-proof-debug",
1366
                              "TheoryEngine::conflict_explained_sharing");
1367
14470
      Trace("te-proof-debug") << "Process conflict: " << conflict << std::endl;
1368
28940
      Trace("te-proof-debug") << "Conflict " << tconflict << " from "
1369
14470
                              << tconflict.identifyGenerator() << std::endl;
1370
28940
      Trace("te-proof-debug") << "Explanation " << tncExp << " from "
1371
14470
                              << tncExp.identifyGenerator() << std::endl;
1372
14470
      Assert(d_lazyProof != nullptr);
1373
14470
      if (tconflict.getGenerator() != nullptr)
1374
      {
1375
14032
        d_lazyProof->addLazyStep(tconflict.getProven(),
1376
                                 tconflict.getGenerator());
1377
      }
1378
      else
1379
      {
1380
        // add theory lemma step
1381
876
        Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(theoryId);
1382
876
        Node conf = tconflict.getProven();
1383
438
        d_lazyProof->addStep(conf, PfRule::THEORY_LEMMA, {}, {conf, tidn});
1384
      }
1385
      // store the explicit step, which should come from a different
1386
      // generator, e.g. d_tepg.
1387
28940
      Node proven = tncExp.getProven();
1388
14470
      Assert(tncExp.getGenerator() != d_lazyProof.get());
1389
28940
      Trace("te-proof-debug") << "add lazy step " << tncExp.identifyGenerator()
1390
14470
                              << " for " << proven << std::endl;
1391
14470
      d_lazyProof->addLazyStep(proven, tncExp.getGenerator());
1392
14470
      pfgEnsureClosed(proven,
1393
14470
                      d_lazyProof.get(),
1394
                      "te-proof-debug",
1395
                      "TheoryEngine::conflict_during");
1396
28940
      Node fullConflictNeg = fullConflict.notNode();
1397
28940
      std::vector<Node> children;
1398
14470
      children.push_back(proven);
1399
28940
      std::vector<Node> args;
1400
14470
      args.push_back(fullConflictNeg);
1401
14470
      if (conflict == d_false)
1402
      {
1403
120
        AlwaysAssert(proven == fullConflictNeg);
1404
      }
1405
      else
1406
      {
1407
14350
        if (!CDProof::isSame(fullConflict, conflict))
1408
        {
1409
          // ------------------------- explained  ---------- from theory
1410
          // fullConflict => conflict              ~conflict
1411
          // ------------------------------------------ MACRO_SR_PRED_TRANSFORM
1412
          // ~fullConflict
1413
13865
          children.push_back(conflict.notNode());
1414
13865
          args.push_back(mkMethodId(MethodId::SB_LITERAL));
1415
13865
          d_lazyProof->addStep(
1416
              fullConflictNeg, PfRule::MACRO_SR_PRED_TRANSFORM, children, args);
1417
        }
1418
      }
1419
    }
1420
    // pass the processed trust node
1421
    TrustNode tconf =
1422
247524
        TrustNode::mkTrustConflict(fullConflict, d_lazyProof.get());
1423
247524
    Debug("theory::conflict")
1424
123762
        << "TheoryEngine::conflict(" << conflict << ", " << theoryId
1425
123762
        << "): full = " << fullConflict << endl;
1426
123762
    Assert(properConflict(fullConflict));
1427
247524
    Trace("te-proof-debug")
1428
123762
        << "Check closed conflict with sharing" << std::endl;
1429
123762
    if (isProofEnabled())
1430
    {
1431
14470
      tconf.debugCheckClosed("te-proof-debug", "TheoryEngine::conflict:sharing");
1432
    }
1433
123762
    lemma(tconf, LemmaProperty::REMOVABLE);
1434
  } else {
1435
    // When only one theory, the conflict should need no processing
1436
21382
    Assert(properConflict(conflict));
1437
    // pass the trust node that was sent from the theory
1438
21382
    lemma(tconflict, LemmaProperty::REMOVABLE, theoryId);
1439
  }
1440
145144
}
1441
1442
4992
void TheoryEngine::setIncomplete(theory::TheoryId theory,
1443
                                 theory::IncompleteId id)
1444
{
1445
4992
  d_incomplete = true;
1446
4992
  d_incompleteTheory = theory;
1447
4992
  d_incompleteId = id;
1448
4992
}
1449
1450
206471
TrustNode TheoryEngine::getExplanation(
1451
    std::vector<NodeTheoryPair>& explanationVector)
1452
{
1453
206471
  Assert(explanationVector.size() == 1);
1454
412942
  Node conclusion = explanationVector[0].d_node;
1455
  // if the theory explains using the central equality engine, we always start
1456
  // with THEORY_BUILTIN.
1457
206471
  if (Theory::expUsingCentralEqualityEngine(explanationVector[0].d_theory))
1458
  {
1459
47713
    explanationVector[0].d_theory = THEORY_BUILTIN;
1460
  }
1461
412942
  std::shared_ptr<LazyCDProof> lcp;
1462
206471
  if (isProofEnabled())
1463
  {
1464
40248
    Trace("te-proof-exp") << "=== TheoryEngine::getExplanation " << conclusion
1465
20124
                          << std::endl;
1466
    // We do not use auto-symmetry in this proof, since in very rare cases, it
1467
    // is possible that the proof of explanations is cyclic when considering
1468
    // (dis)equalities modulo symmetry, where such a proof looks like:
1469
    // x = y
1470
    // -----
1471
    //   A    ...
1472
    // ----------
1473
    //   y = x
1474
    // Notice that this complication arises since propagations consider
1475
    // equalities that are not in rewritten form. This complication would not
1476
    // exist otherwise. It is the shared term database that introduces these
1477
    // unrewritten equalities; it must do so since theory combination requires
1478
    // communicating arrangements between shared terms, and the rewriter
1479
    // for arithmetic equalities does not preserve terms, e.g. x=y may become
1480
    // x+-1*y=0.
1481
40248
    lcp.reset(new LazyCDProof(d_pnm,
1482
                              nullptr,
1483
                              nullptr,
1484
                              "TheoryEngine::LazyCDProof::getExplanation",
1485
20124
                              false));
1486
  }
1487
206471
  unsigned i = 0; // Index of the current literal we are processing
1488
1489
412942
  std::unique_ptr<std::set<Node>> inputAssertions = nullptr;
1490
  // the overall explanation
1491
412942
  std::set<TNode> exp;
1492
  // vector of trust nodes to explain at the end
1493
412942
  std::vector<std::pair<TheoryId, TrustNode>> texplains;
1494
  // cache of nodes we have already explained by some theory
1495
412942
  std::unordered_map<Node, size_t> cache;
1496
1497
8499429
  while (i < explanationVector.size()) {
1498
    // Get the current literal to explain
1499
4507275
    NodeTheoryPair toExplain = explanationVector[i];
1500
1501
8292958
    Debug("theory::explain")
1502
4146479
        << "[i=" << i << "] TheoryEngine::explain(): processing ["
1503
4146479
        << toExplain.d_timestamp << "] " << toExplain.d_node << " sent from "
1504
4146479
        << toExplain.d_theory << endl;
1505
1506
8415646
    if (cache.find(toExplain.d_node) != cache.end()
1507
4146479
        && cache[toExplain.d_node] < toExplain.d_timestamp)
1508
    {
1509
122688
      ++i;
1510
122688
      continue;
1511
    }
1512
4023791
    cache[toExplain.d_node] = toExplain.d_timestamp;
1513
1514
    // If a true constant or a negation of a false constant we can ignore it
1515
8060273
    if ((toExplain.d_node.isConst() && toExplain.d_node.getConst<bool>())
1516
12071373
        || (toExplain.d_node.getKind() == kind::NOT
1517
4503906
            && toExplain.d_node[0].isConst()
1518
4023791
            && !toExplain.d_node[0].getConst<bool>()))
1519
    {
1520
12276
      ++ i;
1521
      // if we are building a proof
1522
12276
      if (lcp != nullptr)
1523
      {
1524
2880
        Trace("te-proof-exp")
1525
1440
            << "- explain " << toExplain.d_node << " trivially..." << std::endl;
1526
        // ------------------MACRO_SR_PRED_INTRO
1527
        // toExplain.d_node
1528
2880
        std::vector<Node> children;
1529
2880
        std::vector<Node> args;
1530
1440
        args.push_back(toExplain.d_node);
1531
1440
        lcp->addStep(
1532
            toExplain.d_node, PfRule::MACRO_SR_PRED_INTRO, children, args);
1533
      }
1534
12276
      continue;
1535
    }
1536
1537
    // If from the SAT solver, keep it
1538
5443799
    if (toExplain.d_theory == THEORY_SAT_SOLVER)
1539
    {
1540
2864568
      Debug("theory::explain")
1541
1432284
          << "\tLiteral came from THEORY_SAT_SOLVER. Keeping it." << endl;
1542
1432284
      exp.insert(explanationVector[i++].d_node);
1543
      // it will be a free assumption in the proof
1544
1432284
      Trace("te-proof-exp") << "- keep " << toExplain.d_node << std::endl;
1545
1432284
      continue;
1546
    }
1547
1548
    // If an and, expand it
1549
2579231
    if (toExplain.d_node.getKind() == kind::AND)
1550
    {
1551
768406
      Debug("theory::explain")
1552
384203
          << "TheoryEngine::explain(): expanding " << toExplain.d_node
1553
384203
          << " got from " << toExplain.d_theory << endl;
1554
384203
      size_t nchild = toExplain.d_node.getNumChildren();
1555
2129183
      for (size_t k = 0; k < nchild; ++k)
1556
      {
1557
        NodeTheoryPair newExplain(
1558
3489960
            toExplain.d_node[k], toExplain.d_theory, toExplain.d_timestamp);
1559
1744980
        explanationVector.push_back(newExplain);
1560
      }
1561
384203
      if (lcp != nullptr)
1562
      {
1563
91984
        Trace("te-proof-exp")
1564
45992
            << "- AND expand " << toExplain.d_node << std::endl;
1565
        // delay explanation, use a dummy trust node
1566
        TrustNode tnAndExp = TrustNode::mkTrustPropExp(
1567
91984
            toExplain.d_node, toExplain.d_node, nullptr);
1568
45992
        texplains.push_back(
1569
91984
            std::pair<TheoryId, TrustNode>(THEORY_LAST, tnAndExp));
1570
      }
1571
384203
      ++ i;
1572
384203
      continue;
1573
    }
1574
1575
    // See if it was sent to the theory by another theory
1576
2195028
    PropagationMap::const_iterator find = d_propagationMap.find(toExplain);
1577
2195028
    if (find != d_propagationMap.end()) {
1578
4160044
      Debug("theory::explain")
1579
2080022
          << "\tTerm was propagated by another theory (theory = "
1580
2080022
          << getTheoryString((*find).second.d_theory) << ")" << std::endl;
1581
      // There is some propagation, check if its a timely one
1582
2080022
      if ((*find).second.d_timestamp < toExplain.d_timestamp)
1583
      {
1584
3668464
        Debug("theory::explain")
1585
1834232
            << "\tRelevant timetsamp, pushing " << (*find).second.d_node
1586
1834232
            << "to index = " << explanationVector.size() << std::endl;
1587
1834232
        explanationVector.push_back((*find).second);
1588
1834232
        ++i;
1589
1590
1834232
        if (lcp != nullptr)
1591
        {
1592
214022
          if (toExplain.d_node != (*find).second.d_node)
1593
          {
1594
6708
            Trace("te-proof-exp")
1595
3354
                << "- t-explained cached: " << toExplain.d_node << " by "
1596
3354
                << (*find).second.d_node << std::endl;
1597
            // delay explanation, use a dummy trust node that says that
1598
            // (*find).second.d_node explains toExplain.d_node.
1599
            TrustNode tnRewExp = TrustNode::mkTrustPropExp(
1600
6708
                toExplain.d_node, (*find).second.d_node, nullptr);
1601
3354
            texplains.push_back(
1602
6708
                std::pair<TheoryId, TrustNode>(THEORY_LAST, tnRewExp));
1603
          }
1604
        }
1605
1834232
        continue;
1606
      }
1607
    }
1608
    // It was produced by the theory, so ask for an explanation
1609
    TrustNode texplanation =
1610
721592
        d_sharedSolver->explain(toExplain.d_node, toExplain.d_theory);
1611
360796
    if (lcp != nullptr)
1612
    {
1613
44730
      texplanation.debugCheckClosed("te-proof-exp", "texplanation", false);
1614
89460
      Trace("te-proof-exp")
1615
44730
          << "- t-explained[" << toExplain.d_theory << "]: " << toExplain.d_node
1616
44730
          << " by " << texplanation.getNode() << std::endl;
1617
      // should prove the propagation we asked for
1618
44730
      Assert(texplanation.getKind() == TrustNodeKind::PROP_EXP
1619
             && texplanation.getProven()[1] == toExplain.d_node);
1620
      // We add it to the list of theory explanations, to be processed at
1621
      // the end of this method. We wait to explain here because it may
1622
      // be that a later explanation may preempt the need for proving this
1623
      // step. For instance, if the conclusion lit is later added as an
1624
      // assumption in the final explanation. This avoids cyclic proofs.
1625
44730
      texplains.push_back(
1626
89460
          std::pair<TheoryId, TrustNode>(toExplain.d_theory, texplanation));
1627
    }
1628
721592
    Node explanation = texplanation.getNode();
1629
1630
721592
    Debug("theory::explain")
1631
360796
        << "TheoryEngine::explain(): got explanation " << explanation
1632
360796
        << " got from " << toExplain.d_theory << endl;
1633
360796
    Assert(explanation != toExplain.d_node)
1634
        << "wasn't sent to you, so why are you explaining it trivially, for "
1635
           "fact "
1636
        << explanation;
1637
    // Mark the explanation
1638
    NodeTheoryPair newExplain(
1639
721592
        explanation, toExplain.d_theory, toExplain.d_timestamp);
1640
360796
    explanationVector.push_back(newExplain);
1641
1642
360796
    ++ i;
1643
  }
1644
1645
  // make the explanation node
1646
412942
  Node expNode;
1647
206471
  if (exp.size() == 0)
1648
  {
1649
    // Normalize to true
1650
45
    expNode = NodeManager::currentNM()->mkConst<bool>(true);
1651
  }
1652
206426
  else if (exp.size() == 1)
1653
  {
1654
    // All the same, or just one
1655
7106
    expNode = *exp.begin();
1656
  }
1657
  else
1658
  {
1659
398640
    NodeBuilder conjunction(kind::AND);
1660
199320
    std::set<TNode>::const_iterator it = exp.begin();
1661
199320
    std::set<TNode>::const_iterator it_end = exp.end();
1662
2944808
    while (it != it_end)
1663
    {
1664
1372744
      conjunction << *it;
1665
1372744
      ++it;
1666
    }
1667
199320
    expNode = conjunction;
1668
  }
1669
  // if we are building a proof, go back through the explanations and
1670
  // build the proof
1671
206471
  if (lcp != nullptr)
1672
  {
1673
20124
    if (Trace.isOn("te-proof-exp"))
1674
    {
1675
      Trace("te-proof-exp") << "Explanation is:" << std::endl;
1676
      for (TNode e : exp)
1677
      {
1678
        Trace("te-proof-exp") << "  " << e << std::endl;
1679
      }
1680
      Trace("te-proof-exp") << "=== Replay explanations..." << std::endl;
1681
    }
1682
    // Now, go back and add the necessary steps of theory explanations, i.e.
1683
    // add those that prove things that aren't in the final explanation. We
1684
    // iterate in reverse order so that most recent steps take priority. This
1685
    // avoids cyclic proofs in the lazy proof we are building (lcp).
1686
94076
    for (std::vector<std::pair<TheoryId, TrustNode>>::reverse_iterator
1687
20124
             it = texplains.rbegin(),
1688
20124
             itEnd = texplains.rend();
1689
114200
         it != itEnd;
1690
         ++it)
1691
    {
1692
137091
      TrustNode trn = it->second;
1693
94076
      Assert(trn.getKind() == TrustNodeKind::PROP_EXP);
1694
137091
      Node proven = trn.getProven();
1695
94076
      Assert(proven.getKind() == kind::IMPLIES);
1696
137091
      Node tConc = proven[1];
1697
94076
      Trace("te-proof-exp") << "- Process " << trn << std::endl;
1698
98074
      if (exp.find(tConc) != exp.end())
1699
      {
1700
        // already added to proof
1701
3998
        Trace("te-proof-exp") << "...already added" << std::endl;
1702
3998
        continue;
1703
      }
1704
      // remember that we've explained this formula, to avoid cycles in lcp
1705
90078
      exp.insert(tConc);
1706
90078
      TheoryId ttid = it->first;
1707
133093
      Node tExp = proven[0];
1708
90078
      if (ttid == THEORY_LAST)
1709
      {
1710
47063
        if (tConc == tExp)
1711
        {
1712
          // dummy trust node, do AND expansion
1713
44939
          Assert(tConc.getKind() == kind::AND);
1714
          // tConc[0] ... tConc[n]
1715
          // ---------------------- AND_INTRO
1716
          // tConc
1717
89878
          std::vector<Node> pfChildren;
1718
44939
          pfChildren.insert(pfChildren.end(), tConc.begin(), tConc.end());
1719
44939
          lcp->addStep(tConc, PfRule::AND_INTRO, pfChildren, {});
1720
44939
          Trace("te-proof-exp") << "...via AND_INTRO" << std::endl;
1721
44939
          continue;
1722
        }
1723
        // otherwise should hold by rewriting
1724
2124
        Assert(Rewriter::rewrite(tConc) == Rewriter::rewrite(tExp));
1725
        // tExp
1726
        // ---- MACRO_SR_PRED_TRANSFORM
1727
        // tConc
1728
2124
        lcp->addStep(tConc, PfRule::MACRO_SR_PRED_TRANSFORM, {tExp}, {tConc});
1729
2124
        Trace("te-proof-exp") << "...via MACRO_SR_PRED_TRANSFORM" << std::endl;
1730
2124
        continue;
1731
      }
1732
43015
      if (tExp == tConc)
1733
      {
1734
        // trivial
1735
        Trace("te-proof-exp") << "...trivial" << std::endl;
1736
        continue;
1737
      }
1738
      //       ------------- Via theory
1739
      // tExp  tExp => tConc
1740
      // ---------------------------------MODUS_PONENS
1741
      // tConc
1742
43015
      if (trn.getGenerator() != nullptr)
1743
      {
1744
42570
        Trace("te-proof-exp") << "...via theory generator" << std::endl;
1745
42570
        lcp->addLazyStep(proven, trn.getGenerator());
1746
      }
1747
      else
1748
      {
1749
445
        Trace("te-proof-exp") << "...via trust THEORY_LEMMA" << std::endl;
1750
        // otherwise, trusted theory lemma
1751
890
        Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(ttid);
1752
445
        lcp->addStep(proven, PfRule::THEORY_LEMMA, {}, {proven, tidn});
1753
      }
1754
86030
      std::vector<Node> pfChildren;
1755
43015
      pfChildren.push_back(trn.getNode());
1756
43015
      pfChildren.push_back(proven);
1757
43015
      lcp->addStep(tConc, PfRule::MODUS_PONENS, pfChildren, {});
1758
    }
1759
    // If we don't have a step and the conclusion is not part of the
1760
    // explanation (for unit T-conflicts), it must be by symmetry. We must do
1761
    // this manually since lcp does not have auto-symmetry enabled due to the
1762
    // complication mentioned above.
1763
20124
    if (!lcp->hasStep(conclusion) && exp.find(conclusion) == exp.end())
1764
    {
1765
      Node sconc = CDProof::getSymmFact(conclusion);
1766
      if (!sconc.isNull())
1767
      {
1768
        lcp->addStep(conclusion, PfRule::SYMM, {sconc}, {});
1769
      }
1770
      else
1771
      {
1772
        Assert(false)
1773
            << "TheoryEngine::getExplanation: no step found for conclusion "
1774
            << conclusion;
1775
      }
1776
    }
1777
    // store in the proof generator
1778
40248
    TrustNode trn = d_tepg->mkTrustExplain(conclusion, expNode, lcp);
1779
    // return the trust node
1780
20124
    return trn;
1781
  }
1782
1783
186347
  return TrustNode::mkTrustPropExp(conclusion, expNode, nullptr);
1784
}
1785
1786
997767
bool TheoryEngine::isProofEnabled() const { return d_pnm != nullptr; }
1787
1788
2183
void TheoryEngine::checkTheoryAssertionsWithModel(bool hardFailure) {
1789
30562
  for(TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) {
1790
28379
    Theory* theory = d_theoryTable[theoryId];
1791
28379
    if(theory && d_logicInfo.isTheoryEnabled(theoryId)) {
1792
116667
      for(context::CDList<Assertion>::const_iterator it = theory->facts_begin(),
1793
13444
            it_end = theory->facts_end();
1794
116667
          it != it_end;
1795
          ++it) {
1796
206446
        Node assertion = (*it).d_assertion;
1797
103223
        if (!isRelevant(assertion))
1798
        {
1799
          // not relevant, skip
1800
          continue;
1801
        }
1802
206446
        Node val = d_tc->getModel()->getValue(assertion);
1803
103223
        if (val != d_true)
1804
        {
1805
10
          std::stringstream ss;
1806
10
          ss << " " << theoryId
1807
10
             << " has an asserted fact that the model doesn't satisfy." << endl
1808
10
             << "The fact: " << assertion << endl
1809
5
             << "Model value: " << val << endl;
1810
5
          if (hardFailure)
1811
          {
1812
5
            if (val == d_false)
1813
            {
1814
              // Always an error if it is false
1815
              InternalError() << ss.str();
1816
            }
1817
            else
1818
            {
1819
              // Otherwise just a warning. Notice this case may happen for
1820
              // assertions with unevaluable operators, e.g. transcendental
1821
              // functions. It also may happen for separation logic, where
1822
              // check-model support is limited.
1823
5
              warning() << ss.str();
1824
            }
1825
          }
1826
        }
1827
      }
1828
    }
1829
  }
1830
2183
}
1831
1832
8478
std::pair<bool, Node> TheoryEngine::entailmentCheck(options::TheoryOfMode mode,
1833
                                                    TNode lit)
1834
{
1835
16956
  TNode atom = (lit.getKind() == kind::NOT) ? lit[0] : lit;
1836
8478
  if( atom.getKind()==kind::AND || atom.getKind()==kind::OR || atom.getKind()==kind::IMPLIES ){
1837
    //Boolean connective, recurse
1838
    std::vector< Node > children;
1839
    bool pol = (lit.getKind()!=kind::NOT);
1840
    bool is_conjunction = pol==(lit.getKind()==kind::AND);
1841
    for( unsigned i=0; i<atom.getNumChildren(); i++ ){
1842
      Node ch = atom[i];
1843
      if( pol==( lit.getKind()==kind::IMPLIES && i==0 ) ){
1844
        ch = atom[i].negate();
1845
      }
1846
      std::pair<bool, Node> chres = entailmentCheck(mode, ch);
1847
      if( chres.first ){
1848
        if( !is_conjunction ){
1849
          return chres;
1850
        }else{
1851
          children.push_back( chres.second );
1852
        }
1853
      }else if( !chres.first && is_conjunction ){
1854
        return std::pair<bool, Node>(false, Node::null());
1855
      }
1856
    }
1857
    if( is_conjunction ){
1858
      return std::pair<bool, Node>(true, NodeManager::currentNM()->mkNode(kind::AND, children));
1859
    }else{
1860
      return std::pair<bool, Node>(false, Node::null());
1861
    }
1862
8478
  }else if( atom.getKind()==kind::ITE || ( atom.getKind()==kind::EQUAL && atom[0].getType().isBoolean() ) ){
1863
    bool pol = (lit.getKind()!=kind::NOT);
1864
    for( unsigned r=0; r<2; r++ ){
1865
      Node ch = atom[0];
1866
      if( r==1 ){
1867
        ch = ch.negate();
1868
      }
1869
      std::pair<bool, Node> chres = entailmentCheck(mode, ch);
1870
      if( chres.first ){
1871
        Node ch2 = atom[ atom.getKind()==kind::ITE ? r+1 : 1 ];
1872
        if( pol==( atom.getKind()==kind::ITE ? true : r==1 ) ){
1873
          ch2 = ch2.negate();
1874
        }
1875
        std::pair<bool, Node> chres2 = entailmentCheck(mode, ch2);
1876
        if( chres2.first ){
1877
          return std::pair<bool, Node>(true, NodeManager::currentNM()->mkNode(kind::AND, chres.second, chres2.second));
1878
        }else{
1879
          break;
1880
        }
1881
      }
1882
    }
1883
    return std::pair<bool, Node>(false, Node::null());
1884
  }else{
1885
    //it is a theory atom
1886
8478
    theory::TheoryId tid = theory::Theory::theoryOf(mode, atom);
1887
8478
    theory::Theory* th = theoryOf(tid);
1888
1889
8478
    Assert(th != NULL);
1890
8478
    Trace("theory-engine-entc") << "Entailment check : " << lit << std::endl;
1891
1892
16956
    std::pair<bool, Node> chres = th->entailmentCheck(lit);
1893
8478
    return chres;
1894
  }
1895
}
1896
1897
11358086
void TheoryEngine::spendResource(Resource r)
1898
{
1899
11358086
  d_env.getResourceManager()->spendResource(r);
1900
11358086
}
1901
1902
7987
void TheoryEngine::initializeProofChecker(ProofChecker* pc)
1903
{
1904
111818
  for (theory::TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST;
1905
       ++id)
1906
  {
1907
103831
    ProofRuleChecker* prc = d_theoryTable[id]->getProofChecker();
1908
103831
    if (prc)
1909
    {
1910
71864
      prc->registerTo(pc);
1911
    }
1912
  }
1913
7987
}
1914
1915
198559
theory::Rewriter* TheoryEngine::getRewriter() { return d_env.getRewriter(); }
1916
1917
31125
}  // namespace cvc5