GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/fc_simplex.cpp Lines: 21 471 4.5 %
Date: 2021-11-07 Branches: 16 2092 0.8 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Tim King, Aina Niemetz, Mathias Preiner
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 is an implementation of the Simplex Module for the Simplex for
14
 * DPLL(T)decision procedure.
15
 */
16
#include "theory/arith/fc_simplex.h"
17
18
#include "base/output.h"
19
#include "options/arith_options.h"
20
#include "smt/smt_statistics_registry.h"
21
#include "theory/arith/constraint.h"
22
#include "theory/arith/error_set.h"
23
#include "util/statistics_stats.h"
24
25
using namespace std;
26
27
namespace cvc5 {
28
namespace theory {
29
namespace arith {
30
31
15273
FCSimplexDecisionProcedure::FCSimplexDecisionProcedure(
32
    Env& env,
33
    LinearEqualityModule& linEq,
34
    ErrorSet& errors,
35
    RaiseConflict conflictChannel,
36
15273
    TempVarMalloc tvmalloc)
37
    : SimplexDecisionProcedure(env, linEq, errors, conflictChannel, tvmalloc),
38
      d_focusSize(0),
39
      d_focusErrorVar(ARITHVAR_SENTINEL),
40
      d_focusCoefficients(),
41
      d_pivotBudget(0),
42
      d_prevWitnessImprovement(AntiProductive),
43
      d_witnessImprovementInARow(0),
44
      d_sgnDisagreements(),
45
15273
      d_statistics("theory::arith::FC::", d_pivots)
46
15273
{ }
47
48
15273
FCSimplexDecisionProcedure::Statistics::Statistics(const std::string& name,
49
15273
                                                   uint32_t& pivots)
50
    : d_initialSignalsTime(
51
30546
        smtStatisticsRegistry().registerTimer(name + "initialProcessTime")),
52
      d_initialConflicts(
53
30546
          smtStatisticsRegistry().registerInt(name + "UpdateConflicts")),
54
30546
      d_fcFoundUnsat(smtStatisticsRegistry().registerInt(name + "FoundUnsat")),
55
30546
      d_fcFoundSat(smtStatisticsRegistry().registerInt(name + "FoundSat")),
56
30546
      d_fcMissed(smtStatisticsRegistry().registerInt(name + "Missed")),
57
30546
      d_fcTimer(smtStatisticsRegistry().registerTimer(name + "Timer")),
58
      d_fcFocusConstructionTimer(
59
30546
          smtStatisticsRegistry().registerTimer(name + "Construction")),
60
15273
      d_selectUpdateForDualLike(smtStatisticsRegistry().registerTimer(
61
30546
          name + "selectUpdateForDualLike")),
62
15273
      d_selectUpdateForPrimal(smtStatisticsRegistry().registerTimer(
63
30546
          name + "selectUpdateForPrimal")),
64
      d_finalCheckPivotCounter(
65
15273
          smtStatisticsRegistry().registerReference<uint32_t>(
66
152730
              name + "lastPivots", pivots))
67
{
68
15273
}
69
70
Result::Sat FCSimplexDecisionProcedure::findModel(bool exactResult){
71
  Assert(d_conflictVariables.empty());
72
  Assert(d_sgnDisagreements.empty());
73
74
  d_pivots = 0;
75
  static thread_local unsigned int instance = 0;
76
  instance = instance + 1;
77
78
  if(d_errorSet.errorEmpty() && !d_errorSet.moreSignals()){
79
    Debug("arith::findModel") << "fcFindModel("<< instance <<") trivial" << endl;
80
    Assert(d_conflictVariables.empty());
81
    return Result::SAT;
82
  }
83
84
  // We need to reduce this because of
85
  d_errorSet.reduceToSignals();
86
87
  // We must start tracking NOW
88
  d_errorSet.setSelectionRule(options::ErrorSelectionRule::SUM_METRIC);
89
90
  if(initialProcessSignals()){
91
    d_conflictVariables.purge();
92
    Debug("arith::findModel") << "fcFindModel("<< instance <<") early conflict" << endl;
93
    Assert(d_conflictVariables.empty());
94
    return Result::UNSAT;
95
  }else if(d_errorSet.errorEmpty()){
96
    Debug("arith::findModel") << "fcFindModel("<< instance <<") fixed itself" << endl;
97
    Assert(d_conflictVariables.empty());
98
    return Result::SAT;
99
  }
100
101
  Debug("arith::findModel") << "fcFindModel(" << instance <<") start non-trivial" << endl;
102
103
  exactResult |= d_varOrderPivotLimit < 0;
104
105
  d_prevWitnessImprovement = HeuristicDegenerate;
106
  d_witnessImprovementInARow = 0;
107
108
  Result::Sat result = Result::SAT_UNKNOWN;
109
110
  if(result == Result::SAT_UNKNOWN){
111
    if(exactResult){
112
      d_pivotBudget = -1;
113
    }else{
114
      d_pivotBudget = d_varOrderPivotLimit;
115
    }
116
117
    result = dualLike();
118
119
    if(result ==  Result::UNSAT){
120
      ++(d_statistics.d_fcFoundUnsat);
121
    }else if(d_errorSet.errorEmpty()){
122
      ++(d_statistics.d_fcFoundSat);
123
    }else{
124
      ++(d_statistics.d_fcMissed);
125
    }
126
  }
127
128
  Assert(!d_errorSet.moreSignals());
129
  if(result == Result::SAT_UNKNOWN && d_errorSet.errorEmpty()){
130
    result = Result::SAT;
131
  }
132
133
  // ensure that the conflict variable is still in the queue.
134
  d_conflictVariables.purge();
135
136
  Debug("arith::findModel") << "end findModel() " << instance << " " << result <<  endl;
137
138
  Assert(d_conflictVariables.empty());
139
  return result;
140
}
141
142
143
void FCSimplexDecisionProcedure::logPivot(WitnessImprovement w){
144
  if(d_pivotBudget > 0) {
145
    --d_pivotBudget;
146
  }
147
  Assert(w != AntiProductive);
148
149
  if(w == d_prevWitnessImprovement){
150
    ++d_witnessImprovementInARow;
151
    // ignore overflow : probably never reached
152
    if(d_witnessImprovementInARow == 0){
153
      --d_witnessImprovementInARow;
154
    }
155
  }else{
156
    if(w != BlandsDegenerate){
157
      d_witnessImprovementInARow = 1;
158
    }
159
    // if w == BlandsDegenerate do not reset the counter
160
    d_prevWitnessImprovement = w;
161
  }
162
  if(strongImprovement(w)){
163
    d_leavingCountSinceImprovement.purge();
164
  }
165
166
  Debug("logPivot") << "logPivot " << d_prevWitnessImprovement << " "  << d_witnessImprovementInARow << endl;
167
168
}
169
170
uint32_t FCSimplexDecisionProcedure::degeneratePivotsInARow() const {
171
  switch(d_prevWitnessImprovement){
172
  case ConflictFound:
173
  case ErrorDropped:
174
  case FocusImproved:
175
    return 0;
176
  case HeuristicDegenerate:
177
  case BlandsDegenerate:
178
    return d_witnessImprovementInARow;
179
  // Degenerate is unreachable for its own reasons
180
  case Degenerate:
181
  case FocusShrank:
182
  case AntiProductive:
183
    Unreachable();
184
    return -1;
185
  }
186
  Unreachable();
187
}
188
189
void FCSimplexDecisionProcedure::adjustFocusAndError(const UpdateInfo& up, const AVIntPairVec& focusChanges){
190
  uint32_t newErrorSize = d_errorSet.errorSize();
191
  uint32_t newFocusSize = d_errorSet.focusSize();
192
193
  //Assert(!d_conflictVariables.empty() || newFocusSize <= d_focusSize);
194
  Assert(!d_conflictVariables.empty() || newErrorSize <= d_errorSize);
195
196
  if(newFocusSize == 0 || !d_conflictVariables.empty() ){
197
    tearDownInfeasiblityFunction(d_statistics.d_fcFocusConstructionTimer, d_focusErrorVar);
198
    d_focusErrorVar = ARITHVAR_SENTINEL;
199
  }else if(2*newFocusSize < d_focusSize ){
200
    tearDownInfeasiblityFunction(d_statistics.d_fcFocusConstructionTimer, d_focusErrorVar);
201
    d_focusErrorVar = constructInfeasiblityFunction(d_statistics.d_fcFocusConstructionTimer);
202
  }else{
203
    adjustInfeasFunc(d_statistics.d_fcFocusConstructionTimer, d_focusErrorVar, focusChanges);
204
  }
205
206
  d_errorSize = newErrorSize;
207
  d_focusSize = newFocusSize;
208
}
209
210
WitnessImprovement FCSimplexDecisionProcedure::adjustFocusShrank(const ArithVarVec& dropped){
211
  Assert(dropped.size() > 0);
212
  Assert(d_errorSet.focusSize() == d_focusSize);
213
  Assert(d_errorSet.focusSize() > dropped.size());
214
215
  uint32_t newFocusSize = d_focusSize - dropped.size();
216
  Assert(newFocusSize > 0);
217
218
  if(2 * newFocusSize <= d_focusSize){
219
    d_errorSet.dropFromFocusAll(dropped);
220
    tearDownInfeasiblityFunction(d_statistics.d_fcFocusConstructionTimer, d_focusErrorVar);
221
    d_focusErrorVar = constructInfeasiblityFunction(d_statistics.d_fcFocusConstructionTimer);
222
  }else{
223
    shrinkInfeasFunc(d_statistics.d_fcFocusConstructionTimer, d_focusErrorVar, dropped);
224
    d_errorSet.dropFromFocusAll(dropped);
225
  }
226
227
  d_focusSize = newFocusSize;
228
  Assert(d_errorSet.focusSize() == d_focusSize);
229
  return FocusShrank;
230
}
231
232
WitnessImprovement FCSimplexDecisionProcedure::focusDownToJust(ArithVar v){
233
  // uint32_t newErrorSize = d_errorSet.errorSize();
234
  // uint32_t newFocusSize = d_errorSet.focusSize();
235
  Assert(d_focusSize == d_errorSet.focusSize());
236
  Assert(d_focusSize > 1);
237
  Assert(d_errorSet.inFocus(v));
238
239
  d_errorSet.focusDownToJust(v);
240
  Assert(d_errorSet.focusSize() == 1);
241
  d_focusSize = 1;
242
243
  tearDownInfeasiblityFunction(d_statistics.d_fcFocusConstructionTimer, d_focusErrorVar);
244
  d_focusErrorVar = constructInfeasiblityFunction(d_statistics.d_fcFocusConstructionTimer);
245
246
  return FocusShrank;
247
}
248
249
250
251
UpdateInfo FCSimplexDecisionProcedure::selectPrimalUpdate(ArithVar basic, LinearEqualityModule::UpdatePreferenceFunction upf, LinearEqualityModule::VarPreferenceFunction bpf) {
252
  UpdateInfo selected;
253
254
  static int instance = 0 ;
255
  ++instance;
256
257
  Debug("arith::selectPrimalUpdate")
258
    << "selectPrimalUpdate " << instance << endl
259
    << basic << " " << d_tableau.basicRowLength(basic)
260
    << " " << d_linEq.debugBasicAtBoundCount(basic) << endl;
261
262
  static const int s_maxCandidatesAfterImprove = 3;
263
  bool isFocus = basic == d_focusErrorVar;
264
  Assert(isFocus || d_errorSet.inError(basic));
265
  int basicDir =  isFocus? 1 : d_errorSet.getSgn(basic);
266
  bool dualLike = !isFocus && d_focusSize > 1;
267
268
  if(!isFocus){
269
    loadFocusSigns();
270
  }
271
272
  decreasePenalties();
273
274
  typedef std::vector<Cand> CandVector;
275
  CandVector candidates;
276
277
  for(Tableau::RowIterator ri = d_tableau.basicRowIterator(basic); !ri.atEnd(); ++ri){
278
    const Tableau::Entry& e = *ri;
279
    ArithVar curr = e.getColVar();
280
    if(curr == basic){ continue; }
281
282
    int sgn = e.getCoefficient().sgn();
283
    int curr_movement = basicDir * sgn;
284
285
    bool candidate =
286
      (curr_movement > 0 && d_variables.cmpAssignmentUpperBound(curr) < 0) ||
287
      (curr_movement < 0 && d_variables.cmpAssignmentLowerBound(curr) > 0);
288
289
    Debug("arith::selectPrimalUpdate")
290
      << "storing " << basic
291
      << " " << curr
292
      << " " << candidate
293
      << " " << e.getCoefficient()
294
      << " " << curr_movement
295
      << " " << focusCoefficient(curr) << endl;
296
297
    if(!candidate) { continue; }
298
299
    if(!isFocus){
300
      const Rational& focusC = focusCoefficient(curr);
301
      Assert(dualLike || !focusC.isZero());
302
      if(dualLike && curr_movement != focusC.sgn()){
303
        Debug("arith::selectPrimalUpdate") << "sgn disagreement " << curr << endl;
304
        d_sgnDisagreements.push_back(curr);
305
        continue;
306
      }else{
307
        candidates.push_back(Cand(curr, penalty(curr), curr_movement, &focusC));
308
      }
309
    }else{
310
      candidates.push_back(Cand(curr, penalty(curr), curr_movement, &e.getCoefficient()));
311
    }
312
  }
313
314
  CompPenaltyColLength colCmp(&d_linEq, options().arith.havePenalties);
315
  CandVector::iterator i = candidates.begin();
316
  CandVector::iterator end = candidates.end();
317
  std::make_heap(i, end, colCmp);
318
319
  bool checkEverything = d_pivots == 0;
320
321
  int candidatesAfterFocusImprove = 0;
322
  while(i != end && (checkEverything || candidatesAfterFocusImprove <= s_maxCandidatesAfterImprove)){
323
    std::pop_heap(i, end, colCmp);
324
    --end;
325
    Cand& cand = (*end);
326
    ArithVar curr = cand.d_nb;
327
    const Rational& coeff = *cand.d_coeff;
328
329
    LinearEqualityModule::UpdatePreferenceFunction leavingPrefFunc = selectLeavingFunction(curr);
330
    UpdateInfo currProposal = d_linEq.speculativeUpdate(curr, coeff, leavingPrefFunc);
331
332
    Debug("arith::selectPrimalUpdate")
333
      << "selected " << selected << endl
334
      << "currProp " << currProposal << endl
335
      << "coeff " << coeff << endl;
336
337
    Assert(!currProposal.uninitialized());
338
339
    if(candidatesAfterFocusImprove > 0){
340
      candidatesAfterFocusImprove++;
341
    }
342
343
    if(selected.uninitialized() || (d_linEq.*upf)(selected, currProposal)){
344
345
      selected = currProposal;
346
      WitnessImprovement w = selected.getWitness(false);
347
      Debug("arith::selectPrimalUpdate") << "selected " << w << endl;
348
      setPenalty(curr, w);
349
      if(improvement(w)){
350
        bool exitEarly;
351
        switch(w){
352
        case ConflictFound: exitEarly = true; break;
353
        case ErrorDropped:
354
          if(checkEverything){
355
            exitEarly = d_errorSize + selected.errorsChange() == 0;
356
            Debug("arith::selectPrimalUpdate")
357
              << "ee " << d_errorSize << " "
358
              << selected.errorsChange() << " "
359
              << d_errorSize + selected.errorsChange() << endl;
360
          }else{
361
            exitEarly = true;
362
          }
363
          break;
364
        case FocusImproved:
365
          candidatesAfterFocusImprove = 1;
366
          exitEarly = false;
367
          break;
368
        default:
369
          exitEarly = false; break;
370
        }
371
        if(exitEarly){ break; }
372
      }
373
    }else{
374
      Debug("arith::selectPrimalUpdate") << "dropped "<< endl;
375
    }
376
377
  }
378
379
  if(!isFocus){
380
    unloadFocusSigns();
381
  }
382
  return selected;
383
}
384
385
bool FCSimplexDecisionProcedure::debugCheckWitness(const UpdateInfo& inf, WitnessImprovement w, bool useBlands){
386
  if(inf.getWitness(useBlands) == w){
387
    switch(w){
388
    case ConflictFound: return inf.foundConflict();
389
    case ErrorDropped: return inf.errorsChange() < 0;
390
    case FocusImproved: return inf.focusDirection() > 0;
391
    case FocusShrank: return false; // This is not a valid output
392
    case Degenerate: return false; // This is not a valid output
393
    case BlandsDegenerate: return useBlands;
394
    case HeuristicDegenerate: return !useBlands;
395
    case AntiProductive: return false;
396
    }
397
  }
398
  return false;
399
}
400
401
WitnessImprovement FCSimplexDecisionProcedure::primalImproveError(ArithVar errorVar){
402
  bool useBlands = degeneratePivotsInARow() >= s_maxDegeneratePivotsBeforeBlandsOnLeaving;
403
  UpdateInfo selected = selectUpdateForPrimal (errorVar, useBlands);
404
  Assert(!selected.uninitialized());
405
  WitnessImprovement w = selected.getWitness(useBlands);
406
  Assert(debugCheckWitness(selected, w, useBlands));
407
408
  updateAndSignal(selected, w);
409
  logPivot(w);
410
  return w;
411
}
412
413
414
WitnessImprovement FCSimplexDecisionProcedure::focusUsingSignDisagreements(ArithVar basic){
415
  Assert(!d_sgnDisagreements.empty());
416
  Assert(d_errorSet.focusSize() >= 2);
417
418
  if(Debug.isOn("arith::focus")){
419
    d_errorSet.debugPrint(Debug("arith::focus"));
420
  }
421
422
  ArithVar nb = d_linEq.minBy(d_sgnDisagreements, &LinearEqualityModule::minColLength);
423
  const Tableau::Entry& e_evar_nb = d_tableau.basicFindEntry(basic, nb);
424
  int oppositeSgn = - (e_evar_nb.getCoefficient().sgn());
425
  Debug("arith::focus") << "focusUsingSignDisagreements " << basic << " " << oppositeSgn << endl;
426
427
  ArithVarVec dropped;
428
429
  Tableau::ColIterator colIter = d_tableau.colIterator(nb);
430
  for(; !colIter.atEnd(); ++colIter){
431
    const Tableau::Entry& entry = *colIter;
432
    Assert(entry.getColVar() == nb);
433
434
    int sgn = entry.getCoefficient().sgn();
435
    Debug("arith::focus")
436
      << "on row "
437
      << d_tableau.rowIndexToBasic(entry.getRowIndex())
438
      << " "
439
      << entry.getCoefficient() << endl;
440
    ArithVar currRow = d_tableau.rowIndexToBasic(entry.getRowIndex());
441
    if(d_errorSet.inError(currRow) && d_errorSet.inFocus(currRow)){
442
      int errSgn = d_errorSet.getSgn(currRow);
443
444
      if(errSgn * sgn == oppositeSgn){
445
        dropped.push_back(currRow);
446
        Debug("arith::focus") << "dropping from focus " << currRow << endl;
447
      }
448
    }
449
  }
450
451
  d_sgnDisagreements.clear();
452
  return adjustFocusShrank(dropped);
453
}
454
455
bool debugSelectedErrorDropped(const UpdateInfo& selected, int32_t prevErrorSize, int32_t currErrorSize){
456
  int diff = currErrorSize - prevErrorSize;
457
  return selected.foundConflict() || diff == selected.errorsChange();
458
}
459
460
void FCSimplexDecisionProcedure::debugPrintSignal(ArithVar updated) const{
461
  Debug("updateAndSignal") << "updated basic " << updated;
462
  Debug("updateAndSignal") << " length " << d_tableau.basicRowLength(updated);
463
  Debug("updateAndSignal") << " consistent " << d_variables.assignmentIsConsistent(updated);
464
  int dir = !d_variables.assignmentIsConsistent(updated) ?
465
    d_errorSet.getSgn(updated) : 0;
466
  Debug("updateAndSignal") << " dir " << dir;
467
  Debug("updateAndSignal") << " debugBasicAtBoundCount " << d_linEq.debugBasicAtBoundCount(updated) << endl;
468
}
469
470
bool debugUpdatedBasic(const UpdateInfo& selected, ArithVar updated){
471
  if(selected.describesPivot() &&  updated == selected.leaving()){
472
    return selected.foundConflict();
473
  }else{
474
    return true;
475
  }
476
}
477
478
void FCSimplexDecisionProcedure::updateAndSignal(const UpdateInfo& selected, WitnessImprovement w){
479
  ArithVar nonbasic = selected.nonbasic();
480
481
  Debug("updateAndSignal") << "updateAndSignal " << selected << endl;
482
483
  stringstream ss;
484
485
  if(selected.describesPivot()){
486
    ConstraintP limiting = selected.limiting();
487
    ArithVar basic = limiting->getVariable();
488
    Assert(d_linEq.basicIsTracked(basic));
489
    d_linEq.pivotAndUpdate(basic, nonbasic, limiting->getValue());
490
  }else{
491
    Assert(!selected.unbounded() || selected.errorsChange() < 0);
492
493
    DeltaRational newAssignment =
494
      d_variables.getAssignment(nonbasic) + selected.nonbasicDelta();
495
496
    d_linEq.updateTracked(nonbasic, newAssignment);
497
  }
498
  d_pivots++;
499
500
  increaseLeavingCount(nonbasic);
501
502
  vector< pair<ArithVar, int> > focusChanges;
503
  while(d_errorSet.moreSignals()){
504
    ArithVar updated = d_errorSet.topSignal();
505
    int prevFocusSgn = d_errorSet.popSignal();
506
507
    if(d_tableau.isBasic(updated)){
508
      Assert(!d_variables.assignmentIsConsistent(updated)
509
             == d_errorSet.inError(updated));
510
      if(Debug.isOn("updateAndSignal")){debugPrintSignal(updated);}
511
      if(!d_variables.assignmentIsConsistent(updated)){
512
        if(checkBasicForConflict(updated)){
513
          reportConflict(updated);
514
          Assert(debugUpdatedBasic(selected, updated));
515
        }
516
      }
517
    }else{
518
      Debug("updateAndSignal") << "updated nonbasic " << updated << endl;
519
    }
520
    int currFocusSgn = d_errorSet.focusSgn(updated);
521
    if(currFocusSgn != prevFocusSgn){
522
      int change = currFocusSgn - prevFocusSgn;
523
      focusChanges.push_back(make_pair(updated, change));
524
    }
525
  }
526
527
  if(Debug.isOn("error")){ d_errorSet.debugPrint(Debug("error")); }
528
529
  Assert(
530
      debugSelectedErrorDropped(selected, d_errorSize, d_errorSet.errorSize()));
531
532
  adjustFocusAndError(selected, focusChanges);
533
}
534
535
WitnessImprovement FCSimplexDecisionProcedure::dualLikeImproveError(ArithVar errorVar){
536
  Assert(d_sgnDisagreements.empty());
537
  Assert(d_focusSize > 1);
538
539
  UpdateInfo selected = selectUpdateForDualLike(errorVar);
540
541
  if(selected.uninitialized()){
542
    // we found no proposals
543
    // If this is empty, there must be an error on this variable!
544
    // this should not be possible. It Should have been caught as a signal earlier
545
    WitnessImprovement dropped = focusUsingSignDisagreements(errorVar);
546
    Assert(d_sgnDisagreements.empty());
547
548
    return dropped;
549
  }else{
550
    d_sgnDisagreements.clear();
551
  }
552
553
  Assert(d_sgnDisagreements.empty());
554
  Assert(!selected.uninitialized());
555
556
  if(selected.focusDirection() == 0 &&
557
     d_prevWitnessImprovement == HeuristicDegenerate &&
558
     d_witnessImprovementInARow >= s_focusThreshold){
559
560
    Debug("focusDownToJust") << "focusDownToJust " << errorVar << endl;
561
562
    return focusDownToJust(errorVar);
563
  }else{
564
    WitnessImprovement w = selected.getWitness(false);
565
    Assert(debugCheckWitness(selected, w, false));
566
    updateAndSignal(selected, w);
567
    logPivot(w);
568
    return w;
569
  }
570
}
571
572
WitnessImprovement FCSimplexDecisionProcedure::focusDownToLastHalf(){
573
  Assert(d_focusSize >= 2);
574
575
  Debug("focusDownToLastHalf") << "focusDownToLastHalf "
576
       << d_errorSet.errorSize()  << " "
577
       << d_errorSet.focusSize() << " ";
578
579
  uint32_t half = d_focusSize/2;
580
  ArithVarVec buf;
581
  for(ErrorSet::focus_iterator i = d_errorSet.focusBegin(),
582
        i_end = d_errorSet.focusEnd(); i != i_end; ++i){
583
    if(half > 0){
584
      --half;
585
    } else{
586
      buf.push_back(*i);
587
    }
588
  }
589
  WitnessImprovement w = adjustFocusShrank(buf);
590
  Debug("focusDownToLastHalf") << "-> " << d_errorSet.focusSize() << endl;
591
  return w;
592
}
593
594
WitnessImprovement FCSimplexDecisionProcedure::selectFocusImproving() {
595
  Assert(d_focusErrorVar != ARITHVAR_SENTINEL);
596
  Assert(d_focusSize >= 2);
597
598
  LinearEqualityModule::UpdatePreferenceFunction upf =
599
    &LinearEqualityModule::preferWitness<true>;
600
601
  LinearEqualityModule::VarPreferenceFunction bpf =
602
    &LinearEqualityModule::minRowLength;
603
604
  UpdateInfo selected = selectPrimalUpdate(d_focusErrorVar, upf, bpf);
605
606
  if(selected.uninitialized()){
607
    Debug("selectFocusImproving") << "focus is optimum, but we don't have sat/conflict yet" << endl;
608
609
    return focusDownToLastHalf();
610
  }
611
  Assert(!selected.uninitialized());
612
  WitnessImprovement w = selected.getWitness(false);
613
  Assert(debugCheckWitness(selected, w, false));
614
615
  if(degenerate(w)){
616
    Debug("selectFocusImproving") << "only degenerate" << endl;
617
    if(d_prevWitnessImprovement == HeuristicDegenerate &&
618
       d_witnessImprovementInARow >= s_focusThreshold){
619
      Debug("selectFocusImproving") << "focus down been degenerate too long" << endl;
620
      return focusDownToLastHalf();
621
    }else{
622
      Debug("selectFocusImproving") << "taking degenerate" << endl;
623
    }
624
  }
625
  Debug("selectFocusImproving") << "selectFocusImproving did this " << selected << endl;
626
627
  updateAndSignal(selected, w);
628
  logPivot(w);
629
  return w;
630
}
631
632
bool FCSimplexDecisionProcedure::debugDualLike(WitnessImprovement w, ostream& out, int instance, uint32_t prevFocusSize, uint32_t prevErrorSize ) const{
633
  out << "DLV("<<instance<<") ";
634
  switch(w){
635
  case ConflictFound:
636
    out << "found conflict" << endl;
637
    return !d_conflictVariables.empty();
638
  case ErrorDropped:
639
    out << "dropped " << prevErrorSize - d_errorSize << endl;
640
    return d_errorSize < prevErrorSize;
641
  case FocusImproved:
642
    out << "focus improved"<< endl;
643
    return d_errorSize == prevErrorSize;
644
  case FocusShrank:
645
    out << "focus shrank"<< endl;
646
    return d_errorSize == prevErrorSize && prevFocusSize > d_focusSize;
647
  case BlandsDegenerate:
648
    out << "bland degenerate"<< endl;
649
    return true;
650
  case HeuristicDegenerate:
651
    out << "heuristic degenerate"<< endl;
652
    return true;
653
  case AntiProductive:
654
    out << "focus blur" << endl;
655
    return prevFocusSize == 0;
656
  case Degenerate:
657
    return false;
658
  }
659
  return false;
660
}
661
662
Result::Sat FCSimplexDecisionProcedure::dualLike(){
663
  static int instance = 0;
664
665
  TimerStat::CodeTimer codeTimer(d_statistics.d_fcTimer);
666
667
  Assert(d_sgnDisagreements.empty());
668
  Assert(d_pivotBudget != 0);
669
  Assert(d_errorSize == d_errorSet.errorSize());
670
  Assert(d_errorSize > 0);
671
  Assert(d_focusSize == d_errorSet.focusSize());
672
  Assert(d_focusSize > 0);
673
  Assert(d_conflictVariables.empty());
674
  Assert(d_focusErrorVar == ARITHVAR_SENTINEL);
675
676
  d_scores.purge();
677
  d_focusErrorVar = constructInfeasiblityFunction(d_statistics.d_fcFocusConstructionTimer);
678
679
680
  while(d_pivotBudget != 0  && d_errorSize > 0 && d_conflictVariables.empty()){
681
    ++instance;
682
    Debug("dualLike") << "dualLike " << instance << endl;
683
684
    Assert(d_errorSet.noSignals());
685
686
    WitnessImprovement w = AntiProductive;
687
    uint32_t prevFocusSize = d_focusSize;
688
    uint32_t prevErrorSize = d_errorSize;
689
690
    if(d_focusSize == 0){
691
      Assert(d_errorSize == d_errorSet.errorSize());
692
      Assert(d_focusErrorVar == ARITHVAR_SENTINEL);
693
694
      d_errorSet.blur();
695
696
      d_focusSize = d_errorSet.focusSize();
697
698
      Assert(d_errorSize == d_focusSize);
699
      Assert(d_errorSize >= 1);
700
701
      d_focusErrorVar = constructInfeasiblityFunction(d_statistics.d_fcFocusConstructionTimer);
702
703
      Debug("dualLike") << "blur " << d_focusSize << endl;
704
    }else if(d_focusSize == 1){
705
      // Possible outcomes:
706
      // - errorSet size shrunk
707
      // -- fixed v
708
      // -- fixed something other than v
709
      // - conflict
710
      // - budget was exhausted
711
712
      ArithVar e = d_errorSet.topFocusVariable();
713
      Debug("dualLike") << "primalImproveError " << e << endl;
714
      w = primalImproveError(e);
715
    }else{
716
717
      // Possible outcomes:
718
      // - errorSet size shrunk
719
      // -- fixed v
720
      // -- fixed something other than v
721
      // - conflict
722
      // - budget was exhausted
723
      // - focus went down
724
      Assert(d_focusSize > 1);
725
      ArithVar e = d_errorSet.topFocusVariable();
726
      static const unsigned s_sumMetricThreshold = 1;
727
      if(d_errorSet.sumMetric(e) <= s_sumMetricThreshold){
728
        Debug("dualLike") << "dualLikeImproveError " << e << endl;
729
        w = dualLikeImproveError(e);
730
      }else{
731
        Debug("dualLike") << "selectFocusImproving " << endl;
732
        w = selectFocusImproving();
733
      }
734
    }
735
    Debug("dualLike") << "witnessImprovement: " << w << endl;
736
    Assert(d_focusSize == d_errorSet.focusSize());
737
    Assert(d_errorSize == d_errorSet.errorSize());
738
739
    Assert(debugDualLike(
740
        w, Debug("dualLike"), instance, prevFocusSize, prevErrorSize));
741
    Debug("dualLike") << "Focus size " << d_focusSize << " (was " << prevFocusSize << ")" << endl;
742
    Debug("dualLike") << "Error size " << d_errorSize << " (was " << prevErrorSize << ")" << endl;
743
  }
744
745
746
  if(d_focusErrorVar != ARITHVAR_SENTINEL){
747
    tearDownInfeasiblityFunction(d_statistics.d_fcFocusConstructionTimer, d_focusErrorVar);
748
    d_focusErrorVar = ARITHVAR_SENTINEL;
749
  }
750
751
  Assert(d_focusErrorVar == ARITHVAR_SENTINEL);
752
  if(!d_conflictVariables.empty()){
753
    return Result::UNSAT;
754
  }else if(d_errorSet.errorEmpty()){
755
    Assert(d_errorSet.noSignals());
756
    return Result::SAT;
757
  }else{
758
    Assert(d_pivotBudget == 0);
759
    return Result::SAT_UNKNOWN;
760
  }
761
}
762
763
764
void FCSimplexDecisionProcedure::loadFocusSigns(){
765
  Assert(d_focusCoefficients.empty());
766
  Assert(d_focusErrorVar != ARITHVAR_SENTINEL);
767
  for(Tableau::RowIterator ri = d_tableau.basicRowIterator(d_focusErrorVar); !ri.atEnd(); ++ri){
768
    const Tableau::Entry& e = *ri;
769
    ArithVar curr = e.getColVar();
770
    d_focusCoefficients.set(curr, &e.getCoefficient());
771
  }
772
}
773
774
void FCSimplexDecisionProcedure::unloadFocusSigns(){
775
  d_focusCoefficients.purge();
776
}
777
778
const Rational& FCSimplexDecisionProcedure::focusCoefficient(ArithVar nb) const {
779
  if(d_focusCoefficients.isKey(nb)){
780
    return *(d_focusCoefficients[nb]);
781
  }else{
782
    return d_zero;
783
  }
784
}
785
786
}  // namespace arith
787
}  // namespace theory
788
31137
}  // namespace cvc5