GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/dual_simplex.cpp Lines: 105 120 87.5 %
Date: 2021-11-07 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/env.h"
21
#include "smt/smt_statistics_registry.h"
22
#include "theory/arith/constraint.h"
23
#include "theory/arith/error_set.h"
24
#include "theory/arith/linear_equality.h"
25
26
27
using namespace std;
28
29
namespace cvc5 {
30
namespace theory {
31
namespace arith {
32
33
15273
DualSimplexDecisionProcedure::DualSimplexDecisionProcedure(
34
    Env& env,
35
    LinearEqualityModule& linEq,
36
    ErrorSet& errors,
37
    RaiseConflict conflictChannel,
38
15273
    TempVarMalloc tvmalloc)
39
    : SimplexDecisionProcedure(env, linEq, errors, conflictChannel, tvmalloc),
40
      d_pivotsInRound(),
41
15273
      d_statistics(d_pivots)
42
15273
{ }
43
44
15273
DualSimplexDecisionProcedure::Statistics::Statistics(uint32_t& pivots)
45
15273
    : d_statUpdateConflicts(smtStatisticsRegistry().registerInt(
46
30546
        "theory::arith::dual::UpdateConflicts")),
47
15273
      d_processSignalsTime(smtStatisticsRegistry().registerTimer(
48
30546
          "theory::arith::dual::findConflictOnTheQueueTime")),
49
15273
      d_simplexConflicts(smtStatisticsRegistry().registerInt(
50
30546
          "theory::arith::dual::simplexConflicts")),
51
15273
      d_recentViolationCatches(smtStatisticsRegistry().registerInt(
52
30546
          "theory::arith::dual::recentViolationCatches")),
53
15273
      d_searchTime(smtStatisticsRegistry().registerTimer(
54
30546
          "theory::arith::dual::searchTime")),
55
      d_finalCheckPivotCounter(
56
15273
          smtStatisticsRegistry().registerReference<uint32_t>(
57
91638
              "theory::arith::dual::lastPivots", pivots))
58
{
59
15273
}
60
61
2416045
Result::Sat DualSimplexDecisionProcedure::dualFindModel(bool exactResult){
62
2416045
  Assert(d_conflictVariables.empty());
63
64
  static thread_local unsigned int instance = 0;
65
2416045
  instance = instance + 1;
66
2416045
  d_pivots = 0;
67
68
2416045
  if(d_errorSet.errorEmpty() && !d_errorSet.moreSignals()){
69
1372541
    Debug("arith::findModel") << "dualFindModel("<< instance <<") trivial" << endl;
70
1372541
    return Result::SAT;
71
  }
72
73
  // We need to reduce this because of
74
1043504
  d_errorSet.reduceToSignals();
75
1043504
  d_errorSet.setSelectionRule(options::ErrorSelectionRule::VAR_ORDER);
76
77
1043504
  if(processSignals()){
78
37418
    d_conflictVariables.purge();
79
80
37418
    Debug("arith::findModel") << "dualFindModel("<< instance <<") early conflict" << endl;
81
37418
    return Result::UNSAT;
82
1006086
  }else if(d_errorSet.errorEmpty()){
83
898638
    Debug("arith::findModel") << "dualFindModel("<< instance <<") fixed itself" << endl;
84
898638
    Assert(!d_errorSet.moreSignals());
85
898638
    return Result::SAT;
86
  }
87
88
107448
  Debug("arith::findModel") << "dualFindModel(" << instance <<") start non-trivial" << endl;
89
90
107448
  Result::Sat result = Result::SAT_UNKNOWN;
91
92
107448
  exactResult |= d_varOrderPivotLimit < 0;
93
94
107448
  uint32_t checkPeriod = options().arith.arithSimplexCheckPeriod;
95
107448
  if(result == Result::SAT_UNKNOWN){
96
107448
    uint32_t numDifferencePivots = options().arith.arithHeuristicPivots < 0
97
14168
                                       ? d_numVariables + 1
98
121616
                                       : options().arith.arithHeuristicPivots;
99
    // The signed to unsigned conversion is safe.
100
107448
    if(numDifferencePivots > 0){
101
102
94372
      d_errorSet.setSelectionRule(d_heuristicRule);
103
94372
      if(searchForFeasibleSolution(numDifferencePivots)){
104
13343
        result = Result::UNSAT;
105
      }
106
    }
107
  }
108
107448
  Assert(!d_errorSet.moreSignals());
109
110
107448
  if(!d_errorSet.errorEmpty() && result != Result::UNSAT){
111
15458
    if(exactResult){
112
15458
      d_errorSet.setSelectionRule(options::ErrorSelectionRule::VAR_ORDER);
113
46526
      while(!d_errorSet.errorEmpty() && result != Result::UNSAT){
114
15534
        Assert(checkPeriod > 0);
115
15534
        if(searchForFeasibleSolution(checkPeriod)){
116
3946
          result = Result::UNSAT;
117
        }
118
      }
119
    }
120
    else if (d_varOrderPivotLimit > 0)
121
    {
122
      d_errorSet.setSelectionRule(options::ErrorSelectionRule::VAR_ORDER);
123
      if (searchForFeasibleSolution(d_varOrderPivotLimit))
124
      {
125
        result = Result::UNSAT;
126
      }
127
    }
128
  }
129
130
107448
  Assert(!d_errorSet.moreSignals());
131
107448
  if(result == Result::SAT_UNKNOWN && d_errorSet.errorEmpty()){
132
90159
    result = Result::SAT;
133
  }
134
135
107448
  d_pivotsInRound.purge();
136
  // ensure that the conflict variable is still in the queue.
137
107448
  d_conflictVariables.purge();
138
139
107448
  Debug("arith::findModel") << "end findModel() " << instance << " " << result <<  endl;
140
141
107448
  return result;
142
}
143
144
//corresponds to Check() in dM06
145
//template <SimplexDecisionProcedure::PreferenceFunction pf>
146
109906
bool DualSimplexDecisionProcedure::searchForFeasibleSolution(uint32_t remainingIterations){
147
219812
  TimerStat::CodeTimer codeTimer(d_statistics.d_searchTime);
148
149
109906
  Debug("arith") << "searchForFeasibleSolution" << endl;
150
109906
  Assert(remainingIterations > 0);
151
152
581766
  while(remainingIterations > 0 && !d_errorSet.focusEmpty()){
153
253219
    if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
154
253219
    Assert(d_conflictVariables.empty());
155
253219
    ArithVar x_i = d_errorSet.topFocusVariable();
156
157
253219
    Debug("arith::update::select") << "selectSmallestInconsistentVar()=" << x_i << endl;
158
253219
    if(x_i == ARITHVAR_SENTINEL){
159
      Debug("arith::update") << "No inconsistent variables" << endl;
160
17289
      return false; //sat
161
    }
162
163
253219
    --remainingIterations;
164
165
    bool useVarOrderPivot =
166
253219
        d_pivotsInRound.count(x_i) >= options().arith.arithPivotThreshold;
167
253219
    if(!useVarOrderPivot){
168
237081
      d_pivotsInRound.add(x_i);
169
    }
170
171
506438
    Debug("arith::update") << "pivots in rounds: " << d_pivotsInRound.count(x_i)
172
253219
                           << " use " << useVarOrderPivot << " threshold "
173
253219
                           << options().arith.arithPivotThreshold << std::endl;
174
175
253219
    LinearEqualityModule::VarPreferenceFunction pf = useVarOrderPivot ?
176
      &LinearEqualityModule::minVarOrder : &LinearEqualityModule::minBoundAndColLength;
177
178
    //DeltaRational beta_i = d_variables.getAssignment(x_i);
179
253219
    ArithVar x_j = ARITHVAR_SENTINEL;
180
181
253219
    int32_t prevErrorSize CVC5_UNUSED = d_errorSet.errorSize();
182
183
253219
    if(d_variables.cmpAssignmentLowerBound(x_i) < 0 ){
184
140782
      x_j = d_linEq.selectSlackUpperBound(x_i, pf);
185
140782
      if(x_j == ARITHVAR_SENTINEL ){
186
        Unreachable();
187
        // ++(d_statistics.d_statUpdateConflicts);
188
        // reportConflict(x_i);
189
        // ++(d_statistics.d_simplexConflicts);
190
        // Node conflict = d_linEq.generateConflictBelowLowerBound(x_i); //unsat
191
        // d_conflictVariable = x_i;
192
        // reportConflict(conflict);
193
        // return true;
194
      }else{
195
140782
        const DeltaRational& l_i = d_variables.getLowerBound(x_i);
196
140782
        d_linEq.pivotAndUpdate(x_i, x_j, l_i);
197
      }
198
112437
    }else if(d_variables.cmpAssignmentUpperBound(x_i) > 0){
199
112437
      x_j = d_linEq.selectSlackLowerBound(x_i, pf);
200
112437
      if(x_j == ARITHVAR_SENTINEL ){
201
        Unreachable();
202
        // ++(d_statistics.d_statUpdateConflicts);
203
        // reportConflict(x_i);
204
        // ++(d_statistics.d_simplexConflicts);
205
        // Node conflict = d_linEq.generateConflictAboveUpperBound(x_i); //unsat
206
        // d_conflictVariable = x_i;
207
        // reportConflict(conflict);
208
        // return true;
209
      }else{
210
112437
        const DeltaRational& u_i = d_variables.getUpperBound(x_i);
211
112437
        d_linEq.pivotAndUpdate(x_i, x_j, u_i);
212
      }
213
    }
214
253219
    Assert(x_j != ARITHVAR_SENTINEL);
215
216
253219
    bool conflict = processSignals();
217
253219
    int32_t currErrorSize CVC5_UNUSED = d_errorSet.errorSize();
218
253219
    d_pivots++;
219
220
253219
    if(Debug.isOn("arith::dual")){
221
      Debug("arith::dual")
222
        << "#" << d_pivots
223
        << " c" << conflict
224
        << " d" << (prevErrorSize - currErrorSize)
225
        << " f"  << d_errorSet.inError(x_j)
226
        << " h" << d_conflictVariables.isMember(x_j)
227
        << " " << x_i << "->" << x_j
228
        << endl;
229
    }
230
231
253219
    if(conflict){
232
17289
      return true;
233
    }
234
  }
235
92617
  Assert(!d_errorSet.focusEmpty() || d_errorSet.errorEmpty());
236
92617
  Assert(remainingIterations == 0 || d_errorSet.focusEmpty());
237
92617
  Assert(d_errorSet.noSignals());
238
239
92617
  return false;
240
}
241
242
}  // namespace arith
243
}  // namespace theory
244
31137
}  // namespace cvc5