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

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