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