GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/dual_simplex.cpp Lines: 109 120 90.8 %
Date: 2021-05-22 Branches: 212 564 37.6 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Tim King, Aina Niemetz, 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 is an implementation of the Simplex Module for the Simplex for
14
 * DPLL(T) decision procedure.
15
 */
16
#include "theory/arith/dual_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 "theory/arith/linear_equality.h"
24
25
26
using namespace std;
27
28
namespace cvc5 {
29
namespace theory {
30
namespace arith {
31
32
9459
DualSimplexDecisionProcedure::DualSimplexDecisionProcedure(LinearEqualityModule& linEq, ErrorSet& errors, RaiseConflict conflictChannel, TempVarMalloc tvmalloc)
33
  : SimplexDecisionProcedure(linEq, errors, conflictChannel, tvmalloc)
34
  , d_pivotsInRound()
35
9459
  , d_statistics(d_pivots)
36
9459
{ }
37
38
9459
DualSimplexDecisionProcedure::Statistics::Statistics(uint32_t& pivots)
39
9459
    : d_statUpdateConflicts(smtStatisticsRegistry().registerInt(
40
18918
        "theory::arith::dual::UpdateConflicts")),
41
9459
      d_processSignalsTime(smtStatisticsRegistry().registerTimer(
42
18918
          "theory::arith::dual::findConflictOnTheQueueTime")),
43
9459
      d_simplexConflicts(smtStatisticsRegistry().registerInt(
44
18918
          "theory::arith::dual::simplexConflicts")),
45
9459
      d_recentViolationCatches(smtStatisticsRegistry().registerInt(
46
18918
          "theory::arith::dual::recentViolationCatches")),
47
9459
      d_searchTime(smtStatisticsRegistry().registerTimer(
48
18918
          "theory::arith::dual::searchTime")),
49
      d_finalCheckPivotCounter(
50
9459
          smtStatisticsRegistry().registerReference<uint32_t>(
51
56754
              "theory::arith::dual::lastPivots", pivots))
52
{
53
9459
}
54
55
1267778
Result::Sat DualSimplexDecisionProcedure::dualFindModel(bool exactResult){
56
1267778
  Assert(d_conflictVariables.empty());
57
58
  static thread_local unsigned int instance = 0;
59
1267778
  instance = instance + 1;
60
1267778
  d_pivots = 0;
61
62
1267778
  if(d_errorSet.errorEmpty() && !d_errorSet.moreSignals()){
63
669385
    Debug("arith::findModel") << "dualFindModel("<< instance <<") trivial" << endl;
64
669385
    return Result::SAT;
65
  }
66
67
  // We need to reduce this because of
68
598393
  d_errorSet.reduceToSignals();
69
598393
  d_errorSet.setSelectionRule(options::ErrorSelectionRule::VAR_ORDER);
70
71
598393
  if(processSignals()){
72
22713
    d_conflictVariables.purge();
73
74
22713
    Debug("arith::findModel") << "dualFindModel("<< instance <<") early conflict" << endl;
75
22713
    return Result::UNSAT;
76
575680
  }else if(d_errorSet.errorEmpty()){
77
491406
    Debug("arith::findModel") << "dualFindModel("<< instance <<") fixed itself" << endl;
78
491406
    Assert(!d_errorSet.moreSignals());
79
491406
    return Result::SAT;
80
  }
81
82
84274
  Debug("arith::findModel") << "dualFindModel(" << instance <<") start non-trivial" << endl;
83
84
84274
  Result::Sat result = Result::SAT_UNKNOWN;
85
86
  static const bool verbose = false;
87
84274
  exactResult |= options::arithStandardCheckVarOrderPivots() < 0;
88
89
90
168548
  uint32_t checkPeriod = options::arithSimplexCheckPeriod();
91
84274
  if(result == Result::SAT_UNKNOWN){
92
168548
    uint32_t numDifferencePivots = options::arithHeuristicPivots() < 0 ?
93
168548
      d_numVariables + 1 : options::arithHeuristicPivots();
94
    // The signed to unsigned conversion is safe.
95
84274
    if(numDifferencePivots > 0){
96
97
71093
      d_errorSet.setSelectionRule(d_heuristicRule);
98
71093
      if(searchForFeasibleSolution(numDifferencePivots)){
99
9863
        result = Result::UNSAT;
100
      }
101
    }
102
103
    if (verbose && numDifferencePivots > 0)
104
    {
105
      if (result == Result::UNSAT)
106
      {
107
        CVC5Message() << "diff order found unsat" << endl;
108
      }
109
      else if (d_errorSet.errorEmpty())
110
      {
111
        CVC5Message() << "diff order found model" << endl;
112
      }
113
      else
114
      {
115
        CVC5Message() << "diff order missed" << endl;
116
      }
117
    }
118
  }
119
84274
  Assert(!d_errorSet.moreSignals());
120
121
84274
  if(!d_errorSet.errorEmpty() && result != Result::UNSAT){
122
14574
    if(exactResult){
123
1161
      d_errorSet.setSelectionRule(options::ErrorSelectionRule::VAR_ORDER);
124
3495
      while(!d_errorSet.errorEmpty() && result != Result::UNSAT){
125
1167
        Assert(checkPeriod > 0);
126
1167
        if(searchForFeasibleSolution(checkPeriod)){
127
132
          result = Result::UNSAT;
128
        }
129
      }
130
13413
    }else if( options::arithStandardCheckVarOrderPivots() > 0){
131
13413
      d_errorSet.setSelectionRule(options::ErrorSelectionRule::VAR_ORDER);
132
13413
      if(searchForFeasibleSolution(options::arithStandardCheckVarOrderPivots())){
133
3720
        result = Result::UNSAT;
134
      }
135
      if (verbose)
136
      {
137
        if (result == Result::UNSAT)
138
        {
139
          CVC5Message() << "restricted var order found unsat" << endl;
140
        }
141
        else if (d_errorSet.errorEmpty())
142
        {
143
          CVC5Message() << "restricted var order found model" << endl;
144
        }
145
        else
146
        {
147
          CVC5Message() << "restricted var order missed" << endl;
148
        }
149
      }
150
    }
151
  }
152
153
84274
  Assert(!d_errorSet.moreSignals());
154
84274
  if(result == Result::SAT_UNKNOWN && d_errorSet.errorEmpty()){
155
70559
    result = Result::SAT;
156
  }
157
158
84274
  d_pivotsInRound.purge();
159
  // ensure that the conflict variable is still in the queue.
160
84274
  d_conflictVariables.purge();
161
162
84274
  Debug("arith::findModel") << "end findModel() " << instance << " " << result <<  endl;
163
164
84274
  return result;
165
}
166
167
//corresponds to Check() in dM06
168
//template <SimplexDecisionProcedure::PreferenceFunction pf>
169
85673
bool DualSimplexDecisionProcedure::searchForFeasibleSolution(uint32_t remainingIterations){
170
171346
  TimerStat::CodeTimer codeTimer(d_statistics.d_searchTime);
171
172
85673
  Debug("arith") << "searchForFeasibleSolution" << endl;
173
85673
  Assert(remainingIterations > 0);
174
175
445323
  while(remainingIterations > 0 && !d_errorSet.focusEmpty()){
176
193540
    if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
177
193540
    Assert(d_conflictVariables.empty());
178
193540
    ArithVar x_i = d_errorSet.topFocusVariable();
179
180
193540
    Debug("arith::update::select") << "selectSmallestInconsistentVar()=" << x_i << endl;
181
193540
    if(x_i == ARITHVAR_SENTINEL){
182
      Debug("arith::update") << "No inconsistent variables" << endl;
183
13715
      return false; //sat
184
    }
185
186
193540
    --remainingIterations;
187
188
193540
    bool useVarOrderPivot = d_pivotsInRound.count(x_i) >=  options::arithPivotThreshold();
189
193540
    if(!useVarOrderPivot){
190
193414
      d_pivotsInRound.add(x_i);
191
    }
192
193
194
387080
    Debug("arith::update")
195
387080
      << "pivots in rounds: " <<  d_pivotsInRound.count(x_i)
196
193540
      << " use " << useVarOrderPivot
197
387080
      << " threshold " << options::arithPivotThreshold()
198
193540
      << endl;
199
200
193540
    LinearEqualityModule::VarPreferenceFunction pf = useVarOrderPivot ?
201
      &LinearEqualityModule::minVarOrder : &LinearEqualityModule::minBoundAndColLength;
202
203
    //DeltaRational beta_i = d_variables.getAssignment(x_i);
204
193540
    ArithVar x_j = ARITHVAR_SENTINEL;
205
206
193540
    int32_t prevErrorSize CVC5_UNUSED = d_errorSet.errorSize();
207
208
193540
    if(d_variables.cmpAssignmentLowerBound(x_i) < 0 ){
209
105857
      x_j = d_linEq.selectSlackUpperBound(x_i, pf);
210
105857
      if(x_j == ARITHVAR_SENTINEL ){
211
        Unreachable();
212
        // ++(d_statistics.d_statUpdateConflicts);
213
        // reportConflict(x_i);
214
        // ++(d_statistics.d_simplexConflicts);
215
        // Node conflict = d_linEq.generateConflictBelowLowerBound(x_i); //unsat
216
        // d_conflictVariable = x_i;
217
        // reportConflict(conflict);
218
        // return true;
219
      }else{
220
105857
        const DeltaRational& l_i = d_variables.getLowerBound(x_i);
221
105857
        d_linEq.pivotAndUpdate(x_i, x_j, l_i);
222
      }
223
87683
    }else if(d_variables.cmpAssignmentUpperBound(x_i) > 0){
224
87683
      x_j = d_linEq.selectSlackLowerBound(x_i, pf);
225
87683
      if(x_j == ARITHVAR_SENTINEL ){
226
        Unreachable();
227
        // ++(d_statistics.d_statUpdateConflicts);
228
        // reportConflict(x_i);
229
        // ++(d_statistics.d_simplexConflicts);
230
        // Node conflict = d_linEq.generateConflictAboveUpperBound(x_i); //unsat
231
        // d_conflictVariable = x_i;
232
        // reportConflict(conflict);
233
        // return true;
234
      }else{
235
87683
        const DeltaRational& u_i = d_variables.getUpperBound(x_i);
236
87683
        d_linEq.pivotAndUpdate(x_i, x_j, u_i);
237
      }
238
    }
239
193540
    Assert(x_j != ARITHVAR_SENTINEL);
240
241
193540
    bool conflict = processSignals();
242
193540
    int32_t currErrorSize CVC5_UNUSED = d_errorSet.errorSize();
243
193540
    d_pivots++;
244
245
193540
    if(Debug.isOn("arith::dual")){
246
      Debug("arith::dual")
247
        << "#" << d_pivots
248
        << " c" << conflict
249
        << " d" << (prevErrorSize - currErrorSize)
250
        << " f"  << d_errorSet.inError(x_j)
251
        << " h" << d_conflictVariables.isMember(x_j)
252
        << " " << x_i << "->" << x_j
253
        << endl;
254
    }
255
256
193540
    if(conflict){
257
13715
      return true;
258
    }
259
  }
260
71958
  Assert(!d_errorSet.focusEmpty() || d_errorSet.errorEmpty());
261
71958
  Assert(remainingIterations == 0 || d_errorSet.focusEmpty());
262
71958
  Assert(d_errorSet.noSignals());
263
264
71958
  return false;
265
}
266
267
}  // namespace arith
268
}  // namespace theory
269
28191
}  // namespace cvc5