GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/linear_equality.h Lines: 49 184 26.6 %
Date: 2021-09-29 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
12536
class BorderHeap {
99
  const int d_dir;
100
101
  class BorderHeapCmp {
102
  private:
103
    int d_nbDirection;
104
  public:
105
12542
    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
12542
  BorderHeap(int dir)
137
12542
  : d_dir(dir), d_cmp(dir), d_possibleFixes(0), d_numZeroes(0)
138
12542
  {}
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
6268
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
83541
  void update(ArithVar x_i, const DeltaRational& v){
236
83541
    if(d_areTracking){
237
      updateTracked(x_i,v);
238
    }else{
239
83541
      updateUntracked(x_i,v);
240
    }
241
83541
  }
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
25084
  ArithVariables& getVariables() const{ return d_variables; }
258
2284613
  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, bool produceProofs);
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 { return x; }
454
455
 /**
456
  * minVarOrder is a PreferenceFunction for selecting the smaller of the 2
457
  * ArithVars. This PreferenceFunction is used during the VarOrder stage of
458
  * findModel.
459
  */
460
 ArithVar minVarOrder(ArithVar x, ArithVar y) const;
461
462
 /**
463
  * minColLength is a PreferenceFunction for selecting the variable with the
464
  * smaller row count in the tableau.
465
  *
466
  * This is a heuristic rule and should not be used during the VarOrder
467
  * stage of findModel.
468
  */
469
 ArithVar minColLength(ArithVar x, ArithVar y) const;
470
471
 /**
472
  * minRowLength is a PreferenceFunction for selecting the variable with the
473
  * smaller row count in the tableau.
474
  *
475
  * This is a heuristic rule and should not be used during the VarOrder
476
  * stage of findModel.
477
  */
478
 ArithVar minRowLength(ArithVar x, ArithVar y) const;
479
480
 /**
481
  * minBoundAndRowCount is a PreferenceFunction for preferring a variable
482
  * without an asserted bound over variables with an asserted bound.
483
  * If both have bounds or both do not have bounds,
484
  * the rule falls back to minRowCount(...).
485
  *
486
  * This is a heuristic rule and should not be used during the VarOrder
487
  * stage of findModel.
488
  */
489
 ArithVar minBoundAndColLength(ArithVar x, ArithVar y) const;
490
491
 template <bool above>
492
4302308
 inline bool isAcceptableSlack(int sgn, ArithVar nonbasic) const
493
 {
494
438946
   return (above && sgn < 0 && d_variables.strictlyBelowUpperBound(nonbasic))
495
759587
          || (above && sgn > 0 && d_variables.strictlyAboveLowerBound(nonbasic))
496
          || (!above && sgn > 0
497
991582
              && d_variables.strictlyBelowUpperBound(nonbasic))
498
8082668
          || (!above && sgn < 0
499
6615909
              && d_variables.strictlyAboveLowerBound(nonbasic));
500
  }
501
502
  /**
503
   * Given the basic variable x_i,
504
   * this function finds the smallest nonbasic variable x_j in the row of x_i
505
   * in the tableau that can "take up the slack" to let x_i satisfy its bounds.
506
   * This returns ARITHVAR_SENTINEL if none exists.
507
   *
508
   * More formally one of the following conditions must be satisfied:
509
   * -  lowerBound && a_ij < 0 && assignment(x_j) < upperbound(x_j)
510
   * -  lowerBound && a_ij > 0 && assignment(x_j) > lowerbound(x_j)
511
   * - !lowerBound && a_ij > 0 && assignment(x_j) < upperbound(x_j)
512
   * - !lowerBound && a_ij < 0 && assignment(x_j) > lowerbound(x_j)
513
   *
514
   */
515
  template <bool lowerBound>  ArithVar selectSlack(ArithVar x_i, VarPreferenceFunction pf) const;
516
58257
  ArithVar selectSlackLowerBound(ArithVar x_i, VarPreferenceFunction pf) const {
517
58257
    return selectSlack<true>(x_i, pf);
518
  }
519
76635
  ArithVar selectSlackUpperBound(ArithVar x_i, VarPreferenceFunction pf) const {
520
76635
    return selectSlack<false>(x_i, pf);
521
  }
522
523
  const Tableau::Entry* selectSlackEntry(ArithVar x_i, bool above) const;
524
525
50565214
  inline bool rowIndexIsTracked(RowIndex ridx) const {
526
50565214
    return d_btracking.isKey(ridx);
527
  }
528
3761775
  inline bool basicIsTracked(ArithVar v) const {
529
3761775
    return rowIndexIsTracked(d_tableau.basicToRowIndex(v));
530
  }
531
  void trackRowIndex(RowIndex ridx);
532
  void stopTrackingRowIndex(RowIndex ridx){
533
    Assert(rowIndexIsTracked(ridx));
534
    d_btracking.remove(ridx);
535
  }
536
537
  /**
538
   * If the pivot described in u were performed,
539
   * then the row would qualify as being either at the minimum/maximum
540
   * to the non-basics being at their bounds.
541
   * The minimum/maximum is determined by the direction the non-basic is changing.
542
   */
543
  bool basicsAtBounds(const UpdateInfo& u) const;
544
545
private:
546
547
  /**
548
   * Recomputes the bound info for a row using either the information
549
   * in the bounds queue or the current information.
550
   * O(row length of ridx)
551
   */
552
  BoundsInfo computeRowBoundInfo(RowIndex ridx, bool inQueue) const;
553
554
public:
555
  /** Debug only routine. */
556
  BoundCounts debugBasicAtBoundCount(ArithVar x_i) const;
557
558
  /** Track the effect of the change of coefficient for bound counting. */
559
  void trackingCoefficientChange(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn);
560
561
  /** Track the effect of multiplying a row by a sign for bound counting. */
562
  void trackingMultiplyRow(RowIndex ridx, int sgn);
563
564
  /** Count for how many on a row have *an* upper/lower bounds. */
565
5236689
  BoundCounts hasBoundCount(RowIndex ri) const {
566
5236689
    Assert(d_variables.boundsQueueEmpty());
567
5236689
    return d_btracking[ri].hasBounds();
568
  }
569
570
  /**
571
   * Are there any non-basics on x_i's row that are not at
572
   * their respective lower bounds (mod sgns).
573
   * O(1) time due to the atBound() count.
574
   */
575
  bool nonbasicsAtLowerBounds(ArithVar x_i) const;
576
577
  /**
578
   * Are there any non-basics on x_i's row that are not at
579
   * their respective upper bounds (mod sgns).
580
   * O(1) time due to the atBound() count.
581
   */
582
  bool nonbasicsAtUpperBounds(ArithVar x_i) const;
583
584
private:
585
6268
  class TrackingCallback : public CoefficientChangeCallback {
586
  private:
587
    LinearEqualityModule* d_linEq;
588
  public:
589
6271
    TrackingCallback(LinearEqualityModule* le) : d_linEq(le) {}
590
44223216
    void update(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn) override
591
    {
592
44223216
      d_linEq->trackingCoefficientChange(ridx, nb, oldSgn, currSgn);
593
44223216
    }
594
134892
    void multiplyRow(RowIndex ridx, int sgn) override
595
    {
596
134892
      d_linEq->trackingMultiplyRow(ridx, sgn);
597
134892
    }
598
2259529
    bool canUseRow(RowIndex ridx) const override
599
    {
600
2259529
      ArithVar basic = d_linEq->getTableau().rowIndexToBasic(ridx);
601
2259529
      return d_linEq->basicIsTracked(basic);
602
    }
603
 } d_trackCallback;
604
605
  /**
606
   * Selects the constraint for the variable v on the row for basic
607
   * with the weakest possible constraint that is consistent with the surplus
608
   * surplus.
609
   */
610
  ConstraintP weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v,
611
                                const Rational& coeff, bool& anyWeakening, ArithVar basic) const;
612
613
public:
614
  /**
615
   * Constructs a minimally weak conflict for the basic variable basicVar.
616
   *
617
   * Returns a constraint that is now in conflict.
618
   */
619
  ConstraintCP minimallyWeakConflict(bool aboveUpper, ArithVar basicVar, FarkasConflictBuilder& rc) const;
620
621
  /**
622
   * Given a basic variable that is know to have a conflict on it,
623
   * construct and return a conflict.
624
   * Follows section 4.2 in the CAV06 paper.
625
   */
626
16508
  inline ConstraintCP generateConflictAboveUpperBound(ArithVar conflictVar, FarkasConflictBuilder& rc) const {
627
16508
    return minimallyWeakConflict(true, conflictVar, rc);
628
  }
629
630
25432
  inline ConstraintCP generateConflictBelowLowerBound(ArithVar conflictVar, FarkasConflictBuilder& rc) const {
631
25432
    return minimallyWeakConflict(false, conflictVar, rc);
632
  }
633
634
  /**
635
   * Computes the sum of the upper/lower bound of row.
636
   * The variable skip is not included in the sum.
637
   */
638
  DeltaRational computeRowBound(RowIndex ridx, bool rowUb, ArithVar skip) const;
639
640
public:
641
  void substitutePlusTimesConstant(ArithVar to, ArithVar from, const Rational& mult);
642
  void directlyAddToCoefficient(ArithVar row, ArithVar col, const Rational& mult);
643
644
645
  /**
646
   * Checks to make sure the assignment is consistent with the tableau.
647
   * This code is for debugging.
648
   */
649
  void debugCheckTableau();
650
651
  void debugCheckTracking();
652
653
  /** Debugging information for a pivot. */
654
  void debugPivot(ArithVar x_i, ArithVar x_j);
655
656
  /** Checks the tableau + partial model for consistency. */
657
  bool debugEntireLinEqIsConsistent(const std::string& s);
658
659
660
  ArithVar minBy(const ArithVarVec& vec, VarPreferenceFunction pf) const;
661
662
  /**
663
   * Returns true if there would be a conflict on this row after a pivot
664
   * and update using its basic variable and one of the non-basic variables on
665
   * the row.
666
   */
667
  bool willBeInConflictAfterPivot(const Tableau::Entry& entry, const DeltaRational& nbDiff, bool bToUB) const;
668
  UpdateInfo mkConflictUpdate(const Tableau::Entry& entry, bool ub) const;
669
670
  /**
671
   * Looks more an update for fcSimplex on the nonbasic variable nb with the focus coefficient.
672
   */
673
  UpdateInfo speculativeUpdate(ArithVar nb, const Rational& focusCoeff, UpdatePreferenceFunction pref);
674
675
private:
676
677
  /**
678
   * Examines the effects of pivoting the entries column variable
679
   * with the row's basic variable and setting the variable s.t.
680
   * the basic variable is equal to one of its bounds.
681
   *
682
   * If ub, then the basic variable will be equal its upper bound.
683
   * If not ub,then the basic variable will be equal its lower bound.
684
   *
685
   * Returns iff this row will be in conflict after the pivot.
686
   *
687
   * If this is false, add the bound to the relevant heap.
688
   * If the bound is +/-infinity, this is ignored.
689
690
   *
691
   * Returns true if this would be a conflict.
692
   * If it returns false, this
693
   */
694
  bool accumulateBorder(const Tableau::Entry& entry, bool ub);
695
696
  void handleBorders(UpdateInfo& selected, ArithVar nb, const Rational& focusCoeff, BorderHeap& heap, int minimumFixes, UpdatePreferenceFunction pref);
697
  void pop_block(BorderHeap& heap, int& brokenInBlock, int& fixesRemaining, int& negErrorChange);
698
  void clearSpeculative();
699
  Rational updateCoefficient(BorderVec::const_iterator startBlock, BorderVec::const_iterator endBlock);
700
701
private:
702
  /** These fields are designed to be accessible to TheoryArith methods. */
703
  class Statistics {
704
  public:
705
    IntStat d_statPivots, d_statUpdates;
706
    TimerStat d_pivotTime;
707
    TimerStat d_adjTime;
708
709
    IntStat d_weakeningAttempts, d_weakeningSuccesses, d_weakenings;
710
    TimerStat d_weakenTime;
711
    TimerStat d_forceTime;
712
713
    Statistics();
714
  };
715
  mutable Statistics d_statistics;
716
717
};/* class LinearEqualityModule */
718
719
struct Cand {
720
  ArithVar d_nb;
721
  uint32_t d_penalty;
722
  int d_sgn;
723
  const Rational* d_coeff;
724
725
  Cand(ArithVar nb, uint32_t penalty, int s, const Rational* c) :
726
    d_nb(nb), d_penalty(penalty), d_sgn(s), d_coeff(c){}
727
};
728
729
730
class CompPenaltyColLength {
731
private:
732
  LinearEqualityModule* d_mod;
733
public:
734
  CompPenaltyColLength(LinearEqualityModule* mod): d_mod(mod){}
735
736
  bool operator()(const Cand& x, const Cand& y) const {
737
    if(x.d_penalty == y.d_penalty || !options::havePenalties()){
738
      return x.d_nb == d_mod->minBoundAndColLength(x.d_nb,y.d_nb);
739
    }else{
740
      return x.d_penalty < y.d_penalty;
741
    }
742
  }
743
};
744
745
1790997
class UpdateTrackingCallback : public BoundUpdateCallback {
746
private:
747
  LinearEqualityModule* d_mod;
748
public:
749
1790997
  UpdateTrackingCallback(LinearEqualityModule* mod): d_mod(mod){}
750
2803904
  void operator()(ArithVar v, const BoundsInfo& bi) override
751
  {
752
2803904
    d_mod->includeBoundUpdate(v, bi);
753
2803904
  }
754
};
755
756
}  // namespace arith
757
}  // namespace theory
758
}  // namespace cvc5