GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/theory_engine.cpp Lines: 719 892 80.6 %
Date: 2021-09-10 Branches: 1802 4428 40.7 %

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