GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/dual_simplex.cpp Lines: 105 120 87.5 %
Date: 2021-09-29 Branches: 195 538 36.2 %

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