GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/theory_engine.cpp Lines: 729 899 81.1 %
Date: 2021-09-16 Branches: 1817 4458 40.8 %

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