GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/constraint.cpp Lines: 1086 1489 72.9 %
Date: 2021-09-29 Branches: 1805 6437 28.0 %

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