GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/theory_engine.cpp Lines: 741 911 81.3 %
Date: 2021-08-14 Branches: 1822 4458 40.9 %

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