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