GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/constraint.cpp Lines: 1072 1472 72.8 %
Date: 2021-08-20 Branches: 1801 6399 28.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Tim King, Alex Ozdemir, Haniel Barbosa
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
#include "theory/arith/constraint.h"
19
20
#include <algorithm>
21
#include <ostream>
22
#include <unordered_set>
23
24
#include "base/output.h"
25
#include "proof/eager_proof_generator.h"
26
#include "proof/proof_node_manager.h"
27
#include "smt/smt_statistics_registry.h"
28
#include "theory/arith/arith_utilities.h"
29
#include "theory/arith/congruence_manager.h"
30
#include "theory/arith/normal_form.h"
31
#include "theory/arith/partial_model.h"
32
#include "theory/rewriter.h"
33
34
using namespace std;
35
using namespace cvc5::kind;
36
37
namespace cvc5 {
38
namespace theory {
39
namespace arith {
40
41
/** Given a simplifiedKind this returns the corresponding ConstraintType. */
42
//ConstraintType constraintTypeOfLiteral(Kind k);
43
526869
ConstraintType Constraint::constraintTypeOfComparison(const Comparison& cmp){
44
526869
  Kind k = cmp.comparisonKind();
45
526869
  switch(k){
46
141362
  case LT:
47
  case LEQ:
48
    {
49
282724
      Polynomial l = cmp.getLeft();
50
141362
      if(l.leadingCoefficientIsPositive()){ // (< x c)
51
116700
        return UpperBound;
52
      }else{
53
24662
        return LowerBound; // (< (-x) c)
54
      }
55
    }
56
142540
  case GT:
57
  case GEQ:
58
    {
59
285080
      Polynomial l = cmp.getLeft();
60
142540
      if(l.leadingCoefficientIsPositive()){
61
117684
        return LowerBound; // (> x c)
62
      }else{
63
24856
        return UpperBound; // (> (-x) c)
64
      }
65
    }
66
121589
  case EQUAL:
67
121589
    return Equality;
68
121378
  case DISTINCT:
69
121378
    return Disequality;
70
  default: Unhandled() << k;
71
  }
72
}
73
74
652855
Constraint::Constraint(ArithVar x,  ConstraintType t, const DeltaRational& v)
75
  : d_variable(x),
76
    d_type(t),
77
    d_value(v),
78
    d_database(NULL),
79
    d_literal(Node::null()),
80
    d_negation(NullConstraint),
81
    d_canBePropagated(false),
82
    d_assertionOrder(AssertionOrderSentinel),
83
    d_witness(TNode::null()),
84
    d_crid(ConstraintRuleIdSentinel),
85
    d_split(false),
86
652855
    d_variablePosition()
87
{
88
652855
  Assert(!initialized());
89
652855
}
90
91
92
std::ostream& operator<<(std::ostream& o, const ArithProofType apt){
93
  switch(apt){
94
  case NoAP:  o << "NoAP"; break;
95
  case AssumeAP:  o << "AssumeAP"; break;
96
  case InternalAssumeAP:  o << "InternalAssumeAP"; break;
97
  case FarkasAP:  o << "FarkasAP"; break;
98
  case TrichotomyAP:  o << "TrichotomyAP"; break;
99
  case EqualityEngineAP:  o << "EqualityEngineAP"; break;
100
  case IntTightenAP: o << "IntTightenAP"; break;
101
  case IntHoleAP: o << "IntHoleAP"; break;
102
  default: break;
103
  }
104
  return o;
105
}
106
107
std::ostream& operator<<(std::ostream& o, const ConstraintCP c){
108
  if(c == NullConstraint){
109
    return o << "NullConstraint";
110
  }else{
111
    return o << *c;
112
  }
113
}
114
115
std::ostream& operator<<(std::ostream& o, const ConstraintP c){
116
  if(c == NullConstraint){
117
    return o << "NullConstraint";
118
  }else{
119
    return o << *c;
120
  }
121
}
122
123
std::ostream& operator<<(std::ostream& o, const ConstraintType t){
124
  switch(t){
125
  case LowerBound:
126
    return o << ">=";
127
  case UpperBound:
128
    return o << "<=";
129
  case Equality:
130
    return o << "=";
131
  case Disequality:
132
    return o << "!=";
133
  default:
134
    Unreachable();
135
  }
136
}
137
138
std::ostream& operator<<(std::ostream& o, const Constraint& c){
139
  o << c.getVariable() << ' ' << c.getType() << ' ' << c.getValue();
140
  if(c.hasLiteral()){
141
    o << "(node " << c.getLiteral() << ')';
142
  }
143
  return o;
144
}
145
146
std::ostream& operator<<(std::ostream& o, const ValueCollection& vc){
147
  o << "{";
148
  bool pending = false;
149
  if(vc.hasEquality()){
150
    o << "eq: " << vc.getEquality();
151
    pending = true;
152
  }
153
  if(vc.hasLowerBound()){
154
    if(pending){
155
      o << ", ";
156
    }
157
    o << "lb: " << vc.getLowerBound();
158
    pending = true;
159
  }
160
  if(vc.hasUpperBound()){
161
    if(pending){
162
      o << ", ";
163
    }
164
    o << "ub: " << vc.getUpperBound();
165
    pending = true;
166
  }
167
  if(vc.hasDisequality()){
168
    if(pending){
169
      o << ", ";
170
    }
171
    o << "de: " << vc.getDisequality();
172
  }
173
  return o << "}";
174
}
175
176
std::ostream& operator<<(std::ostream& o, const ConstraintCPVec& v){
177
  o << "[" << v.size() << "x";
178
  ConstraintCPVec::const_iterator i, end;
179
  for(i=v.begin(), end=v.end(); i != end; ++i){
180
    ConstraintCP c = *i;
181
    o << ", " << (*c);
182
  }
183
  o << "]";
184
  return o;
185
}
186
187
void Constraint::debugPrint() const { CVC5Message() << *this << endl; }
188
189
2097092
ValueCollection::ValueCollection()
190
  : d_lowerBound(NullConstraint),
191
    d_upperBound(NullConstraint),
192
    d_equality(NullConstraint),
193
2097092
    d_disequality(NullConstraint)
194
2097092
{}
195
196
19024281
bool ValueCollection::hasLowerBound() const{
197
19024281
  return d_lowerBound != NullConstraint;
198
}
199
200
20375465
bool ValueCollection::hasUpperBound() const{
201
20375465
  return d_upperBound != NullConstraint;
202
}
203
204
4590568
bool ValueCollection::hasEquality() const{
205
4590568
  return d_equality != NullConstraint;
206
}
207
208
14423744
bool ValueCollection::hasDisequality() const {
209
14423744
  return d_disequality != NullConstraint;
210
}
211
212
3855738
ConstraintP ValueCollection::getLowerBound() const {
213
3855738
  Assert(hasLowerBound());
214
3855738
  return d_lowerBound;
215
}
216
217
3994502
ConstraintP ValueCollection::getUpperBound() const {
218
3994502
  Assert(hasUpperBound());
219
3994502
  return d_upperBound;
220
}
221
222
410686
ConstraintP ValueCollection::getEquality() const {
223
410686
  Assert(hasEquality());
224
410686
  return d_equality;
225
}
226
227
2153211
ConstraintP ValueCollection::getDisequality() const {
228
2153211
  Assert(hasDisequality());
229
2153211
  return d_disequality;
230
}
231
232
233
439210
void ValueCollection::push_into(std::vector<ConstraintP>& vec) const {
234
439210
  Debug("arith::constraint") << "push_into " << *this << endl;
235
439210
  if(hasEquality()){
236
126238
    vec.push_back(d_equality);
237
  }
238
439210
  if(hasLowerBound()){
239
199495
    vec.push_back(d_lowerBound);
240
  }
241
439210
  if(hasUpperBound()){
242
199495
    vec.push_back(d_upperBound);
243
  }
244
439210
  if(hasDisequality()){
245
126238
    vec.push_back(d_disequality);
246
  }
247
439210
}
248
249
ValueCollection ValueCollection::mkFromConstraint(ConstraintP c){
250
  ValueCollection ret;
251
  Assert(ret.empty());
252
  switch(c->getType()){
253
  case LowerBound:
254
    ret.d_lowerBound = c;
255
    break;
256
  case UpperBound:
257
    ret.d_upperBound = c;
258
    break;
259
  case Equality:
260
    ret.d_equality = c;
261
    break;
262
  case Disequality:
263
    ret.d_disequality = c;
264
    break;
265
  default:
266
    Unreachable();
267
  }
268
  return ret;
269
}
270
271
3519946
bool ValueCollection::hasConstraintOfType(ConstraintType t) const{
272
3519946
  switch(t){
273
1168030
  case LowerBound:
274
1168030
    return hasLowerBound();
275
1910325
  case UpperBound:
276
1910325
    return hasUpperBound();
277
441591
  case Equality:
278
441591
    return hasEquality();
279
  case Disequality:
280
    return hasDisequality();
281
  default:
282
    Unreachable();
283
  }
284
}
285
286
218428
ArithVar ValueCollection::getVariable() const{
287
218428
  Assert(!empty());
288
218428
  return nonNull()->getVariable();
289
}
290
291
218428
const DeltaRational& ValueCollection::getValue() const{
292
218428
  Assert(!empty());
293
218428
  return nonNull()->getValue();
294
}
295
296
651466
void ValueCollection::add(ConstraintP c){
297
651466
  Assert(c != NullConstraint);
298
299
651466
  Assert(empty() || getVariable() == c->getVariable());
300
651466
  Assert(empty() || getValue() == c->getValue());
301
302
651466
  switch(c->getType()){
303
199495
  case LowerBound:
304
199495
    Assert(!hasLowerBound());
305
199495
    d_lowerBound = c;
306
199495
    break;
307
126238
  case Equality:
308
126238
    Assert(!hasEquality());
309
126238
    d_equality = c;
310
126238
    break;
311
199495
  case UpperBound:
312
199495
    Assert(!hasUpperBound());
313
199495
    d_upperBound = c;
314
199495
    break;
315
126238
  case Disequality:
316
126238
    Assert(!hasDisequality());
317
126238
    d_disequality = c;
318
126238
    break;
319
  default:
320
    Unreachable();
321
  }
322
651466
}
323
324
2683378
ConstraintP ValueCollection::getConstraintOfType(ConstraintType t) const{
325
2683378
  switch(t){
326
734598
    case LowerBound: Assert(hasLowerBound()); return d_lowerBound;
327
315353
    case Equality: Assert(hasEquality()); return d_equality;
328
1633427
    case UpperBound: Assert(hasUpperBound()); return d_upperBound;
329
    case Disequality: Assert(hasDisequality()); return d_disequality;
330
    default: Unreachable();
331
  }
332
}
333
334
651466
void ValueCollection::remove(ConstraintType t){
335
651466
  switch(t){
336
199495
  case LowerBound:
337
199495
    Assert(hasLowerBound());
338
199495
    d_lowerBound = NullConstraint;
339
199495
    break;
340
126238
  case Equality:
341
126238
    Assert(hasEquality());
342
126238
    d_equality = NullConstraint;
343
126238
    break;
344
199495
  case UpperBound:
345
199495
    Assert(hasUpperBound());
346
199495
    d_upperBound = NullConstraint;
347
199495
    break;
348
126238
  case Disequality:
349
126238
    Assert(hasDisequality());
350
126238
    d_disequality = NullConstraint;
351
126238
    break;
352
  default:
353
    Unreachable();
354
  }
355
651466
}
356
357
2391254
bool ValueCollection::empty() const{
358
  return
359
5768728
    !(hasLowerBound() ||
360
4019468
      hasUpperBound() ||
361
1959624
      hasEquality() ||
362
3708884
      hasDisequality());
363
}
364
365
436856
ConstraintP ValueCollection::nonNull() const{
366
  //This can be optimized by caching, but this is not necessary yet!
367
  /* "Premature optimization is the root of all evil." */
368
436856
  if(hasLowerBound()){
369
131464
    return d_lowerBound;
370
305392
  }else if(hasUpperBound()){
371
47514
    return d_upperBound;
372
257878
  }else if(hasEquality()){
373
257878
    return d_equality;
374
  }else if(hasDisequality()){
375
    return d_disequality;
376
  }else{
377
    return NullConstraint;
378
  }
379
}
380
381
2635876
bool Constraint::initialized() const {
382
2635876
  return d_database != NULL;
383
}
384
385
const ConstraintDatabase& Constraint::getDatabase() const{
386
  Assert(initialized());
387
  return *d_database;
388
}
389
390
651466
void Constraint::initialize(ConstraintDatabase* db, SortedConstraintMapIterator v, ConstraintP negation){
391
651466
  Assert(!initialized());
392
651466
  d_database = db;
393
651466
  d_variablePosition = v;
394
651466
  d_negation = negation;
395
651466
}
396
397
1305710
Constraint::~Constraint() {
398
  // Call this instead of safeToGarbageCollect()
399
652855
  Assert(!contextDependentDataIsSet());
400
401
652855
  if(initialized()){
402
651466
    ValueCollection& vc =  d_variablePosition->second;
403
651466
    Debug("arith::constraint") << "removing" << vc << endl;
404
405
651466
    vc.remove(getType());
406
407
651466
    if(vc.empty()){
408
439210
      Debug("arith::constraint") << "erasing" << vc << endl;
409
439210
      SortedConstraintMap& perVariable = d_database->getVariableSCM(getVariable());
410
439210
      perVariable.erase(d_variablePosition);
411
    }
412
413
651466
    if(hasLiteral()){
414
528258
      d_database->d_nodetoConstraintMap.erase(getLiteral());
415
    }
416
  }
417
652855
}
418
419
26004919
const ConstraintRule& Constraint::getConstraintRule() const {
420
26004919
  Assert(hasProof());
421
26004919
  return d_database->d_watches->d_constraintProofs[d_crid];
422
}
423
424
3025822
const ValueCollection& Constraint::getValueCollection() const{
425
3025822
  return d_variablePosition->second;
426
}
427
428
429
69494
ConstraintP Constraint::getCeiling() {
430
69494
  Debug("getCeiling") << "Constraint_::getCeiling on " << *this << endl;
431
69494
  Assert(getValue().getInfinitesimalPart().sgn() > 0);
432
433
138988
  const DeltaRational ceiling(getValue().ceiling());
434
138988
  return d_database->getConstraint(getVariable(), getType(), ceiling);
435
}
436
437
1237800
ConstraintP Constraint::getFloor() {
438
1237800
  Assert(getValue().getInfinitesimalPart().sgn() < 0);
439
440
2475600
  const DeltaRational floor(Rational(getValue().floor()));
441
2475600
  return d_database->getConstraint(getVariable(), getType(), floor);
442
}
443
444
800084
void Constraint::setCanBePropagated() {
445
800084
  Assert(!canBePropagated());
446
800084
  d_database->pushCanBePropagatedWatch(this);
447
800084
}
448
449
5684029
void Constraint::setAssertedToTheTheory(TNode witness, bool nowInConflict) {
450
5684029
  Assert(hasLiteral());
451
5684029
  Assert(!assertedToTheTheory());
452
5684029
  Assert(negationHasProof() == nowInConflict);
453
5684029
  d_database->pushAssertionOrderWatch(this, witness);
454
455
5684029
  if(Debug.isOn("constraint::conflictCommit") && nowInConflict ){
456
    Debug("constraint::conflictCommit") << "inConflict@setAssertedToTheTheory";
457
    Debug("constraint::conflictCommit") << "\t" << this << std::endl;
458
    Debug("constraint::conflictCommit") << "\t" << getNegation() << std::endl;
459
    Debug("constraint::conflictCommit") << "\t" << getNegation()->externalExplainByAssertions() << std::endl;
460
461
  }
462
5684029
}
463
464
bool Constraint::satisfiedBy(const DeltaRational& dr) const {
465
  switch(getType()){
466
  case LowerBound:
467
    return getValue() <= dr;
468
  case Equality:
469
    return getValue() == dr;
470
  case UpperBound:
471
    return getValue() >= dr;
472
  case Disequality:
473
    return getValue() != dr;
474
  }
475
  Unreachable();
476
}
477
478
10863182
bool Constraint::isInternalAssumption() const {
479
10863182
  return getProofType() == InternalAssumeAP;
480
}
481
482
TrustNode Constraint::externalExplainByAssertions() const
483
{
484
  NodeBuilder nb(kind::AND);
485
  auto pfFromAssumptions = externalExplain(nb, AssertionOrderSentinel);
486
  Node exp = safeConstructNary(nb);
487
  if (d_database->isProofEnabled())
488
  {
489
    std::vector<Node> assumptions;
490
    if (exp.getKind() == Kind::AND)
491
    {
492
      assumptions.insert(assumptions.end(), exp.begin(), exp.end());
493
    }
494
    else
495
    {
496
      assumptions.push_back(exp);
497
    }
498
    auto pf = d_database->d_pnm->mkScope(pfFromAssumptions, assumptions);
499
    return d_database->d_pfGen->mkTrustedPropagation(
500
        getLiteral(), safeConstructNary(Kind::AND, assumptions), pf);
501
  }
502
  return TrustNode::mkTrustPropExp(getLiteral(), exp);
503
}
504
505
11502214
bool Constraint::isAssumption() const {
506
11502214
  return getProofType() == AssumeAP;
507
}
508
509
620590
bool Constraint::hasEqualityEngineProof() const {
510
620590
  return getProofType() == EqualityEngineAP;
511
}
512
513
bool Constraint::hasFarkasProof() const {
514
  return getProofType() == FarkasAP;
515
}
516
517
bool Constraint::hasSimpleFarkasProof() const
518
{
519
  Debug("constraints::hsfp") << "hasSimpleFarkasProof " << this << std::endl;
520
  if (!hasFarkasProof())
521
  {
522
    Debug("constraints::hsfp") << "There is no simple Farkas proof because "
523
                                  "there is no farkas proof."
524
                               << std::endl;
525
    return false;
526
  }
527
528
  // For each antecdent ...
529
  AntecedentId i = getConstraintRule().d_antecedentEnd;
530
  for (ConstraintCP a = d_database->getAntecedent(i); a != NullConstraint;
531
       a = d_database->getAntecedent(--i))
532
  {
533
    // ... that antecdent must be an assumption OR a tightened assumption ...
534
    if (a->isPossiblyTightenedAssumption())
535
    {
536
      continue;
537
    }
538
539
    // ... otherwise, we do not have a simple Farkas proof.
540
    if (Debug.isOn("constraints::hsfp"))
541
    {
542
      Debug("constraints::hsfp") << "There is no simple Farkas proof b/c there "
543
                                    "is an antecdent w/ rule ";
544
      a->getConstraintRule().print(Debug("constraints::hsfp"));
545
      Debug("constraints::hsfp") << std::endl;
546
    }
547
548
    return false;
549
  }
550
  return true;
551
}
552
553
bool Constraint::isPossiblyTightenedAssumption() const
554
{
555
  // ... that antecdent must be an assumption ...
556
557
  if (isAssumption()) return true;
558
  if (!hasIntTightenProof()) return false;
559
  if (getConstraintRule().d_antecedentEnd == AntecedentIdSentinel) return false;
560
  return d_database->getAntecedent(getConstraintRule().d_antecedentEnd)
561
      ->isAssumption();
562
}
563
564
bool Constraint::hasIntTightenProof() const {
565
  return getProofType() == IntTightenAP;
566
}
567
568
bool Constraint::hasIntHoleProof() const {
569
  return getProofType() == IntHoleAP;
570
}
571
572
bool Constraint::hasTrichotomyProof() const {
573
  return getProofType() == TrichotomyAP;
574
}
575
576
void Constraint::printProofTree(std::ostream& out, size_t depth) const
577
{
578
  if (ARITH_PROOF_ON())
579
  {
580
    const ConstraintRule& rule = getConstraintRule();
581
    out << std::string(2 * depth, ' ') << "* " << getVariable() << " [";
582
    out << getProofLiteral();
583
    if (assertedToTheTheory())
584
    {
585
      out << " | wit: " << getWitness();
586
    }
587
    out << "]" << ' ' << getType() << ' ' << getValue() << " ("
588
        << getProofType() << ")";
589
    if (getProofType() == FarkasAP)
590
    {
591
      out << " [";
592
      bool first = true;
593
      for (const auto& coeff : *rule.d_farkasCoefficients)
594
      {
595
        if (not first)
596
        {
597
          out << ", ";
598
        }
599
        first = false;
600
        out << coeff;
601
      }
602
      out << "]";
603
    }
604
    out << endl;
605
606
    for (AntecedentId i = rule.d_antecedentEnd; i != AntecedentIdSentinel; --i)
607
    {
608
      ConstraintCP antecdent = d_database->getAntecedent(i);
609
      if (antecdent == NullConstraint)
610
      {
611
        break;
612
      }
613
      antecdent->printProofTree(out, depth + 1);
614
    }
615
    return;
616
  }
617
  out << "Cannot print proof. This is not a proof build." << endl;
618
}
619
620
528258
bool Constraint::sanityChecking(Node n) const {
621
1056516
  Comparison cmp = Comparison::parseNormalForm(n);
622
528258
  Kind k = cmp.comparisonKind();
623
1056516
  Polynomial pleft = cmp.normalizedVariablePart();
624
528258
  Assert(k == EQUAL || k == DISTINCT || pleft.leadingCoefficientIsPositive());
625
528258
  Assert(k != EQUAL || Monomial::isMember(n[0]));
626
528258
  Assert(k != DISTINCT || Monomial::isMember(n[0][0]));
627
628
1056516
  TNode left = pleft.getNode();
629
1056516
  DeltaRational right = cmp.normalizedDeltaRational();
630
631
528258
  const ArithVariables& avariables = d_database->getArithVariables();
632
633
528258
  Debug("Constraint::sanityChecking") << cmp.getNode() << endl;
634
528258
  Debug("Constraint::sanityChecking") << k << endl;
635
528258
  Debug("Constraint::sanityChecking") << pleft.getNode() << endl;
636
528258
  Debug("Constraint::sanityChecking") << left << endl;
637
528258
  Debug("Constraint::sanityChecking") << right << endl;
638
528258
  Debug("Constraint::sanityChecking") << getValue() << endl;
639
528258
  Debug("Constraint::sanityChecking") << avariables.hasArithVar(left) << endl;
640
528258
  Debug("Constraint::sanityChecking") << avariables.asArithVar(left) << endl;
641
528258
  Debug("Constraint::sanityChecking") << getVariable() << endl;
642
643
644
2641290
  if(avariables.hasArithVar(left) &&
645
2641290
     avariables.asArithVar(left) == getVariable() &&
646
528258
     getValue() == right){
647
528258
    switch(getType()){
648
285080
    case LowerBound:
649
    case UpperBound:
650
      //Be overapproximate
651
285080
      return k == GT || k == GEQ ||k == LT || k == LEQ;
652
121589
    case Equality:
653
121589
      return k == EQUAL;
654
121589
    case Disequality:
655
121589
      return k == DISTINCT;
656
    default:
657
      Unreachable();
658
    }
659
  }else{
660
    return false;
661
  }
662
}
663
664
void ConstraintRule::debugPrint() const {
665
  print(std::cerr);
666
}
667
668
ConstraintCP ConstraintDatabase::getAntecedent (AntecedentId p) const {
669
  Assert(p < d_antecedents.size());
670
  return d_antecedents[p];
671
}
672
673
674
void ConstraintRule::print(std::ostream& out) const {
675
  RationalVectorCP coeffs = ARITH_NULLPROOF(d_farkasCoefficients);
676
  out << "{ConstraintRule, ";
677
  out << d_constraint << std::endl;
678
  out << "d_proofType= " << d_proofType << ", " << std::endl;
679
  out << "d_antecedentEnd= "<< d_antecedentEnd << std::endl;
680
681
  if (d_constraint != NullConstraint && d_antecedentEnd != AntecedentIdSentinel)
682
  {
683
    const ConstraintDatabase& database = d_constraint->getDatabase();
684
685
    size_t coeffIterator = (coeffs != RationalVectorCPSentinel) ? coeffs->size()-1 : 0;
686
    AntecedentId p = d_antecedentEnd;
687
    // must have at least one antecedent
688
    ConstraintCP antecedent = database.getAntecedent(p);
689
    while(antecedent != NullConstraint){
690
      if(coeffs != RationalVectorCPSentinel){
691
        out << coeffs->at(coeffIterator);
692
      } else {
693
        out << "_";
694
      }
695
      out << " * (" << *antecedent << ")" << std::endl;
696
697
      Assert((coeffs == RationalVectorCPSentinel) || coeffIterator > 0);
698
      --p;
699
      coeffIterator = (coeffs != RationalVectorCPSentinel) ? coeffIterator-1 : 0;
700
      antecedent = database.getAntecedent(p);
701
    }
702
    if(coeffs != RationalVectorCPSentinel){
703
      out << coeffs->front();
704
    } else {
705
      out << "_";
706
    }
707
    out << " * (" << *(d_constraint->getNegation()) << ")";
708
    out << " [not d_constraint] " << endl;
709
  }
710
  out << "}";
711
}
712
713
2240271
bool Constraint::wellFormedFarkasProof() const {
714
2240271
  Assert(hasProof());
715
716
2240271
  const ConstraintRule& cr = getConstraintRule();
717
2240271
  if(cr.d_constraint != this){ return false; }
718
2240271
  if(cr.d_proofType != FarkasAP){ return false; }
719
720
2240271
  AntecedentId p = cr.d_antecedentEnd;
721
722
  // must have at least one antecedent
723
2240271
  ConstraintCP antecedent = d_database->d_antecedents[p];
724
2240271
  if(antecedent  == NullConstraint) { return false; }
725
726
2240271
  if (!ARITH_PROOF_ON())
727
  {
728
1067372
    return cr.d_farkasCoefficients == RationalVectorCPSentinel;
729
  }
730
1172899
  Assert(ARITH_PROOF_ON());
731
732
1172899
  if(cr.d_farkasCoefficients == RationalVectorCPSentinel){ return false; }
733
1172899
  if(cr.d_farkasCoefficients->size() < 2){ return false; }
734
735
1172899
  const ArithVariables& vars = d_database->getArithVariables();
736
737
2345798
  DeltaRational rhs(0);
738
2345798
  Node lhs = Polynomial::mkZero().getNode();
739
740
1172899
  RationalVector::const_iterator coeffIterator = cr.d_farkasCoefficients->end()-1;
741
1172899
  RationalVector::const_iterator coeffBegin = cr.d_farkasCoefficients->begin();
742
743
4249055
  while(antecedent != NullConstraint){
744
1538078
    Assert(lhs.isNull() || Polynomial::isMember(lhs));
745
746
1538078
    const Rational& coeff = *coeffIterator;
747
1538078
    int coeffSgn = coeff.sgn();
748
749
1538078
    rhs += antecedent->getValue() * coeff;
750
751
1538078
    ArithVar antVar = antecedent->getVariable();
752
1538078
    if(!lhs.isNull() && vars.hasNode(antVar)){
753
3076156
      Node antAsNode = vars.asNode(antVar);
754
1538078
      if(Polynomial::isMember(antAsNode)){
755
3076156
        Polynomial lhsPoly = Polynomial::parsePolynomial(lhs);
756
3076156
        Polynomial antPoly = Polynomial::parsePolynomial(antAsNode);
757
3076156
        Polynomial sum = lhsPoly + (antPoly * coeff);
758
1538078
        lhs = sum.getNode();
759
      }else{
760
        lhs = Node::null();
761
      }
762
    } else {
763
      lhs = Node::null();
764
    }
765
1538078
    Debug("constraints::wffp") << "running sum: " << lhs << " <= " << rhs << endl;
766
767
1538078
    switch( antecedent->getType() ){
768
491972
    case LowerBound:
769
      // fc[l] < 0, therefore return false if coeffSgn >= 0
770
491972
      if(coeffSgn >= 0){ return false; }
771
491972
      break;
772
244867
    case UpperBound:
773
      // fc[u] > 0, therefore return false if coeffSgn <= 0
774
244867
      if(coeffSgn <= 0){ return false; }
775
244867
      break;
776
801239
    case Equality:
777
801239
      if(coeffSgn == 0) { return false; }
778
801239
      break;
779
    case Disequality:
780
    default:
781
      return false;
782
    }
783
784
1538078
    if(coeffIterator == coeffBegin){ return false; }
785
1538078
    --coeffIterator;
786
1538078
    --p;
787
1538078
    antecedent = d_database->d_antecedents[p];
788
  }
789
1172899
  if(coeffIterator != coeffBegin){ return false; }
790
791
1172899
  const Rational& firstCoeff = (*coeffBegin);
792
1172899
  int firstCoeffSgn = firstCoeff.sgn();
793
1172899
  rhs += (getNegation()->getValue()) * firstCoeff;
794
1172899
  if(!lhs.isNull() && vars.hasNode(getVariable())){
795
2345798
    Node firstAsNode = vars.asNode(getVariable());
796
1172899
    if(Polynomial::isMember(firstAsNode)){
797
2345798
      Polynomial lhsPoly = Polynomial::parsePolynomial(lhs);
798
2345798
      Polynomial firstPoly = Polynomial::parsePolynomial(firstAsNode);
799
2345798
      Polynomial sum = lhsPoly + (firstPoly * firstCoeff);
800
1172899
      lhs = sum.getNode();
801
    }else{
802
      lhs = Node::null();
803
    }
804
  }else{
805
    lhs = Node::null();
806
  }
807
808
1172899
  switch( getNegation()->getType() ){
809
301331
  case LowerBound:
810
    // fc[l] < 0, therefore return false if coeffSgn >= 0
811
301331
    if(firstCoeffSgn >= 0){ return false; }
812
301331
    break;
813
402000
  case UpperBound:
814
    // fc[u] > 0, therefore return false if coeffSgn <= 0
815
402000
    if(firstCoeffSgn <= 0){ return false; }
816
402000
    break;
817
469568
  case Equality:
818
469568
    if(firstCoeffSgn == 0) { return false; }
819
469568
    break;
820
  case Disequality:
821
  default:
822
    return false;
823
  }
824
1172899
  Debug("constraints::wffp") << "final sum: " << lhs << " <= " << rhs << endl;
825
  // 0 = lhs <= rhs < 0
826
3518697
  return (lhs.isNull() || (Constant::isMember(lhs) && Constant(lhs).isZero()))
827
3518697
         && rhs.sgn() < 0;
828
}
829
830
62993
ConstraintP Constraint::makeNegation(ArithVar v, ConstraintType t, const DeltaRational& r){
831
62993
  switch(t){
832
3153
  case LowerBound:
833
    {
834
3153
      Assert(r.infinitesimalSgn() >= 0);
835
3153
      if(r.infinitesimalSgn() > 0){
836
        Assert(r.getInfinitesimalPart() == 1);
837
        // make (not (v > r)), which is (v <= r)
838
        DeltaRational dropInf(r.getNoninfinitesimalPart(), 0);
839
        return new Constraint(v, UpperBound, dropInf);
840
      }else{
841
3153
        Assert(r.infinitesimalSgn() == 0);
842
        // make (not (v >= r)), which is (v < r)
843
6306
        DeltaRational addInf(r.getNoninfinitesimalPart(), -1);
844
3153
        return new Constraint(v, UpperBound, addInf);
845
      }
846
    }
847
54980
  case UpperBound:
848
    {
849
54980
      Assert(r.infinitesimalSgn() <= 0);
850
54980
      if(r.infinitesimalSgn() < 0){
851
        Assert(r.getInfinitesimalPart() == -1);
852
        // make (not (v < r)), which is (v >= r)
853
        DeltaRational dropInf(r.getNoninfinitesimalPart(), 0);
854
        return new Constraint(v, LowerBound, dropInf);
855
      }else{
856
54980
        Assert(r.infinitesimalSgn() == 0);
857
        // make (not (v <= r)), which is (v > r)
858
109960
        DeltaRational addInf(r.getNoninfinitesimalPart(), 1);
859
54980
        return new Constraint(v, LowerBound, addInf);
860
      }
861
    }
862
4860
  case Equality:
863
4860
    return new Constraint(v, Disequality, r);
864
  case Disequality:
865
    return new Constraint(v, Equality, r);
866
  default:
867
    Unreachable();
868
    return NullConstraint;
869
  }
870
}
871
872
9856
ConstraintDatabase::ConstraintDatabase(context::Context* satContext,
873
                                       context::Context* userContext,
874
                                       const ArithVariables& avars,
875
                                       ArithCongruenceManager& cm,
876
                                       RaiseConflict raiseConflict,
877
                                       EagerProofGenerator* pfGen,
878
9856
                                       ProofNodeManager* pnm)
879
    : d_varDatabases(),
880
      d_toPropagate(satContext),
881
      d_antecedents(satContext, false),
882
9856
      d_watches(new Watches(satContext, userContext)),
883
      d_avariables(avars),
884
      d_congruenceManager(cm),
885
      d_satContext(satContext),
886
      d_pfGen(pfGen),
887
      d_pnm(pnm),
888
      d_raiseConflict(raiseConflict),
889
      d_one(1),
890
19712
      d_negOne(-1)
891
{
892
9856
}
893
894
10540802
SortedConstraintMap& ConstraintDatabase::getVariableSCM(ArithVar v) const{
895
10540802
  Assert(variableDatabaseIsSetup(v));
896
10540802
  return d_varDatabases[v]->d_constraints;
897
}
898
899
29938
void ConstraintDatabase::pushSplitWatch(ConstraintP c){
900
29938
  Assert(!c->d_split);
901
29938
  c->d_split = true;
902
29938
  d_watches->d_splitWatches.push_back(c);
903
29938
}
904
905
906
800084
void ConstraintDatabase::pushCanBePropagatedWatch(ConstraintP c){
907
800084
  Assert(!c->d_canBePropagated);
908
800084
  c->d_canBePropagated = true;
909
800084
  d_watches->d_canBePropagatedWatches.push_back(c);
910
800084
}
911
912
5684029
void ConstraintDatabase::pushAssertionOrderWatch(ConstraintP c, TNode witness){
913
5684029
  Assert(!c->assertedToTheTheory());
914
5684029
  c->d_assertionOrder = d_watches->d_assertionOrderWatches.size();
915
5684029
  c->d_witness = witness;
916
5684029
  d_watches->d_assertionOrderWatches.push_back(c);
917
5684029
}
918
919
920
8759361
void ConstraintDatabase::pushConstraintRule(const ConstraintRule& crp){
921
8759361
  ConstraintP c = crp.d_constraint;
922
8759361
  Assert(c->d_crid == ConstraintRuleIdSentinel);
923
8759361
  Assert(!c->hasProof());
924
8759361
  c->d_crid = d_watches->d_constraintProofs.size();
925
8759361
  d_watches->d_constraintProofs.push_back(crp);
926
8759361
}
927
928
1633468
ConstraintP ConstraintDatabase::getConstraint(ArithVar v, ConstraintType t, const DeltaRational& r){
929
  //This must always return a constraint.
930
931
1633468
  SortedConstraintMap& scm = getVariableSCM(v);
932
1633468
  pair<SortedConstraintMapIterator, bool> insertAttempt;
933
1633468
  insertAttempt = scm.insert(make_pair(r, ValueCollection()));
934
935
1633468
  SortedConstraintMapIterator pos = insertAttempt.first;
936
1633468
  ValueCollection& vc = pos->second;
937
1633468
  if(vc.hasConstraintOfType(t)){
938
1570475
    return vc.getConstraintOfType(t);
939
  }else{
940
62993
    ConstraintP c = new Constraint(v, t, r);
941
62993
    ConstraintP negC = Constraint::makeNegation(v, t, r);
942
943
62993
    SortedConstraintMapIterator negPos;
944
62993
    if(t == Equality || t == Disequality){
945
4860
      negPos = pos;
946
    }else{
947
58133
      pair<SortedConstraintMapIterator, bool> negInsertAttempt;
948
58133
      negInsertAttempt = scm.insert(make_pair(negC->getValue(), ValueCollection()));
949
58133
      Assert(negInsertAttempt.second
950
             || !negInsertAttempt.first->second.hasConstraintOfType(
951
                 negC->getType()));
952
58133
      negPos = negInsertAttempt.first;
953
    }
954
955
62993
    c->initialize(this, pos, negC);
956
62993
    negC->initialize(this, negPos, c);
957
958
62993
    vc.add(c);
959
62993
    negPos->second.add(negC);
960
961
62993
    return c;
962
  }
963
}
964
965
246229
ConstraintP ConstraintDatabase::ensureConstraint(ValueCollection& vc, ConstraintType t){
966
246229
  if(vc.hasConstraintOfType(t)){
967
240057
    return vc.getConstraintOfType(t);
968
  }else{
969
6172
    return getConstraint(vc.getVariable(), t, vc.getValue());
970
  }
971
}
972
973
bool ConstraintDatabase::emptyDatabase(const std::vector<PerVariableDatabase>& vec){
974
  std::vector<PerVariableDatabase>::const_iterator first = vec.begin();
975
  std::vector<PerVariableDatabase>::const_iterator last = vec.end();
976
  return std::find_if(first, last, PerVariableDatabase::IsEmpty) == last;
977
}
978
979
19712
ConstraintDatabase::~ConstraintDatabase(){
980
9856
  delete d_watches;
981
982
19712
  std::vector<ConstraintP> constraintList;
983
984
331930
  while(!d_varDatabases.empty()){
985
161037
    PerVariableDatabase* back = d_varDatabases.back();
986
987
161037
    SortedConstraintMap& scm = back->d_constraints;
988
161037
    SortedConstraintMapIterator i = scm.begin(), i_end = scm.end();
989
1039457
    for(; i != i_end; ++i){
990
439210
      (i->second).push_into(constraintList);
991
    }
992
1463969
    while(!constraintList.empty()){
993
651466
      ConstraintP c = constraintList.back();
994
651466
      constraintList.pop_back();
995
651466
      delete c;
996
    }
997
161037
    Assert(scm.empty());
998
161037
    d_varDatabases.pop_back();
999
161037
    delete back;
1000
  }
1001
1002
9856
  Assert(d_nodetoConstraintMap.empty());
1003
9856
}
1004
1005
9856
ConstraintDatabase::Statistics::Statistics()
1006
9856
    : d_unatePropagateCalls(smtStatisticsRegistry().registerInt(
1007
19712
        "theory::arith::cd::unatePropagateCalls")),
1008
9856
      d_unatePropagateImplications(smtStatisticsRegistry().registerInt(
1009
19712
          "theory::arith::cd::unatePropagateImplications"))
1010
{
1011
9856
}
1012
1013
void ConstraintDatabase::deleteConstraintAndNegation(ConstraintP c){
1014
  Assert(c->safeToGarbageCollect());
1015
  ConstraintP neg = c->getNegation();
1016
  Assert(neg->safeToGarbageCollect());
1017
  delete c;
1018
  delete neg;
1019
}
1020
1021
161037
void ConstraintDatabase::addVariable(ArithVar v){
1022
161037
  if(d_reclaimable.isMember(v)){
1023
    SortedConstraintMap& scm = getVariableSCM(v);
1024
1025
    std::vector<ConstraintP> constraintList;
1026
1027
    for(SortedConstraintMapIterator i = scm.begin(), end = scm.end(); i != end; ++i){
1028
      (i->second).push_into(constraintList);
1029
    }
1030
    while(!constraintList.empty()){
1031
      ConstraintP c = constraintList.back();
1032
      constraintList.pop_back();
1033
      Assert(c->safeToGarbageCollect());
1034
      delete c;
1035
    }
1036
    Assert(scm.empty());
1037
1038
    d_reclaimable.remove(v);
1039
  }else{
1040
161037
    Debug("arith::constraint") << "about to fail" << v << " " << d_varDatabases.size() << endl;
1041
161037
    Assert(v == d_varDatabases.size());
1042
161037
    d_varDatabases.push_back(new PerVariableDatabase(v));
1043
  }
1044
161037
}
1045
1046
void ConstraintDatabase::removeVariable(ArithVar v){
1047
  Assert(!d_reclaimable.isMember(v));
1048
  d_reclaimable.add(v);
1049
}
1050
1051
bool Constraint::safeToGarbageCollect() const{
1052
  // Do not call during destructor as getNegation() may be Null by this point
1053
  Assert(getNegation() != NullConstraint);
1054
  return !contextDependentDataIsSet() && ! getNegation()->contextDependentDataIsSet();
1055
}
1056
1057
652855
bool Constraint::contextDependentDataIsSet() const{
1058
652855
  return hasProof() || isSplit() || canBePropagated() || assertedToTheTheory();
1059
}
1060
1061
14969
TrustNode Constraint::split()
1062
{
1063
14969
  Assert(isEquality() || isDisequality());
1064
1065
14969
  bool isEq = isEquality();
1066
1067
14969
  ConstraintP eq = isEq ? this : d_negation;
1068
14969
  ConstraintP diseq = isEq ? d_negation : this;
1069
1070
29938
  TNode eqNode = eq->getLiteral();
1071
14969
  Assert(eqNode.getKind() == kind::EQUAL);
1072
29938
  TNode lhs = eqNode[0];
1073
29938
  TNode rhs = eqNode[1];
1074
1075
29938
  Node leqNode = NodeBuilder(kind::LEQ) << lhs << rhs;
1076
29938
  Node ltNode = NodeBuilder(kind::LT) << lhs << rhs;
1077
29938
  Node gtNode = NodeBuilder(kind::GT) << lhs << rhs;
1078
29938
  Node geqNode = NodeBuilder(kind::GEQ) << lhs << rhs;
1079
1080
29938
  Node lemma = NodeBuilder(OR) << leqNode << geqNode;
1081
1082
14969
  TrustNode trustedLemma;
1083
14969
  if (d_database->isProofEnabled())
1084
  {
1085
    // Farkas proof that this works.
1086
2215
    auto nm = NodeManager::currentNM();
1087
4430
    auto nLeqPf = d_database->d_pnm->mkAssume(leqNode.negate());
1088
2215
    auto gtPf = d_database->d_pnm->mkNode(
1089
4430
        PfRule::MACRO_SR_PRED_TRANSFORM, {nLeqPf}, {gtNode});
1090
4430
    auto nGeqPf = d_database->d_pnm->mkAssume(geqNode.negate());
1091
2215
    auto ltPf = d_database->d_pnm->mkNode(
1092
4430
        PfRule::MACRO_SR_PRED_TRANSFORM, {nGeqPf}, {ltNode});
1093
2215
    auto sumPf = d_database->d_pnm->mkNode(
1094
        PfRule::MACRO_ARITH_SCALE_SUM_UB,
1095
        {gtPf, ltPf},
1096
4430
        {nm->mkConst<Rational>(-1), nm->mkConst<Rational>(1)});
1097
2215
    auto botPf = d_database->d_pnm->mkNode(
1098
4430
        PfRule::MACRO_SR_PRED_TRANSFORM, {sumPf}, {nm->mkConst(false)});
1099
4430
    std::vector<Node> a = {leqNode.negate(), geqNode.negate()};
1100
4430
    auto notAndNotPf = d_database->d_pnm->mkScope(botPf, a);
1101
    // No need to ensure that the expected node aggrees with `a` because we are
1102
    // not providing an expected node.
1103
    auto orNotNotPf =
1104
4430
        d_database->d_pnm->mkNode(PfRule::NOT_AND, {notAndNotPf}, {});
1105
2215
    auto orPf = d_database->d_pnm->mkNode(
1106
4430
        PfRule::MACRO_SR_PRED_TRANSFORM, {orNotNotPf}, {lemma});
1107
2215
    trustedLemma = d_database->d_pfGen->mkTrustNode(lemma, orPf);
1108
  }
1109
  else
1110
  {
1111
12754
    trustedLemma = TrustNode::mkTrustLemma(lemma);
1112
  }
1113
1114
14969
  eq->d_database->pushSplitWatch(eq);
1115
14969
  diseq->d_database->pushSplitWatch(diseq);
1116
1117
29938
  return trustedLemma;
1118
}
1119
1120
1056517
bool ConstraintDatabase::hasLiteral(TNode literal) const {
1121
1056517
  return lookup(literal) != NullConstraint;
1122
}
1123
1124
264129
ConstraintP ConstraintDatabase::addLiteral(TNode literal){
1125
264129
  Assert(!hasLiteral(literal));
1126
264129
  bool isNot = (literal.getKind() == NOT);
1127
528258
  Node atomNode = (isNot ? literal[0] : literal);
1128
528258
  Node negationNode  = atomNode.notNode();
1129
1130
264129
  Assert(!hasLiteral(atomNode));
1131
264129
  Assert(!hasLiteral(negationNode));
1132
528258
  Comparison posCmp = Comparison::parseNormalForm(atomNode);
1133
1134
264129
  ConstraintType posType = Constraint::constraintTypeOfComparison(posCmp);
1135
1136
528258
  Polynomial nvp = posCmp.normalizedVariablePart();
1137
264129
  ArithVar v = d_avariables.asArithVar(nvp.getNode());
1138
1139
528258
  DeltaRational posDR = posCmp.normalizedDeltaRational();
1140
1141
264129
  ConstraintP posC = new Constraint(v, posType, posDR);
1142
1143
264129
  Debug("arith::constraint") << "addliteral( literal ->" << literal << ")" << endl;
1144
264129
  Debug("arith::constraint") << "addliteral( posC ->" << posC << ")" << endl;
1145
1146
264129
  SortedConstraintMap& scm = getVariableSCM(posC->getVariable());
1147
264129
  pair<SortedConstraintMapIterator, bool> insertAttempt;
1148
264129
  insertAttempt = scm.insert(make_pair(posC->getValue(), ValueCollection()));
1149
1150
264129
  SortedConstraintMapIterator posI = insertAttempt.first;
1151
  // If the attempt succeeds, i points to a new empty ValueCollection
1152
  // If the attempt fails, i points to a pre-existing ValueCollection
1153
1154
264129
  if(posI->second.hasConstraintOfType(posC->getType())){
1155
    //This is the situation where the ConstraintP exists, but
1156
    //the literal has not been  associated with it.
1157
1389
    ConstraintP hit = posI->second.getConstraintOfType(posC->getType());
1158
1389
    Debug("arith::constraint") << "hit " << hit << endl;
1159
1389
    Debug("arith::constraint") << "posC " << posC << endl;
1160
1161
1389
    delete posC;
1162
1163
1389
    hit->setLiteral(atomNode);
1164
1389
    hit->getNegation()->setLiteral(negationNode);
1165
1389
    return isNot ? hit->getNegation(): hit;
1166
  }else{
1167
525480
    Comparison negCmp = Comparison::parseNormalForm(negationNode);
1168
1169
262740
    ConstraintType negType = Constraint::constraintTypeOfComparison(negCmp);
1170
525480
    DeltaRational negDR = negCmp.normalizedDeltaRational();
1171
1172
262740
    ConstraintP negC = new Constraint(v, negType, negDR);
1173
1174
262740
    SortedConstraintMapIterator negI;
1175
1176
262740
    if(posC->isEquality()){
1177
121378
      negI = posI;
1178
    }else{
1179
141362
      Assert(posC->isLowerBound() || posC->isUpperBound());
1180
1181
141362
      pair<SortedConstraintMapIterator, bool> negInsertAttempt;
1182
141362
      negInsertAttempt = scm.insert(make_pair(negC->getValue(), ValueCollection()));
1183
1184
141362
      Debug("nf::tmp") << "sdhjfgdhjkldfgljkhdfg" << endl;
1185
141362
      Debug("nf::tmp") << negC << endl;
1186
141362
      Debug("nf::tmp") << negC->getValue() << endl;
1187
1188
      //This should always succeed as the DeltaRational for the negation is unique!
1189
141362
      Assert(negInsertAttempt.second);
1190
1191
141362
      negI = negInsertAttempt.first;
1192
    }
1193
1194
262740
    (posI->second).add(posC);
1195
262740
    (negI->second).add(negC);
1196
1197
262740
    posC->initialize(this, posI, negC);
1198
262740
    negC->initialize(this, negI, posC);
1199
1200
262740
    posC->setLiteral(atomNode);
1201
262740
    negC->setLiteral(negationNode);
1202
1203
262740
    return isNot ? negC : posC;
1204
  }
1205
}
1206
1207
1208
9831824
ConstraintP ConstraintDatabase::lookup(TNode literal) const{
1209
9831824
  NodetoConstraintMap::const_iterator iter = d_nodetoConstraintMap.find(literal);
1210
9831824
  if(iter == d_nodetoConstraintMap.end()){
1211
1888927
    return NullConstraint;
1212
  }else{
1213
7942897
    return iter->second;
1214
  }
1215
}
1216
1217
4757531
void Constraint::setAssumption(bool nowInConflict){
1218
4757531
  Debug("constraints::pf") << "setAssumption(" << this << ")" << std::endl;
1219
4757531
  Assert(!hasProof());
1220
4757531
  Assert(negationHasProof() == nowInConflict);
1221
4757531
  Assert(hasLiteral());
1222
4757531
  Assert(assertedToTheTheory());
1223
1224
4757531
  d_database->pushConstraintRule(ConstraintRule(this, AssumeAP));
1225
1226
4757531
  Assert(inConflict() == nowInConflict);
1227
4757531
  if(Debug.isOn("constraint::conflictCommit") && inConflict()){
1228
    Debug("constraint::conflictCommit") << "inConflict@setAssumption " << this << std::endl;
1229
  }
1230
4757531
}
1231
1232
3730244
void Constraint::tryToPropagate(){
1233
3730244
  Assert(hasProof());
1234
3730244
  Assert(!isAssumption());
1235
3730244
  Assert(!isInternalAssumption());
1236
1237
3730244
  if(canBePropagated() && !assertedToTheTheory() && !isAssumption() && !isInternalAssumption()){
1238
722939
    propagate();
1239
  }
1240
3730244
}
1241
1242
741114
void Constraint::propagate(){
1243
741114
  Assert(hasProof());
1244
741114
  Assert(canBePropagated());
1245
741114
  Assert(!assertedToTheTheory());
1246
741114
  Assert(!isAssumption());
1247
741114
  Assert(!isInternalAssumption());
1248
1249
741114
  d_database->d_toPropagate.push(this);
1250
741114
}
1251
1252
1253
/*
1254
 * Example:
1255
 *    x <= a and a < b
1256
 * |= x <= b
1257
 * ---
1258
 *  1*(x <= a) + (-1)*(x > b) => (0 <= a-b)
1259
 */
1260
2146214
void Constraint::impliedByUnate(ConstraintCP imp, bool nowInConflict){
1261
2146214
  Debug("constraints::pf") << "impliedByUnate(" << this << ", " << *imp << ")" << std::endl;
1262
2146214
  Assert(!hasProof());
1263
2146214
  Assert(imp->hasProof());
1264
2146214
  Assert(negationHasProof() == nowInConflict);
1265
1266
2146214
  d_database->d_antecedents.push_back(NullConstraint);
1267
2146214
  d_database->d_antecedents.push_back(imp);
1268
1269
2146214
  AntecedentId antecedentEnd = d_database->d_antecedents.size() - 1;
1270
1271
  RationalVectorP coeffs;
1272
2146214
  if (ARITH_PROOF_ON())
1273
  {
1274
1126106
    std::pair<int, int> sgns = unateFarkasSigns(getNegation(), imp);
1275
1276
2252212
    Rational first(sgns.first);
1277
2252212
    Rational second(sgns.second);
1278
1279
1126106
    coeffs = new RationalVector();
1280
1126106
    coeffs->push_back(first);
1281
1126106
    coeffs->push_back(second);
1282
  }
1283
  else
1284
  {
1285
1020108
    coeffs = RationalVectorPSentinel;
1286
  }
1287
  // no need to delete coeffs the memory is owned by ConstraintRule
1288
2146214
  d_database->pushConstraintRule(ConstraintRule(this, FarkasAP, antecedentEnd, coeffs));
1289
1290
2146214
  Assert(inConflict() == nowInConflict);
1291
2146214
  if(Debug.isOn("constraint::conflictCommit") && inConflict()){
1292
    Debug("constraint::conflictCommit") << "inConflict@impliedByUnate " << this << std::endl;
1293
  }
1294
1295
2146214
  if(Debug.isOn("constraints::wffp") && !wellFormedFarkasProof()){
1296
    getConstraintRule().print(Debug("constraints::wffp"));
1297
  }
1298
2146214
  Assert(wellFormedFarkasProof());
1299
2146214
}
1300
1301
462106
void Constraint::impliedByTrichotomy(ConstraintCP a, ConstraintCP b, bool nowInConflict){
1302
462106
  Debug("constraints::pf") << "impliedByTrichotomy(" << this << ", " << *a << ", ";
1303
462106
  Debug("constraints::pf") << *b << ")" << std::endl;
1304
462106
  Assert(!hasProof());
1305
462106
  Assert(negationHasProof() == nowInConflict);
1306
462106
  Assert(a->hasProof());
1307
462106
  Assert(b->hasProof());
1308
1309
462106
  d_database->d_antecedents.push_back(NullConstraint);
1310
462106
  d_database->d_antecedents.push_back(a);
1311
462106
  d_database->d_antecedents.push_back(b);
1312
1313
462106
  AntecedentId antecedentEnd = d_database->d_antecedents.size() - 1;
1314
462106
  d_database->pushConstraintRule(ConstraintRule(this, TrichotomyAP, antecedentEnd));
1315
1316
462106
  Assert(inConflict() == nowInConflict);
1317
462106
  if(Debug.isOn("constraint::conflictCommit") && inConflict()){
1318
    Debug("constraint::conflictCommit") << "inConflict@impliedByTrichotomy " << this << std::endl;
1319
  }
1320
462106
}
1321
1322
1323
94057
bool Constraint::allHaveProof(const ConstraintCPVec& b){
1324
1380378
  for(ConstraintCPVec::const_iterator i=b.begin(), i_end=b.end(); i != i_end; ++i){
1325
1286321
    ConstraintCP cp = *i;
1326
1286321
    if(! (cp->hasProof())){ return false; }
1327
  }
1328
94057
  return true;
1329
}
1330
1331
1094243
void Constraint::impliedByIntTighten(ConstraintCP a, bool nowInConflict){
1332
1094243
  Debug("constraints::pf") << "impliedByIntTighten(" << this << ", " << *a << ")" << std::endl;
1333
1094243
  Assert(!hasProof());
1334
1094243
  Assert(negationHasProof() == nowInConflict);
1335
1094243
  Assert(a->hasProof());
1336
2188486
  Debug("pf::arith") << "impliedByIntTighten(" << this << ", " << a << ")"
1337
1094243
                     << std::endl;
1338
1339
1094243
  d_database->d_antecedents.push_back(NullConstraint);
1340
1094243
  d_database->d_antecedents.push_back(a);
1341
1094243
  AntecedentId antecedentEnd = d_database->d_antecedents.size() - 1;
1342
1094243
  d_database->pushConstraintRule(ConstraintRule(this, IntTightenAP, antecedentEnd));
1343
1344
1094243
  Assert(inConflict() == nowInConflict);
1345
1094243
  if(inConflict()){
1346
2799
    Debug("constraint::conflictCommit") << "inConflict impliedByIntTighten" << this << std::endl;
1347
  }
1348
1094243
}
1349
1350
void Constraint::impliedByIntHole(ConstraintCP a, bool nowInConflict){
1351
  Debug("constraints::pf") << "impliedByIntHole(" << this << ", " << *a << ")" << std::endl;
1352
  Assert(!hasProof());
1353
  Assert(negationHasProof() == nowInConflict);
1354
  Assert(a->hasProof());
1355
  Debug("pf::arith") << "impliedByIntHole(" << this << ", " << a << ")"
1356
                     << std::endl;
1357
1358
  d_database->d_antecedents.push_back(NullConstraint);
1359
  d_database->d_antecedents.push_back(a);
1360
  AntecedentId antecedentEnd = d_database->d_antecedents.size() - 1;
1361
  d_database->pushConstraintRule(ConstraintRule(this, IntHoleAP, antecedentEnd));
1362
1363
  Assert(inConflict() == nowInConflict);
1364
  if(Debug.isOn("constraint::conflictCommit") && inConflict()){
1365
    Debug("constraint::conflictCommit") << "inConflict impliedByIntHole" << this << std::endl;
1366
  }
1367
}
1368
1369
void Constraint::impliedByIntHole(const ConstraintCPVec& b, bool nowInConflict){
1370
  Debug("constraints::pf") << "impliedByIntHole(" << this;
1371
  if (Debug.isOn("constraints::pf")) {
1372
    for (const ConstraintCP& p : b)
1373
    {
1374
      Debug("constraints::pf") << ", " << p;
1375
    }
1376
  }
1377
  Debug("constraints::pf") << ")" << std::endl;
1378
1379
  Assert(!hasProof());
1380
  Assert(negationHasProof() == nowInConflict);
1381
  Assert(allHaveProof(b));
1382
1383
  CDConstraintList& antecedents = d_database->d_antecedents;
1384
  antecedents.push_back(NullConstraint);
1385
  for(ConstraintCPVec::const_iterator i=b.begin(), i_end=b.end(); i != i_end; ++i){
1386
    antecedents.push_back(*i);
1387
  }
1388
  AntecedentId antecedentEnd = antecedents.size() - 1;
1389
1390
  d_database->pushConstraintRule(ConstraintRule(this, IntHoleAP, antecedentEnd));
1391
1392
  Assert(inConflict() == nowInConflict);
1393
  if(Debug.isOn("constraint::conflictCommit") && inConflict()){
1394
    Debug("constraint::conflictCommit") << "inConflict@impliedByIntHole[vec] " << this << std::endl;
1395
  }
1396
}
1397
1398
/*
1399
 * If proofs are off, coeffs == RationalVectorSentinal.
1400
 * If proofs are on,
1401
 *   coeffs != RationalVectorSentinal,
1402
 *   coeffs->size() = a.size() + 1,
1403
 *   for i in [0,a.size) : coeff[i] corresponds to a[i], and
1404
 *   coeff.back() corresponds to the current constraint.
1405
 */
1406
94057
void Constraint::impliedByFarkas(const ConstraintCPVec& a, RationalVectorCP coeffs, bool nowInConflict){
1407
94057
  Debug("constraints::pf") << "impliedByFarkas(" << this;
1408
94057
  if (Debug.isOn("constraints::pf")) {
1409
    for (const ConstraintCP& p : a)
1410
    {
1411
      Debug("constraints::pf") << ", " << p;
1412
    }
1413
  }
1414
94057
  Debug("constraints::pf") << ", <coeffs>";
1415
94057
  Debug("constraints::pf") << ")" << std::endl;
1416
94057
  Assert(!hasProof());
1417
94057
  Assert(negationHasProof() == nowInConflict);
1418
94057
  Assert(allHaveProof(a));
1419
1420
94057
  Assert(ARITH_PROOF_ON() == (coeffs != RationalVectorCPSentinel));
1421
94057
  Assert(!ARITH_PROOF_ON() || coeffs->size() == a.size() + 1);
1422
1423
94057
  Assert(a.size() >= 1);
1424
1425
94057
  d_database->d_antecedents.push_back(NullConstraint);
1426
1380378
  for(ConstraintCPVec::const_iterator i = a.begin(), end = a.end(); i != end; ++i){
1427
1286321
    ConstraintCP c_i = *i;
1428
1286321
    Assert(c_i->hasProof());
1429
1286321
    d_database->d_antecedents.push_back(c_i);
1430
  }
1431
94057
  AntecedentId antecedentEnd = d_database->d_antecedents.size() - 1;
1432
1433
  RationalVectorCP coeffsCopy;
1434
94057
  if (ARITH_PROOF_ON())
1435
  {
1436
46793
    Assert(coeffs != RationalVectorCPSentinel);
1437
46793
    coeffsCopy = new RationalVector(*coeffs);
1438
  }
1439
  else
1440
  {
1441
47264
    coeffsCopy = RationalVectorCPSentinel;
1442
  }
1443
94057
  d_database->pushConstraintRule(ConstraintRule(this, FarkasAP, antecedentEnd, coeffsCopy));
1444
1445
94057
  Assert(inConflict() == nowInConflict);
1446
94057
  if(Debug.isOn("constraint::conflictCommit") && inConflict()){
1447
    Debug("constraint::conflictCommit") << "inConflict@impliedByFarkas " << this << std::endl;
1448
  }
1449
94057
  if(Debug.isOn("constraints::wffp") && !wellFormedFarkasProof()){
1450
    getConstraintRule().print(Debug("constraints::wffp"));
1451
  }
1452
94057
  Assert(wellFormedFarkasProof());
1453
94057
}
1454
1455
1456
void Constraint::setInternalAssumption(bool nowInConflict){
1457
  Debug("constraints::pf") << "setInternalAssumption(" << this;
1458
  Debug("constraints::pf") << ")" << std::endl;
1459
  Assert(!hasProof());
1460
  Assert(negationHasProof() == nowInConflict);
1461
  Assert(!assertedToTheTheory());
1462
1463
  d_database->pushConstraintRule(ConstraintRule(this, InternalAssumeAP));
1464
1465
  Assert(inConflict() == nowInConflict);
1466
  if(Debug.isOn("constraint::conflictCommit") && inConflict()){
1467
    Debug("constraint::conflictCommit") << "inConflict@setInternalAssumption " << this << std::endl;
1468
  }
1469
}
1470
1471
1472
205210
void Constraint::setEqualityEngineProof(){
1473
205210
  Debug("constraints::pf") << "setEqualityEngineProof(" << this;
1474
205210
  Debug("constraints::pf") << ")" << std::endl;
1475
205210
  Assert(truthIsUnknown());
1476
205210
  Assert(hasLiteral());
1477
205210
  d_database->pushConstraintRule(ConstraintRule(this, EqualityEngineAP));
1478
205210
}
1479
1480
1481
4049175
SortedConstraintMap& Constraint::constraintSet() const{
1482
4049175
  Assert(d_database->variableDatabaseIsSetup(d_variable));
1483
4049175
  return (d_database->d_varDatabases[d_variable])->d_constraints;
1484
}
1485
1486
bool Constraint::antecentListIsEmpty() const{
1487
  Assert(hasProof());
1488
  return d_database->d_antecedents[getEndAntecedent()] == NullConstraint;
1489
}
1490
1491
bool Constraint::antecedentListLengthIsOne() const {
1492
  Assert(hasProof());
1493
  return !antecentListIsEmpty() &&
1494
    d_database->d_antecedents[getEndAntecedent()-1] == NullConstraint;
1495
}
1496
1497
96864
Node Constraint::externalImplication(const ConstraintCPVec& b) const{
1498
96864
  Assert(hasLiteral());
1499
193728
  Node antecedent = externalExplainByAssertions(b);
1500
193728
  Node implied = getLiteral();
1501
193728
  return antecedent.impNode(implied);
1502
}
1503
1504
1505
1043907
Node Constraint::externalExplainByAssertions(const ConstraintCPVec& b){
1506
1043907
  return externalExplain(b, AssertionOrderSentinel);
1507
}
1508
1509
14656
TrustNode Constraint::externalExplainForPropagation(TNode lit) const
1510
{
1511
14656
  Assert(hasProof());
1512
14656
  Assert(!isAssumption());
1513
14656
  Assert(!isInternalAssumption());
1514
29312
  NodeBuilder nb(Kind::AND);
1515
29312
  auto pfFromAssumptions = externalExplain(nb, d_assertionOrder);
1516
29312
  Node n = safeConstructNary(nb);
1517
14656
  if (d_database->isProofEnabled())
1518
  {
1519
    // Check that the literal we're explaining via this constraint actually
1520
    // matches the constraint's canonical literal.
1521
2034
    Assert(Rewriter::rewrite(lit) == getLiteral());
1522
4068
    std::vector<Node> assumptions;
1523
2034
    if (n.getKind() == Kind::AND)
1524
    {
1525
1233
      assumptions.insert(assumptions.end(), n.begin(), n.end());
1526
    }
1527
    else
1528
    {
1529
801
      assumptions.push_back(n);
1530
    }
1531
2034
    if (getProofLiteral() != lit)
1532
    {
1533
3933
      pfFromAssumptions = d_database->d_pnm->mkNode(
1534
2622
          PfRule::MACRO_SR_PRED_TRANSFORM, {pfFromAssumptions}, {lit});
1535
    }
1536
4068
    auto pf = d_database->d_pnm->mkScope(pfFromAssumptions, assumptions);
1537
2034
    return d_database->d_pfGen->mkTrustedPropagation(
1538
2034
        lit, safeConstructNary(Kind::AND, assumptions), pf);
1539
  }
1540
  else
1541
  {
1542
12622
    return TrustNode::mkTrustPropExp(lit, n);
1543
  }
1544
}
1545
1546
72674
TrustNode Constraint::externalExplainConflict() const
1547
{
1548
72674
  Debug("pf::arith::explain") << this << std::endl;
1549
72674
  Assert(inConflict());
1550
145348
  NodeBuilder nb(kind::AND);
1551
145348
  auto pf1 = externalExplainByAssertions(nb);
1552
145348
  auto not2 = getNegation()->getProofLiteral().negate();
1553
145348
  auto pf2 = getNegation()->externalExplainByAssertions(nb);
1554
145348
  Node n = safeConstructNary(nb);
1555
72674
  if (d_database->isProofEnabled())
1556
  {
1557
11575
    auto pfNot2 = d_database->d_pnm->mkNode(
1558
23150
        PfRule::MACRO_SR_PRED_TRANSFORM, {pf1}, {not2});
1559
23150
    std::vector<Node> lits;
1560
11575
    if (n.getKind() == Kind::AND)
1561
    {
1562
11575
      lits.insert(lits.end(), n.begin(), n.end());
1563
    }
1564
    else
1565
    {
1566
      lits.push_back(n);
1567
    }
1568
11575
    if (Debug.isOn("arith::pf::externalExplainConflict"))
1569
    {
1570
      Debug("arith::pf::externalExplainConflict") << "Lits:" << std::endl;
1571
      for (const auto& l : lits)
1572
      {
1573
        Debug("arith::pf::externalExplainConflict") << "  : " << l << std::endl;
1574
      }
1575
    }
1576
    std::vector<Node> contraLits = {getProofLiteral(),
1577
23150
                                    getNegation()->getProofLiteral()};
1578
    auto bot =
1579
11575
        not2.getKind() == Kind::NOT
1580
31920
            ? d_database->d_pnm->mkNode(PfRule::CONTRA, {pf2, pfNot2}, {})
1581
45365
            : d_database->d_pnm->mkNode(PfRule::CONTRA, {pfNot2, pf2}, {});
1582
11575
    if (Debug.isOn("arith::pf::tree"))
1583
    {
1584
      Debug("arith::pf::tree") << *this << std::endl;
1585
      Debug("arith::pf::tree") << *getNegation() << std::endl;
1586
      Debug("arith::pf::tree") << "\n\nTree:\n";
1587
      printProofTree(Debug("arith::pf::tree"));
1588
      getNegation()->printProofTree(Debug("arith::pf::tree"));
1589
    }
1590
23150
    auto confPf = d_database->d_pnm->mkScope(bot, lits);
1591
11575
    return d_database->d_pfGen->mkTrustNode(
1592
11575
        safeConstructNary(Kind::AND, lits), confPf, true);
1593
  }
1594
  else
1595
  {
1596
61099
    return TrustNode::mkTrustConflict(n);
1597
  }
1598
}
1599
1600
struct ConstraintCPHash {
1601
  /* Todo replace with an id */
1602
  size_t operator()(ConstraintCP c) const{
1603
    Assert(sizeof(ConstraintCP) > 0);
1604
    return ((size_t)c)/sizeof(ConstraintCP);
1605
  }
1606
};
1607
1608
void Constraint::assertionFringe(ConstraintCPVec& v){
1609
  unordered_set<ConstraintCP, ConstraintCPHash> visited;
1610
  size_t writePos = 0;
1611
1612
  if(!v.empty()){
1613
    const ConstraintDatabase* db = v.back()->d_database;
1614
    const CDConstraintList& antecedents = db->d_antecedents;
1615
    for(size_t i = 0; i < v.size(); ++i){
1616
      ConstraintCP vi = v[i];
1617
      if(visited.find(vi) == visited.end()){
1618
        Assert(vi->hasProof());
1619
        visited.insert(vi);
1620
        if(vi->onFringe()){
1621
          v[writePos] = vi;
1622
          writePos++;
1623
        }else{
1624
          Assert(vi->hasTrichotomyProof() || vi->hasFarkasProof()
1625
                 || vi->hasIntHoleProof() || vi->hasIntTightenProof());
1626
          AntecedentId p = vi->getEndAntecedent();
1627
1628
          ConstraintCP antecedent = antecedents[p];
1629
          while(antecedent != NullConstraint){
1630
            v.push_back(antecedent);
1631
            --p;
1632
            antecedent = antecedents[p];
1633
          }
1634
        }
1635
      }
1636
    }
1637
    v.resize(writePos);
1638
  }
1639
}
1640
1641
void Constraint::assertionFringe(ConstraintCPVec& o, const ConstraintCPVec& i){
1642
  o.insert(o.end(), i.begin(), i.end());
1643
  assertionFringe(o);
1644
}
1645
1646
1043907
Node Constraint::externalExplain(const ConstraintCPVec& v, AssertionOrder order){
1647
2087814
  NodeBuilder nb(kind::AND);
1648
1043907
  ConstraintCPVec::const_iterator i, end;
1649
2325320
  for(i = v.begin(), end = v.end(); i != end; ++i){
1650
1281413
    ConstraintCP v_i = *i;
1651
1281413
    v_i->externalExplain(nb, order);
1652
  }
1653
2087814
  return safeConstructNary(nb);
1654
}
1655
1656
5654229
std::shared_ptr<ProofNode> Constraint::externalExplain(
1657
    NodeBuilder& nb, AssertionOrder order) const
1658
{
1659
5654229
  if (Debug.isOn("pf::arith::explain"))
1660
  {
1661
    this->printProofTree(Debug("arith::pf::tree"));
1662
    Debug("pf::arith::explain") << "Explaining: " << this << " with rule ";
1663
    getConstraintRule().print(Debug("pf::arith::explain"));
1664
    Debug("pf::arith::explain") << std::endl;
1665
  }
1666
5654229
  Assert(hasProof());
1667
5654229
  Assert(!isAssumption() || assertedToTheTheory());
1668
5654229
  Assert(!isInternalAssumption());
1669
5654229
  std::shared_ptr<ProofNode> pf{};
1670
1671
5654229
  ProofNodeManager* pnm = d_database->d_pnm;
1672
1673
5654229
  if (assertedBefore(order))
1674
  {
1675
5033639
    Debug("pf::arith::explain") << "  already asserted" << std::endl;
1676
5033639
    nb << getWitness();
1677
5033639
    if (d_database->isProofEnabled())
1678
    {
1679
570424
      pf = pnm->mkAssume(getWitness());
1680
      // If the witness and literal differ, prove the difference through a
1681
      // rewrite.
1682
570424
      if (getWitness() != getProofLiteral())
1683
      {
1684
1113795
        pf = pnm->mkNode(
1685
742530
            PfRule::MACRO_SR_PRED_TRANSFORM, {pf}, {getProofLiteral()});
1686
      }
1687
    }
1688
  }
1689
620590
  else if (hasEqualityEngineProof())
1690
  {
1691
6484
    Debug("pf::arith::explain") << "  going to ee:" << std::endl;
1692
12968
    TrustNode exp = d_database->eeExplain(this);
1693
6484
    if (d_database->isProofEnabled())
1694
    {
1695
709
      Assert(exp.getProven().getKind() == Kind::IMPLIES);
1696
1418
      std::vector<std::shared_ptr<ProofNode>> hypotheses;
1697
709
      hypotheses.push_back(exp.getGenerator()->getProofFor(exp.getProven()));
1698
709
      if (exp.getNode().getKind() == Kind::AND)
1699
      {
1700
2448
        for (const auto& h : exp.getNode())
1701
        {
1702
1816
          hypotheses.push_back(
1703
3632
              pnm->mkNode(PfRule::TRUE_INTRO, {pnm->mkAssume(h)}, {}));
1704
        }
1705
      }
1706
      else
1707
      {
1708
308
        hypotheses.push_back(pnm->mkNode(
1709
231
            PfRule::TRUE_INTRO, {pnm->mkAssume(exp.getNode())}, {}));
1710
      }
1711
1418
      pf = pnm->mkNode(
1712
709
          PfRule::MACRO_SR_PRED_TRANSFORM, {hypotheses}, {getProofLiteral()});
1713
    }
1714
12968
    Debug("pf::arith::explain")
1715
6484
        << "    explanation: " << exp.getNode() << std::endl;
1716
6484
    if (exp.getNode().getKind() == Kind::AND)
1717
    {
1718
5793
      nb.append(exp.getNode().begin(), exp.getNode().end());
1719
    }
1720
    else
1721
    {
1722
691
      nb << exp.getNode();
1723
    }
1724
  }
1725
  else
1726
  {
1727
614106
    Debug("pf::arith::explain") << "  recursion!" << std::endl;
1728
614106
    Assert(!isAssumption());
1729
614106
    AntecedentId p = getEndAntecedent();
1730
614106
    ConstraintCP antecedent = d_database->d_antecedents[p];
1731
1228212
    std::vector<std::shared_ptr<ProofNode>> children;
1732
1733
3508996
    while (antecedent != NullConstraint)
1734
    {
1735
1447445
      Debug("pf::arith::explain") << "Explain " << antecedent << std::endl;
1736
2894890
      auto pn = antecedent->externalExplain(nb, order);
1737
1447445
      if (d_database->isProofEnabled())
1738
      {
1739
134436
        children.push_back(pn);
1740
      }
1741
1447445
      --p;
1742
1447445
      antecedent = d_database->d_antecedents[p];
1743
    }
1744
1745
614106
    if (d_database->isProofEnabled())
1746
    {
1747
79887
      switch (getProofType())
1748
      {
1749
        case ArithProofType::AssumeAP:
1750
        case ArithProofType::EqualityEngineAP:
1751
        {
1752
          Unreachable() << "These should be handled above";
1753
          break;
1754
        }
1755
11995
        case ArithProofType::FarkasAP:
1756
        {
1757
          // Per docs in constraint.h,
1758
          // the 0th farkas coefficient is for the negation of the deduced
1759
          // constraint the 1st corresponds to the last antecedent the nth
1760
          // corresponds to the first antecedent Then, the farkas coefficients
1761
          // and the antecedents are in the same order.
1762
1763
          // Enumerate child proofs (negation included) in d_farkasCoefficients
1764
          // order
1765
23990
          std::vector<std::shared_ptr<ProofNode>> farkasChildren;
1766
11995
          farkasChildren.push_back(
1767
23990
              pnm->mkAssume(getNegation()->getProofLiteral()));
1768
11995
          farkasChildren.insert(
1769
23990
              farkasChildren.end(), children.rbegin(), children.rend());
1770
1771
11995
          NodeManager* nm = NodeManager::currentNM();
1772
1773
          // Enumerate d_farkasCoefficients as nodes.
1774
23990
          std::vector<Node> farkasCoeffs;
1775
85290
          for (Rational r : *getFarkasCoefficients())
1776
          {
1777
73295
            farkasCoeffs.push_back(nm->mkConst<Rational>(r));
1778
          }
1779
1780
          // Apply the scaled-sum rule.
1781
          std::shared_ptr<ProofNode> sumPf = pnm->mkNode(
1782
23990
              PfRule::MACRO_ARITH_SCALE_SUM_UB, farkasChildren, farkasCoeffs);
1783
1784
          // Provable rewrite the result
1785
          auto botPf = pnm->mkNode(
1786
23990
              PfRule::MACRO_SR_PRED_TRANSFORM, {sumPf}, {nm->mkConst(false)});
1787
1788
          // Scope out the negated constraint, yielding a proof of the
1789
          // constraint.
1790
23990
          std::vector<Node> assump{getNegation()->getProofLiteral()};
1791
23990
          auto maybeDoubleNotPf = pnm->mkScope(botPf, assump, false);
1792
1793
          // No need to ensure that the expected node aggrees with `assump`
1794
          // because we are not providing an expected node.
1795
          //
1796
          // Prove that this is the literal (may need to clean a double-not)
1797
35985
          pf = pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
1798
                           {maybeDoubleNotPf},
1799
23990
                           {getProofLiteral()});
1800
1801
11995
          break;
1802
        }
1803
62648
        case ArithProofType::IntTightenAP:
1804
        {
1805
62648
          if (isUpperBound())
1806
          {
1807
61268
            pf = pnm->mkNode(
1808
122536
                PfRule::INT_TIGHT_UB, children, {}, getProofLiteral());
1809
          }
1810
1380
          else if (isLowerBound())
1811
          {
1812
1380
            pf = pnm->mkNode(
1813
2760
                PfRule::INT_TIGHT_LB, children, {}, getProofLiteral());
1814
          }
1815
          else
1816
          {
1817
            Unreachable();
1818
          }
1819
62648
          break;
1820
        }
1821
        case ArithProofType::IntHoleAP:
1822
        {
1823
          pf = pnm->mkNode(PfRule::INT_TRUST,
1824
                           children,
1825
                           {getProofLiteral()},
1826
                           getProofLiteral());
1827
          break;
1828
        }
1829
5244
        case ArithProofType::TrichotomyAP:
1830
        {
1831
10488
          pf = pnm->mkNode(PfRule::ARITH_TRICHOTOMY,
1832
                           children,
1833
                           {getProofLiteral()},
1834
15732
                           getProofLiteral());
1835
5244
          break;
1836
        }
1837
        case ArithProofType::InternalAssumeAP:
1838
        case ArithProofType::NoAP:
1839
        default:
1840
        {
1841
          Unreachable() << getProofType()
1842
                        << " should not be visible in explanation";
1843
          break;
1844
        }
1845
      }
1846
    }
1847
  }
1848
5654229
  return pf;
1849
}
1850
1851
1595
Node Constraint::externalExplainByAssertions(ConstraintCP a, ConstraintCP b){
1852
3190
  NodeBuilder nb(kind::AND);
1853
1595
  a->externalExplainByAssertions(nb);
1854
1595
  b->externalExplainByAssertions(nb);
1855
3190
  return nb;
1856
}
1857
1858
Node Constraint::externalExplainByAssertions(ConstraintCP a, ConstraintCP b, ConstraintCP c){
1859
  NodeBuilder nb(kind::AND);
1860
  a->externalExplainByAssertions(nb);
1861
  b->externalExplainByAssertions(nb);
1862
  c->externalExplainByAssertions(nb);
1863
  return nb;
1864
}
1865
1866
678700
ConstraintP Constraint::getStrictlyWeakerLowerBound(bool hasLiteral, bool asserted) const {
1867
678700
  Assert(initialized());
1868
678700
  Assert(!asserted || hasLiteral);
1869
1870
678700
  SortedConstraintMapConstIterator i = d_variablePosition;
1871
678700
  const SortedConstraintMap& scm = constraintSet();
1872
678700
  SortedConstraintMapConstIterator i_begin = scm.begin();
1873
2165176
  while(i != i_begin){
1874
859508
    --i;
1875
859508
    const ValueCollection& vc = i->second;
1876
859508
    if(vc.hasLowerBound()){
1877
218557
      ConstraintP weaker = vc.getLowerBound();
1878
1879
      // asserted -> hasLiteral
1880
      // hasLiteral -> weaker->hasLiteral()
1881
      // asserted -> weaker->assertedToTheTheory()
1882
462041
      if((!hasLiteral || (weaker->hasLiteral())) &&
1883
253238
         (!asserted || ( weaker->assertedToTheTheory()))){
1884
116270
        return weaker;
1885
      }
1886
    }
1887
  }
1888
562430
  return NullConstraint;
1889
}
1890
1891
323088
ConstraintP Constraint::getStrictlyWeakerUpperBound(bool hasLiteral, bool asserted) const {
1892
323088
  SortedConstraintMapConstIterator i = d_variablePosition;
1893
323088
  const SortedConstraintMap& scm = constraintSet();
1894
323088
  SortedConstraintMapConstIterator i_end = scm.end();
1895
1896
323088
  ++i;
1897
944380
  for(; i != i_end; ++i){
1898
416222
    const ValueCollection& vc = i->second;
1899
416222
    if(vc.hasUpperBound()){
1900
142544
      ConstraintP weaker = vc.getUpperBound();
1901
363977
      if((!hasLiteral || (weaker->hasLiteral())) &&
1902
227102
         (!asserted || ( weaker->assertedToTheTheory()))){
1903
105576
        return weaker;
1904
      }
1905
    }
1906
  }
1907
1908
217512
  return NullConstraint;
1909
}
1910
1911
8086813
ConstraintP ConstraintDatabase::getBestImpliedBound(ArithVar v, ConstraintType t, const DeltaRational& r) const {
1912
8086813
  Assert(variableDatabaseIsSetup(v));
1913
8086813
  Assert(t == UpperBound || t == LowerBound);
1914
1915
8086813
  SortedConstraintMap& scm = getVariableSCM(v);
1916
8086813
  if(t == UpperBound){
1917
3922388
    SortedConstraintMapConstIterator i = scm.lower_bound(r);
1918
3922388
    SortedConstraintMapConstIterator i_end = scm.end();
1919
3922388
    Assert(i == i_end || r <= i->first);
1920
8125242
    for(; i != i_end; i++){
1921
3445029
      Assert(r <= i->first);
1922
3445029
      const ValueCollection& vc = i->second;
1923
3445029
      if(vc.hasUpperBound()){
1924
1343602
        return vc.getUpperBound();
1925
      }
1926
    }
1927
2578786
    return NullConstraint;
1928
  }else{
1929
4164425
    Assert(t == LowerBound);
1930
4164425
    if(scm.empty()){
1931
271097
      return NullConstraint;
1932
    }else{
1933
3893328
      SortedConstraintMapConstIterator i = scm.lower_bound(r);
1934
3893328
      SortedConstraintMapConstIterator i_begin = scm.begin();
1935
3893328
      SortedConstraintMapConstIterator i_end = scm.end();
1936
3893328
      Assert(i == i_end || r <= i->first);
1937
1938
3893328
      int fdj = 0;
1939
1940
3893328
      if(i == i_end){
1941
1498003
        --i;
1942
1498003
        Debug("getBestImpliedBound") << fdj++ << " " << r << " " << i->first << endl;
1943
2395325
      }else if( (i->first) > r){
1944
631792
        if(i == i_begin){
1945
585686
          return NullConstraint;
1946
        }else{
1947
46106
          --i;
1948
46106
          Debug("getBestImpliedBound") << fdj++ << " " << r << " " << i->first << endl;
1949
        }
1950
      }
1951
1952
      do{
1953
3691780
        Debug("getBestImpliedBound") << fdj++ << " " << r << " " << i->first << endl;
1954
3691780
        Assert(r >= i->first);
1955
3691780
        const ValueCollection& vc = i->second;
1956
1957
3691780
        if(vc.hasLowerBound()){
1958
1614031
          return vc.getLowerBound();
1959
        }
1960
1961
2077749
        if(i == i_begin){
1962
1693611
          break;
1963
        }else{
1964
384138
          --i;
1965
384138
        }
1966
      }while(true);
1967
1693611
      return NullConstraint;
1968
    }
1969
  }
1970
}
1971
6484
TrustNode ConstraintDatabase::eeExplain(const Constraint* const c) const
1972
{
1973
6484
  Assert(c->hasLiteral());
1974
6484
  return d_congruenceManager.explain(c->getLiteral());
1975
}
1976
1977
void ConstraintDatabase::eeExplain(ConstraintCP c, NodeBuilder& nb) const
1978
{
1979
  Assert(c->hasLiteral());
1980
  // NOTE: this is not a recommended method since it ignores proofs
1981
  d_congruenceManager.explain(c->getLiteral(), nb);
1982
}
1983
1984
22676790
bool ConstraintDatabase::variableDatabaseIsSetup(ArithVar v) const {
1985
22676790
  return v < d_varDatabases.size();
1986
}
1987
1988
1989
9856
ConstraintDatabase::Watches::Watches(context::Context* satContext, context::Context* userContext):
1990
  d_constraintProofs(satContext),
1991
  d_canBePropagatedWatches(satContext),
1992
  d_assertionOrderWatches(satContext),
1993
9856
  d_splitWatches(userContext)
1994
9856
{}
1995
1996
1997
528258
void Constraint::setLiteral(Node n) {
1998
528258
  Debug("arith::constraint") << "Mapping " << *this << " to " << n << std::endl;
1999
528258
  Assert(Comparison::isNormalAtom(n));
2000
528258
  Assert(!hasLiteral());
2001
528258
  Assert(sanityChecking(n));
2002
528258
  d_literal = n;
2003
528258
  NodetoConstraintMap& map = d_database->d_nodetoConstraintMap;
2004
528258
  Assert(map.find(n) == map.end());
2005
528258
  map.insert(make_pair(d_literal, this));
2006
528258
}
2007
2008
1198592
Node Constraint::getProofLiteral() const
2009
{
2010
1198592
  Assert(d_database != nullptr);
2011
1198592
  Assert(d_database->d_avariables.hasNode(d_variable));
2012
2397184
  Node varPart = d_database->d_avariables.asNode(d_variable);
2013
  Kind cmp;
2014
1198592
  bool neg = false;
2015
1198592
  switch (d_type)
2016
  {
2017
466149
    case ConstraintType::UpperBound:
2018
    {
2019
466149
      if (d_value.infinitesimalIsZero())
2020
      {
2021
135913
        cmp = Kind::LEQ;
2022
      }
2023
      else
2024
      {
2025
330236
        cmp = Kind::LT;
2026
      }
2027
466149
      break;
2028
    }
2029
200509
    case ConstraintType::LowerBound:
2030
    {
2031
200509
      if (d_value.infinitesimalIsZero())
2032
      {
2033
163442
        cmp = Kind::GEQ;
2034
      }
2035
      else
2036
      {
2037
37067
        cmp = Kind::GT;
2038
      }
2039
200509
      break;
2040
    }
2041
416406
    case ConstraintType::Equality:
2042
    {
2043
416406
      cmp = Kind::EQUAL;
2044
416406
      break;
2045
    }
2046
115528
    case ConstraintType::Disequality:
2047
    {
2048
115528
      cmp = Kind::EQUAL;
2049
115528
      neg = true;
2050
115528
      break;
2051
    }
2052
    default: Unreachable() << d_type;
2053
  }
2054
1198592
  NodeManager* nm = NodeManager::currentNM();
2055
2397184
  Node constPart = nm->mkConst<Rational>(d_value.getNoninfinitesimalPart());
2056
2397184
  Node posLit = nm->mkNode(cmp, varPart, constPart);
2057
2397184
  return neg ? posLit.negate() : posLit;
2058
}
2059
2060
40128
void ConstraintDatabase::proveOr(std::vector<TrustNode>& out,
2061
                                 ConstraintP a,
2062
                                 ConstraintP b,
2063
                                 bool negateSecond) const
2064
{
2065
80256
  Node la = a->getLiteral();
2066
80256
  Node lb = b->getLiteral();
2067
80256
  Node orN = (la < lb) ? la.orNode(lb) : lb.orNode(la);
2068
40128
  if (isProofEnabled())
2069
  {
2070
6601
    Assert(b->getNegation()->getType() != ConstraintType::Disequality);
2071
6601
    auto nm = NodeManager::currentNM();
2072
6601
    auto pf_neg_la = d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
2073
13202
                                   {d_pnm->mkAssume(la.negate())},
2074
26404
                                   {a->getNegation()->getProofLiteral()});
2075
6601
    auto pf_neg_lb = d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
2076
13202
                                   {d_pnm->mkAssume(lb.negate())},
2077
26404
                                   {b->getNegation()->getProofLiteral()});
2078
6601
    int sndSign = negateSecond ? -1 : 1;
2079
    auto bot_pf =
2080
6601
        d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
2081
6601
                      {d_pnm->mkNode(PfRule::MACRO_ARITH_SCALE_SUM_UB,
2082
                                     {pf_neg_la, pf_neg_lb},
2083
                                     {nm->mkConst<Rational>(-1 * sndSign),
2084
26404
                                      nm->mkConst<Rational>(sndSign)})},
2085
33005
                      {nm->mkConst(false)});
2086
13202
    std::vector<Node> as;
2087
19803
    std::transform(orN.begin(), orN.end(), std::back_inserter(as), [](Node n) {
2088
      return n.negate();
2089
19803
    });
2090
    // No need to ensure that the expected node aggrees with `as` because we
2091
    // are not providing an expected node.
2092
6601
    auto pf = d_pnm->mkNode(
2093
        PfRule::MACRO_SR_PRED_TRANSFORM,
2094
19803
        {d_pnm->mkNode(PfRule::NOT_AND, {d_pnm->mkScope(bot_pf, as)}, {})},
2095
33005
        {orN});
2096
6601
    out.push_back(d_pfGen->mkTrustNode(orN, pf));
2097
  }
2098
  else
2099
  {
2100
33527
    out.push_back(TrustNode::mkTrustLemma(orN));
2101
  }
2102
40128
}
2103
2104
37830
void ConstraintDatabase::implies(std::vector<TrustNode>& out,
2105
                                 ConstraintP a,
2106
                                 ConstraintP b) const
2107
{
2108
75660
  Node la = a->getLiteral();
2109
75660
  Node lb = b->getLiteral();
2110
2111
75660
  Node neg_la = (la.getKind() == kind::NOT)? la[0] : la.notNode();
2112
2113
37830
  Assert(lb != neg_la);
2114
37830
  Assert(b->getNegation()->getType() == ConstraintType::LowerBound
2115
         || b->getNegation()->getType() == ConstraintType::UpperBound);
2116
37830
  proveOr(out,
2117
          a->getNegation(),
2118
          b,
2119
37830
          b->getNegation()->getType() == ConstraintType::LowerBound);
2120
37830
}
2121
2122
2298
void ConstraintDatabase::mutuallyExclusive(std::vector<TrustNode>& out,
2123
                                           ConstraintP a,
2124
                                           ConstraintP b) const
2125
{
2126
4596
  Node la = a->getLiteral();
2127
4596
  Node lb = b->getLiteral();
2128
2129
4596
  Node neg_la = la.negate();
2130
4596
  Node neg_lb = lb.negate();
2131
2298
  proveOr(out, a->getNegation(), b->getNegation(), true);
2132
2298
}
2133
2134
58591
void ConstraintDatabase::outputUnateInequalityLemmas(
2135
    std::vector<TrustNode>& out, ArithVar v) const
2136
{
2137
58591
  SortedConstraintMap& scm = getVariableSCM(v);
2138
58591
  SortedConstraintMapConstIterator scm_iter = scm.begin();
2139
58591
  SortedConstraintMapConstIterator scm_end = scm.end();
2140
58591
  ConstraintP prev = NullConstraint;
2141
  //get transitive unates
2142
  //Only lower bounds or upperbounds should be done.
2143
321405
  for(; scm_iter != scm_end; ++scm_iter){
2144
131407
    const ValueCollection& vc = scm_iter->second;
2145
131407
    if(vc.hasUpperBound()){
2146
63432
      ConstraintP ub = vc.getUpperBound();
2147
63432
      if(ub->hasLiteral()){
2148
63432
        if(prev != NullConstraint){
2149
30271
          implies(out, prev, ub);
2150
        }
2151
63432
        prev = ub;
2152
      }
2153
    }
2154
  }
2155
58591
}
2156
2157
58591
void ConstraintDatabase::outputUnateEqualityLemmas(std::vector<TrustNode>& out,
2158
                                                   ArithVar v) const
2159
{
2160
117182
  vector<ConstraintP> equalities;
2161
2162
58591
  SortedConstraintMap& scm = getVariableSCM(v);
2163
58591
  SortedConstraintMapConstIterator scm_iter = scm.begin();
2164
58591
  SortedConstraintMapConstIterator scm_end = scm.end();
2165
2166
321405
  for(; scm_iter != scm_end; ++scm_iter){
2167
131407
    const ValueCollection& vc = scm_iter->second;
2168
131407
    if(vc.hasEquality()){
2169
17548
      ConstraintP eq = vc.getEquality();
2170
17548
      if(eq->hasLiteral()){
2171
17548
        equalities.push_back(eq);
2172
      }
2173
    }
2174
  }
2175
2176
58591
  vector<ConstraintP>::const_iterator i, j, eq_end = equalities.end();
2177
76139
  for(i = equalities.begin(); i != eq_end; ++i){
2178
17548
    ConstraintP at_i = *i;
2179
19846
    for(j= i + 1; j != eq_end; ++j){
2180
2298
      ConstraintP at_j = *j;
2181
2182
2298
      mutuallyExclusive(out, at_i, at_j);
2183
    }
2184
  }
2185
2186
76139
  for(i = equalities.begin(); i != eq_end; ++i){
2187
17548
    ConstraintP eq = *i;
2188
17548
    const ValueCollection& vc = eq->getValueCollection();
2189
17548
    Assert(vc.hasEquality() && vc.getEquality()->hasLiteral());
2190
2191
17548
    bool hasLB = vc.hasLowerBound() && vc.getLowerBound()->hasLiteral();
2192
17548
    bool hasUB = vc.hasUpperBound() && vc.getUpperBound()->hasLiteral();
2193
2194
17548
    ConstraintP lb = hasLB ?
2195
17548
      vc.getLowerBound() : eq->getStrictlyWeakerLowerBound(true, false);
2196
17548
    ConstraintP ub = hasUB ?
2197
17548
      vc.getUpperBound() : eq->getStrictlyWeakerUpperBound(true, false);
2198
2199
17548
    if(hasUB && hasLB && !eq->isSplit()){
2200
115
      out.push_back(eq->split());
2201
    }
2202
17548
    if(lb != NullConstraint){
2203
2764
      implies(out, eq, lb);
2204
    }
2205
17548
    if(ub != NullConstraint){
2206
4795
      implies(out, eq, ub);
2207
    }
2208
  }
2209
58591
}
2210
2211
7637
void ConstraintDatabase::outputUnateEqualityLemmas(
2212
    std::vector<TrustNode>& lemmas) const
2213
{
2214
66228
  for(ArithVar v = 0, N = d_varDatabases.size(); v < N; ++v){
2215
58591
    outputUnateEqualityLemmas(lemmas, v);
2216
  }
2217
7637
}
2218
2219
7637
void ConstraintDatabase::outputUnateInequalityLemmas(
2220
    std::vector<TrustNode>& lemmas) const
2221
{
2222
66228
  for(ArithVar v = 0, N = d_varDatabases.size(); v < N; ++v){
2223
58591
    outputUnateInequalityLemmas(lemmas, v);
2224
  }
2225
7637
}
2226
2227
4208107
bool ConstraintDatabase::handleUnateProp(ConstraintP ant, ConstraintP cons){
2228
4208107
  if(cons->negationHasProof()){
2229
    Debug("arith::unate") << "handleUnate: " << ant << " implies " << cons << endl;
2230
    cons->impliedByUnate(ant, true);
2231
    d_raiseConflict.raiseConflict(cons, InferenceId::UNKNOWN);
2232
    return true;
2233
4208107
  }else if(!cons->isTrue()){
2234
2141369
    ++d_statistics.d_unatePropagateImplications;
2235
2141369
    Debug("arith::unate") << "handleUnate: " << ant << " implies " << cons << endl;
2236
2141369
    cons->impliedByUnate(ant, false);
2237
2141369
    cons->tryToPropagate();
2238
2141369
    return false;
2239
  } else {
2240
2066738
    return false;
2241
  }
2242
}
2243
2244
1127125
void ConstraintDatabase::unatePropLowerBound(ConstraintP curr, ConstraintP prev){
2245
1127125
  Debug("arith::unate") << "unatePropLowerBound " << curr << " " << prev << endl;
2246
1127125
  Assert(curr != prev);
2247
1127125
  Assert(curr != NullConstraint);
2248
1127125
  bool hasPrev = ! (prev == NullConstraint);
2249
1127125
  Assert(!hasPrev || curr->getValue() > prev->getValue());
2250
2251
1127125
  ++d_statistics.d_unatePropagateCalls;
2252
2253
1127125
  const SortedConstraintMap& scm = curr->constraintSet();
2254
1127125
  const SortedConstraintMapConstIterator scm_begin = scm.begin();
2255
1127125
  SortedConstraintMapConstIterator scm_i = curr->d_variablePosition;
2256
2257
  //Ignore the first ValueCollection
2258
  // NOPE: (>= p c) then (= p c) NOPE
2259
  // NOPE: (>= p c) then (not (= p c)) NOPE
2260
2261
6715629
  while(scm_i != scm_begin){
2262
3026962
    --scm_i; // move the iterator back
2263
2264
3026962
    const ValueCollection& vc = scm_i->second;
2265
2266
    //If it has the previous element, do nothing and stop!
2267
3889763
    if(hasPrev &&
2268
862801
       vc.hasConstraintOfType(prev->getType())
2269
3577426
       && vc.getConstraintOfType(prev->getType()) == prev){
2270
232710
      break;
2271
    }
2272
2273
    //Don't worry about implying the negation of upperbound.
2274
    //These should all be handled by propagating the LowerBounds!
2275
2794252
    if(vc.hasLowerBound()){
2276
1056176
      ConstraintP lb = vc.getLowerBound();
2277
1056176
      if(handleUnateProp(curr, lb)){ return; }
2278
    }
2279
2794252
    if(vc.hasDisequality()){
2280
246906
      ConstraintP dis = vc.getDisequality();
2281
246906
      if(handleUnateProp(curr, dis)){ return; }
2282
    }
2283
  }
2284
}
2285
2286
996049
void ConstraintDatabase::unatePropUpperBound(ConstraintP curr, ConstraintP prev){
2287
996049
  Debug("arith::unate") << "unatePropUpperBound " << curr << " " << prev << endl;
2288
996049
  Assert(curr != prev);
2289
996049
  Assert(curr != NullConstraint);
2290
996049
  bool hasPrev = ! (prev == NullConstraint);
2291
996049
  Assert(!hasPrev || curr->getValue() < prev->getValue());
2292
2293
996049
  ++d_statistics.d_unatePropagateCalls;
2294
2295
996049
  const SortedConstraintMap& scm = curr->constraintSet();
2296
996049
  const SortedConstraintMapConstIterator scm_end = scm.end();
2297
996049
  SortedConstraintMapConstIterator scm_i = curr->d_variablePosition;
2298
996049
  ++scm_i;
2299
6706907
  for(; scm_i != scm_end; ++scm_i){
2300
3016306
    const ValueCollection& vc = scm_i->second;
2301
2302
    //If it has the previous element, do nothing and stop!
2303
3529625
    if(hasPrev &&
2304
3337299
       vc.hasConstraintOfType(prev->getType()) &&
2305
320993
       vc.getConstraintOfType(prev->getType()) == prev){
2306
160877
      break;
2307
    }
2308
    //Don't worry about implying the negation of upperbound.
2309
    //These should all be handled by propagating the UpperBounds!
2310
2855429
    if(vc.hasUpperBound()){
2311
1106505
      ConstraintP ub = vc.getUpperBound();
2312
1106505
      if(handleUnateProp(curr, ub)){ return; }
2313
    }
2314
2855429
    if(vc.hasDisequality()){
2315
216384
      ConstraintP dis = vc.getDisequality();
2316
216384
      if(handleUnateProp(curr, dis)){ return; }
2317
    }
2318
  }
2319
}
2320
2321
924213
void ConstraintDatabase::unatePropEquality(ConstraintP curr, ConstraintP prevLB, ConstraintP prevUB){
2322
924213
  Debug("arith::unate") << "unatePropEquality " << curr << " " << prevLB << " " << prevUB << endl;
2323
924213
  Assert(curr != prevLB);
2324
924213
  Assert(curr != prevUB);
2325
924213
  Assert(curr != NullConstraint);
2326
924213
  bool hasPrevLB = ! (prevLB == NullConstraint);
2327
924213
  bool hasPrevUB = ! (prevUB == NullConstraint);
2328
924213
  Assert(!hasPrevLB || curr->getValue() >= prevLB->getValue());
2329
924213
  Assert(!hasPrevUB || curr->getValue() <= prevUB->getValue());
2330
2331
924213
  ++d_statistics.d_unatePropagateCalls;
2332
2333
924213
  const SortedConstraintMap& scm = curr->constraintSet();
2334
924213
  SortedConstraintMapConstIterator scm_curr = curr->d_variablePosition;
2335
924213
  SortedConstraintMapConstIterator scm_last = hasPrevUB ? prevUB->d_variablePosition : scm.end();
2336
924213
  SortedConstraintMapConstIterator scm_i;
2337
924213
  if(hasPrevLB){
2338
141328
    scm_i = prevLB->d_variablePosition;
2339
141328
    if(scm_i != scm_curr){ // If this does not move this past scm_curr, move it one forward
2340
36429
      ++scm_i;
2341
    }
2342
  }else{
2343
782885
    scm_i = scm.begin();
2344
  }
2345
2346
2363423
  for(; scm_i != scm_curr; ++scm_i){
2347
    // between the previous LB and the curr
2348
719605
    const ValueCollection& vc = scm_i->second;
2349
2350
    //Don't worry about implying the negation of upperbound.
2351
    //These should all be handled by propagating the LowerBounds!
2352
719605
    if(vc.hasLowerBound()){
2353
253623
      ConstraintP lb = vc.getLowerBound();
2354
253623
      if(handleUnateProp(curr, lb)){ return; }
2355
    }
2356
719605
    if(vc.hasDisequality()){
2357
250310
      ConstraintP dis = vc.getDisequality();
2358
250310
      if(handleUnateProp(curr, dis)){ return; }
2359
    }
2360
  }
2361
924213
  Assert(scm_i == scm_curr);
2362
924213
  if(!hasPrevUB || scm_i != scm_last){
2363
894654
    ++scm_i;
2364
  } // hasPrevUB implies scm_i != scm_last
2365
2366
4186927
  for(; scm_i != scm_last; ++scm_i){
2367
    // between the curr and the previous UB imply the upperbounds and disequalities.
2368
1631357
    const ValueCollection& vc = scm_i->second;
2369
2370
    //Don't worry about implying the negation of upperbound.
2371
    //These should all be handled by propagating the UpperBounds!
2372
1631357
    if(vc.hasUpperBound()){
2373
619990
      ConstraintP ub = vc.getUpperBound();
2374
619990
      if(handleUnateProp(curr, ub)){ return; }
2375
    }
2376
1631357
    if(vc.hasDisequality()){
2377
458213
      ConstraintP dis = vc.getDisequality();
2378
458213
      if(handleUnateProp(curr, dis)){ return; }
2379
    }
2380
  }
2381
}
2382
2383
1126106
std::pair<int, int> Constraint::unateFarkasSigns(ConstraintCP ca, ConstraintCP cb){
2384
1126106
  ConstraintType a = ca->getType();
2385
1126106
  ConstraintType b = cb->getType();
2386
2387
1126106
  Assert(a != Disequality);
2388
1126106
  Assert(b != Disequality);
2389
2390
1126106
  int a_sgn = (a == LowerBound) ? -1 : ((a == UpperBound) ? 1 : 0);
2391
1126106
  int b_sgn = (b == LowerBound) ? -1 : ((b == UpperBound) ? 1 : 0);
2392
2393
1126106
  if(a_sgn == 0 && b_sgn == 0){
2394
285467
    Assert(a == Equality);
2395
285467
    Assert(b == Equality);
2396
285467
    Assert(ca->getValue() != cb->getValue());
2397
570934
    if(ca->getValue() < cb->getValue()){
2398
93792
      a_sgn = 1;
2399
93792
      b_sgn = -1;
2400
    }else{
2401
191675
      a_sgn = -1;
2402
191675
      b_sgn = 1;
2403
    }
2404
840639
  }else if(a_sgn == 0){
2405
174054
    Assert(b_sgn != 0);
2406
174054
    Assert(a == Equality);
2407
174054
    a_sgn = -b_sgn;
2408
666585
  }else if(b_sgn == 0){
2409
337672
    Assert(a_sgn != 0);
2410
337672
    Assert(b == Equality);
2411
337672
    b_sgn = -a_sgn;
2412
  }
2413
1126106
  Assert(a_sgn != 0);
2414
1126106
  Assert(b_sgn != 0);
2415
2416
2252212
  Debug("arith::unateFarkasSigns") << "Constraint::unateFarkasSigns("<<a <<", " << b << ") -> "
2417
1126106
                                   << "("<<a_sgn<<", "<< b_sgn <<")"<< endl;
2418
1126106
  return make_pair(a_sgn, b_sgn);
2419
}
2420
2421
}  // namespace arith
2422
}  // namespace theory
2423
29358
}  // namespace cvc5