GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/simplex.cpp Lines: 59 163 36.2 %
Date: 2021-11-07 Branches: 83 590 14.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Tim King, Gereon Kremer, Andres Noetzli
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
17
#include "theory/arith/simplex.h"
18
19
#include "base/output.h"
20
#include "options/arith_options.h"
21
#include "options/smt_options.h"
22
#include "smt/env.h"
23
#include "theory/arith/constraint.h"
24
#include "theory/arith/error_set.h"
25
#include "theory/arith/linear_equality.h"
26
#include "theory/arith/tableau.h"
27
#include "util/statistics_value.h"
28
29
using namespace std;
30
31
namespace cvc5 {
32
namespace theory {
33
namespace arith {
34
35
61092
SimplexDecisionProcedure::SimplexDecisionProcedure(
36
    Env& env,
37
    LinearEqualityModule& linEq,
38
    ErrorSet& errors,
39
    RaiseConflict conflictChannel,
40
61092
    TempVarMalloc tvmalloc)
41
    : EnvObj(env),
42
      d_pivots(0),
43
      d_conflictVariables(),
44
      d_linEq(linEq),
45
61092
      d_variables(d_linEq.getVariables()),
46
61092
      d_tableau(d_linEq.getTableau()),
47
      d_errorSet(errors),
48
      d_numVariables(0),
49
      d_conflictChannel(conflictChannel),
50
      d_conflictBuilder(NULL),
51
      d_arithVarMalloc(tvmalloc),
52
      d_errorSize(0),
53
      d_zero(0),
54
      d_posOne(1),
55
183276
      d_negOne(-1)
56
{
57
61092
  d_heuristicRule = options().arith.arithErrorSelectionRule;
58
61092
  d_errorSet.setSelectionRule(d_heuristicRule);
59
61092
  d_conflictBuilder = new FarkasConflictBuilder(options().smt.produceProofs);
60
61092
}
61
62
122144
SimplexDecisionProcedure::~SimplexDecisionProcedure(){
63
61072
  delete d_conflictBuilder;
64
61072
}
65
66
67
1296723
bool SimplexDecisionProcedure::standardProcessSignals(TimerStat &timer, IntStat& conflicts) {
68
2593446
  TimerStat::CodeTimer codeTimer(timer);
69
1296723
  Assert(d_conflictVariables.empty());
70
71
22620213
  while(d_errorSet.moreSignals()){
72
10661745
    ArithVar curr = d_errorSet.topSignal();
73
10661745
    if(d_tableau.isBasic(curr) && !d_variables.assignmentIsConsistent(curr)){
74
832538
      Assert(d_linEq.basicIsTracked(curr));
75
76
832538
      if(!d_conflictVariables.isMember(curr) && checkBasicForConflict(curr)){
77
78
169240
        Debug("recentlyViolated")
79
84620
          << "It worked? "
80
169240
          << conflicts.get()
81
84620
          << " " << curr
82
84620
          << " "  << checkBasicForConflict(curr) << endl;
83
84620
        reportConflict(curr);
84
84620
        ++conflicts;
85
      }
86
    }
87
    // Pop signal afterwards in case d_linEq.trackVariable(curr);
88
    // is needed for for the ErrorSet
89
10661745
    d_errorSet.popSignal();
90
  }
91
1296723
  d_errorSize = d_errorSet.errorSize();
92
93
1296723
  Assert(d_errorSet.noSignals());
94
2593446
  return !d_conflictVariables.empty();
95
}
96
97
/** Reports a conflict to on the output channel. */
98
84620
void SimplexDecisionProcedure::reportConflict(ArithVar basic){
99
84620
  Assert(!d_conflictVariables.isMember(basic));
100
84620
  Assert(checkBasicForConflict(basic));
101
102
84620
  ConstraintCP conflicted = generateConflictForBasic(basic);
103
84620
  Assert(conflicted != NullConstraint);
104
84620
  d_conflictChannel.raiseConflict(conflicted, InferenceId::ARITH_CONF_SIMPLEX);
105
106
84620
  d_conflictVariables.add(basic);
107
84620
}
108
109
84620
ConstraintCP SimplexDecisionProcedure::generateConflictForBasic(ArithVar basic) const {
110
84620
  Assert(d_tableau.isBasic(basic));
111
84620
  Assert(checkBasicForConflict(basic));
112
113
84620
  if(d_variables.cmpAssignmentLowerBound(basic) < 0){
114
46703
    Assert(d_linEq.nonbasicsAtUpperBounds(basic));
115
46703
    return d_linEq.generateConflictBelowLowerBound(basic, *d_conflictBuilder);
116
37917
  }else if(d_variables.cmpAssignmentUpperBound(basic) > 0){
117
37917
    Assert(d_linEq.nonbasicsAtLowerBounds(basic));
118
37917
    return d_linEq.generateConflictAboveUpperBound(basic, *d_conflictBuilder);
119
  }else{
120
    Unreachable();
121
    return NullConstraint;
122
  }
123
}
124
bool SimplexDecisionProcedure::maybeGenerateConflictForBasic(ArithVar basic) const {
125
  if(checkBasicForConflict(basic)){
126
    ConstraintCP conflicted = generateConflictForBasic(basic);
127
    d_conflictChannel.raiseConflict(conflicted, InferenceId::UNKNOWN);
128
    return true;
129
  }else{
130
    return false;
131
  }
132
}
133
134
1074106
bool SimplexDecisionProcedure::checkBasicForConflict(ArithVar basic) const {
135
1074106
  Assert(d_tableau.isBasic(basic));
136
1074106
  Assert(d_linEq.basicIsTracked(basic));
137
138
1074106
  if(d_variables.cmpAssignmentLowerBound(basic) < 0){
139
591926
    if(d_linEq.nonbasicsAtUpperBounds(basic)){
140
186812
      return true;
141
    }
142
482180
  }else if(d_variables.cmpAssignmentUpperBound(basic) > 0){
143
482180
    if(d_linEq.nonbasicsAtLowerBounds(basic)){
144
151668
      return true;
145
    }
146
  }
147
735626
  return false;
148
}
149
150
void SimplexDecisionProcedure::tearDownInfeasiblityFunction(TimerStat& timer, ArithVar tmp){
151
  TimerStat::CodeTimer codeTimer(timer);
152
  Assert(tmp != ARITHVAR_SENTINEL);
153
  Assert(d_tableau.isBasic(tmp));
154
155
  RowIndex ri = d_tableau.basicToRowIndex(tmp);
156
  d_linEq.stopTrackingRowIndex(ri);
157
  d_tableau.removeBasicRow(tmp);
158
  releaseVariable(tmp);
159
}
160
161
void SimplexDecisionProcedure::shrinkInfeasFunc(TimerStat& timer, ArithVar inf, const ArithVarVec& dropped){
162
  TimerStat::CodeTimer codeTimer(timer);
163
  for(ArithVarVec::const_iterator i=dropped.begin(), i_end = dropped.end(); i != i_end; ++i){
164
    ArithVar back = *i;
165
166
    int focusSgn = d_errorSet.focusSgn(back);
167
    Rational chg(-focusSgn);
168
169
    d_linEq.substitutePlusTimesConstant(inf, back, chg);
170
  }
171
}
172
173
void SimplexDecisionProcedure::adjustInfeasFunc(TimerStat& timer, ArithVar inf, const AVIntPairVec& focusChanges){
174
  TimerStat::CodeTimer codeTimer(timer);
175
  for(AVIntPairVec::const_iterator i=focusChanges.begin(), i_end = focusChanges.end(); i != i_end; ++i){
176
    ArithVar v = (*i).first;
177
    int focusChange = (*i).second;
178
179
    Rational chg(focusChange);
180
    if(d_tableau.isBasic(v)){
181
      d_linEq.substitutePlusTimesConstant(inf, v, chg);
182
    }else{
183
      d_linEq.directlyAddToCoefficient(inf, v, chg);
184
    }
185
  }
186
}
187
188
void SimplexDecisionProcedure::addToInfeasFunc(TimerStat& timer, ArithVar inf, ArithVar e){
189
  AVIntPairVec justE;
190
  int sgn  = d_errorSet.getSgn(e);
191
  justE.push_back(make_pair(e, sgn));
192
  adjustInfeasFunc(timer, inf, justE);
193
}
194
195
void SimplexDecisionProcedure::removeFromInfeasFunc(TimerStat& timer, ArithVar inf, ArithVar e){
196
  AVIntPairVec justE;
197
  int opSgn  = -d_errorSet.getSgn(e);
198
  justE.push_back(make_pair(e, opSgn));
199
  adjustInfeasFunc(timer, inf, justE);
200
}
201
202
ArithVar SimplexDecisionProcedure::constructInfeasiblityFunction(TimerStat& timer, const ArithVarVec& set){
203
  Debug("constructInfeasiblityFunction") << "constructInfeasiblityFunction start" << endl;
204
205
  TimerStat::CodeTimer codeTimer(timer);
206
  Assert(!d_errorSet.focusEmpty());
207
  Assert(debugIsASet(set));
208
209
  ArithVar inf = requestVariable();
210
  Assert(inf != ARITHVAR_SENTINEL);
211
212
  std::vector<Rational> coeffs;
213
  std::vector<ArithVar> variables;
214
215
  for(ArithVarVec::const_iterator iter = set.begin(), iend = set.end(); iter != iend; ++iter){
216
    ArithVar e = *iter;
217
218
    Assert(d_tableau.isBasic(e));
219
    Assert(!d_variables.assignmentIsConsistent(e));
220
221
    int sgn = d_errorSet.getSgn(e);
222
    Assert(sgn == -1 || sgn == 1);
223
    const Rational& violatedCoeff = sgn < 0 ? d_negOne : d_posOne;
224
    coeffs.push_back(violatedCoeff);
225
    variables.push_back(e);
226
227
    Debug("constructInfeasiblityFunction") << violatedCoeff << " " << e << endl;
228
229
  }
230
  d_tableau.addRow(inf, coeffs, variables);
231
  DeltaRational newAssignment = d_linEq.computeRowValue(inf, false);
232
  d_variables.setAssignment(inf, newAssignment);
233
234
  //d_linEq.trackVariable(inf);
235
  d_linEq.trackRowIndex(d_tableau.basicToRowIndex(inf));
236
237
  Debug("constructInfeasiblityFunction") << inf << " " << newAssignment << endl;
238
  Debug("constructInfeasiblityFunction") << "constructInfeasiblityFunction done" << endl;
239
  return inf;
240
}
241
242
ArithVar SimplexDecisionProcedure::constructInfeasiblityFunction(TimerStat& timer){
243
  ArithVarVec inError;
244
  d_errorSet.pushFocusInto(inError);
245
  return constructInfeasiblityFunction(timer, inError);
246
}
247
248
ArithVar SimplexDecisionProcedure::constructInfeasiblityFunction(TimerStat& timer, ArithVar e){
249
  ArithVarVec justE;
250
  justE.push_back(e);
251
  return constructInfeasiblityFunction(timer, justE);
252
}
253
254
void SimplexDecisionProcedure::addSgn(sgn_table& sgns, ArithVar col, int sgn, ArithVar basic){
255
  pair<ArithVar, int> p = make_pair(col, determinizeSgn(sgn));
256
  sgns[p].push_back(basic);
257
}
258
259
void SimplexDecisionProcedure::addRowSgns(sgn_table& sgns, ArithVar basic, int norm){
260
  for(Tableau::RowIterator i = d_tableau.basicRowIterator(basic); !i.atEnd(); ++i){
261
    const Tableau::Entry& entry = *i;
262
    ArithVar v = entry.getColVar();
263
    int sgn = (entry.getCoefficient().sgn());
264
    addSgn(sgns, v, norm * sgn, basic);
265
  }
266
}
267
268
ArithVar SimplexDecisionProcedure::find_basic_in_sgns(const sgn_table& sgns, ArithVar col, int sgn, const DenseSet& m, bool inside){
269
  pair<ArithVar, int> p = make_pair(col, determinizeSgn(sgn));
270
  sgn_table::const_iterator i = sgns.find(p);
271
272
  if(i != sgns.end()){
273
    const ArithVarVec& vec = (*i).second;
274
    for(ArithVarVec::const_iterator viter = vec.begin(), vend = vec.end(); viter != vend; ++viter){
275
      ArithVar curr = *viter;
276
      if(inside == m.isMember(curr)){
277
        return curr;
278
      }
279
    }
280
  }
281
  return ARITHVAR_SENTINEL;
282
}
283
284
SimplexDecisionProcedure::sgn_table::const_iterator SimplexDecisionProcedure::find_sgns(const sgn_table& sgns, ArithVar col, int sgn){
285
  pair<ArithVar, int> p = make_pair(col, determinizeSgn(sgn));
286
  return sgns.find(p);
287
}
288
}  // namespace arith
289
}  // namespace theory
290
31137
}  // namespace cvc5