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