GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/constraint.cpp Lines: 1088 1489 73.1 %
Date: 2021-09-22 Branches: 1814 6437 28.2 %

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
4821911
ConstraintRule::ConstraintRule(ConstraintP con, ArithProofType pt)
53
4821911
    : d_constraint(con), d_proofType(pt), d_antecedentEnd(AntecedentIdSentinel)
54
{
55
4821911
  d_farkasCoefficients = RationalVectorCPSentinel;
56
4821911
}
57
1466027
ConstraintRule::ConstraintRule(ConstraintP con,
58
                               ArithProofType pt,
59
1466027
                               AntecedentId antecedentEnd)
60
1466027
    : d_constraint(con), d_proofType(pt), d_antecedentEnd(antecedentEnd)
61
{
62
1466027
  d_farkasCoefficients = RationalVectorCPSentinel;
63
1466027
}
64
65
2197942
ConstraintRule::ConstraintRule(ConstraintP con,
66
                               ArithProofType pt,
67
                               AntecedentId antecedentEnd,
68
2197942
                               RationalVectorCP coeffs)
69
2197942
    : d_constraint(con), d_proofType(pt), d_antecedentEnd(antecedentEnd)
70
{
71
2197942
  Assert(con->isProofProducing() || coeffs == RationalVectorCPSentinel);
72
2197942
  d_farkasCoefficients = coeffs;
73
2197942
}
74
75
/** Given a simplifiedKind this returns the corresponding ConstraintType. */
76
//ConstraintType constraintTypeOfLiteral(Kind k);
77
541063
ConstraintType Constraint::constraintTypeOfComparison(const Comparison& cmp){
78
541063
  Kind k = cmp.comparisonKind();
79
541063
  switch(k){
80
142430
  case LT:
81
  case LEQ:
82
    {
83
284860
      Polynomial l = cmp.getLeft();
84
142430
      if(l.leadingCoefficientIsPositive()){ // (< x c)
85
117463
        return UpperBound;
86
      }else{
87
24967
        return LowerBound; // (< (-x) c)
88
      }
89
    }
90
143647
  case GT:
91
  case GEQ:
92
    {
93
287294
      Polynomial l = cmp.getLeft();
94
143647
      if(l.leadingCoefficientIsPositive()){
95
118484
        return LowerBound; // (> x c)
96
      }else{
97
25163
        return UpperBound; // (> (-x) c)
98
      }
99
    }
100
127607
  case EQUAL:
101
127607
    return Equality;
102
127379
  case DISTINCT:
103
127379
    return Disequality;
104
  default: Unhandled() << k;
105
  }
106
}
107
108
669085
Constraint::Constraint(ArithVar x,
109
                       ConstraintType t,
110
                       const DeltaRational& v,
111
669085
                       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
669085
      d_produceProofs(produceProofs)
125
{
126
669085
  Assert(!initialized());
127
669085
}
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
2001337
ValueCollection::ValueCollection()
228
  : d_lowerBound(NullConstraint),
229
    d_upperBound(NullConstraint),
230
    d_equality(NullConstraint),
231
2001337
    d_disequality(NullConstraint)
232
2001337
{}
233
234
19562673
bool ValueCollection::hasLowerBound() const{
235
19562673
  return d_lowerBound != NullConstraint;
236
}
237
238
20773964
bool ValueCollection::hasUpperBound() const{
239
20773964
  return d_upperBound != NullConstraint;
240
}
241
242
4357967
bool ValueCollection::hasEquality() const{
243
4357967
  return d_equality != NullConstraint;
244
}
245
246
13906229
bool ValueCollection::hasDisequality() const {
247
13906229
  return d_disequality != NullConstraint;
248
}
249
250
4073740
ConstraintP ValueCollection::getLowerBound() const {
251
4073740
  Assert(hasLowerBound());
252
4073740
  return d_lowerBound;
253
}
254
255
4076953
ConstraintP ValueCollection::getUpperBound() const {
256
4076953
  Assert(hasUpperBound());
257
4076953
  return d_upperBound;
258
}
259
260
334391
ConstraintP ValueCollection::getEquality() const {
261
334391
  Assert(hasEquality());
262
334391
  return d_equality;
263
}
264
265
1974399
ConstraintP ValueCollection::getDisequality() const {
266
1974399
  Assert(hasDisequality());
267
1974399
  return d_disequality;
268
}
269
270
271
448516
void ValueCollection::push_into(std::vector<ConstraintP>& vec) const {
272
448516
  Debug("arith::constraint") << "push_into " << *this << endl;
273
448516
  if(hasEquality()){
274
131583
    vec.push_back(d_equality);
275
  }
276
448516
  if(hasLowerBound()){
277
202237
    vec.push_back(d_lowerBound);
278
  }
279
448516
  if(hasUpperBound()){
280
202237
    vec.push_back(d_upperBound);
281
  }
282
448516
  if(hasDisequality()){
283
131583
    vec.push_back(d_disequality);
284
  }
285
448516
}
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
3349924
bool ValueCollection::hasConstraintOfType(ConstraintType t) const{
310
3349924
  switch(t){
311
1081640
  case LowerBound:
312
1081640
    return hasLowerBound();
313
1897672
  case UpperBound:
314
1897672
    return hasUpperBound();
315
370612
  case Equality:
316
370612
    return hasEquality();
317
  case Disequality:
318
    return hasDisequality();
319
  default:
320
    Unreachable();
321
  }
322
}
323
324
225757
ArithVar ValueCollection::getVariable() const{
325
225757
  Assert(!empty());
326
225757
  return nonNull()->getVariable();
327
}
328
329
225757
const DeltaRational& ValueCollection::getValue() const{
330
225757
  Assert(!empty());
331
225757
  return nonNull()->getValue();
332
}
333
334
667640
void ValueCollection::add(ConstraintP c){
335
667640
  Assert(c != NullConstraint);
336
337
667640
  Assert(empty() || getVariable() == c->getVariable());
338
667640
  Assert(empty() || getValue() == c->getValue());
339
340
667640
  switch(c->getType()){
341
202237
  case LowerBound:
342
202237
    Assert(!hasLowerBound());
343
202237
    d_lowerBound = c;
344
202237
    break;
345
131583
  case Equality:
346
131583
    Assert(!hasEquality());
347
131583
    d_equality = c;
348
131583
    break;
349
202237
  case UpperBound:
350
202237
    Assert(!hasUpperBound());
351
202237
    d_upperBound = c;
352
202237
    break;
353
131583
  case Disequality:
354
131583
    Assert(!hasDisequality());
355
131583
    d_disequality = c;
356
131583
    break;
357
  default:
358
    Unreachable();
359
  }
360
667640
}
361
362
2543971
ConstraintP ValueCollection::getConstraintOfType(ConstraintType t) const{
363
2543971
  switch(t){
364
691417
    case LowerBound: Assert(hasLowerBound()); return d_lowerBound;
365
239029
    case Equality: Assert(hasEquality()); return d_equality;
366
1613525
    case UpperBound: Assert(hasUpperBound()); return d_upperBound;
367
    case Disequality: Assert(hasDisequality()); return d_disequality;
368
    default: Unreachable();
369
  }
370
}
371
372
667640
void ValueCollection::remove(ConstraintType t){
373
667640
  switch(t){
374
202237
  case LowerBound:
375
202237
    Assert(hasLowerBound());
376
202237
    d_lowerBound = NullConstraint;
377
202237
    break;
378
131583
  case Equality:
379
131583
    Assert(hasEquality());
380
131583
    d_equality = NullConstraint;
381
131583
    break;
382
202237
  case UpperBound:
383
202237
    Assert(hasUpperBound());
384
202237
    d_upperBound = NullConstraint;
385
202237
    break;
386
131583
  case Disequality:
387
131583
    Assert(hasDisequality());
388
131583
    d_disequality = NullConstraint;
389
131583
    break;
390
  default:
391
    Unreachable();
392
  }
393
667640
}
394
395
2454434
bool ValueCollection::empty() const{
396
  return
397
5919609
    !(hasLowerBound() ||
398
4137294
      hasUpperBound() ||
399
2017667
      hasEquality() ||
400
3799982
      hasDisequality());
401
}
402
403
451514
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
451514
  if(hasLowerBound()){
407
132964
    return d_lowerBound;
408
318550
  }else if(hasUpperBound()){
409
48282
    return d_upperBound;
410
270268
  }else if(hasEquality()){
411
270268
    return d_equality;
412
  }else if(hasDisequality()){
413
    return d_disequality;
414
  }else{
415
    return NullConstraint;
416
  }
417
}
418
419
2735697
bool Constraint::initialized() const {
420
2735697
  return d_database != NULL;
421
}
422
423
const ConstraintDatabase& Constraint::getDatabase() const{
424
  Assert(initialized());
425
  return *d_database;
426
}
427
428
667640
void Constraint::initialize(ConstraintDatabase* db, SortedConstraintMapIterator v, ConstraintP negation){
429
667640
  Assert(!initialized());
430
667640
  d_database = db;
431
667640
  d_variablePosition = v;
432
667640
  d_negation = negation;
433
667640
}
434
435
1338170
Constraint::~Constraint() {
436
  // Call this instead of safeToGarbageCollect()
437
669085
  Assert(!contextDependentDataIsSet());
438
439
669085
  if(initialized()){
440
667640
    ValueCollection& vc =  d_variablePosition->second;
441
667640
    Debug("arith::constraint") << "removing" << vc << endl;
442
443
667640
    vc.remove(getType());
444
445
667640
    if(vc.empty()){
446
448516
      Debug("arith::constraint") << "erasing" << vc << endl;
447
448516
      SortedConstraintMap& perVariable = d_database->getVariableSCM(getVariable());
448
448516
      perVariable.erase(d_variablePosition);
449
    }
450
451
667640
    if(hasLiteral()){
452
542508
      d_database->d_nodetoConstraintMap.erase(getLiteral());
453
    }
454
  }
455
669085
}
456
457
25426600
const ConstraintRule& Constraint::getConstraintRule() const {
458
25426600
  Assert(hasProof());
459
25426600
  return d_database->d_watches->d_constraintProofs[d_crid];
460
}
461
462
3005410
const ValueCollection& Constraint::getValueCollection() const{
463
3005410
  return d_variablePosition->second;
464
}
465
466
467
86885
ConstraintP Constraint::getCeiling() {
468
86885
  Debug("getCeiling") << "Constraint_::getCeiling on " << *this << endl;
469
86885
  Assert(getValue().getInfinitesimalPart().sgn() > 0);
470
471
173770
  const DeltaRational ceiling(getValue().ceiling());
472
173770
  return d_database->getConstraint(getVariable(), getType(), ceiling);
473
}
474
475
1191323
ConstraintP Constraint::getFloor() {
476
1191323
  Assert(getValue().getInfinitesimalPart().sgn() < 0);
477
478
2382646
  const DeltaRational floor(Rational(getValue().floor()));
479
2382646
  return d_database->getConstraint(getVariable(), getType(), floor);
480
}
481
482
851164
void Constraint::setCanBePropagated() {
483
851164
  Assert(!canBePropagated());
484
851164
  d_database->pushCanBePropagatedWatch(this);
485
851164
}
486
487
5613400
void Constraint::setAssertedToTheTheory(TNode witness, bool nowInConflict) {
488
5613400
  Assert(hasLiteral());
489
5613400
  Assert(!assertedToTheTheory());
490
5613400
  Assert(negationHasProof() == nowInConflict);
491
5613400
  d_database->pushAssertionOrderWatch(this, witness);
492
493
5613400
  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
5613400
}
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
10772485
bool Constraint::isInternalAssumption() const {
517
10772485
  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
11285959
bool Constraint::isAssumption() const {
544
11285959
  return getProofType() == AssumeAP;
545
}
546
547
497211
bool Constraint::hasEqualityEngineProof() const {
548
497211
  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
542508
bool Constraint::sanityChecking(Node n) const {
659
1085016
  Comparison cmp = Comparison::parseNormalForm(n);
660
542508
  Kind k = cmp.comparisonKind();
661
1085016
  Polynomial pleft = cmp.normalizedVariablePart();
662
542508
  Assert(k == EQUAL || k == DISTINCT || pleft.leadingCoefficientIsPositive());
663
542508
  Assert(k != EQUAL || Monomial::isMember(n[0]));
664
542508
  Assert(k != DISTINCT || Monomial::isMember(n[0][0]));
665
666
1085016
  TNode left = pleft.getNode();
667
1085016
  DeltaRational right = cmp.normalizedDeltaRational();
668
669
542508
  const ArithVariables& avariables = d_database->getArithVariables();
670
671
542508
  Debug("Constraint::sanityChecking") << cmp.getNode() << endl;
672
542508
  Debug("Constraint::sanityChecking") << k << endl;
673
542508
  Debug("Constraint::sanityChecking") << pleft.getNode() << endl;
674
542508
  Debug("Constraint::sanityChecking") << left << endl;
675
542508
  Debug("Constraint::sanityChecking") << right << endl;
676
542508
  Debug("Constraint::sanityChecking") << getValue() << endl;
677
542508
  Debug("Constraint::sanityChecking") << avariables.hasArithVar(left) << endl;
678
542508
  Debug("Constraint::sanityChecking") << avariables.asArithVar(left) << endl;
679
542508
  Debug("Constraint::sanityChecking") << getVariable() << endl;
680
681
682
2712540
  if(avariables.hasArithVar(left) &&
683
2712540
     avariables.asArithVar(left) == getVariable() &&
684
542508
     getValue() == right){
685
542508
    switch(getType()){
686
287294
    case LowerBound:
687
    case UpperBound:
688
      //Be overapproximate
689
287294
      return k == GT || k == GEQ ||k == LT || k == LEQ;
690
127607
    case Equality:
691
127607
      return k == EQUAL;
692
127607
    case Disequality:
693
127607
      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
2197942
bool Constraint::wellFormedFarkasProof() const {
750
2197942
  Assert(hasProof());
751
752
2197942
  const ConstraintRule& cr = getConstraintRule();
753
2197942
  if(cr.d_constraint != this){ return false; }
754
2197942
  if(cr.d_proofType != FarkasAP){ return false; }
755
756
2197942
  AntecedentId p = cr.d_antecedentEnd;
757
758
  // must have at least one antecedent
759
2197942
  ConstraintCP antecedent = d_database->d_antecedents[p];
760
2197942
  if(antecedent  == NullConstraint) { return false; }
761
762
2197942
  if (!d_produceProofs)
763
  {
764
1361583
    return cr.d_farkasCoefficients == RationalVectorCPSentinel;
765
  }
766
836359
  Assert(d_produceProofs);
767
768
836359
  if(cr.d_farkasCoefficients == RationalVectorCPSentinel){ return false; }
769
836359
  if(cr.d_farkasCoefficients->size() < 2){ return false; }
770
771
836359
  const ArithVariables& vars = d_database->getArithVariables();
772
773
1672718
  DeltaRational rhs(0);
774
1672718
  Node lhs = Polynomial::mkZero().getNode();
775
776
836359
  RationalVector::const_iterator coeffIterator = cr.d_farkasCoefficients->end()-1;
777
836359
  RationalVector::const_iterator coeffBegin = cr.d_farkasCoefficients->begin();
778
779
3241879
  while(antecedent != NullConstraint){
780
1202760
    Assert(lhs.isNull() || Polynomial::isMember(lhs));
781
782
1202760
    const Rational& coeff = *coeffIterator;
783
1202760
    int coeffSgn = coeff.sgn();
784
785
1202760
    rhs += antecedent->getValue() * coeff;
786
787
1202760
    ArithVar antVar = antecedent->getVariable();
788
1202760
    if(!lhs.isNull() && vars.hasNode(antVar)){
789
2405520
      Node antAsNode = vars.asNode(antVar);
790
1202760
      if(Polynomial::isMember(antAsNode)){
791
2405520
        Polynomial lhsPoly = Polynomial::parsePolynomial(lhs);
792
2405520
        Polynomial antPoly = Polynomial::parsePolynomial(antAsNode);
793
2405520
        Polynomial sum = lhsPoly + (antPoly * coeff);
794
1202760
        lhs = sum.getNode();
795
      }else{
796
        lhs = Node::null();
797
      }
798
    } else {
799
      lhs = Node::null();
800
    }
801
1202760
    Debug("constraints::wffp") << "running sum: " << lhs << " <= " << rhs << endl;
802
803
1202760
    switch( antecedent->getType() ){
804
363618
    case LowerBound:
805
      // fc[l] < 0, therefore return false if coeffSgn >= 0
806
363618
      if(coeffSgn >= 0){ return false; }
807
363618
      break;
808
212792
    case UpperBound:
809
      // fc[u] > 0, therefore return false if coeffSgn <= 0
810
212792
      if(coeffSgn <= 0){ return false; }
811
212792
      break;
812
626350
    case Equality:
813
626350
      if(coeffSgn == 0) { return false; }
814
626350
      break;
815
    case Disequality:
816
    default:
817
      return false;
818
    }
819
820
1202760
    if(coeffIterator == coeffBegin){ return false; }
821
1202760
    --coeffIterator;
822
1202760
    --p;
823
1202760
    antecedent = d_database->d_antecedents[p];
824
  }
825
836359
  if(coeffIterator != coeffBegin){ return false; }
826
827
836359
  const Rational& firstCoeff = (*coeffBegin);
828
836359
  int firstCoeffSgn = firstCoeff.sgn();
829
836359
  rhs += (getNegation()->getValue()) * firstCoeff;
830
836359
  if(!lhs.isNull() && vars.hasNode(getVariable())){
831
1672718
    Node firstAsNode = vars.asNode(getVariable());
832
836359
    if(Polynomial::isMember(firstAsNode)){
833
1672718
      Polynomial lhsPoly = Polynomial::parsePolynomial(lhs);
834
1672718
      Polynomial firstPoly = Polynomial::parsePolynomial(firstAsNode);
835
1672718
      Polynomial sum = lhsPoly + (firstPoly * firstCoeff);
836
836359
      lhs = sum.getNode();
837
    }else{
838
      lhs = Node::null();
839
    }
840
  }else{
841
    lhs = Node::null();
842
  }
843
844
836359
  switch( getNegation()->getType() ){
845
246221
  case LowerBound:
846
    // fc[l] < 0, therefore return false if coeffSgn >= 0
847
246221
    if(firstCoeffSgn >= 0){ return false; }
848
246221
    break;
849
257116
  case UpperBound:
850
    // fc[u] > 0, therefore return false if coeffSgn <= 0
851
257116
    if(firstCoeffSgn <= 0){ return false; }
852
257116
    break;
853
333022
  case Equality:
854
333022
    if(firstCoeffSgn == 0) { return false; }
855
333022
    break;
856
  case Disequality:
857
  default:
858
    return false;
859
  }
860
836359
  Debug("constraints::wffp") << "final sum: " << lhs << " <= " << rhs << endl;
861
  // 0 = lhs <= rhs < 0
862
2509077
  return (lhs.isNull() || (Constant::isMember(lhs) && Constant(lhs).isZero()))
863
2509077
         && rhs.sgn() < 0;
864
}
865
866
64011
ConstraintP Constraint::makeNegation(ArithVar v,
867
                                     ConstraintType t,
868
                                     const DeltaRational& r,
869
                                     bool produceProofs)
870
{
871
64011
  switch(t){
872
3292
  case LowerBound:
873
    {
874
3292
      Assert(r.infinitesimalSgn() >= 0);
875
3292
      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
3292
        Assert(r.infinitesimalSgn() == 0);
882
        // make (not (v >= r)), which is (v < r)
883
6584
        DeltaRational addInf(r.getNoninfinitesimalPart(), -1);
884
3292
        return new Constraint(v, UpperBound, addInf, produceProofs);
885
      }
886
    }
887
56515
  case UpperBound:
888
    {
889
56515
      Assert(r.infinitesimalSgn() <= 0);
890
56515
      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
56515
        Assert(r.infinitesimalSgn() == 0);
897
        // make (not (v <= r)), which is (v > r)
898
113030
        DeltaRational addInf(r.getNoninfinitesimalPart(), 1);
899
56515
        return new Constraint(v, LowerBound, addInf, produceProofs);
900
      }
901
    }
902
4204
    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
9945
ConstraintDatabase::ConstraintDatabase(Env& env,
909
                                       const ArithVariables& avars,
910
                                       ArithCongruenceManager& cm,
911
                                       RaiseConflict raiseConflict,
912
9945
                                       EagerProofGenerator* pfGen)
913
    : EnvObj(env),
914
      d_varDatabases(),
915
      d_toPropagate(context()),
916
      d_antecedents(context(), false),
917
9945
      d_watches(new Watches(context(), userContext())),
918
      d_avariables(avars),
919
      d_congruenceManager(cm),
920
      d_pfGen(pfGen),
921
9945
      d_pnm(d_env.isTheoryProofProducing() ? d_env.getProofNodeManager()
922
                                           : nullptr),
923
      d_raiseConflict(raiseConflict),
924
      d_one(1),
925
29835
      d_negOne(-1)
926
{
927
9945
}
928
929
11140083
SortedConstraintMap& ConstraintDatabase::getVariableSCM(ArithVar v) const{
930
11140083
  Assert(variableDatabaseIsSetup(v));
931
11140083
  return d_varDatabases[v]->d_constraints;
932
}
933
934
31692
void ConstraintDatabase::pushSplitWatch(ConstraintP c){
935
31692
  Assert(!c->d_split);
936
31692
  c->d_split = true;
937
31692
  d_watches->d_splitWatches.push_back(c);
938
31692
}
939
940
941
851164
void ConstraintDatabase::pushCanBePropagatedWatch(ConstraintP c){
942
851164
  Assert(!c->d_canBePropagated);
943
851164
  c->d_canBePropagated = true;
944
851164
  d_watches->d_canBePropagatedWatches.push_back(c);
945
851164
}
946
947
5613400
void ConstraintDatabase::pushAssertionOrderWatch(ConstraintP c, TNode witness){
948
5613400
  Assert(!c->assertedToTheTheory());
949
5613400
  c->d_assertionOrder = d_watches->d_assertionOrderWatches.size();
950
5613400
  c->d_witness = witness;
951
5613400
  d_watches->d_assertionOrderWatches.push_back(c);
952
5613400
}
953
954
955
8485880
void ConstraintDatabase::pushConstraintRule(const ConstraintRule& crp){
956
8485880
  ConstraintP c = crp.d_constraint;
957
8485880
  Assert(c->d_crid == ConstraintRuleIdSentinel);
958
8485880
  Assert(!c->hasProof());
959
8485880
  c->d_crid = d_watches->d_constraintProofs.size();
960
8485880
  d_watches->d_constraintProofs.push_back(crp);
961
8485880
}
962
963
1527846
ConstraintP ConstraintDatabase::getConstraint(ArithVar v, ConstraintType t, const DeltaRational& r){
964
  //This must always return a constraint.
965
966
1527846
  SortedConstraintMap& scm = getVariableSCM(v);
967
1527846
  pair<SortedConstraintMapIterator, bool> insertAttempt;
968
1527846
  insertAttempt = scm.insert(make_pair(r, ValueCollection()));
969
970
1527846
  SortedConstraintMapIterator pos = insertAttempt.first;
971
1527846
  ValueCollection& vc = pos->second;
972
1527846
  if(vc.hasConstraintOfType(t)){
973
1463835
    return vc.getConstraintOfType(t);
974
  }else{
975
64011
    ConstraintP c = new Constraint(v, t, r, options().smt.produceProofs);
976
    ConstraintP negC =
977
64011
        Constraint::makeNegation(v, t, r, options().smt.produceProofs);
978
979
64011
    SortedConstraintMapIterator negPos;
980
64011
    if(t == Equality || t == Disequality){
981
4204
      negPos = pos;
982
    }else{
983
59807
      pair<SortedConstraintMapIterator, bool> negInsertAttempt;
984
59807
      negInsertAttempt = scm.insert(make_pair(negC->getValue(), ValueCollection()));
985
59807
      Assert(negInsertAttempt.second
986
             || !negInsertAttempt.first->second.hasConstraintOfType(
987
                 negC->getType()));
988
59807
      negPos = negInsertAttempt.first;
989
    }
990
991
64011
    c->initialize(this, pos, negC);
992
64011
    negC->initialize(this, negPos, c);
993
994
64011
    vc.add(c);
995
64011
    negPos->second.add(negC);
996
997
64011
    return c;
998
  }
999
}
1000
1001
275843
ConstraintP ConstraintDatabase::ensureConstraint(ValueCollection& vc, ConstraintType t){
1002
275843
  if(vc.hasConstraintOfType(t)){
1003
269210
    return vc.getConstraintOfType(t);
1004
  }else{
1005
6633
    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
19884
ConstraintDatabase::~ConstraintDatabase(){
1016
9942
  delete d_watches;
1017
1018
19884
  std::vector<ConstraintP> constraintList;
1019
1020
340624
  while(!d_varDatabases.empty()){
1021
165341
    PerVariableDatabase* back = d_varDatabases.back();
1022
1023
165341
    SortedConstraintMap& scm = back->d_constraints;
1024
165341
    SortedConstraintMapIterator i = scm.begin(), i_end = scm.end();
1025
1062373
    for(; i != i_end; ++i){
1026
448516
      (i->second).push_into(constraintList);
1027
    }
1028
1500621
    while(!constraintList.empty()){
1029
667640
      ConstraintP c = constraintList.back();
1030
667640
      constraintList.pop_back();
1031
667640
      delete c;
1032
    }
1033
165341
    Assert(scm.empty());
1034
165341
    d_varDatabases.pop_back();
1035
165341
    delete back;
1036
  }
1037
1038
9942
  Assert(d_nodetoConstraintMap.empty());
1039
9942
}
1040
1041
9945
ConstraintDatabase::Statistics::Statistics()
1042
9945
    : d_unatePropagateCalls(smtStatisticsRegistry().registerInt(
1043
19890
        "theory::arith::cd::unatePropagateCalls")),
1044
9945
      d_unatePropagateImplications(smtStatisticsRegistry().registerInt(
1045
19890
          "theory::arith::cd::unatePropagateImplications"))
1046
{
1047
9945
}
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
165341
void ConstraintDatabase::addVariable(ArithVar v){
1058
165341
  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
165341
    Debug("arith::constraint") << "about to fail" << v << " " << d_varDatabases.size() << endl;
1077
165341
    Assert(v == d_varDatabases.size());
1078
165341
    d_varDatabases.push_back(new PerVariableDatabase(v));
1079
  }
1080
165341
}
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
669085
bool Constraint::contextDependentDataIsSet() const{
1094
669085
  return hasProof() || isSplit() || canBePropagated() || assertedToTheTheory();
1095
}
1096
1097
15846
TrustNode Constraint::split()
1098
{
1099
15846
  Assert(isEquality() || isDisequality());
1100
1101
15846
  bool isEq = isEquality();
1102
1103
15846
  ConstraintP eq = isEq ? this : d_negation;
1104
15846
  ConstraintP diseq = isEq ? d_negation : this;
1105
1106
31692
  TNode eqNode = eq->getLiteral();
1107
15846
  Assert(eqNode.getKind() == kind::EQUAL);
1108
31692
  TNode lhs = eqNode[0];
1109
31692
  TNode rhs = eqNode[1];
1110
1111
31692
  Node leqNode = NodeBuilder(kind::LEQ) << lhs << rhs;
1112
31692
  Node ltNode = NodeBuilder(kind::LT) << lhs << rhs;
1113
31692
  Node gtNode = NodeBuilder(kind::GT) << lhs << rhs;
1114
31692
  Node geqNode = NodeBuilder(kind::GEQ) << lhs << rhs;
1115
1116
31692
  Node lemma = NodeBuilder(OR) << leqNode << geqNode;
1117
1118
15846
  TrustNode trustedLemma;
1119
15846
  if (d_database->isProofEnabled())
1120
  {
1121
    // Farkas proof that this works.
1122
2445
    auto nm = NodeManager::currentNM();
1123
4890
    auto nLeqPf = d_database->d_pnm->mkAssume(leqNode.negate());
1124
2445
    auto gtPf = d_database->d_pnm->mkNode(
1125
4890
        PfRule::MACRO_SR_PRED_TRANSFORM, {nLeqPf}, {gtNode});
1126
4890
    auto nGeqPf = d_database->d_pnm->mkAssume(geqNode.negate());
1127
2445
    auto ltPf = d_database->d_pnm->mkNode(
1128
4890
        PfRule::MACRO_SR_PRED_TRANSFORM, {nGeqPf}, {ltNode});
1129
2445
    auto sumPf = d_database->d_pnm->mkNode(
1130
        PfRule::MACRO_ARITH_SCALE_SUM_UB,
1131
        {gtPf, ltPf},
1132
4890
        {nm->mkConst<Rational>(-1), nm->mkConst<Rational>(1)});
1133
2445
    auto botPf = d_database->d_pnm->mkNode(
1134
4890
        PfRule::MACRO_SR_PRED_TRANSFORM, {sumPf}, {nm->mkConst(false)});
1135
4890
    std::vector<Node> a = {leqNode.negate(), geqNode.negate()};
1136
4890
    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
4890
        d_database->d_pnm->mkNode(PfRule::NOT_AND, {notAndNotPf}, {});
1141
2445
    auto orPf = d_database->d_pnm->mkNode(
1142
4890
        PfRule::MACRO_SR_PRED_TRANSFORM, {orNotNotPf}, {lemma});
1143
2445
    trustedLemma = d_database->d_pfGen->mkTrustNode(lemma, orPf);
1144
  }
1145
  else
1146
  {
1147
13401
    trustedLemma = TrustNode::mkTrustLemma(lemma);
1148
  }
1149
1150
15846
  eq->d_database->pushSplitWatch(eq);
1151
15846
  diseq->d_database->pushSplitWatch(diseq);
1152
1153
31692
  return trustedLemma;
1154
}
1155
1156
1085017
bool ConstraintDatabase::hasLiteral(TNode literal) const {
1157
1085017
  return lookup(literal) != NullConstraint;
1158
}
1159
1160
271254
ConstraintP ConstraintDatabase::addLiteral(TNode literal){
1161
271254
  Assert(!hasLiteral(literal));
1162
271254
  bool isNot = (literal.getKind() == NOT);
1163
542508
  Node atomNode = (isNot ? literal[0] : literal);
1164
542508
  Node negationNode  = atomNode.notNode();
1165
1166
271254
  Assert(!hasLiteral(atomNode));
1167
271254
  Assert(!hasLiteral(negationNode));
1168
542508
  Comparison posCmp = Comparison::parseNormalForm(atomNode);
1169
1170
271254
  ConstraintType posType = Constraint::constraintTypeOfComparison(posCmp);
1171
1172
542508
  Polynomial nvp = posCmp.normalizedVariablePart();
1173
271254
  ArithVar v = d_avariables.asArithVar(nvp.getNode());
1174
1175
542508
  DeltaRational posDR = posCmp.normalizedDeltaRational();
1176
1177
  ConstraintP posC =
1178
271254
      new Constraint(v, posType, posDR, options().smt.produceProofs);
1179
1180
271254
  Debug("arith::constraint") << "addliteral( literal ->" << literal << ")" << endl;
1181
271254
  Debug("arith::constraint") << "addliteral( posC ->" << posC << ")" << endl;
1182
1183
271254
  SortedConstraintMap& scm = getVariableSCM(posC->getVariable());
1184
271254
  pair<SortedConstraintMapIterator, bool> insertAttempt;
1185
271254
  insertAttempt = scm.insert(make_pair(posC->getValue(), ValueCollection()));
1186
1187
271254
  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
271254
  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
1445
    ConstraintP hit = posI->second.getConstraintOfType(posC->getType());
1195
1445
    Debug("arith::constraint") << "hit " << hit << endl;
1196
1445
    Debug("arith::constraint") << "posC " << posC << endl;
1197
1198
1445
    delete posC;
1199
1200
1445
    hit->setLiteral(atomNode);
1201
1445
    hit->getNegation()->setLiteral(negationNode);
1202
1445
    return isNot ? hit->getNegation(): hit;
1203
  }else{
1204
539618
    Comparison negCmp = Comparison::parseNormalForm(negationNode);
1205
1206
269809
    ConstraintType negType = Constraint::constraintTypeOfComparison(negCmp);
1207
539618
    DeltaRational negDR = negCmp.normalizedDeltaRational();
1208
1209
    ConstraintP negC =
1210
269809
        new Constraint(v, negType, negDR, options().smt.produceProofs);
1211
1212
269809
    SortedConstraintMapIterator negI;
1213
1214
269809
    if(posC->isEquality()){
1215
127379
      negI = posI;
1216
    }else{
1217
142430
      Assert(posC->isLowerBound() || posC->isUpperBound());
1218
1219
142430
      pair<SortedConstraintMapIterator, bool> negInsertAttempt;
1220
142430
      negInsertAttempt = scm.insert(make_pair(negC->getValue(), ValueCollection()));
1221
1222
142430
      Debug("nf::tmp") << "sdhjfgdhjkldfgljkhdfg" << endl;
1223
142430
      Debug("nf::tmp") << negC << endl;
1224
142430
      Debug("nf::tmp") << negC->getValue() << endl;
1225
1226
      //This should always succeed as the DeltaRational for the negation is unique!
1227
142430
      Assert(negInsertAttempt.second);
1228
1229
142430
      negI = negInsertAttempt.first;
1230
    }
1231
1232
269809
    (posI->second).add(posC);
1233
269809
    (negI->second).add(negC);
1234
1235
269809
    posC->initialize(this, posI, negC);
1236
269809
    negC->initialize(this, negI, posC);
1237
1238
269809
    posC->setLiteral(atomNode);
1239
269809
    negC->setLiteral(negationNode);
1240
1241
269809
    return isNot ? negC : posC;
1242
  }
1243
}
1244
1245
1246
9820553
ConstraintP ConstraintDatabase::lookup(TNode literal) const{
1247
9820553
  NodetoConstraintMap::const_iterator iter = d_nodetoConstraintMap.find(literal);
1248
9820553
  if(iter == d_nodetoConstraintMap.end()){
1249
1893485
    return NullConstraint;
1250
  }else{
1251
7927068
    return iter->second;
1252
  }
1253
}
1254
1255
4607141
void Constraint::setAssumption(bool nowInConflict){
1256
4607141
  Debug("constraints::pf") << "setAssumption(" << this << ")" << std::endl;
1257
4607141
  Assert(!hasProof());
1258
4607141
  Assert(negationHasProof() == nowInConflict);
1259
4607141
  Assert(hasLiteral());
1260
4607141
  Assert(assertedToTheTheory());
1261
1262
4607141
  d_database->pushConstraintRule(ConstraintRule(this, AssumeAP));
1263
1264
4607141
  Assert(inConflict() == nowInConflict);
1265
4607141
  if(Debug.isOn("constraint::conflictCommit") && inConflict()){
1266
    Debug("constraint::conflictCommit") << "inConflict@setAssumption " << this << std::endl;
1267
  }
1268
4607141
}
1269
1270
3590457
void Constraint::tryToPropagate(){
1271
3590457
  Assert(hasProof());
1272
3590457
  Assert(!isAssumption());
1273
3590457
  Assert(!isInternalAssumption());
1274
1275
3590457
  if(canBePropagated() && !assertedToTheTheory() && !isAssumption() && !isInternalAssumption()){
1276
800184
    propagate();
1277
  }
1278
3590457
}
1279
1280
814571
void Constraint::propagate(){
1281
814571
  Assert(hasProof());
1282
814571
  Assert(canBePropagated());
1283
814571
  Assert(!assertedToTheTheory());
1284
814571
  Assert(!isAssumption());
1285
814571
  Assert(!isInternalAssumption());
1286
1287
814571
  d_database->d_toPropagate.push(this);
1288
814571
}
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
2095257
void Constraint::impliedByUnate(ConstraintCP imp, bool nowInConflict){
1299
2095257
  Debug("constraints::pf") << "impliedByUnate(" << this << ", " << *imp << ")" << std::endl;
1300
2095257
  Assert(!hasProof());
1301
2095257
  Assert(imp->hasProof());
1302
2095257
  Assert(negationHasProof() == nowInConflict);
1303
1304
2095257
  d_database->d_antecedents.push_back(NullConstraint);
1305
2095257
  d_database->d_antecedents.push_back(imp);
1306
1307
2095257
  AntecedentId antecedentEnd = d_database->d_antecedents.size() - 1;
1308
1309
  RationalVectorP coeffs;
1310
2095257
  if (d_produceProofs)
1311
  {
1312
790483
    std::pair<int, int> sgns = unateFarkasSigns(getNegation(), imp);
1313
1314
1580966
    Rational first(sgns.first);
1315
1580966
    Rational second(sgns.second);
1316
1317
790483
    coeffs = new RationalVector();
1318
790483
    coeffs->push_back(first);
1319
790483
    coeffs->push_back(second);
1320
  }
1321
  else
1322
  {
1323
1304774
    coeffs = RationalVectorPSentinel;
1324
  }
1325
  // no need to delete coeffs the memory is owned by ConstraintRule
1326
2095257
  d_database->pushConstraintRule(ConstraintRule(this, FarkasAP, antecedentEnd, coeffs));
1327
1328
2095257
  Assert(inConflict() == nowInConflict);
1329
2095257
  if(Debug.isOn("constraint::conflictCommit") && inConflict()){
1330
    Debug("constraint::conflictCommit") << "inConflict@impliedByUnate " << this << std::endl;
1331
  }
1332
1333
2095257
  if(Debug.isOn("constraints::wffp") && !wellFormedFarkasProof()){
1334
    getConstraintRule().print(Debug("constraints::wffp"), d_produceProofs);
1335
  }
1336
2095257
  Assert(wellFormedFarkasProof());
1337
2095257
}
1338
1339
412054
void Constraint::impliedByTrichotomy(ConstraintCP a, ConstraintCP b, bool nowInConflict){
1340
412054
  Debug("constraints::pf") << "impliedByTrichotomy(" << this << ", " << *a << ", ";
1341
412054
  Debug("constraints::pf") << *b << ")" << std::endl;
1342
412054
  Assert(!hasProof());
1343
412054
  Assert(negationHasProof() == nowInConflict);
1344
412054
  Assert(a->hasProof());
1345
412054
  Assert(b->hasProof());
1346
1347
412054
  d_database->d_antecedents.push_back(NullConstraint);
1348
412054
  d_database->d_antecedents.push_back(a);
1349
412054
  d_database->d_antecedents.push_back(b);
1350
1351
412054
  AntecedentId antecedentEnd = d_database->d_antecedents.size() - 1;
1352
412054
  d_database->pushConstraintRule(ConstraintRule(this, TrichotomyAP, antecedentEnd));
1353
1354
412054
  Assert(inConflict() == nowInConflict);
1355
412054
  if(Debug.isOn("constraint::conflictCommit") && inConflict()){
1356
    Debug("constraint::conflictCommit") << "inConflict@impliedByTrichotomy " << this << std::endl;
1357
  }
1358
412054
}
1359
1360
1361
102685
bool Constraint::allHaveProof(const ConstraintCPVec& b){
1362
1480144
  for(ConstraintCPVec::const_iterator i=b.begin(), i_end=b.end(); i != i_end; ++i){
1363
1377459
    ConstraintCP cp = *i;
1364
1377459
    if(! (cp->hasProof())){ return false; }
1365
  }
1366
102685
  return true;
1367
}
1368
1369
1053973
void Constraint::impliedByIntTighten(ConstraintCP a, bool nowInConflict){
1370
1053973
  Debug("constraints::pf") << "impliedByIntTighten(" << this << ", " << *a << ")" << std::endl;
1371
1053973
  Assert(!hasProof());
1372
1053973
  Assert(negationHasProof() == nowInConflict);
1373
1053973
  Assert(a->hasProof());
1374
2107946
  Debug("pf::arith") << "impliedByIntTighten(" << this << ", " << a << ")"
1375
1053973
                     << std::endl;
1376
1377
1053973
  d_database->d_antecedents.push_back(NullConstraint);
1378
1053973
  d_database->d_antecedents.push_back(a);
1379
1053973
  AntecedentId antecedentEnd = d_database->d_antecedents.size() - 1;
1380
1053973
  d_database->pushConstraintRule(ConstraintRule(this, IntTightenAP, antecedentEnd));
1381
1382
1053973
  Assert(inConflict() == nowInConflict);
1383
1053973
  if(inConflict()){
1384
2398
    Debug("constraint::conflictCommit") << "inConflict impliedByIntTighten" << this << std::endl;
1385
  }
1386
1053973
}
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
102685
void Constraint::impliedByFarkas(const ConstraintCPVec& a, RationalVectorCP coeffs, bool nowInConflict){
1445
102685
  Debug("constraints::pf") << "impliedByFarkas(" << this;
1446
102685
  if (Debug.isOn("constraints::pf")) {
1447
    for (const ConstraintCP& p : a)
1448
    {
1449
      Debug("constraints::pf") << ", " << p;
1450
    }
1451
  }
1452
102685
  Debug("constraints::pf") << ", <coeffs>";
1453
102685
  Debug("constraints::pf") << ")" << std::endl;
1454
102685
  Assert(!hasProof());
1455
102685
  Assert(negationHasProof() == nowInConflict);
1456
102685
  Assert(allHaveProof(a));
1457
1458
102685
  Assert(d_produceProofs == (coeffs != RationalVectorCPSentinel));
1459
102685
  Assert(!d_produceProofs || coeffs->size() == a.size() + 1);
1460
1461
102685
  Assert(a.size() >= 1);
1462
1463
102685
  d_database->d_antecedents.push_back(NullConstraint);
1464
1480144
  for(ConstraintCPVec::const_iterator i = a.begin(), end = a.end(); i != end; ++i){
1465
1377459
    ConstraintCP c_i = *i;
1466
1377459
    Assert(c_i->hasProof());
1467
1377459
    d_database->d_antecedents.push_back(c_i);
1468
  }
1469
102685
  AntecedentId antecedentEnd = d_database->d_antecedents.size() - 1;
1470
1471
  RationalVectorCP coeffsCopy;
1472
102685
  if (d_produceProofs)
1473
  {
1474
45876
    Assert(coeffs != RationalVectorCPSentinel);
1475
45876
    coeffsCopy = new RationalVector(*coeffs);
1476
  }
1477
  else
1478
  {
1479
56809
    coeffsCopy = RationalVectorCPSentinel;
1480
  }
1481
102685
  d_database->pushConstraintRule(ConstraintRule(this, FarkasAP, antecedentEnd, coeffsCopy));
1482
1483
102685
  Assert(inConflict() == nowInConflict);
1484
102685
  if(Debug.isOn("constraint::conflictCommit") && inConflict()){
1485
    Debug("constraint::conflictCommit") << "inConflict@impliedByFarkas " << this << std::endl;
1486
  }
1487
102685
  if(Debug.isOn("constraints::wffp") && !wellFormedFarkasProof()){
1488
    getConstraintRule().print(Debug("constraints::wffp"), d_produceProofs);
1489
  }
1490
102685
  Assert(wellFormedFarkasProof());
1491
102685
}
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
214770
void Constraint::setEqualityEngineProof(){
1511
214770
  Debug("constraints::pf") << "setEqualityEngineProof(" << this;
1512
214770
  Debug("constraints::pf") << ")" << std::endl;
1513
214770
  Assert(truthIsUnknown());
1514
214770
  Assert(hasLiteral());
1515
214770
  d_database->pushConstraintRule(ConstraintRule(this, EqualityEngineAP));
1516
214770
}
1517
1518
1519
4111144
SortedConstraintMap& Constraint::constraintSet() const{
1520
4111144
  Assert(d_database->variableDatabaseIsSetup(d_variable));
1521
4111144
  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
110764
Node Constraint::externalImplication(const ConstraintCPVec& b) const{
1536
110764
  Assert(hasLiteral());
1537
221528
  Node antecedent = externalExplainByAssertions(b);
1538
221528
  Node implied = getLiteral();
1539
221528
  return antecedent.impNode(implied);
1540
}
1541
1542
1543
1138147
Node Constraint::externalExplainByAssertions(const ConstraintCPVec& b){
1544
1138147
  return externalExplain(b, AssertionOrderSentinel);
1545
}
1546
1547
15936
TrustNode Constraint::externalExplainForPropagation(TNode lit) const
1548
{
1549
15936
  Assert(hasProof());
1550
15936
  Assert(!isAssumption());
1551
15936
  Assert(!isInternalAssumption());
1552
31872
  NodeBuilder nb(Kind::AND);
1553
31872
  auto pfFromAssumptions = externalExplain(nb, d_assertionOrder);
1554
31872
  Node n = safeConstructNary(nb);
1555
15936
  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
2308
    Assert(Rewriter::rewrite(lit) == getLiteral());
1560
4616
    std::vector<Node> assumptions;
1561
2308
    if (n.getKind() == Kind::AND)
1562
    {
1563
1402
      assumptions.insert(assumptions.end(), n.begin(), n.end());
1564
    }
1565
    else
1566
    {
1567
906
      assumptions.push_back(n);
1568
    }
1569
2308
    if (getProofLiteral() != lit)
1570
    {
1571
4497
      pfFromAssumptions = d_database->d_pnm->mkNode(
1572
2998
          PfRule::MACRO_SR_PRED_TRANSFORM, {pfFromAssumptions}, {lit});
1573
    }
1574
4616
    auto pf = d_database->d_pnm->mkScope(pfFromAssumptions, assumptions);
1575
2308
    return d_database->d_pfGen->mkTrustedPropagation(
1576
2308
        lit, safeConstructNary(Kind::AND, assumptions), pf);
1577
  }
1578
  else
1579
  {
1580
13628
    return TrustNode::mkTrustPropExp(lit, n);
1581
  }
1582
}
1583
1584
78971
TrustNode Constraint::externalExplainConflict() const
1585
{
1586
78971
  Debug("pf::arith::explain") << this << std::endl;
1587
78971
  Assert(inConflict());
1588
157942
  NodeBuilder nb(kind::AND);
1589
157942
  auto pf1 = externalExplainByAssertions(nb);
1590
157942
  auto not2 = getNegation()->getProofLiteral().negate();
1591
157942
  auto pf2 = getNegation()->externalExplainByAssertions(nb);
1592
157942
  Node n = safeConstructNary(nb);
1593
78971
  if (d_database->isProofEnabled())
1594
  {
1595
13028
    auto pfNot2 = d_database->d_pnm->mkNode(
1596
26056
        PfRule::MACRO_SR_PRED_TRANSFORM, {pf1}, {not2});
1597
26056
    std::vector<Node> lits;
1598
13028
    if (n.getKind() == Kind::AND)
1599
    {
1600
13028
      lits.insert(lits.end(), n.begin(), n.end());
1601
    }
1602
    else
1603
    {
1604
      lits.push_back(n);
1605
    }
1606
13028
    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
26056
                                    getNegation()->getProofLiteral()};
1616
    auto bot =
1617
13028
        not2.getKind() == Kind::NOT
1618
36192
            ? d_database->d_pnm->mkNode(PfRule::CONTRA, {pf2, pfNot2}, {})
1619
51148
            : d_database->d_pnm->mkNode(PfRule::CONTRA, {pfNot2, pf2}, {});
1620
13028
    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
26056
    auto confPf = d_database->d_pnm->mkScope(bot, lits);
1629
13028
    return d_database->d_pfGen->mkTrustNode(
1630
13028
        safeConstructNary(Kind::AND, lits), confPf, true);
1631
  }
1632
  else
1633
  {
1634
65943
    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
1138147
Node Constraint::externalExplain(const ConstraintCPVec& v, AssertionOrder order){
1685
2276294
  NodeBuilder nb(kind::AND);
1686
1138147
  ConstraintCPVec::const_iterator i, end;
1687
2556890
  for(i = v.begin(), end = v.end(); i != end; ++i){
1688
1418743
    ConstraintCP v_i = *i;
1689
1418743
    v_i->externalExplain(nb, order);
1690
  }
1691
2276294
  return safeConstructNary(nb);
1692
}
1693
1694
5551337
std::shared_ptr<ProofNode> Constraint::externalExplain(
1695
    NodeBuilder& nb, AssertionOrder order) const
1696
{
1697
5551337
  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
5551337
  Assert(hasProof());
1705
5551337
  Assert(!isAssumption() || assertedToTheTheory());
1706
5551337
  Assert(!isInternalAssumption());
1707
5551337
  std::shared_ptr<ProofNode> pf{};
1708
1709
5551337
  ProofNodeManager* pnm = d_database->d_pnm;
1710
1711
5551337
  if (assertedBefore(order))
1712
  {
1713
5054126
    Debug("pf::arith::explain") << "  already asserted" << std::endl;
1714
5054126
    nb << getWitness();
1715
5054126
    if (d_database->isProofEnabled())
1716
    {
1717
680381
      pf = pnm->mkAssume(getWitness());
1718
      // If the witness and literal differ, prove the difference through a
1719
      // rewrite.
1720
680381
      if (getWitness() != getProofLiteral())
1721
      {
1722
1348881
        pf = pnm->mkNode(
1723
899254
            PfRule::MACRO_SR_PRED_TRANSFORM, {pf}, {getProofLiteral()});
1724
      }
1725
    }
1726
  }
1727
497211
  else if (hasEqualityEngineProof())
1728
  {
1729
6287
    Debug("pf::arith::explain") << "  going to ee:" << std::endl;
1730
12574
    TrustNode exp = d_database->eeExplain(this);
1731
6287
    if (d_database->isProofEnabled())
1732
    {
1733
883
      Assert(exp.getProven().getKind() == Kind::IMPLIES);
1734
1766
      std::vector<std::shared_ptr<ProofNode>> hypotheses;
1735
883
      hypotheses.push_back(exp.getGenerator()->getProofFor(exp.getProven()));
1736
883
      if (exp.getNode().getKind() == Kind::AND)
1737
      {
1738
3004
        for (const auto& h : exp.getNode())
1739
        {
1740
2197
          hypotheses.push_back(
1741
4394
              pnm->mkNode(PfRule::TRUE_INTRO, {pnm->mkAssume(h)}, {}));
1742
        }
1743
      }
1744
      else
1745
      {
1746
304
        hypotheses.push_back(pnm->mkNode(
1747
228
            PfRule::TRUE_INTRO, {pnm->mkAssume(exp.getNode())}, {}));
1748
      }
1749
1766
      pf = pnm->mkNode(
1750
883
          PfRule::MACRO_SR_PRED_TRANSFORM, {hypotheses}, {getProofLiteral()});
1751
    }
1752
12574
    Debug("pf::arith::explain")
1753
6287
        << "    explanation: " << exp.getNode() << std::endl;
1754
6287
    if (exp.getNode().getKind() == Kind::AND)
1755
    {
1756
5576
      nb.append(exp.getNode().begin(), exp.getNode().end());
1757
    }
1758
    else
1759
    {
1760
711
      nb << exp.getNode();
1761
    }
1762
  }
1763
  else
1764
  {
1765
490924
    Debug("pf::arith::explain") << "  recursion!" << std::endl;
1766
490924
    Assert(!isAssumption());
1767
490924
    AntecedentId p = getEndAntecedent();
1768
490924
    ConstraintCP antecedent = d_database->d_antecedents[p];
1769
981848
    std::vector<std::shared_ptr<ProofNode>> children;
1770
1771
3276354
    while (antecedent != NullConstraint)
1772
    {
1773
1392715
      Debug("pf::arith::explain") << "Explain " << antecedent << std::endl;
1774
2785430
      auto pn = antecedent->externalExplain(nb, order);
1775
1392715
      if (d_database->isProofEnabled())
1776
      {
1777
153444
        children.push_back(pn);
1778
      }
1779
1392715
      --p;
1780
1392715
      antecedent = d_database->d_antecedents[p];
1781
    }
1782
1783
490924
    if (d_database->isProofEnabled())
1784
    {
1785
89583
      switch (getProofType())
1786
      {
1787
        case ArithProofType::AssumeAP:
1788
        case ArithProofType::EqualityEngineAP:
1789
        {
1790
          Unreachable() << "These should be handled above";
1791
          break;
1792
        }
1793
13525
        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
27050
          std::vector<std::shared_ptr<ProofNode>> farkasChildren;
1804
13525
          farkasChildren.push_back(
1805
27050
              pnm->mkAssume(getNegation()->getProofLiteral()));
1806
13525
          farkasChildren.insert(
1807
27050
              farkasChildren.end(), children.rbegin(), children.rend());
1808
1809
13525
          NodeManager* nm = NodeManager::currentNM();
1810
1811
          // Enumerate d_farkasCoefficients as nodes.
1812
27050
          std::vector<Node> farkasCoeffs;
1813
97633
          for (Rational r : *getFarkasCoefficients())
1814
          {
1815
84108
            farkasCoeffs.push_back(nm->mkConst<Rational>(r));
1816
          }
1817
1818
          // Apply the scaled-sum rule.
1819
          std::shared_ptr<ProofNode> sumPf = pnm->mkNode(
1820
27050
              PfRule::MACRO_ARITH_SCALE_SUM_UB, farkasChildren, farkasCoeffs);
1821
1822
          // Provable rewrite the result
1823
          auto botPf = pnm->mkNode(
1824
27050
              PfRule::MACRO_SR_PRED_TRANSFORM, {sumPf}, {nm->mkConst(false)});
1825
1826
          // Scope out the negated constraint, yielding a proof of the
1827
          // constraint.
1828
27050
          std::vector<Node> assump{getNegation()->getProofLiteral()};
1829
27050
          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
40575
          pf = pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
1836
                           {maybeDoubleNotPf},
1837
27050
                           {getProofLiteral()});
1838
1839
13525
          break;
1840
        }
1841
69255
        case ArithProofType::IntTightenAP:
1842
        {
1843
69255
          if (isUpperBound())
1844
          {
1845
67020
            pf = pnm->mkNode(
1846
134040
                PfRule::INT_TIGHT_UB, children, {}, getProofLiteral());
1847
          }
1848
2235
          else if (isLowerBound())
1849
          {
1850
2235
            pf = pnm->mkNode(
1851
4470
                PfRule::INT_TIGHT_LB, children, {}, getProofLiteral());
1852
          }
1853
          else
1854
          {
1855
            Unreachable();
1856
          }
1857
69255
          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
6803
        case ArithProofType::TrichotomyAP:
1870
        {
1871
13606
          pf = pnm->mkNode(PfRule::ARITH_TRICHOTOMY,
1872
                           children,
1873
                           {getProofLiteral()},
1874
20409
                           getProofLiteral());
1875
6803
          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
5551337
  return pf;
1889
}
1890
1891
1776
Node Constraint::externalExplainByAssertions(ConstraintCP a, ConstraintCP b){
1892
3552
  NodeBuilder nb(kind::AND);
1893
1776
  a->externalExplainByAssertions(nb);
1894
1776
  b->externalExplainByAssertions(nb);
1895
3552
  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
729887
ConstraintP Constraint::getStrictlyWeakerLowerBound(bool hasLiteral, bool asserted) const {
1907
729887
  Assert(initialized());
1908
729887
  Assert(!asserted || hasLiteral);
1909
1910
729887
  SortedConstraintMapConstIterator i = d_variablePosition;
1911
729887
  const SortedConstraintMap& scm = constraintSet();
1912
729887
  SortedConstraintMapConstIterator i_begin = scm.begin();
1913
2362281
  while(i != i_begin){
1914
945615
    --i;
1915
945615
    const ValueCollection& vc = i->second;
1916
945615
    if(vc.hasLowerBound()){
1917
252692
      ConstraintP weaker = vc.getLowerBound();
1918
1919
      // asserted -> hasLiteral
1920
      // hasLiteral -> weaker->hasLiteral()
1921
      // asserted -> weaker->assertedToTheTheory()
1922
523067
      if((!hasLiteral || (weaker->hasLiteral())) &&
1923
280675
         (!asserted || ( weaker->assertedToTheTheory()))){
1924
129418
        return weaker;
1925
      }
1926
    }
1927
  }
1928
600469
  return NullConstraint;
1929
}
1930
1931
378456
ConstraintP Constraint::getStrictlyWeakerUpperBound(bool hasLiteral, bool asserted) const {
1932
378456
  SortedConstraintMapConstIterator i = d_variablePosition;
1933
378456
  const SortedConstraintMap& scm = constraintSet();
1934
378456
  SortedConstraintMapConstIterator i_end = scm.end();
1935
1936
378456
  ++i;
1937
1111282
  for(; i != i_end; ++i){
1938
505689
    const ValueCollection& vc = i->second;
1939
505689
    if(vc.hasUpperBound()){
1940
187529
      ConstraintP weaker = vc.getUpperBound();
1941
477983
      if((!hasLiteral || (weaker->hasLiteral())) &&
1942
297548
         (!asserted || ( weaker->assertedToTheTheory()))){
1943
139276
        return weaker;
1944
      }
1945
    }
1946
  }
1947
1948
239180
  return NullConstraint;
1949
}
1950
1951
8779851
ConstraintP ConstraintDatabase::getBestImpliedBound(ArithVar v, ConstraintType t, const DeltaRational& r) const {
1952
8779851
  Assert(variableDatabaseIsSetup(v));
1953
8779851
  Assert(t == UpperBound || t == LowerBound);
1954
1955
8779851
  SortedConstraintMap& scm = getVariableSCM(v);
1956
8779851
  if(t == UpperBound){
1957
4262211
    SortedConstraintMapConstIterator i = scm.lower_bound(r);
1958
4262211
    SortedConstraintMapConstIterator i_end = scm.end();
1959
4262211
    Assert(i == i_end || r <= i->first);
1960
8828435
    for(; i != i_end; i++){
1961
3693162
      Assert(r <= i->first);
1962
3693162
      const ValueCollection& vc = i->second;
1963
3693162
      if(vc.hasUpperBound()){
1964
1410050
        return vc.getUpperBound();
1965
      }
1966
    }
1967
2852161
    return NullConstraint;
1968
  }else{
1969
4517640
    Assert(t == LowerBound);
1970
4517640
    if(scm.empty()){
1971
311753
      return NullConstraint;
1972
    }else{
1973
4205887
      SortedConstraintMapConstIterator i = scm.lower_bound(r);
1974
4205887
      SortedConstraintMapConstIterator i_begin = scm.begin();
1975
4205887
      SortedConstraintMapConstIterator i_end = scm.end();
1976
4205887
      Assert(i == i_end || r <= i->first);
1977
1978
4205887
      int fdj = 0;
1979
1980
4205887
      if(i == i_end){
1981
1811030
        --i;
1982
1811030
        Debug("getBestImpliedBound") << fdj++ << " " << r << " " << i->first << endl;
1983
2394857
      }else if( (i->first) > r){
1984
678505
        if(i == i_begin){
1985
614550
          return NullConstraint;
1986
        }else{
1987
63955
          --i;
1988
63955
          Debug("getBestImpliedBound") << fdj++ << " " << r << " " << i->first << endl;
1989
        }
1990
      }
1991
1992
      do{
1993
4023013
        Debug("getBestImpliedBound") << fdj++ << " " << r << " " << i->first << endl;
1994
4023013
        Assert(r >= i->first);
1995
4023013
        const ValueCollection& vc = i->second;
1996
1997
4023013
        if(vc.hasLowerBound()){
1998
1825031
          return vc.getLowerBound();
1999
        }
2000
2001
2197982
        if(i == i_begin){
2002
1766306
          break;
2003
        }else{
2004
431676
          --i;
2005
431676
        }
2006
      }while(true);
2007
1766306
      return NullConstraint;
2008
    }
2009
  }
2010
}
2011
6287
TrustNode ConstraintDatabase::eeExplain(const Constraint* const c) const
2012
{
2013
6287
  Assert(c->hasLiteral());
2014
6287
  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
24031078
bool ConstraintDatabase::variableDatabaseIsSetup(ArithVar v) const {
2025
24031078
  return v < d_varDatabases.size();
2026
}
2027
2028
2029
9945
ConstraintDatabase::Watches::Watches(context::Context* satContext, context::Context* userContext):
2030
  d_constraintProofs(satContext),
2031
  d_canBePropagatedWatches(satContext),
2032
  d_assertionOrderWatches(satContext),
2033
9945
  d_splitWatches(userContext)
2034
9945
{}
2035
2036
2037
542508
void Constraint::setLiteral(Node n) {
2038
542508
  Debug("arith::constraint") << "Mapping " << *this << " to " << n << std::endl;
2039
542508
  Assert(Comparison::isNormalAtom(n));
2040
542508
  Assert(!hasLiteral());
2041
542508
  Assert(sanityChecking(n));
2042
542508
  d_literal = n;
2043
542508
  NodetoConstraintMap& map = d_database->d_nodetoConstraintMap;
2044
542508
  Assert(map.find(n) == map.end());
2045
542508
  map.insert(make_pair(d_literal, this));
2046
542508
}
2047
2048
1410788
Node Constraint::getProofLiteral() const
2049
{
2050
1410788
  Assert(d_database != nullptr);
2051
1410788
  Assert(d_database->d_avariables.hasNode(d_variable));
2052
2821576
  Node varPart = d_database->d_avariables.asNode(d_variable);
2053
  Kind cmp;
2054
1410788
  bool neg = false;
2055
1410788
  switch (d_type)
2056
  {
2057
538468
    case ConstraintType::UpperBound:
2058
    {
2059
538468
      if (d_value.infinitesimalIsZero())
2060
      {
2061
145781
        cmp = Kind::LEQ;
2062
      }
2063
      else
2064
      {
2065
392687
        cmp = Kind::LT;
2066
      }
2067
538468
      break;
2068
    }
2069
220213
    case ConstraintType::LowerBound:
2070
    {
2071
220213
      if (d_value.infinitesimalIsZero())
2072
      {
2073
178680
        cmp = Kind::GEQ;
2074
      }
2075
      else
2076
      {
2077
41533
        cmp = Kind::GT;
2078
      }
2079
220213
      break;
2080
    }
2081
516068
    case ConstraintType::Equality:
2082
    {
2083
516068
      cmp = Kind::EQUAL;
2084
516068
      break;
2085
    }
2086
136039
    case ConstraintType::Disequality:
2087
    {
2088
136039
      cmp = Kind::EQUAL;
2089
136039
      neg = true;
2090
136039
      break;
2091
    }
2092
    default: Unreachable() << d_type;
2093
  }
2094
1410788
  NodeManager* nm = NodeManager::currentNM();
2095
2821576
  Node constPart = nm->mkConst<Rational>(d_value.getNoninfinitesimalPart());
2096
2821576
  Node posLit = nm->mkNode(cmp, varPart, constPart);
2097
2821576
  return neg ? posLit.negate() : posLit;
2098
}
2099
2100
37065
void ConstraintDatabase::proveOr(std::vector<TrustNode>& out,
2101
                                 ConstraintP a,
2102
                                 ConstraintP b,
2103
                                 bool negateSecond) const
2104
{
2105
74130
  Node la = a->getLiteral();
2106
74130
  Node lb = b->getLiteral();
2107
74130
  Node orN = (la < lb) ? la.orNode(lb) : lb.orNode(la);
2108
37065
  if (isProofEnabled())
2109
  {
2110
5910
    Assert(b->getNegation()->getType() != ConstraintType::Disequality);
2111
5910
    auto nm = NodeManager::currentNM();
2112
5910
    auto pf_neg_la = d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
2113
11820
                                   {d_pnm->mkAssume(la.negate())},
2114
23640
                                   {a->getNegation()->getProofLiteral()});
2115
5910
    auto pf_neg_lb = d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
2116
11820
                                   {d_pnm->mkAssume(lb.negate())},
2117
23640
                                   {b->getNegation()->getProofLiteral()});
2118
5910
    int sndSign = negateSecond ? -1 : 1;
2119
    auto bot_pf =
2120
5910
        d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
2121
5910
                      {d_pnm->mkNode(PfRule::MACRO_ARITH_SCALE_SUM_UB,
2122
                                     {pf_neg_la, pf_neg_lb},
2123
                                     {nm->mkConst<Rational>(-1 * sndSign),
2124
23640
                                      nm->mkConst<Rational>(sndSign)})},
2125
29550
                      {nm->mkConst(false)});
2126
11820
    std::vector<Node> as;
2127
17730
    std::transform(orN.begin(), orN.end(), std::back_inserter(as), [](Node n) {
2128
      return n.negate();
2129
17730
    });
2130
    // No need to ensure that the expected node aggrees with `as` because we
2131
    // are not providing an expected node.
2132
5910
    auto pf = d_pnm->mkNode(
2133
        PfRule::MACRO_SR_PRED_TRANSFORM,
2134
17730
        {d_pnm->mkNode(PfRule::NOT_AND, {d_pnm->mkScope(bot_pf, as)}, {})},
2135
29550
        {orN});
2136
5910
    out.push_back(d_pfGen->mkTrustNode(orN, pf));
2137
  }
2138
  else
2139
  {
2140
31155
    out.push_back(TrustNode::mkTrustLemma(orN));
2141
  }
2142
37065
}
2143
2144
34711
void ConstraintDatabase::implies(std::vector<TrustNode>& out,
2145
                                 ConstraintP a,
2146
                                 ConstraintP b) const
2147
{
2148
69422
  Node la = a->getLiteral();
2149
69422
  Node lb = b->getLiteral();
2150
2151
69422
  Node neg_la = (la.getKind() == kind::NOT)? la[0] : la.notNode();
2152
2153
34711
  Assert(lb != neg_la);
2154
34711
  Assert(b->getNegation()->getType() == ConstraintType::LowerBound
2155
         || b->getNegation()->getType() == ConstraintType::UpperBound);
2156
34711
  proveOr(out,
2157
          a->getNegation(),
2158
          b,
2159
34711
          b->getNegation()->getType() == ConstraintType::LowerBound);
2160
34711
}
2161
2162
2354
void ConstraintDatabase::mutuallyExclusive(std::vector<TrustNode>& out,
2163
                                           ConstraintP a,
2164
                                           ConstraintP b) const
2165
{
2166
4708
  Node la = a->getLiteral();
2167
4708
  Node lb = b->getLiteral();
2168
2169
4708
  Node neg_la = la.negate();
2170
4708
  Node neg_lb = lb.negate();
2171
2354
  proveOr(out, a->getNegation(), b->getNegation(), true);
2172
2354
}
2173
2174
56308
void ConstraintDatabase::outputUnateInequalityLemmas(
2175
    std::vector<TrustNode>& out, ArithVar v) const
2176
{
2177
56308
  SortedConstraintMap& scm = getVariableSCM(v);
2178
56308
  SortedConstraintMapConstIterator scm_iter = scm.begin();
2179
56308
  SortedConstraintMapConstIterator scm_end = scm.end();
2180
56308
  ConstraintP prev = NullConstraint;
2181
  //get transitive unates
2182
  //Only lower bounds or upperbounds should be done.
2183
298804
  for(; scm_iter != scm_end; ++scm_iter){
2184
121248
    const ValueCollection& vc = scm_iter->second;
2185
121248
    if(vc.hasUpperBound()){
2186
58200
      ConstraintP ub = vc.getUpperBound();
2187
58200
      if(ub->hasLiteral()){
2188
58200
        if(prev != NullConstraint){
2189
26850
          implies(out, prev, ub);
2190
        }
2191
58200
        prev = ub;
2192
      }
2193
    }
2194
  }
2195
56308
}
2196
2197
56308
void ConstraintDatabase::outputUnateEqualityLemmas(std::vector<TrustNode>& out,
2198
                                                   ArithVar v) const
2199
{
2200
112616
  vector<ConstraintP> equalities;
2201
2202
56308
  SortedConstraintMap& scm = getVariableSCM(v);
2203
56308
  SortedConstraintMapConstIterator scm_iter = scm.begin();
2204
56308
  SortedConstraintMapConstIterator scm_end = scm.end();
2205
2206
298804
  for(; scm_iter != scm_end; ++scm_iter){
2207
121248
    const ValueCollection& vc = scm_iter->second;
2208
121248
    if(vc.hasEquality()){
2209
17910
      ConstraintP eq = vc.getEquality();
2210
17910
      if(eq->hasLiteral()){
2211
17910
        equalities.push_back(eq);
2212
      }
2213
    }
2214
  }
2215
2216
56308
  vector<ConstraintP>::const_iterator i, j, eq_end = equalities.end();
2217
74218
  for(i = equalities.begin(); i != eq_end; ++i){
2218
17910
    ConstraintP at_i = *i;
2219
20264
    for(j= i + 1; j != eq_end; ++j){
2220
2354
      ConstraintP at_j = *j;
2221
2222
2354
      mutuallyExclusive(out, at_i, at_j);
2223
    }
2224
  }
2225
2226
74218
  for(i = equalities.begin(); i != eq_end; ++i){
2227
17910
    ConstraintP eq = *i;
2228
17910
    const ValueCollection& vc = eq->getValueCollection();
2229
17910
    Assert(vc.hasEquality() && vc.getEquality()->hasLiteral());
2230
2231
17910
    bool hasLB = vc.hasLowerBound() && vc.getLowerBound()->hasLiteral();
2232
17910
    bool hasUB = vc.hasUpperBound() && vc.getUpperBound()->hasLiteral();
2233
2234
17910
    ConstraintP lb = hasLB ?
2235
17910
      vc.getLowerBound() : eq->getStrictlyWeakerLowerBound(true, false);
2236
17910
    ConstraintP ub = hasUB ?
2237
17910
      vc.getUpperBound() : eq->getStrictlyWeakerUpperBound(true, false);
2238
2239
17910
    if(hasUB && hasLB && !eq->isSplit()){
2240
115
      out.push_back(eq->split());
2241
    }
2242
17910
    if(lb != NullConstraint){
2243
2870
      implies(out, eq, lb);
2244
    }
2245
17910
    if(ub != NullConstraint){
2246
4991
      implies(out, eq, ub);
2247
    }
2248
  }
2249
56308
}
2250
2251
7681
void ConstraintDatabase::outputUnateEqualityLemmas(
2252
    std::vector<TrustNode>& lemmas) const
2253
{
2254
63989
  for(ArithVar v = 0, N = d_varDatabases.size(); v < N; ++v){
2255
56308
    outputUnateEqualityLemmas(lemmas, v);
2256
  }
2257
7681
}
2258
2259
7681
void ConstraintDatabase::outputUnateInequalityLemmas(
2260
    std::vector<TrustNode>& lemmas) const
2261
{
2262
63989
  for(ArithVar v = 0, N = d_varDatabases.size(); v < N; ++v){
2263
56308
    outputUnateInequalityLemmas(lemmas, v);
2264
  }
2265
7681
}
2266
2267
3994352
bool ConstraintDatabase::handleUnateProp(ConstraintP ant, ConstraintP cons){
2268
3994352
  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
3994352
  }else if(!cons->isTrue()){
2274
2090280
    ++d_statistics.d_unatePropagateImplications;
2275
2090280
    Debug("arith::unate") << "handleUnate: " << ant << " implies " << cons << endl;
2276
2090280
    cons->impliedByUnate(ant, false);
2277
2090280
    cons->tryToPropagate();
2278
2090280
    return false;
2279
  } else {
2280
1904072
    return false;
2281
  }
2282
}
2283
2284
1084067
void ConstraintDatabase::unatePropLowerBound(ConstraintP curr, ConstraintP prev){
2285
1084067
  Debug("arith::unate") << "unatePropLowerBound " << curr << " " << prev << endl;
2286
1084067
  Assert(curr != prev);
2287
1084067
  Assert(curr != NullConstraint);
2288
1084067
  bool hasPrev = ! (prev == NullConstraint);
2289
1084067
  Assert(!hasPrev || curr->getValue() > prev->getValue());
2290
2291
1084067
  ++d_statistics.d_unatePropagateCalls;
2292
2293
1084067
  const SortedConstraintMap& scm = curr->constraintSet();
2294
1084067
  const SortedConstraintMapConstIterator scm_begin = scm.begin();
2295
1084067
  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
6426761
  while(scm_i != scm_begin){
2302
2902615
    --scm_i; // move the iterator back
2303
2304
2902615
    const ValueCollection& vc = scm_i->second;
2305
2306
    //If it has the previous element, do nothing and stop!
2307
3654951
    if(hasPrev &&
2308
752336
       vc.hasConstraintOfType(prev->getType())
2309
3386806
       && vc.getConstraintOfType(prev->getType()) == prev){
2310
231268
      break;
2311
    }
2312
2313
    //Don't worry about implying the negation of upperbound.
2314
    //These should all be handled by propagating the LowerBounds!
2315
2671347
    if(vc.hasLowerBound()){
2316
1000998
      ConstraintP lb = vc.getLowerBound();
2317
1000998
      if(handleUnateProp(curr, lb)){ return; }
2318
    }
2319
2671347
    if(vc.hasDisequality()){
2320
282551
      ConstraintP dis = vc.getDisequality();
2321
282551
      if(handleUnateProp(curr, dis)){ return; }
2322
    }
2323
  }
2324
}
2325
2326
960587
void ConstraintDatabase::unatePropUpperBound(ConstraintP curr, ConstraintP prev){
2327
960587
  Debug("arith::unate") << "unatePropUpperBound " << curr << " " << prev << endl;
2328
960587
  Assert(curr != prev);
2329
960587
  Assert(curr != NullConstraint);
2330
960587
  bool hasPrev = ! (prev == NullConstraint);
2331
960587
  Assert(!hasPrev || curr->getValue() < prev->getValue());
2332
2333
960587
  ++d_statistics.d_unatePropagateCalls;
2334
2335
960587
  const SortedConstraintMap& scm = curr->constraintSet();
2336
960587
  const SortedConstraintMapConstIterator scm_end = scm.end();
2337
960587
  SortedConstraintMapConstIterator scm_i = curr->d_variablePosition;
2338
960587
  ++scm_i;
2339
6437087
  for(; scm_i != scm_end; ++scm_i){
2340
2902970
    const ValueCollection& vc = scm_i->second;
2341
2342
    //If it has the previous element, do nothing and stop!
2343
3425615
    if(hasPrev &&
2344
3228260
       vc.hasConstraintOfType(prev->getType()) &&
2345
325290
       vc.getConstraintOfType(prev->getType()) == prev){
2346
164720
      break;
2347
    }
2348
    //Don't worry about implying the negation of upperbound.
2349
    //These should all be handled by propagating the UpperBounds!
2350
2738250
    if(vc.hasUpperBound()){
2351
1056632
      ConstraintP ub = vc.getUpperBound();
2352
1056632
      if(handleUnateProp(curr, ub)){ return; }
2353
    }
2354
2738250
    if(vc.hasDisequality()){
2355
221233
      ConstraintP dis = vc.getDisequality();
2356
221233
      if(handleUnateProp(curr, dis)){ return; }
2357
    }
2358
  }
2359
}
2360
2361
958147
void ConstraintDatabase::unatePropEquality(ConstraintP curr, ConstraintP prevLB, ConstraintP prevUB){
2362
958147
  Debug("arith::unate") << "unatePropEquality " << curr << " " << prevLB << " " << prevUB << endl;
2363
958147
  Assert(curr != prevLB);
2364
958147
  Assert(curr != prevUB);
2365
958147
  Assert(curr != NullConstraint);
2366
958147
  bool hasPrevLB = ! (prevLB == NullConstraint);
2367
958147
  bool hasPrevUB = ! (prevUB == NullConstraint);
2368
958147
  Assert(!hasPrevLB || curr->getValue() >= prevLB->getValue());
2369
958147
  Assert(!hasPrevUB || curr->getValue() <= prevUB->getValue());
2370
2371
958147
  ++d_statistics.d_unatePropagateCalls;
2372
2373
958147
  const SortedConstraintMap& scm = curr->constraintSet();
2374
958147
  SortedConstraintMapConstIterator scm_curr = curr->d_variablePosition;
2375
958147
  SortedConstraintMapConstIterator scm_last = hasPrevUB ? prevUB->d_variablePosition : scm.end();
2376
958147
  SortedConstraintMapConstIterator scm_i;
2377
958147
  if(hasPrevLB){
2378
141257
    scm_i = prevLB->d_variablePosition;
2379
141257
    if(scm_i != scm_curr){ // If this does not move this past scm_curr, move it one forward
2380
33993
      ++scm_i;
2381
    }
2382
  }else{
2383
816890
    scm_i = scm.begin();
2384
  }
2385
2386
2296883
  for(; scm_i != scm_curr; ++scm_i){
2387
    // between the previous LB and the curr
2388
669368
    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
669368
    if(vc.hasLowerBound()){
2393
232025
      ConstraintP lb = vc.getLowerBound();
2394
232025
      if(handleUnateProp(curr, lb)){ return; }
2395
    }
2396
669368
    if(vc.hasDisequality()){
2397
216553
      ConstraintP dis = vc.getDisequality();
2398
216553
      if(handleUnateProp(curr, dis)){ return; }
2399
    }
2400
  }
2401
958147
  Assert(scm_i == scm_curr);
2402
958147
  if(!hasPrevUB || scm_i != scm_last){
2403
932339
    ++scm_i;
2404
  } // hasPrevUB implies scm_i != scm_last
2405
2406
4157367
  for(; scm_i != scm_last; ++scm_i){
2407
    // between the curr and the previous UB imply the upperbounds and disequalities.
2408
1599610
    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
1599610
    if(vc.hasUpperBound()){
2413
595891
      ConstraintP ub = vc.getUpperBound();
2414
595891
      if(handleUnateProp(curr, ub)){ return; }
2415
    }
2416
1599610
    if(vc.hasDisequality()){
2417
388469
      ConstraintP dis = vc.getDisequality();
2418
388469
      if(handleUnateProp(curr, dis)){ return; }
2419
    }
2420
  }
2421
}
2422
2423
790483
std::pair<int, int> Constraint::unateFarkasSigns(ConstraintCP ca, ConstraintCP cb){
2424
790483
  ConstraintType a = ca->getType();
2425
790483
  ConstraintType b = cb->getType();
2426
2427
790483
  Assert(a != Disequality);
2428
790483
  Assert(b != Disequality);
2429
2430
790483
  int a_sgn = (a == LowerBound) ? -1 : ((a == UpperBound) ? 1 : 0);
2431
790483
  int b_sgn = (b == LowerBound) ? -1 : ((b == UpperBound) ? 1 : 0);
2432
2433
790483
  if(a_sgn == 0 && b_sgn == 0){
2434
191005
    Assert(a == Equality);
2435
191005
    Assert(b == Equality);
2436
191005
    Assert(ca->getValue() != cb->getValue());
2437
382010
    if(ca->getValue() < cb->getValue()){
2438
61465
      a_sgn = 1;
2439
61465
      b_sgn = -1;
2440
    }else{
2441
129540
      a_sgn = -1;
2442
129540
      b_sgn = 1;
2443
    }
2444
599478
  }else if(a_sgn == 0){
2445
133678
    Assert(b_sgn != 0);
2446
133678
    Assert(a == Equality);
2447
133678
    a_sgn = -b_sgn;
2448
465800
  }else if(b_sgn == 0){
2449
248391
    Assert(a_sgn != 0);
2450
248391
    Assert(b == Equality);
2451
248391
    b_sgn = -a_sgn;
2452
  }
2453
790483
  Assert(a_sgn != 0);
2454
790483
  Assert(b_sgn != 0);
2455
2456
1580966
  Debug("arith::unateFarkasSigns") << "Constraint::unateFarkasSigns("<<a <<", " << b << ") -> "
2457
790483
                                   << "("<<a_sgn<<", "<< b_sgn <<")"<< endl;
2458
790483
  return make_pair(a_sgn, b_sgn);
2459
}
2460
2461
}  // namespace arith
2462
}  // namespace theory
2463
29598
}  // namespace cvc5