GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/linear_equality.h Lines: 48 183 26.2 %
Date: 2021-09-15 Branches: 19 454 4.2 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Tim King, Mathias Preiner, Morgan Deters
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
 * This module maintains the relationship between a Tableau and
14
 * PartialModel.
15
 *
16
 * This shares with the theory a Tableau, and a PartialModel that:
17
 *  - satisfies the equalities in the Tableau, and
18
 *  - the assignment for the non-basic variables satisfies their bounds.
19
 * This maintains the relationship needed by the SimplexDecisionProcedure.
20
 *
21
 * In the language of Simplex for DPLL(T), this provides:
22
 * - update()
23
 * - pivotAndUpdate()
24
 *
25
 * This class also provides utility functions that require
26
 * using both the Tableau and PartialModel.
27
 */
28
29
#include "cvc5_private.h"
30
31
#pragma once
32
33
#include "options/arith_options.h"
34
#include "theory/arith/arithvar.h"
35
#include "theory/arith/constraint_forward.h"
36
#include "theory/arith/delta_rational.h"
37
#include "theory/arith/partial_model.h"
38
#include "theory/arith/simplex_update.h"
39
#include "theory/arith/tableau.h"
40
#include "util/statistics_stats.h"
41
42
namespace cvc5 {
43
namespace theory {
44
namespace arith {
45
46
struct Border{
47
  // The constraint for the border
48
  ConstraintP d_bound;
49
50
  // The change to the nonbasic to reach the border
51
  DeltaRational d_diff;
52
53
  // Is reach this value fixing the constraint
54
  // or is going past this value hurting the constraint
55
  bool d_areFixing;
56
57
  // Entry into the tableau
58
  const Tableau::Entry* d_entry;
59
60
  // Was this an upper bound or a lower bound?
61
  bool d_upperbound;
62
63
  Border():
64
    d_bound(NullConstraint) // ignore the other values
65
  {}
66
67
  Border(ConstraintP l, const DeltaRational& diff, bool areFixing, const Tableau::Entry* en, bool ub):
68
    d_bound(l), d_diff(diff), d_areFixing(areFixing), d_entry(en),  d_upperbound(ub)
69
  {}
70
71
  Border(ConstraintP l, const DeltaRational& diff, bool areFixing, bool ub):
72
    d_bound(l), d_diff(diff), d_areFixing(areFixing), d_entry(NULL),  d_upperbound(ub)
73
  {}
74
  bool operator<(const Border& other) const{
75
    return d_diff < other.d_diff;
76
  }
77
78
  /** d_lim is the nonbasic variable's own bound. */
79
  bool ownBorder() const { return d_entry == NULL; }
80
81
  bool isZero() const { return d_diff.sgn() == 0; }
82
  static bool nonZero(const Border& b) { return !b.isZero(); }
83
84
  const Rational& getCoefficient() const {
85
    Assert(!ownBorder());
86
    return d_entry->getCoefficient();
87
  }
88
  void output(std::ostream& out) const;
89
};
90
91
inline std::ostream& operator<<(std::ostream& out, const Border& b){
92
  b.output(out);
93
  return out;
94
}
95
96
typedef std::vector<Border> BorderVec;
97
98
19878
class BorderHeap {
99
  const int d_dir;
100
101
  class BorderHeapCmp {
102
  private:
103
    int d_nbDirection;
104
  public:
105
19884
    BorderHeapCmp(int dir): d_nbDirection(dir){}
106
    bool operator()(const Border& a, const Border& b) const{
107
      if(d_nbDirection > 0){
108
        // if nb is increasing,
109
        //  this needs to act like a max
110
        //  in order to have a min heap
111
        return b < a;
112
      }else{
113
        // if nb is decreasing,
114
        //  this needs to act like a min
115
        //  in order to have a max heap
116
        return a < b;
117
      }
118
    }
119
  };
120
  const BorderHeapCmp d_cmp;
121
122
  BorderVec d_vec;
123
124
  BorderVec::iterator d_begin;
125
126
  /**
127
   * Once this is initialized the top of the heap will always
128
   * be at d_end - 1
129
   */
130
  BorderVec::iterator d_end;
131
132
  int d_possibleFixes;
133
  int d_numZeroes;
134
135
public:
136
19884
  BorderHeap(int dir)
137
19884
  : d_dir(dir), d_cmp(dir), d_possibleFixes(0), d_numZeroes(0)
138
19884
  {}
139
140
  void push_back(const Border& b){
141
    d_vec.push_back(b);
142
    if(b.d_areFixing){
143
      d_possibleFixes++;
144
    }
145
    if(b.d_diff.sgn() == 0){
146
      d_numZeroes++;
147
    }
148
  }
149
150
  int numZeroes() const { return d_numZeroes; }
151
  int possibleFixes() const { return d_possibleFixes; }
152
  int direction() const { return d_dir; }
153
154
  void make_heap(){
155
    d_begin = d_vec.begin();
156
    d_end = d_vec.end();
157
    std::make_heap(d_begin, d_end, d_cmp);
158
  }
159
160
  void dropNonZeroes(){
161
    d_vec.erase(std::remove_if(d_vec.begin(), d_vec.end(), &Border::nonZero),
162
                d_vec.end());
163
  }
164
165
  const Border& top() const {
166
    Assert(more());
167
    return *d_begin;
168
  }
169
  void pop_heap(){
170
    Assert(more());
171
172
    std::pop_heap(d_begin, d_end, d_cmp);
173
    --d_end;
174
  }
175
176
  BorderVec::const_iterator end() const{
177
    return BorderVec::const_iterator(d_end);
178
  }
179
  BorderVec::const_iterator begin() const{
180
    return BorderVec::const_iterator(d_begin);
181
  }
182
183
  inline bool more() const{ return d_begin != d_end; }
184
185
  inline bool empty() const{ return d_vec.empty(); }
186
187
  void clear(){
188
    d_possibleFixes = 0;
189
    d_numZeroes = 0;
190
    d_vec.clear();
191
  }
192
};
193
194
195
9939
class LinearEqualityModule {
196
public:
197
  typedef ArithVar (LinearEqualityModule::*VarPreferenceFunction)(ArithVar, ArithVar) const;
198
199
200
  typedef bool (LinearEqualityModule::*UpdatePreferenceFunction)(const UpdateInfo&, const UpdateInfo&) const;
201
202
203
private:
204
  /**
205
   * Manages information about the assignment and upper and lower bounds on the
206
   * variables.
207
   */
208
  ArithVariables& d_variables;
209
210
  /** Reference to the Tableau to operate upon. */
211
  Tableau& d_tableau;
212
213
  /** Called whenever the value of a basic variable is updated. */
214
  BasicVarModelUpdateCallBack d_basicVariableUpdates;
215
216
  BorderHeap d_increasing;
217
  BorderHeap d_decreasing;
218
  std::optional<DeltaRational> d_upperBoundDifference;
219
  std::optional<DeltaRational> d_lowerBoundDifference;
220
221
  Rational d_one;
222
  Rational d_negOne;
223
public:
224
225
  /**
226
   * Initializes a LinearEqualityModule with a partial model, a tableau,
227
   * and a callback function for when basic variables update their values.
228
   */
229
  LinearEqualityModule(ArithVariables& vars, Tableau& t, BoundInfoMap& boundTracking, BasicVarModelUpdateCallBack f);
230
231
  /**
232
   * Updates the assignment of a nonbasic variable x_i to v.
233
   * Also updates the assignment of basic variables accordingly.
234
   */
235
166034
  void update(ArithVar x_i, const DeltaRational& v){
236
166034
    if(d_areTracking){
237
      updateTracked(x_i,v);
238
    }else{
239
166034
      updateUntracked(x_i,v);
240
    }
241
166034
  }
242
243
  /** Specialization of update if the module is not tracking yet (for Assert*). */
244
  void updateUntracked(ArithVar x_i, const DeltaRational& v);
245
246
  /** Specialization of update if the module is not tracking yet (for Simplex). */
247
  void updateTracked(ArithVar x_i, const DeltaRational& v);
248
249
250
  /**
251
   * Updates the value of a basic variable x_i to v,
252
   * and then pivots x_i with the nonbasic variable in its row x_j.
253
   * Updates the assignment of the other basic variables accordingly.
254
   */
255
  void pivotAndUpdate(ArithVar x_i, ArithVar x_j, const DeltaRational& v);
256
257
39768
  ArithVariables& getVariables() const{ return d_variables; }
258
4195839
  Tableau& getTableau() const{ return d_tableau; }
259
260
  /**
261
   * Updates every non-basic to reflect the assignment in many.
262
   * For use with ApproximateSimplex.
263
   */
264
  void updateMany(const DenseMap<DeltaRational>& many);
265
  void forceNewBasis(const DenseSet& newBasis);
266
  void applySolution(const DenseSet& newBasis, const DenseMap<DeltaRational>& newValues);
267
268
269
  /**
270
   * Returns a pointer to the first Tableau entry on the row ridx that does not
271
   * have an either a lower bound/upper bound for proving a bound on skip.
272
   * The variable skip is always excluded. Returns NULL if there is no such element.
273
   *
274
   * If skip == ARITHVAR_SENTINEL, this is equivalent to considering the whole row.
275
   */
276
  const Tableau::Entry* rowLacksBound(RowIndex ridx, bool upperBound, ArithVar skip);
277
278
279
  void startTrackingBoundCounts();
280
  void stopTrackingBoundCounts();
281
282
283
  void includeBoundUpdate(ArithVar nb, const BoundsInfo& prev);
284
285
286
  uint32_t updateProduct(const UpdateInfo& inf) const;
287
288
  inline bool minNonBasicVarOrder(const UpdateInfo& a, const UpdateInfo& b) const{
289
    return a.nonbasic() >= b.nonbasic();
290
  }
291
292
  /**
293
   * Prefer the update that touch the fewest entries in the matrix.
294
   *
295
   * The intuition is that this operation will be cheaper.
296
   * This strongly biases the system towards updates instead of pivots.
297
   */
298
  inline bool minProduct(const UpdateInfo& a, const UpdateInfo& b) const{
299
    uint32_t aprod = updateProduct(a);
300
    uint32_t bprod = updateProduct(b);
301
302
    if(aprod == bprod){
303
      return minNonBasicVarOrder(a,b);
304
    }else{
305
      return aprod > bprod;
306
    }
307
  }
308
  inline bool constrainedMin(const UpdateInfo& a, const UpdateInfo& b) const{
309
    if(a.describesPivot() && b.describesPivot()){
310
      bool aAtBounds = basicsAtBounds(a);
311
      bool bAtBounds = basicsAtBounds(b);
312
      if(aAtBounds != bAtBounds){
313
        return bAtBounds;
314
      }
315
    }
316
    return minProduct(a,b);
317
  }
318
319
  /**
320
   * If both a and b are pivots, prefer the pivot with the leaving variables that has equal bounds.
321
   * The intuition is that such variables will be less likely to lead to future problems.
322
   */
323
  inline bool preferFrozen(const UpdateInfo& a, const UpdateInfo& b) const {
324
    if(a.describesPivot() && b.describesPivot()){
325
      bool aFrozen = d_variables.boundsAreEqual(a.leaving());
326
      bool bFrozen = d_variables.boundsAreEqual(b.leaving());
327
328
      if(aFrozen != bFrozen){
329
        return bFrozen;
330
      }
331
    }
332
    return constrainedMin(a,b);
333
  }
334
335
  /**
336
   * Prefer pivots with entering variables that do not have bounds.
337
   * The intuition is that such variables will be less likely to lead to future problems.
338
   */
339
  bool preferNeitherBound(const UpdateInfo& a, const UpdateInfo& b) const {
340
    if(d_variables.hasEitherBound(a.nonbasic()) == d_variables.hasEitherBound(b.nonbasic())){
341
      return preferFrozen(a,b);
342
    }else{
343
      return d_variables.hasEitherBound(a.nonbasic());
344
    }
345
  }
346
347
  bool modifiedBlands(const UpdateInfo& a, const UpdateInfo& b) const {
348
    Assert(a.focusDirection() == 0 && b.focusDirection() == 0);
349
    Assert(a.describesPivot());
350
    Assert(b.describesPivot());
351
    if(a.nonbasic() == b.nonbasic()){
352
      bool aIsZero = a.nonbasicDelta().sgn() == 0;
353
      bool bIsZero = b.nonbasicDelta().sgn() == 0;
354
355
      if((aIsZero || bIsZero) && (!aIsZero || !bIsZero)){
356
        return bIsZero;
357
      }else{
358
        return a.leaving() >= b.leaving();
359
      }
360
    }else{
361
      return a.nonbasic() > b.nonbasic();
362
    }
363
  }
364
365
  template <bool heuristic>
366
  bool preferWitness(const UpdateInfo& a, const UpdateInfo& b) const{
367
    WitnessImprovement aImp = a.getWitness(!heuristic);
368
    WitnessImprovement bImp = b.getWitness(!heuristic);
369
370
    if(aImp == bImp){
371
      switch(aImp){
372
      case ConflictFound:
373
        return preferNeitherBound(a,b);
374
      case ErrorDropped:
375
        if(a.errorsChange() == b.errorsChange()){
376
          return preferNeitherBound(a,b);
377
        }else{
378
          return a.errorsChange() > b.errorsChange();
379
        }
380
      case FocusImproved:
381
        return preferNeitherBound(a,b);
382
      case BlandsDegenerate:
383
        Assert(a.describesPivot());
384
        Assert(b.describesPivot());
385
        Assert(a.focusDirection() == 0 && b.focusDirection() == 0);
386
        return modifiedBlands(a,b);
387
      case HeuristicDegenerate:
388
        Assert(a.describesPivot());
389
        Assert(b.describesPivot());
390
        Assert(a.focusDirection() == 0 && b.focusDirection() == 0);
391
        return preferNeitherBound(a,b);
392
      case AntiProductive:
393
        return minNonBasicVarOrder(a, b);
394
      // Not valid responses
395
      case Degenerate:
396
      case FocusShrank:
397
        Unreachable();
398
      }
399
      Unreachable();
400
    }else{
401
      return aImp > bImp;
402
    }
403
  }
404
405
private:
406
407
  /**
408
   * This maps each row index to its relevant bounds info.
409
   * This tracks the count for how many variables on a row have bounds
410
   * and how many are assigned at their bounds.
411
   */
412
  BoundInfoMap& d_btracking;
413
  bool d_areTracking;
414
415
public:
416
  /**
417
   * The constraint on a basic variable b is implied by the constraints
418
   * on its row.  This is a wrapper for propagateRow().
419
   */
420
  void propagateBasicFromRow(ConstraintP c);
421
422
  /**
423
   * Let v be the variable for the constraint c.
424
   * Exports either the explanation of an upperbound or a lower bound
425
   * of v using the other variables in the row.
426
   *
427
   * If farkas != RationalVectorPSentinel, this function additionally
428
   * stores the farkas coefficients of the constraints stored in into.
429
   * Position 0 is the coefficient of v.
430
   * Position i > 0, corresponds to the order of the other constraints.
431
   */
432
  void propagateRow(ConstraintCPVec& into
433
                    , RowIndex ridx
434
                    , bool rowUp
435
                    , ConstraintP c
436
                    , RationalVectorP farkas);
437
438
  /**
439
   * Computes the value of a basic variable using the assignments
440
   * of the values of the variables in the basic variable's row tableau.
441
   * This can compute the value using either:
442
   * - the the current assignment (useSafe=false) or
443
   * - the safe assignment (useSafe = true).
444
   */
445
  DeltaRational computeRowValue(ArithVar x, bool useSafe) const;
446
447
  /**
448
   * A PreferenceFunction takes a const ref to the SimplexDecisionProcedure,
449
   * and 2 ArithVar variables and returns one of the ArithVar variables
450
   * potentially using the internals of the SimplexDecisionProcedure.
451
   */
452
453
  ArithVar noPreference(ArithVar x, ArithVar y) const{
454
    return x;
455
  }
456
457
  /**
458
   * minVarOrder is a PreferenceFunction for selecting the smaller of the 2
459
   * ArithVars. This PreferenceFunction is used during the VarOrder stage of
460
   * findModel.
461
   */
462
  ArithVar minVarOrder(ArithVar x, ArithVar y) const;
463
464
  /**
465
   * minColLength is a PreferenceFunction for selecting the variable with the
466
   * smaller row count in the tableau.
467
   *
468
   * This is a heuristic rule and should not be used during the VarOrder
469
   * stage of findModel.
470
   */
471
  ArithVar minColLength(ArithVar x, ArithVar y) const;
472
473
  /**
474
   * minRowLength is a PreferenceFunction for selecting the variable with the
475
   * smaller row count in the tableau.
476
   *
477
   * This is a heuristic rule and should not be used during the VarOrder
478
   * stage of findModel.
479
   */
480
  ArithVar minRowLength(ArithVar x, ArithVar y) const;
481
482
  /**
483
   * minBoundAndRowCount is a PreferenceFunction for preferring a variable
484
   * without an asserted bound over variables with an asserted bound.
485
   * If both have bounds or both do not have bounds,
486
   * the rule falls back to minRowCount(...).
487
   *
488
   * This is a heuristic rule and should not be used during the VarOrder
489
   * stage of findModel.
490
   */
491
  ArithVar minBoundAndColLength(ArithVar x, ArithVar y) const;
492
493
494
  template <bool above>
495
4752327
  inline bool isAcceptableSlack(int sgn, ArithVar nonbasic) const {
496
    return
497
550312
      ( above && sgn < 0 && d_variables.strictlyBelowUpperBound(nonbasic)) ||
498
682868
      ( above && sgn > 0 && d_variables.strictlyAboveLowerBound(nonbasic)) ||
499
5825793
      (!above && sgn > 0 && d_variables.strictlyBelowUpperBound(nonbasic)) ||
500
7163064
      (!above && sgn < 0 && d_variables.strictlyAboveLowerBound(nonbasic));
501
  }
502
503
  /**
504
   * Given the basic variable x_i,
505
   * this function finds the smallest nonbasic variable x_j in the row of x_i
506
   * in the tableau that can "take up the slack" to let x_i satisfy its bounds.
507
   * This returns ARITHVAR_SENTINEL if none exists.
508
   *
509
   * More formally one of the following conditions must be satisfied:
510
   * -  lowerBound && a_ij < 0 && assignment(x_j) < upperbound(x_j)
511
   * -  lowerBound && a_ij > 0 && assignment(x_j) > lowerbound(x_j)
512
   * - !lowerBound && a_ij > 0 && assignment(x_j) < upperbound(x_j)
513
   * - !lowerBound && a_ij < 0 && assignment(x_j) > lowerbound(x_j)
514
   *
515
   */
516
  template <bool lowerBound>  ArithVar selectSlack(ArithVar x_i, VarPreferenceFunction pf) const;
517
98702
  ArithVar selectSlackLowerBound(ArithVar x_i, VarPreferenceFunction pf) const {
518
98702
    return selectSlack<true>(x_i, pf);
519
  }
520
112485
  ArithVar selectSlackUpperBound(ArithVar x_i, VarPreferenceFunction pf) const {
521
112485
    return selectSlack<false>(x_i, pf);
522
  }
523
524
  const Tableau::Entry* selectSlackEntry(ArithVar x_i, bool above) const;
525
526
68236250
  inline bool rowIndexIsTracked(RowIndex ridx) const {
527
68236250
    return d_btracking.isKey(ridx);
528
  }
529
6713022
  inline bool basicIsTracked(ArithVar v) const {
530
6713022
    return rowIndexIsTracked(d_tableau.basicToRowIndex(v));
531
  }
532
  void trackRowIndex(RowIndex ridx);
533
  void stopTrackingRowIndex(RowIndex ridx){
534
    Assert(rowIndexIsTracked(ridx));
535
    d_btracking.remove(ridx);
536
  }
537
538
  /**
539
   * If the pivot described in u were performed,
540
   * then the row would qualify as being either at the minimum/maximum
541
   * to the non-basics being at their bounds.
542
   * The minimum/maximum is determined by the direction the non-basic is changing.
543
   */
544
  bool basicsAtBounds(const UpdateInfo& u) const;
545
546
private:
547
548
  /**
549
   * Recomputes the bound info for a row using either the information
550
   * in the bounds queue or the current information.
551
   * O(row length of ridx)
552
   */
553
  BoundsInfo computeRowBoundInfo(RowIndex ridx, bool inQueue) const;
554
555
public:
556
  /** Debug only routine. */
557
  BoundCounts debugBasicAtBoundCount(ArithVar x_i) const;
558
559
  /** Track the effect of the change of coefficient for bound counting. */
560
  void trackingCoefficientChange(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn);
561
562
  /** Track the effect of multiplying a row by a sign for bound counting. */
563
  void trackingMultiplyRow(RowIndex ridx, int sgn);
564
565
  /** Count for how many on a row have *an* upper/lower bounds. */
566
10005476
  BoundCounts hasBoundCount(RowIndex ri) const {
567
10005476
    Assert(d_variables.boundsQueueEmpty());
568
10005476
    return d_btracking[ri].hasBounds();
569
  }
570
571
  /**
572
   * Are there any non-basics on x_i's row that are not at
573
   * their respective lower bounds (mod sgns).
574
   * O(1) time due to the atBound() count.
575
   */
576
  bool nonbasicsAtLowerBounds(ArithVar x_i) const;
577
578
  /**
579
   * Are there any non-basics on x_i's row that are not at
580
   * their respective upper bounds (mod sgns).
581
   * O(1) time due to the atBound() count.
582
   */
583
  bool nonbasicsAtUpperBounds(ArithVar x_i) const;
584
585
private:
586
9939
  class TrackingCallback : public CoefficientChangeCallback {
587
  private:
588
    LinearEqualityModule* d_linEq;
589
  public:
590
9942
    TrackingCallback(LinearEqualityModule* le) : d_linEq(le) {}
591
56849783
    void update(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn) override
592
    {
593
56849783
      d_linEq->trackingCoefficientChange(ridx, nb, oldSgn, currSgn);
594
56849783
    }
595
211187
    void multiplyRow(RowIndex ridx, int sgn) override
596
    {
597
211187
      d_linEq->trackingMultiplyRow(ridx, sgn);
598
211187
    }
599
4156071
    bool canUseRow(RowIndex ridx) const override
600
    {
601
4156071
      ArithVar basic = d_linEq->getTableau().rowIndexToBasic(ridx);
602
4156071
      return d_linEq->basicIsTracked(basic);
603
    }
604
 } d_trackCallback;
605
606
  /**
607
   * Selects the constraint for the variable v on the row for basic
608
   * with the weakest possible constraint that is consistent with the surplus
609
   * surplus.
610
   */
611
  ConstraintP weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v,
612
                                const Rational& coeff, bool& anyWeakening, ArithVar basic) const;
613
614
public:
615
  /**
616
   * Constructs a minimally weak conflict for the basic variable basicVar.
617
   *
618
   * Returns a constraint that is now in conflict.
619
   */
620
  ConstraintCP minimallyWeakConflict(bool aboveUpper, ArithVar basicVar, FarkasConflictBuilder& rc) const;
621
622
  /**
623
   * Given a basic variable that is know to have a conflict on it,
624
   * construct and return a conflict.
625
   * Follows section 4.2 in the CAV06 paper.
626
   */
627
31495
  inline ConstraintCP generateConflictAboveUpperBound(ArithVar conflictVar, FarkasConflictBuilder& rc) const {
628
31495
    return minimallyWeakConflict(true, conflictVar, rc);
629
  }
630
631
39678
  inline ConstraintCP generateConflictBelowLowerBound(ArithVar conflictVar, FarkasConflictBuilder& rc) const {
632
39678
    return minimallyWeakConflict(false, conflictVar, rc);
633
  }
634
635
  /**
636
   * Computes the sum of the upper/lower bound of row.
637
   * The variable skip is not included in the sum.
638
   */
639
  DeltaRational computeRowBound(RowIndex ridx, bool rowUb, ArithVar skip) const;
640
641
public:
642
  void substitutePlusTimesConstant(ArithVar to, ArithVar from, const Rational& mult);
643
  void directlyAddToCoefficient(ArithVar row, ArithVar col, const Rational& mult);
644
645
646
  /**
647
   * Checks to make sure the assignment is consistent with the tableau.
648
   * This code is for debugging.
649
   */
650
  void debugCheckTableau();
651
652
  void debugCheckTracking();
653
654
  /** Debugging information for a pivot. */
655
  void debugPivot(ArithVar x_i, ArithVar x_j);
656
657
  /** Checks the tableau + partial model for consistency. */
658
  bool debugEntireLinEqIsConsistent(const std::string& s);
659
660
661
  ArithVar minBy(const ArithVarVec& vec, VarPreferenceFunction pf) const;
662
663
  /**
664
   * Returns true if there would be a conflict on this row after a pivot
665
   * and update using its basic variable and one of the non-basic variables on
666
   * the row.
667
   */
668
  bool willBeInConflictAfterPivot(const Tableau::Entry& entry, const DeltaRational& nbDiff, bool bToUB) const;
669
  UpdateInfo mkConflictUpdate(const Tableau::Entry& entry, bool ub) const;
670
671
  /**
672
   * Looks more an update for fcSimplex on the nonbasic variable nb with the focus coefficient.
673
   */
674
  UpdateInfo speculativeUpdate(ArithVar nb, const Rational& focusCoeff, UpdatePreferenceFunction pref);
675
676
private:
677
678
  /**
679
   * Examines the effects of pivoting the entries column variable
680
   * with the row's basic variable and setting the variable s.t.
681
   * the basic variable is equal to one of its bounds.
682
   *
683
   * If ub, then the basic variable will be equal its upper bound.
684
   * If not ub,then the basic variable will be equal its lower bound.
685
   *
686
   * Returns iff this row will be in conflict after the pivot.
687
   *
688
   * If this is false, add the bound to the relevant heap.
689
   * If the bound is +/-infinity, this is ignored.
690
691
   *
692
   * Returns true if this would be a conflict.
693
   * If it returns false, this
694
   */
695
  bool accumulateBorder(const Tableau::Entry& entry, bool ub);
696
697
  void handleBorders(UpdateInfo& selected, ArithVar nb, const Rational& focusCoeff, BorderHeap& heap, int minimumFixes, UpdatePreferenceFunction pref);
698
  void pop_block(BorderHeap& heap, int& brokenInBlock, int& fixesRemaining, int& negErrorChange);
699
  void clearSpeculative();
700
  Rational updateCoefficient(BorderVec::const_iterator startBlock, BorderVec::const_iterator endBlock);
701
702
private:
703
  /** These fields are designed to be accessible to TheoryArith methods. */
704
  class Statistics {
705
  public:
706
    IntStat d_statPivots, d_statUpdates;
707
    TimerStat d_pivotTime;
708
    TimerStat d_adjTime;
709
710
    IntStat d_weakeningAttempts, d_weakeningSuccesses, d_weakenings;
711
    TimerStat d_weakenTime;
712
    TimerStat d_forceTime;
713
714
    Statistics();
715
  };
716
  mutable Statistics d_statistics;
717
718
};/* class LinearEqualityModule */
719
720
struct Cand {
721
  ArithVar d_nb;
722
  uint32_t d_penalty;
723
  int d_sgn;
724
  const Rational* d_coeff;
725
726
  Cand(ArithVar nb, uint32_t penalty, int s, const Rational* c) :
727
    d_nb(nb), d_penalty(penalty), d_sgn(s), d_coeff(c){}
728
};
729
730
731
class CompPenaltyColLength {
732
private:
733
  LinearEqualityModule* d_mod;
734
public:
735
  CompPenaltyColLength(LinearEqualityModule* mod): d_mod(mod){}
736
737
  bool operator()(const Cand& x, const Cand& y) const {
738
    if(x.d_penalty == y.d_penalty || !options::havePenalties()){
739
      return x.d_nb == d_mod->minBoundAndColLength(x.d_nb,y.d_nb);
740
    }else{
741
      return x.d_penalty < y.d_penalty;
742
    }
743
  }
744
};
745
746
2933917
class UpdateTrackingCallback : public BoundUpdateCallback {
747
private:
748
  LinearEqualityModule* d_mod;
749
public:
750
2933917
  UpdateTrackingCallback(LinearEqualityModule* mod): d_mod(mod){}
751
4882862
  void operator()(ArithVar v, const BoundsInfo& bi) override
752
  {
753
4882862
    d_mod->includeBoundUpdate(v, bi);
754
4882862
  }
755
};
756
757
}  // namespace arith
758
}  // namespace theory
759
}  // namespace cvc5