GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/congruence_manager.cpp Lines: 359 411 87.3 %
Date: 2021-09-07 Branches: 723 1910 37.9 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Tim King, Alex Ozdemir, Andrew Reynolds
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
 * [[ Add one-line brief description here ]]
14
 *
15
 * [[ Add lengthier description here ]]
16
 * \todo document this file
17
 */
18
19
#include "theory/arith/congruence_manager.h"
20
21
#include "base/output.h"
22
#include "options/arith_options.h"
23
#include "proof/proof_node.h"
24
#include "proof/proof_node_manager.h"
25
#include "smt/smt_statistics_registry.h"
26
#include "theory/arith/arith_utilities.h"
27
#include "theory/arith/constraint.h"
28
#include "theory/arith/partial_model.h"
29
#include "theory/ee_setup_info.h"
30
#include "theory/rewriter.h"
31
#include "theory/uf/equality_engine.h"
32
#include "theory/uf/proof_equality_engine.h"
33
34
namespace cvc5 {
35
namespace theory {
36
namespace arith {
37
38
9926
ArithCongruenceManager::ArithCongruenceManager(
39
    context::Context* c,
40
    context::UserContext* u,
41
    ConstraintDatabase& cd,
42
    SetupLiteralCallBack setup,
43
    const ArithVariables& avars,
44
    RaiseEqualityEngineConflict raiseConflict,
45
9926
    ProofNodeManager* pnm)
46
    : d_inConflict(c),
47
      d_raiseConflict(raiseConflict),
48
      d_notify(*this),
49
      d_keepAlive(c),
50
      d_propagatations(c),
51
      d_explanationMap(c),
52
      d_constraintDatabase(cd),
53
      d_setupLiteral(setup),
54
      d_avariables(avars),
55
      d_ee(nullptr),
56
      d_satContext(c),
57
      d_userContext(u),
58
      d_pnm(pnm),
59
      // Construct d_pfGenEe with the SAT context, since its proof include
60
      // unclosed assumptions of theory literals.
61
      d_pfGenEe(
62
9926
          new EagerProofGenerator(pnm, c, "ArithCongruenceManager::pfGenEe")),
63
      // Construct d_pfGenEe with the USER context, since its proofs are closed.
64
      d_pfGenExplain(new EagerProofGenerator(
65
9926
          pnm, u, "ArithCongruenceManager::pfGenExplain")),
66
29778
      d_pfee(nullptr)
67
{
68
9926
}
69
70
9923
ArithCongruenceManager::~ArithCongruenceManager() {}
71
72
9887
bool ArithCongruenceManager::needsEqualityEngine(EeSetupInfo& esi)
73
{
74
9887
  Assert(!options::arithEqSolver());
75
9887
  esi.d_notify = &d_notify;
76
9887
  esi.d_name = "arithCong::ee";
77
9887
  return true;
78
}
79
80
9887
void ArithCongruenceManager::finishInit(eq::EqualityEngine* ee)
81
{
82
9887
  if (options::arithEqSolver())
83
  {
84
    // use our own copy
85
    d_allocEe.reset(
86
        new eq::EqualityEngine(d_notify, d_satContext, "arithCong::ee", true));
87
    d_ee = d_allocEe.get();
88
    if (d_pnm != nullptr)
89
    {
90
      // allocate an internal proof equality engine
91
      d_allocPfee.reset(
92
          new eq::ProofEqEngine(d_satContext, d_userContext, *d_ee, d_pnm));
93
      d_ee->setProofEqualityEngine(d_allocPfee.get());
94
    }
95
  }
96
  else
97
  {
98
9887
    Assert(ee != nullptr);
99
    // otherwise, we use the official one
100
9887
    d_ee = ee;
101
  }
102
  // set the congruence kinds on the separate equality engine
103
9887
  d_ee->addFunctionKind(kind::NONLINEAR_MULT);
104
9887
  d_ee->addFunctionKind(kind::EXPONENTIAL);
105
9887
  d_ee->addFunctionKind(kind::SINE);
106
9887
  d_ee->addFunctionKind(kind::IAND);
107
9887
  d_ee->addFunctionKind(kind::POW2);
108
  // the proof equality engine is the one from the equality engine
109
9887
  d_pfee = d_ee->getProofEqualityEngine();
110
  // have proof equality engine only if proofs are enabled
111
9887
  Assert(isProofEnabled() == (d_pfee != nullptr));
112
9887
}
113
114
9926
ArithCongruenceManager::Statistics::Statistics()
115
9926
    : d_watchedVariables(smtStatisticsRegistry().registerInt(
116
19852
        "theory::arith::congruence::watchedVariables")),
117
9926
      d_watchedVariableIsZero(smtStatisticsRegistry().registerInt(
118
19852
          "theory::arith::congruence::watchedVariableIsZero")),
119
9926
      d_watchedVariableIsNotZero(smtStatisticsRegistry().registerInt(
120
19852
          "theory::arith::congruence::watchedVariableIsNotZero")),
121
9926
      d_equalsConstantCalls(smtStatisticsRegistry().registerInt(
122
19852
          "theory::arith::congruence::equalsConstantCalls")),
123
9926
      d_propagations(smtStatisticsRegistry().registerInt(
124
19852
          "theory::arith::congruence::propagations")),
125
9926
      d_propagateConstraints(smtStatisticsRegistry().registerInt(
126
19852
          "theory::arith::congruence::propagateConstraints")),
127
9926
      d_conflicts(smtStatisticsRegistry().registerInt(
128
69482
          "theory::arith::congruence::conflicts"))
129
{
130
9926
}
131
132
9926
ArithCongruenceManager::ArithCongruenceNotify::ArithCongruenceNotify(ArithCongruenceManager& acm)
133
9926
  : d_acm(acm)
134
9926
{}
135
136
bool ArithCongruenceManager::ArithCongruenceNotify::eqNotifyTriggerPredicate(
137
    TNode predicate, bool value)
138
{
139
  Assert(predicate.getKind() == kind::EQUAL);
140
  Debug("arith::congruences")
141
      << "ArithCongruenceNotify::eqNotifyTriggerPredicate(" << predicate << ", "
142
      << (value ? "true" : "false") << ")" << std::endl;
143
  if (value) {
144
    return d_acm.propagate(predicate);
145
  }
146
  return d_acm.propagate(predicate.notNode());
147
}
148
149
918239
bool ArithCongruenceManager::ArithCongruenceNotify::eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) {
150
918239
  Debug("arith::congruences") << "ArithCongruenceNotify::eqNotifyTriggerTermEquality(" << t1 << ", " << t2 << ", " << (value ? "true" : "false") << ")" << std::endl;
151
918239
  if (value) {
152
773081
    return d_acm.propagate(t1.eqNode(t2));
153
  } else {
154
145158
    return d_acm.propagate(t1.eqNode(t2).notNode());
155
  }
156
}
157
2023
void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyConstantTermMerge(TNode t1, TNode t2) {
158
2023
  Debug("arith::congruences") << "ArithCongruenceNotify::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << std::endl;
159
2023
  d_acm.propagate(t1.eqNode(t2));
160
2023
}
161
1322951
void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyNewClass(TNode t) {
162
1322951
}
163
1571377
void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyMerge(TNode t1,
164
                                                                  TNode t2)
165
{
166
1571377
}
167
301647
void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
168
301647
}
169
170
2217
void ArithCongruenceManager::raiseConflict(Node conflict,
171
                                           std::shared_ptr<ProofNode> pf)
172
{
173
2217
  Assert(!inConflict());
174
2217
  Debug("arith::conflict") << "difference manager conflict   " << conflict << std::endl;
175
2217
  d_inConflict.raise();
176
2217
  d_raiseConflict.raiseEEConflict(conflict, pf);
177
2217
}
178
922479
bool ArithCongruenceManager::inConflict() const{
179
922479
  return d_inConflict.isRaised();
180
}
181
182
4256430
bool ArithCongruenceManager::hasMorePropagations() const {
183
4256430
  return !d_propagatations.empty();
184
}
185
738443
const Node ArithCongruenceManager::getNextPropagation() {
186
738443
  Assert(hasMorePropagations());
187
738443
  Node prop = d_propagatations.front();
188
738443
  d_propagatations.dequeue();
189
738443
  return prop;
190
}
191
192
34867
bool ArithCongruenceManager::canExplain(TNode n) const {
193
34867
  return d_explanationMap.find(n) != d_explanationMap.end();
194
}
195
196
20823
Node ArithCongruenceManager::externalToInternal(TNode n) const{
197
20823
  Assert(canExplain(n));
198
20823
  ExplainMap::const_iterator iter = d_explanationMap.find(n);
199
20823
  size_t pos = (*iter).second;
200
20823
  return d_propagatations[pos];
201
}
202
203
662326
void ArithCongruenceManager::pushBack(TNode n){
204
662326
  d_explanationMap.insert(n, d_propagatations.size());
205
662326
  d_propagatations.enqueue(n);
206
207
662326
  ++(d_statistics.d_propagations);
208
662326
}
209
119472
void ArithCongruenceManager::pushBack(TNode n, TNode r){
210
119472
  d_explanationMap.insert(r, d_propagatations.size());
211
119472
  d_explanationMap.insert(n, d_propagatations.size());
212
119472
  d_propagatations.enqueue(n);
213
214
119472
  ++(d_statistics.d_propagations);
215
119472
}
216
void ArithCongruenceManager::pushBack(TNode n, TNode r, TNode w){
217
  d_explanationMap.insert(w, d_propagatations.size());
218
  d_explanationMap.insert(r, d_propagatations.size());
219
  d_explanationMap.insert(n, d_propagatations.size());
220
  d_propagatations.enqueue(n);
221
222
  ++(d_statistics.d_propagations);
223
}
224
225
251448
void ArithCongruenceManager::watchedVariableIsZero(ConstraintCP lb, ConstraintCP ub){
226
251448
  Assert(lb->isLowerBound());
227
251448
  Assert(ub->isUpperBound());
228
251448
  Assert(lb->getVariable() == ub->getVariable());
229
251448
  Assert(lb->getValue().sgn() == 0);
230
251448
  Assert(ub->getValue().sgn() == 0);
231
232
251448
  ++(d_statistics.d_watchedVariableIsZero);
233
234
251448
  ArithVar s = lb->getVariable();
235
502896
  TNode eq = d_watchedEqualities[s];
236
251448
  ConstraintCP eqC = d_constraintDatabase.getConstraint(
237
251448
      s, ConstraintType::Equality, lb->getValue());
238
502896
  NodeBuilder reasonBuilder(Kind::AND);
239
502896
  auto pfLb = lb->externalExplainByAssertions(reasonBuilder);
240
502896
  auto pfUb = ub->externalExplainByAssertions(reasonBuilder);
241
502896
  Node reason = safeConstructNary(reasonBuilder);
242
502896
  std::shared_ptr<ProofNode> pf{};
243
251448
  if (isProofEnabled())
244
  {
245
86028
    pf = d_pnm->mkNode(
246
64521
        PfRule::ARITH_TRICHOTOMY, {pfLb, pfUb}, {eqC->getProofLiteral()});
247
21507
    pf = d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM, {pf}, {eq});
248
  }
249
250
251448
  d_keepAlive.push_back(reason);
251
502896
  Trace("arith-ee") << "Asserting an equality on " << s << ", on trichotomy"
252
251448
                    << std::endl;
253
251448
  Trace("arith-ee") << "  based on " << lb << std::endl;
254
251448
  Trace("arith-ee") << "  based on " << ub << std::endl;
255
251448
  assertionToEqualityEngine(true, s, reason, pf);
256
251448
}
257
258
239866
void ArithCongruenceManager::watchedVariableIsZero(ConstraintCP eq){
259
239866
  Debug("arith::cong") << "Cong::watchedVariableIsZero: " << *eq << std::endl;
260
261
239866
  Assert(eq->isEquality());
262
239866
  Assert(eq->getValue().sgn() == 0);
263
264
239866
  ++(d_statistics.d_watchedVariableIsZero);
265
266
239866
  ArithVar s = eq->getVariable();
267
268
  //Explain for conflict is correct as these proofs are generated
269
  //and stored eagerly
270
  //These will be safe for propagation later as well
271
479732
  NodeBuilder nb(Kind::AND);
272
  // An open proof of eq from literals now in reason.
273
239866
  if (Debug.isOn("arith::cong"))
274
  {
275
    eq->printProofTree(Debug("arith::cong"));
276
  }
277
479732
  auto pf = eq->externalExplainByAssertions(nb);
278
239866
  if (isProofEnabled())
279
  {
280
115422
    pf = d_pnm->mkNode(
281
76948
        PfRule::MACRO_SR_PRED_TRANSFORM, {pf}, {d_watchedEqualities[s]});
282
  }
283
479732
  Node reason = safeConstructNary(nb);
284
285
239866
  d_keepAlive.push_back(reason);
286
239866
  assertionToEqualityEngine(true, s, reason, pf);
287
239866
}
288
289
669282
void ArithCongruenceManager::watchedVariableCannotBeZero(ConstraintCP c){
290
1338564
  Debug("arith::cong::notzero")
291
669282
      << "Cong::watchedVariableCannotBeZero " << *c << std::endl;
292
669282
  ++(d_statistics.d_watchedVariableIsNotZero);
293
294
669282
  ArithVar s = c->getVariable();
295
1338564
  Node disEq = d_watchedEqualities[s].negate();
296
297
  //Explain for conflict is correct as these proofs are generated and stored eagerly
298
  //These will be safe for propagation later as well
299
1338564
  NodeBuilder nb(Kind::AND);
300
  // An open proof of eq from literals now in reason.
301
1338564
  auto pf = c->externalExplainByAssertions(nb);
302
669282
  if (Debug.isOn("arith::cong::notzero"))
303
  {
304
    Debug("arith::cong::notzero") << "  original proof ";
305
    pf->printDebug(Debug("arith::cong::notzero"));
306
    Debug("arith::cong::notzero") << std::endl;
307
  }
308
1338564
  Node reason = safeConstructNary(nb);
309
669282
  if (isProofEnabled())
310
  {
311
63265
    if (c->getType() == ConstraintType::Disequality)
312
    {
313
20845
      Assert(c->getLiteral() == d_watchedEqualities[s].negate());
314
      // We have to prove equivalence to the watched disequality.
315
20845
      pf = d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM, {pf}, {disEq});
316
    }
317
    else
318
    {
319
84840
      Debug("arith::cong::notzero")
320
42420
          << "  proof modification needed" << std::endl;
321
322
      // Four cases:
323
      //   c has form x_i = d, d > 0     => multiply c by -1 in Farkas proof
324
      //   c has form x_i = d, d > 0     => multiply c by 1 in Farkas proof
325
      //   c has form x_i <= d, d < 0     => multiply c by 1 in Farkas proof
326
      //   c has form x_i >= d, d > 0     => multiply c by -1 in Farkas proof
327
42420
      const bool scaleCNegatively = c->getType() == ConstraintType::LowerBound
328
59829
                                    || (c->getType() == ConstraintType::Equality
329
47638
                                        && c->getValue().sgn() > 0);
330
42420
      const int cSign = scaleCNegatively ? -1 : 1;
331
84840
      TNode isZero = d_watchedEqualities[s];
332
84840
      const auto isZeroPf = d_pnm->mkAssume(isZero);
333
42420
      const auto nm = NodeManager::currentNM();
334
42420
      const auto sumPf = d_pnm->mkNode(
335
          PfRule::MACRO_ARITH_SCALE_SUM_UB,
336
          {isZeroPf, pf},
337
          // Trick for getting correct, opposing signs.
338
84840
          {nm->mkConst(Rational(-1 * cSign)), nm->mkConst(Rational(cSign))});
339
42420
      const auto botPf = d_pnm->mkNode(
340
84840
          PfRule::MACRO_SR_PRED_TRANSFORM, {sumPf}, {nm->mkConst(false)});
341
84840
      std::vector<Node> assumption = {isZero};
342
42420
      pf = d_pnm->mkScope(botPf, assumption, false);
343
42420
      Debug("arith::cong::notzero") << "  new proof ";
344
42420
      pf->printDebug(Debug("arith::cong::notzero"));
345
42420
      Debug("arith::cong::notzero") << std::endl;
346
    }
347
63265
    Assert(pf->getResult() == disEq);
348
  }
349
669282
  d_keepAlive.push_back(reason);
350
669282
  assertionToEqualityEngine(false, s, reason, pf);
351
669282
}
352
353
354
920262
bool ArithCongruenceManager::propagate(TNode x){
355
920262
  Debug("arith::congruenceManager")<< "ArithCongruenceManager::propagate("<<x<<")"<<std::endl;
356
920262
  if(inConflict()){
357
    return true;
358
  }
359
360
1840524
  Node rewritten = Rewriter::rewrite(x);
361
362
  //Need to still propagate this!
363
920262
  if(rewritten.getKind() == kind::CONST_BOOLEAN){
364
2170
    pushBack(x);
365
366
2170
    if(rewritten.getConst<bool>()){
367
147
      return true;
368
    }else{
369
      // x rewrites to false.
370
2023
      ++(d_statistics.d_conflicts);
371
4046
      TrustNode trn = explainInternal(x);
372
4046
      Node conf = flattenAnd(trn.getNode());
373
2023
      Debug("arith::congruenceManager") << "rewritten to false "<<x<<" with explanation "<< conf << std::endl;
374
2023
      if (isProofEnabled())
375
      {
376
752
        auto pf = trn.getGenerator()->getProofFor(trn.getProven());
377
376
        auto confPf = d_pnm->mkNode(
378
752
            PfRule::MACRO_SR_PRED_TRANSFORM, {pf}, {conf.negate()});
379
376
        raiseConflict(conf, confPf);
380
      }
381
      else
382
      {
383
1647
        raiseConflict(conf);
384
      }
385
2023
      return false;
386
    }
387
  }
388
389
918092
  Assert(rewritten.getKind() != kind::CONST_BOOLEAN);
390
391
918092
  ConstraintP c = d_constraintDatabase.lookup(rewritten);
392
918092
  if(c == NullConstraint){
393
    //using setup as there may not be a corresponding congruence literal yet
394
20374
    d_setupLiteral(rewritten);
395
20374
    c = d_constraintDatabase.lookup(rewritten);
396
20374
    Assert(c != NullConstraint);
397
  }
398
399
1836184
  Debug("arith::congruenceManager")<< "x is "
400
1836184
                                   <<  c->hasProof() << " "
401
1836184
                                   << (x == rewritten) << " "
402
1836184
                                   << c->canBePropagated() << " "
403
918092
                                   << c->negationHasProof() << std::endl;
404
405
918092
  if(c->negationHasProof()){
406
388
    TrustNode texpC = explainInternal(x);
407
388
    Node expC = texpC.getNode();
408
194
    ConstraintCP negC = c->getNegation();
409
388
    Node neg = Constraint::externalExplainByAssertions({negC});
410
388
    Node conf = expC.andNode(neg);
411
388
    Node final = flattenAnd(conf);
412
413
194
    ++(d_statistics.d_conflicts);
414
194
    raiseConflict(final);
415
194
    Debug("arith::congruenceManager") << "congruenceManager found a conflict " << final << std::endl;
416
194
    return false;
417
  }
418
419
  // Cases for propagation
420
  // C : c has a proof
421
  // S : x == rewritten
422
  // P : c can be propagated
423
  //
424
  // CSP
425
  // 000 : propagate x, and mark C it as being explained
426
  // 001 : propagate x, and propagate c after marking it as being explained
427
  // 01* : propagate x, mark c but do not propagate c
428
  // 10* : propagate x, do not mark c and do not propagate c
429
  // 11* : drop the constraint, do not propagate x or c
430
431
917898
  if(!c->hasProof() && x != rewritten){
432
119472
    if(c->assertedToTheTheory()){
433
      pushBack(x, rewritten, c->getWitness());
434
    }else{
435
119472
      pushBack(x, rewritten);
436
    }
437
438
119472
    c->setEqualityEngineProof();
439
119472
    if(c->canBePropagated() && !c->assertedToTheTheory()){
440
441
17156
      ++(d_statistics.d_propagateConstraints);
442
17156
      c->propagate();
443
    }
444
798426
  }else if(!c->hasProof() && x == rewritten){
445
95981
    if(c->assertedToTheTheory()){
446
      pushBack(x, c->getWitness());
447
    }else{
448
95981
      pushBack(x);
449
    }
450
95981
    c->setEqualityEngineProof();
451
702445
  }else if(c->hasProof() && x != rewritten){
452
564175
    if(c->assertedToTheTheory()){
453
562508
      pushBack(x);
454
    }else{
455
1667
      pushBack(x);
456
    }
457
  }else{
458
138270
    Assert(c->hasProof() && x == rewritten);
459
  }
460
917898
  return true;
461
}
462
463
void ArithCongruenceManager::explain(TNode literal, std::vector<TNode>& assumptions) {
464
  if (literal.getKind() != kind::NOT) {
465
    d_ee->explainEquality(literal[0], literal[1], true, assumptions);
466
  } else {
467
    d_ee->explainEquality(literal[0][0], literal[0][1], false, assumptions);
468
  }
469
}
470
471
void ArithCongruenceManager::enqueueIntoNB(const std::set<TNode> s,
472
                                           NodeBuilder& nb)
473
{
474
  std::set<TNode>::const_iterator it = s.begin();
475
  std::set<TNode>::const_iterator it_end = s.end();
476
  for(; it != it_end; ++it) {
477
    nb << *it;
478
  }
479
}
480
481
23040
TrustNode ArithCongruenceManager::explainInternal(TNode internal)
482
{
483
23040
  if (isProofEnabled())
484
  {
485
4643
    return d_pfee->explain(internal);
486
  }
487
  // otherwise, explain without proof generator
488
36794
  Node exp = d_ee->mkExplainLit(internal);
489
18397
  return TrustNode::mkTrustPropExp(internal, exp, nullptr);
490
}
491
492
20823
TrustNode ArithCongruenceManager::explain(TNode external)
493
{
494
20823
  Trace("arith-ee") << "Ask for explanation of " << external << std::endl;
495
41646
  Node internal = externalToInternal(external);
496
20823
  Trace("arith-ee") << "...internal = " << internal << std::endl;
497
41646
  TrustNode trn = explainInternal(internal);
498
20823
  if (isProofEnabled() && trn.getProven()[1] != external)
499
  {
500
732
    Assert(trn.getKind() == TrustNodeKind::PROP_EXP);
501
732
    Assert(trn.getProven().getKind() == Kind::IMPLIES);
502
732
    Assert(trn.getGenerator() != nullptr);
503
1464
    Trace("arith-ee") << "tweaking proof to prove " << external << " not "
504
732
                      << trn.getProven()[1] << std::endl;
505
1464
    std::vector<std::shared_ptr<ProofNode>> assumptionPfs;
506
1464
    std::vector<Node> assumptions = andComponents(trn.getNode());
507
732
    assumptionPfs.push_back(trn.toProofNode());
508
2708
    for (const auto& a : assumptions)
509
    {
510
1976
      assumptionPfs.push_back(
511
3952
          d_pnm->mkNode(PfRule::TRUE_INTRO, {d_pnm->mkAssume(a)}, {}));
512
    }
513
732
    auto litPf = d_pnm->mkNode(
514
1464
        PfRule::MACRO_SR_PRED_TRANSFORM, {assumptionPfs}, {external});
515
1464
    auto extPf = d_pnm->mkScope(litPf, assumptions);
516
732
    return d_pfGenExplain->mkTrustedPropagation(external, trn.getNode(), extPf);
517
  }
518
20091
  return trn;
519
}
520
521
void ArithCongruenceManager::explain(TNode external, NodeBuilder& out)
522
{
523
  Node internal = externalToInternal(external);
524
525
  std::vector<TNode> assumptions;
526
  explain(internal, assumptions);
527
  std::set<TNode> assumptionSet;
528
  assumptionSet.insert(assumptions.begin(), assumptions.end());
529
530
  enqueueIntoNB(assumptionSet, out);
531
}
532
533
62665
void ArithCongruenceManager::addWatchedPair(ArithVar s, TNode x, TNode y){
534
62665
  Assert(!isWatchedVariable(s));
535
536
125330
  Debug("arith::congruenceManager")
537
62665
    << "addWatchedPair(" << s << ", " << x << ", " << y << ")" << std::endl;
538
539
540
62665
  ++(d_statistics.d_watchedVariables);
541
542
62665
  d_watchedVariables.add(s);
543
544
125330
  Node eq = x.eqNode(y);
545
62665
  d_watchedEqualities.set(s, eq);
546
62665
}
547
548
2120863
void ArithCongruenceManager::assertLitToEqualityEngine(
549
    Node lit, TNode reason, std::shared_ptr<ProofNode> pf)
550
{
551
2120863
  bool isEquality = lit.getKind() != Kind::NOT;
552
4241726
  Node eq = isEquality ? lit : lit[0];
553
2120863
  Assert(eq.getKind() == Kind::EQUAL);
554
555
4241726
  Trace("arith-ee") << "Assert to Eq " << lit << ", reason " << reason
556
2120863
                    << std::endl;
557
2120863
  if (isProofEnabled())
558
  {
559
262728
    if (CDProof::isSame(lit, reason))
560
    {
561
155490
      Trace("arith-pfee") << "Asserting only, b/c implied by symm" << std::endl;
562
      // The equality engine doesn't ref-count for us...
563
155490
      d_keepAlive.push_back(eq);
564
155490
      d_keepAlive.push_back(reason);
565
155490
      d_ee->assertEquality(eq, isEquality, reason);
566
    }
567
107238
    else if (hasProofFor(lit))
568
    {
569
1435
      Trace("arith-pfee") << "Skipping b/c already done" << std::endl;
570
    }
571
    else
572
    {
573
105803
      setProofFor(lit, pf);
574
105803
      Trace("arith-pfee") << "Actually asserting" << std::endl;
575
105803
      if (Debug.isOn("arith-pfee"))
576
      {
577
        Trace("arith-pfee") << "Proof: ";
578
        pf->printDebug(Trace("arith-pfee"));
579
        Trace("arith-pfee") << std::endl;
580
      }
581
      // The proof equality engine *does* ref-count for us...
582
105803
      d_pfee->assertFact(lit, reason, d_pfGenEe.get());
583
    }
584
  }
585
  else
586
  {
587
    // The equality engine doesn't ref-count for us...
588
1858135
    d_keepAlive.push_back(eq);
589
1858135
    d_keepAlive.push_back(reason);
590
1858135
    d_ee->assertEquality(eq, isEquality, reason);
591
  }
592
2120863
}
593
594
1160596
void ArithCongruenceManager::assertionToEqualityEngine(
595
    bool isEquality, ArithVar s, TNode reason, std::shared_ptr<ProofNode> pf)
596
{
597
1160596
  Assert(isWatchedVariable(s));
598
599
2321192
  TNode eq = d_watchedEqualities[s];
600
1160596
  Assert(eq.getKind() == kind::EQUAL);
601
602
2321192
  Node lit = isEquality ? Node(eq) : eq.notNode();
603
2321192
  Trace("arith-ee") << "Assert to Eq " << eq << ", pol " << isEquality
604
1160596
                    << ", reason " << reason << std::endl;
605
1160596
  assertLitToEqualityEngine(lit, reason, pf);
606
1160596
}
607
608
213041
bool ArithCongruenceManager::hasProofFor(TNode f) const
609
{
610
213041
  Assert(isProofEnabled());
611
213041
  if (d_pfGenEe->hasProofFor(f))
612
  {
613
1435
    return true;
614
  }
615
423212
  Node sym = CDProof::getSymmFact(f);
616
211606
  Assert(!sym.isNull());
617
211606
  return d_pfGenEe->hasProofFor(sym);
618
}
619
620
105803
void ArithCongruenceManager::setProofFor(TNode f,
621
                                         std::shared_ptr<ProofNode> pf) const
622
{
623
105803
  Assert(!hasProofFor(f));
624
105803
  d_pfGenEe->mkTrustNode(f, pf);
625
211606
  Node symF = CDProof::getSymmFact(f);
626
211606
  auto symPf = d_pnm->mkNode(PfRule::SYMM, {pf}, {});
627
105803
  d_pfGenEe->mkTrustNode(symF, symPf);
628
105803
}
629
630
791458
void ArithCongruenceManager::equalsConstant(ConstraintCP c){
631
791458
  Assert(c->isEquality());
632
633
791458
  ++(d_statistics.d_equalsConstantCalls);
634
791458
  Debug("equalsConstant") << "equals constant " << c << std::endl;
635
636
791458
  ArithVar x = c->getVariable();
637
1582916
  Node xAsNode = d_avariables.asNode(x);
638
1582916
  Node asRational = mkRationalNode(c->getValue().getNoninfinitesimalPart());
639
640
  // No guarentee this is in normal form!
641
  // Note though, that it happens to be in proof normal form!
642
1582916
  Node eq = xAsNode.eqNode(asRational);
643
791458
  d_keepAlive.push_back(eq);
644
645
1582916
  NodeBuilder nb(Kind::AND);
646
1582916
  auto pf = c->externalExplainByAssertions(nb);
647
1582916
  Node reason = safeConstructNary(nb);
648
791458
  d_keepAlive.push_back(reason);
649
650
791458
  Trace("arith-ee") << "Assert equalsConstant " << eq << ", reason " << reason << std::endl;
651
791458
  assertLitToEqualityEngine(eq, reason, pf);
652
791458
}
653
654
168809
void ArithCongruenceManager::equalsConstant(ConstraintCP lb, ConstraintCP ub){
655
168809
  Assert(lb->isLowerBound());
656
168809
  Assert(ub->isUpperBound());
657
168809
  Assert(lb->getVariable() == ub->getVariable());
658
659
168809
  ++(d_statistics.d_equalsConstantCalls);
660
337618
  Debug("equalsConstant") << "equals constant " << lb << std::endl
661
168809
                          << ub << std::endl;
662
663
168809
  ArithVar x = lb->getVariable();
664
337618
  NodeBuilder nb(Kind::AND);
665
337618
  auto pfLb = lb->externalExplainByAssertions(nb);
666
337618
  auto pfUb = ub->externalExplainByAssertions(nb);
667
337618
  Node reason = safeConstructNary(nb);
668
669
337618
  Node xAsNode = d_avariables.asNode(x);
670
337618
  Node asRational = mkRationalNode(lb->getValue().getNoninfinitesimalPart());
671
672
  // No guarentee this is in normal form!
673
  // Note though, that it happens to be in proof normal form!
674
337618
  Node eq = xAsNode.eqNode(asRational);
675
337618
  std::shared_ptr<ProofNode> pf;
676
168809
  if (isProofEnabled())
677
  {
678
19976
    pf = d_pnm->mkNode(PfRule::ARITH_TRICHOTOMY, {pfLb, pfUb}, {eq});
679
  }
680
168809
  d_keepAlive.push_back(eq);
681
168809
  d_keepAlive.push_back(reason);
682
683
168809
  Trace("arith-ee") << "Assert equalsConstant2 " << eq << ", reason " << reason << std::endl;
684
685
168809
  assertLitToEqualityEngine(eq, reason, pf);
686
168809
}
687
688
3719082
bool ArithCongruenceManager::isProofEnabled() const { return d_pnm != nullptr; }
689
690
732
std::vector<Node> andComponents(TNode an)
691
{
692
732
  auto nm = NodeManager::currentNM();
693
732
  if (an == nm->mkConst(true))
694
  {
695
    return {};
696
  }
697
732
  else if (an.getKind() != Kind::AND)
698
  {
699
1
    return {an};
700
  }
701
1462
  std::vector<Node> a{};
702
731
  a.reserve(an.getNumChildren());
703
731
  a.insert(a.end(), an.begin(), an.end());
704
731
  return a;
705
}
706
707
}  // namespace arith
708
}  // namespace theory
709
29502
}  // namespace cvc5