GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/theory_arith_private.cpp Lines: 1805 3013 59.9 %
Date: 2021-05-22 Branches: 3614 12992 27.8 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Tim King, Alex Ozdemir, Andrew Reynolds
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
 * [[ Add one-line brief description here ]]
14
 *
15
 * [[ Add lengthier description here ]]
16
 * \todo document this file
17
 */
18
19
#include "theory/arith/theory_arith_private.h"
20
21
#include <map>
22
#include <queue>
23
#include <vector>
24
25
#include "base/output.h"
26
#include "context/cdhashset.h"
27
#include "context/cdinsert_hashmap.h"
28
#include "context/cdlist.h"
29
#include "context/cdqueue.h"
30
#include "context/context.h"
31
#include "expr/kind.h"
32
#include "expr/metakind.h"
33
#include "expr/node.h"
34
#include "expr/node_algorithm.h"
35
#include "expr/node_builder.h"
36
#include "expr/proof_generator.h"
37
#include "expr/proof_node_manager.h"
38
#include "expr/proof_rule.h"
39
#include "expr/skolem_manager.h"
40
#include "options/arith_options.h"
41
#include "options/smt_options.h"  // for incrementalSolving()
42
#include "preprocessing/util/ite_utilities.h"
43
#include "smt/logic_exception.h"
44
#include "smt/smt_statistics_registry.h"
45
#include "smt_util/boolean_simplification.h"
46
#include "theory/arith/approx_simplex.h"
47
#include "theory/arith/arith_ite_utils.h"
48
#include "theory/arith/arith_rewriter.h"
49
#include "theory/arith/arith_static_learner.h"
50
#include "theory/arith/arith_utilities.h"
51
#include "theory/arith/arithvar.h"
52
#include "theory/arith/congruence_manager.h"
53
#include "theory/arith/constraint.h"
54
#include "theory/arith/cut_log.h"
55
#include "theory/arith/delta_rational.h"
56
#include "theory/arith/dio_solver.h"
57
#include "theory/arith/linear_equality.h"
58
#include "theory/arith/matrix.h"
59
#include "theory/arith/nl/nonlinear_extension.h"
60
#include "theory/arith/normal_form.h"
61
#include "theory/arith/partial_model.h"
62
#include "theory/arith/simplex.h"
63
#include "theory/arith/theory_arith.h"
64
#include "theory/ext_theory.h"
65
#include "theory/quantifiers/fmf/bounded_integers.h"
66
#include "theory/rewriter.h"
67
#include "theory/theory_model.h"
68
#include "theory/trust_substitutions.h"
69
#include "theory/valuation.h"
70
#include "util/dense_map.h"
71
#include "util/integer.h"
72
#include "util/random.h"
73
#include "util/rational.h"
74
#include "util/result.h"
75
#include "util/statistics_stats.h"
76
77
using namespace std;
78
using namespace cvc5::kind;
79
80
namespace cvc5 {
81
namespace theory {
82
namespace arith {
83
84
static Node toSumNode(const ArithVariables& vars, const DenseMap<Rational>& sum);
85
static bool complexityBelow(const DenseMap<Rational>& row, uint32_t cap);
86
87
9459
TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing,
88
                                       context::Context* c,
89
                                       context::UserContext* u,
90
                                       OutputChannel& out,
91
                                       Valuation valuation,
92
                                       const LogicInfo& logicInfo,
93
9459
                                       ProofNodeManager* pnm)
94
    : d_containing(containing),
95
      d_foundNl(false),
96
      d_rowTracking(),
97
      d_pnm(pnm),
98
      d_checker(),
99
9459
      d_pfGen(new EagerProofGenerator(d_pnm, u)),
100
      d_constraintDatabase(c,
101
                           u,
102
                           d_partialModel,
103
                           d_congruenceManager,
104
                           RaiseConflict(*this),
105
                           d_pfGen.get(),
106
                           d_pnm),
107
      d_qflraStatus(Result::SAT_UNKNOWN),
108
      d_unknownsInARow(0),
109
      d_hasDoneWorkSinceCut(false),
110
      d_learner(u),
111
      d_assertionsThatDoNotMatchTheirLiterals(c),
112
      d_nextIntegerCheckVar(0),
113
      d_constantIntegerVariables(c),
114
      d_diseqQueue(c, false),
115
      d_currentPropagationList(),
116
      d_learnedBounds(c),
117
      d_preregisteredNodes(u),
118
18918
      d_partialModel(c, DeltaComputeCallback(*this)),
119
      d_errorSet(
120
9459
          d_partialModel, TableauSizes(&d_tableau), BoundCountingLookup(*this)),
121
      d_tableau(),
122
      d_linEq(d_partialModel,
123
              d_tableau,
124
              d_rowTracking,
125
18918
              BasicVarModelUpdateCallBack(*this)),
126
      d_diosolver(c),
127
      d_restartsCounter(0),
128
      d_tableauSizeHasBeenModified(false),
129
      d_tableauResetDensity(1.6),
130
      d_tableauResetPeriod(10),
131
      d_conflicts(c),
132
18918
      d_blackBoxConflict(c, Node::null()),
133
18918
      d_blackBoxConflictPf(c, std::shared_ptr<ProofNode>(nullptr)),
134
      d_congruenceManager(c,
135
                          u,
136
                          d_constraintDatabase,
137
18918
                          SetupLiteralCallBack(*this),
138
                          d_partialModel,
139
                          RaiseEqualityEngineConflict(*this),
140
                          d_pnm),
141
      d_cmEnabled(c, true),
142
143
      d_dualSimplex(
144
18918
          d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
145
      d_fcSimplex(
146
18918
          d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
147
      d_soiSimplex(
148
18918
          d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
149
      d_attemptSolSimplex(
150
18918
          d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
151
      d_pass1SDP(NULL),
152
      d_otherSDP(NULL),
153
      d_lastContextIntegerAttempted(c, -1),
154
155
      d_DELTA_ZERO(0),
156
      d_approxCuts(c),
157
      d_fullCheckCounter(0),
158
      d_cutCount(c, 0),
159
      d_cutInContext(c),
160
      d_likelyIntegerInfeasible(c, false),
161
      d_guessedCoeffSet(c, false),
162
      d_guessedCoeffs(),
163
      d_treeLog(NULL),
164
      d_replayVariables(),
165
      d_replayConstraints(),
166
      d_lhsTmp(),
167
      d_approxStats(NULL),
168
      d_attemptSolveIntTurnedOff(u, 0),
169
      d_dioSolveResources(0),
170
      d_solveIntMaybeHelp(0u),
171
      d_solveIntAttempts(0u),
172
      d_newFacts(false),
173
      d_previousStatus(Result::SAT_UNKNOWN),
174
198639
      d_statistics("theory::arith::")
175
{
176
9459
}
177
178
18918
TheoryArithPrivate::~TheoryArithPrivate(){
179
9459
  if(d_treeLog != NULL){ delete d_treeLog; }
180
9459
  if(d_approxStats != NULL) { delete d_approxStats; }
181
9459
}
182
183
9459
bool TheoryArithPrivate::needsEqualityEngine(EeSetupInfo& esi)
184
{
185
9459
  return d_congruenceManager.needsEqualityEngine(esi);
186
}
187
9459
void TheoryArithPrivate::finishInit()
188
{
189
9459
  eq::EqualityEngine* ee = d_containing.getEqualityEngine();
190
9459
  eq::ProofEqEngine* pfee = d_containing.getProofEqEngine();
191
9459
  Assert(ee != nullptr);
192
9459
  d_congruenceManager.finishInit(ee, pfee);
193
9459
}
194
195
static bool contains(const ConstraintCPVec& v, ConstraintP con){
196
  for(unsigned i = 0, N = v.size(); i < N; ++i){
197
    if(v[i] == con){
198
      return true;
199
    }
200
  }
201
  return false;
202
}
203
static void drop( ConstraintCPVec& v, ConstraintP con){
204
  size_t readPos, writePos, N;
205
  for(readPos = 0, writePos = 0, N = v.size(); readPos < N; ++readPos){
206
    ConstraintCP curr = v[readPos];
207
    if(curr != con){
208
      v[writePos] = curr;
209
      writePos++;
210
    }
211
  }
212
  v.resize(writePos);
213
}
214
215
216
static void resolve(ConstraintCPVec& buf, ConstraintP c, const ConstraintCPVec& pos, const ConstraintCPVec& neg){
217
  unsigned posPos CVC5_UNUSED = pos.size();
218
  for(unsigned i = 0, N = pos.size(); i < N; ++i){
219
    if(pos[i] == c){
220
      posPos = i;
221
    }else{
222
      buf.push_back(pos[i]);
223
    }
224
  }
225
  Assert(posPos < pos.size());
226
  ConstraintP negc = c->getNegation();
227
  unsigned negPos CVC5_UNUSED = neg.size();
228
  for(unsigned i = 0, N = neg.size(); i < N; ++i){
229
    if(neg[i] == negc){
230
      negPos = i;
231
    }else{
232
      buf.push_back(neg[i]);
233
    }
234
  }
235
  Assert(negPos < neg.size());
236
237
  // Assert(dnconf.getKind() == kind::AND);
238
  // Assert(upconf.getKind() == kind::AND);
239
  // Assert(dnpos < dnconf.getNumChildren());
240
  // Assert(uppos < upconf.getNumChildren());
241
  // Assert(equalUpToNegation(dnconf[dnpos], upconf[uppos]));
242
243
  // NodeBuilder nb(kind::AND);
244
  // dropPosition(nb, dnconf, dnpos);
245
  // dropPosition(nb, upconf, uppos);
246
  // return safeConstructNary(nb);
247
}
248
249
TheoryArithPrivate::ModelException::ModelException(TNode n, const char* msg)
250
{
251
  stringstream ss;
252
  ss << "Cannot construct a model for " << n << " as " << endl << msg;
253
  setMessage(ss.str());
254
}
255
TheoryArithPrivate::ModelException::~ModelException() {}
256
257
9459
TheoryArithPrivate::Statistics::Statistics(const std::string& name)
258
    : d_statAssertUpperConflicts(
259
18918
        smtStatisticsRegistry().registerInt(name + "AssertUpperConflicts")),
260
      d_statAssertLowerConflicts(
261
18918
          smtStatisticsRegistry().registerInt(name + "AssertLowerConflicts")),
262
      d_statUserVariables(
263
18918
          smtStatisticsRegistry().registerInt(name + "UserVariables")),
264
      d_statAuxiliaryVariables(
265
18918
          smtStatisticsRegistry().registerInt(name + "AuxiliaryVariables")),
266
      d_statDisequalitySplits(
267
18918
          smtStatisticsRegistry().registerInt(name + "DisequalitySplits")),
268
      d_statDisequalityConflicts(
269
18918
          smtStatisticsRegistry().registerInt(name + "DisequalityConflicts")),
270
      d_simplifyTimer(
271
18918
          smtStatisticsRegistry().registerTimer(name + "simplifyTimer")),
272
      d_staticLearningTimer(
273
18918
          smtStatisticsRegistry().registerTimer(name + "staticLearningTimer")),
274
      d_presolveTime(
275
18918
          smtStatisticsRegistry().registerTimer(name + "presolveTime")),
276
      d_newPropTime(
277
18918
          smtStatisticsRegistry().registerTimer(name + "newPropTimer")),
278
9459
      d_externalBranchAndBounds(smtStatisticsRegistry().registerInt(
279
18918
          name + "externalBranchAndBounds")),
280
      d_initialTableauSize(
281
18918
          smtStatisticsRegistry().registerInt(name + "initialTableauSize")),
282
      d_currSetToSmaller(
283
18918
          smtStatisticsRegistry().registerInt(name + "currSetToSmaller")),
284
      d_smallerSetToCurr(
285
18918
          smtStatisticsRegistry().registerInt(name + "smallerSetToCurr")),
286
      d_restartTimer(
287
18918
          smtStatisticsRegistry().registerTimer(name + "restartTimer")),
288
      d_boundComputationTime(
289
18918
          smtStatisticsRegistry().registerTimer(name + "bound::time")),
290
9459
      d_boundComputations(smtStatisticsRegistry().registerInt(
291
18918
          name + "bound::boundComputations")),
292
9459
      d_boundPropagations(smtStatisticsRegistry().registerInt(
293
18918
          name + "bound::boundPropagations")),
294
      d_unknownChecks(
295
18918
          smtStatisticsRegistry().registerInt(name + "status::unknowns")),
296
9459
      d_maxUnknownsInARow(smtStatisticsRegistry().registerInt(
297
18918
          name + "status::maxUnknownsInARow")),
298
9459
      d_avgUnknownsInARow(smtStatisticsRegistry().registerAverage(
299
18918
          name + "status::avgUnknownsInARow")),
300
9459
      d_revertsOnConflicts(smtStatisticsRegistry().registerInt(
301
18918
          name + "status::revertsOnConflicts")),
302
9459
      d_commitsOnConflicts(smtStatisticsRegistry().registerInt(
303
18918
          name + "status::commitsOnConflicts")),
304
9459
      d_nontrivialSatChecks(smtStatisticsRegistry().registerInt(
305
18918
          name + "status::nontrivialSatChecks")),
306
      d_replayLogRecCount(
307
18918
          smtStatisticsRegistry().registerInt(name + "z::approx::replay::rec")),
308
9459
      d_replayLogRecConflictEscalation(smtStatisticsRegistry().registerInt(
309
18918
          name + "z::approx::replay::rec::escalation")),
310
9459
      d_replayLogRecEarlyExit(smtStatisticsRegistry().registerInt(
311
18918
          name + "z::approx::replay::rec::earlyexit")),
312
9459
      d_replayBranchCloseFailures(smtStatisticsRegistry().registerInt(
313
18918
          name + "z::approx::replay::rec::branch::closefailures")),
314
9459
      d_replayLeafCloseFailures(smtStatisticsRegistry().registerInt(
315
18918
          name + "z::approx::replay::rec::leaf::closefailures")),
316
9459
      d_replayBranchSkips(smtStatisticsRegistry().registerInt(
317
18918
          name + "z::approx::replay::rec::branch::skips")),
318
9459
      d_mirCutsAttempted(smtStatisticsRegistry().registerInt(
319
18918
          name + "z::approx::cuts::mir::attempted")),
320
9459
      d_gmiCutsAttempted(smtStatisticsRegistry().registerInt(
321
18918
          name + "z::approx::cuts::gmi::attempted")),
322
9459
      d_branchCutsAttempted(smtStatisticsRegistry().registerInt(
323
18918
          name + "z::approx::cuts::branch::attempted")),
324
9459
      d_cutsReconstructed(smtStatisticsRegistry().registerInt(
325
18918
          name + "z::approx::cuts::reconstructed")),
326
9459
      d_cutsReconstructionFailed(smtStatisticsRegistry().registerInt(
327
18918
          name + "z::approx::cuts::reconstructed::failed")),
328
9459
      d_cutsProven(smtStatisticsRegistry().registerInt(
329
18918
          name + "z::approx::cuts::proofs")),
330
9459
      d_cutsProofFailed(smtStatisticsRegistry().registerInt(
331
18918
          name + "z::approx::cuts::proofs::failed")),
332
9459
      d_mipReplayLemmaCalls(smtStatisticsRegistry().registerInt(
333
18918
          name + "z::approx::external::calls")),
334
9459
      d_mipExternalCuts(smtStatisticsRegistry().registerInt(
335
18918
          name + "z::approx::external::cuts")),
336
9459
      d_mipExternalBranch(smtStatisticsRegistry().registerInt(
337
18918
          name + "z::approx::external::branches")),
338
9459
      d_inSolveInteger(smtStatisticsRegistry().registerInt(
339
18918
          name + "z::approx::inSolverInteger")),
340
9459
      d_branchesExhausted(smtStatisticsRegistry().registerInt(
341
18918
          name + "z::approx::exhausted::branches")),
342
9459
      d_execExhausted(smtStatisticsRegistry().registerInt(
343
18918
          name + "z::approx::exhausted::exec")),
344
9459
      d_pivotsExhausted(smtStatisticsRegistry().registerInt(
345
18918
          name + "z::approx::exhausted::pivots")),
346
      d_panicBranches(
347
18918
          smtStatisticsRegistry().registerInt(name + "z::arith::paniclemmas")),
348
      d_relaxCalls(
349
18918
          smtStatisticsRegistry().registerInt(name + "z::arith::relax::calls")),
350
9459
      d_relaxLinFeas(smtStatisticsRegistry().registerInt(
351
18918
          name + "z::arith::relax::feasible::res")),
352
9459
      d_relaxLinFeasFailures(smtStatisticsRegistry().registerInt(
353
18918
          name + "z::arith::relax::feasible::failures")),
354
9459
      d_relaxLinInfeas(smtStatisticsRegistry().registerInt(
355
18918
          name + "z::arith::relax::infeasible")),
356
9459
      d_relaxLinInfeasFailures(smtStatisticsRegistry().registerInt(
357
18918
          name + "z::arith::relax::infeasible::failures")),
358
9459
      d_relaxLinExhausted(smtStatisticsRegistry().registerInt(
359
18918
          name + "z::arith::relax::exhausted")),
360
      d_relaxOthers(
361
18918
          smtStatisticsRegistry().registerInt(name + "z::arith::relax::other")),
362
9459
      d_applyRowsDeleted(smtStatisticsRegistry().registerInt(
363
18918
          name + "z::arith::cuts::applyRowsDeleted")),
364
9459
      d_replaySimplexTimer(smtStatisticsRegistry().registerTimer(
365
18918
          name + "z::approx::replay::simplex::timer")),
366
9459
      d_replayLogTimer(smtStatisticsRegistry().registerTimer(
367
18918
          name + "z::approx::replay::log::timer")),
368
      d_solveIntTimer(
369
18918
          smtStatisticsRegistry().registerTimer(name + "z::solveInt::timer")),
370
9459
      d_solveRealRelaxTimer(smtStatisticsRegistry().registerTimer(
371
18918
          name + "z::solveRealRelax::timer")),
372
      d_solveIntCalls(
373
18918
          smtStatisticsRegistry().registerInt(name + "z::solveInt::calls")),
374
9459
      d_solveStandardEffort(smtStatisticsRegistry().registerInt(
375
18918
          name + "z::solveInt::calls::standardEffort")),
376
      d_approxDisabled(
377
18918
          smtStatisticsRegistry().registerInt(name + "z::approxDisabled")),
378
      d_replayAttemptFailed(
379
18918
          smtStatisticsRegistry().registerInt(name + "z::replayAttemptFailed")),
380
9459
      d_cutsRejectedDuringReplay(smtStatisticsRegistry().registerInt(
381
18918
          name + "z::approx::replay::cuts::rejected")),
382
9459
      d_cutsRejectedDuringLemmas(smtStatisticsRegistry().registerInt(
383
18918
          name + "z::approx::external::cuts::rejected")),
384
9459
      d_satPivots(smtStatisticsRegistry().registerHistogram<uint32_t>(
385
18918
          name + "pivots::sat")),
386
9459
      d_unsatPivots(smtStatisticsRegistry().registerHistogram<uint32_t>(
387
18918
          name + "pivots::unsat")),
388
9459
      d_unknownPivots(smtStatisticsRegistry().registerHistogram<uint32_t>(
389
18918
          name + "pivots::unknown")),
390
9459
      d_solveIntModelsAttempts(smtStatisticsRegistry().registerInt(
391
18918
          name + "z::solveInt::models::attempts")),
392
9459
      d_solveIntModelsSuccessful(smtStatisticsRegistry().registerInt(
393
18918
          name + "zzz::solveInt::models::successful")),
394
9459
      d_mipTimer(smtStatisticsRegistry().registerTimer(
395
18918
          name + "z::approx::mip::timer")),
396
      d_lpTimer(
397
18918
          smtStatisticsRegistry().registerTimer(name + "z::approx::lp::timer")),
398
9459
      d_mipProofsAttempted(smtStatisticsRegistry().registerInt(
399
18918
          name + "z::mip::proofs::attempted")),
400
9459
      d_mipProofsSuccessful(smtStatisticsRegistry().registerInt(
401
18918
          name + "z::mip::proofs::successful")),
402
9459
      d_numBranchesFailed(smtStatisticsRegistry().registerInt(
403
690507
          name + "z::mip::branch::proof::failed"))
404
{
405
9459
}
406
407
bool complexityBelow(const DenseMap<Rational>& row, uint32_t cap){
408
  DenseMap<Rational>::const_iterator riter, rend;
409
  for(riter=row.begin(), rend=row.end(); riter != rend; ++riter){
410
    ArithVar v = *riter;
411
    const Rational& q = row[v];
412
    if(q.complexity() > cap){
413
      return false;
414
    }
415
  }
416
  return true;
417
}
418
419
160619
bool TheoryArithPrivate::isProofEnabled() const
420
{
421
160619
  return d_pnm != nullptr;
422
}
423
424
67172
void TheoryArithPrivate::raiseConflict(ConstraintCP a, InferenceId id){
425
67172
  Assert(a->inConflict());
426
134344
  d_conflicts.push_back(std::make_pair(a, id));
427
67172
}
428
429
2090
void TheoryArithPrivate::raiseBlackBoxConflict(Node bb,
430
                                               std::shared_ptr<ProofNode> pf)
431
{
432
2090
  Debug("arith::bb") << "raiseBlackBoxConflict: " << bb << std::endl;
433
2090
  if (d_blackBoxConflict.get().isNull())
434
  {
435
2090
    if (isProofEnabled())
436
    {
437
405
      Debug("arith::bb") << "  with proof " << pf << std::endl;
438
405
      d_blackBoxConflictPf.set(pf);
439
    }
440
2090
    d_blackBoxConflict = bb;
441
  }
442
2090
}
443
444
12711578
bool TheoryArithPrivate::anyConflict() const
445
{
446
12711578
  return !conflictQueueEmpty() || !d_blackBoxConflict.get().isNull();
447
}
448
449
49477
void TheoryArithPrivate::revertOutOfConflict(){
450
49477
  d_partialModel.revertAssignmentChanges();
451
49477
  clearUpdates();
452
49477
  d_currentPropagationList.clear();
453
49477
}
454
455
1404734
void TheoryArithPrivate::clearUpdates(){
456
1404734
  d_updatedBounds.purge();
457
1404734
}
458
459
// void TheoryArithPrivate::raiseConflict(ConstraintCP a, ConstraintCP b){
460
//   ConstraintCPVec v;
461
//   v.push_back(a);
462
//   v.push_back(b);
463
//   d_conflicts.push_back(v);
464
// }
465
466
// void TheoryArithPrivate::raiseConflict(ConstraintCP a, ConstraintCP b, ConstraintCP c){
467
//   ConstraintCPVec v;
468
//   v.push_back(a);
469
//   v.push_back(b);
470
//   v.push_back(c);
471
//   d_conflicts.push_back(v);
472
// }
473
474
462450
void TheoryArithPrivate::zeroDifferenceDetected(ArithVar x){
475
462450
  if(d_cmEnabled){
476
462450
    Assert(d_congruenceManager.isWatchedVariable(x));
477
462450
    Assert(d_partialModel.upperBoundIsZero(x));
478
462450
    Assert(d_partialModel.lowerBoundIsZero(x));
479
480
462450
    ConstraintP lb = d_partialModel.getLowerBoundConstraint(x);
481
462450
    ConstraintP ub = d_partialModel.getUpperBoundConstraint(x);
482
483
462450
    if(lb->isEquality()){
484
162817
      d_congruenceManager.watchedVariableIsZero(lb);
485
299633
    }else if(ub->isEquality()){
486
      d_congruenceManager.watchedVariableIsZero(ub);
487
    }else{
488
299633
      d_congruenceManager.watchedVariableIsZero(lb, ub);
489
    }
490
  }
491
462450
}
492
493
bool TheoryArithPrivate::getSolveIntegerResource(){
494
  if(d_attemptSolveIntTurnedOff > 0){
495
    d_attemptSolveIntTurnedOff = d_attemptSolveIntTurnedOff - 1;
496
    return false;
497
  }else{
498
    return true;
499
  }
500
}
501
502
2466
bool TheoryArithPrivate::getDioCuttingResource(){
503
2466
  if(d_dioSolveResources > 0){
504
1820
    d_dioSolveResources--;
505
1820
    if(d_dioSolveResources == 0){
506
246
      d_dioSolveResources = -options::rrTurns();
507
    }
508
1820
    return true;
509
  }else{
510
646
    d_dioSolveResources++;
511
646
    if(d_dioSolveResources >= 0){
512
822
      d_dioSolveResources = options::dioSolverTurns();
513
    }
514
646
    return false;
515
  }
516
}
517
518
/* procedure AssertLower( x_i >= c_i ) */
519
1853830
bool TheoryArithPrivate::AssertLower(ConstraintP constraint){
520
1853830
  Assert(constraint != NullConstraint);
521
1853830
  Assert(constraint->isLowerBound());
522
1853830
  Assert(constraint->isTrue());
523
1853830
  Assert(!constraint->negationHasProof());
524
525
1853830
  ArithVar x_i = constraint->getVariable();
526
1853830
  const DeltaRational& c_i = constraint->getValue();
527
528
1853830
  Debug("arith") << "AssertLower(" << x_i << " " << c_i << ")"<< std::endl;
529
530
1853830
  Assert(!isInteger(x_i) || c_i.isIntegral());
531
532
  //TODO Relax to less than?
533
1853830
  if(d_partialModel.lessThanLowerBound(x_i, c_i)){
534
767053
    return false; //sat
535
  }
536
537
1086777
  int cmpToUB = d_partialModel.cmpToUpperBound(x_i, c_i);
538
1086777
  if(cmpToUB > 0){ //  c_i < \lowerbound(x_i)
539
715
    ConstraintP ubc = d_partialModel.getUpperBoundConstraint(x_i);
540
715
    ConstraintP negation = constraint->getNegation();
541
715
    negation->impliedByUnate(ubc, true);
542
543
715
    raiseConflict(constraint, InferenceId::ARITH_CONF_LOWER);
544
545
715
    ++(d_statistics.d_statAssertLowerConflicts);
546
715
    return true;
547
1086062
  }else if(cmpToUB == 0){
548
349603
    if(isInteger(x_i)){
549
153910
      d_constantIntegerVariables.push_back(x_i);
550
153910
      Debug("dio::push") << "dio::push " << x_i << endl;
551
    }
552
349603
    ConstraintP ub = d_partialModel.getUpperBoundConstraint(x_i);
553
554
349603
    if(d_cmEnabled){
555
349603
      if(!d_congruenceManager.isWatchedVariable(x_i) || c_i.sgn() != 0){
556
        // if it is not a watched variable report it
557
        // if it is is a watched variable and c_i == 0,
558
        // let zeroDifferenceDetected(x_i) catch this
559
112086
        d_congruenceManager.equalsConstant(constraint, ub);
560
      }
561
    }
562
563
349603
    const ValueCollection& vc = constraint->getValueCollection();
564
349603
    if(vc.hasEquality()){
565
246329
      Assert(vc.hasDisequality());
566
246329
      ConstraintP eq = vc.getEquality();
567
246329
      ConstraintP diseq = vc.getDisequality();
568
      // x <= b, x >= b |= x = b
569
      // (x > b or x < b or x = b)
570
246329
      Debug("arith::eq") << "lb == ub, propagate eq" << eq << endl;
571
246329
      bool triConflict = diseq->isTrue();
572
573
246329
      if(!eq->isTrue()){
574
242421
        eq->impliedByTrichotomy(constraint, ub, triConflict);
575
242421
        eq->tryToPropagate();
576
      }
577
246329
      if(triConflict){
578
        ++(d_statistics.d_statDisequalityConflicts);
579
        raiseConflict(eq, InferenceId::ARITH_CONF_TRICHOTOMY);
580
        return true;
581
      }
582
    }
583
  }else{
584
    // l <= x <= u and l < u
585
736459
    Assert(cmpToUB < 0);
586
736459
    const ValueCollection& vc = constraint->getValueCollection();
587
588
736459
    if(vc.hasDisequality()){
589
178582
      const ConstraintP diseq = vc.getDisequality();
590
178582
      if(diseq->isTrue()){
591
9811
        const ConstraintP ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound);
592
9811
        ConstraintP negUb = ub->getNegation();
593
594
        // l <= x, l != x |= l < x
595
        // |= not (l >= x)
596
9811
        bool ubInConflict = ub->hasProof();
597
9811
        bool learnNegUb = !(negUb->hasProof());
598
9811
        if(learnNegUb){
599
9811
          negUb->impliedByTrichotomy(constraint, diseq, ubInConflict);
600
9811
          negUb->tryToPropagate();
601
        }
602
9811
        if(ubInConflict){
603
          raiseConflict(ub, InferenceId::ARITH_CONF_TRICHOTOMY);
604
          return true;
605
9811
        }else if(learnNegUb){
606
9811
          d_learnedBounds.push_back(negUb);
607
        }
608
      }
609
    }
610
  }
611
612
1086062
  d_currentPropagationList.push_back(constraint);
613
1086062
  d_currentPropagationList.push_back(d_partialModel.getLowerBoundConstraint(x_i));
614
615
1086062
  d_partialModel.setLowerBoundConstraint(constraint);
616
617
1086062
  if(d_cmEnabled){
618
1086062
    if(d_congruenceManager.isWatchedVariable(x_i)){
619
731334
      int sgn = c_i.sgn();
620
731334
      if(sgn > 0){
621
156738
        d_congruenceManager.watchedVariableCannotBeZero(constraint);
622
574596
      }else if(sgn == 0 && d_partialModel.upperBoundIsZero(x_i)){
623
237517
        zeroDifferenceDetected(x_i);
624
      }
625
    }
626
  }
627
628
1086062
  d_updatedBounds.softAdd(x_i);
629
630
1086062
  if(Debug.isOn("model")) {
631
    Debug("model") << "before" << endl;
632
    d_partialModel.printModel(x_i);
633
    d_tableau.debugPrintIsBasic(x_i);
634
  }
635
636
1086062
  if(!d_tableau.isBasic(x_i)){
637
396707
    if(d_partialModel.getAssignment(x_i) < c_i){
638
55604
      d_linEq.update(x_i, c_i);
639
    }
640
  }else{
641
689355
    d_errorSet.signalVariable(x_i);
642
  }
643
644
1086062
  if(Debug.isOn("model")) {
645
    Debug("model") << "after" << endl;
646
    d_partialModel.printModel(x_i);
647
    d_tableau.debugPrintIsBasic(x_i);
648
 }
649
650
1086062
  return false; //sat
651
}
652
653
/* procedure AssertUpper( x_i <= c_i) */
654
1740289
bool TheoryArithPrivate::AssertUpper(ConstraintP constraint){
655
1740289
  Assert(constraint != NullConstraint);
656
1740289
  Assert(constraint->isUpperBound());
657
1740289
  Assert(constraint->isTrue());
658
1740289
  Assert(!constraint->negationHasProof());
659
660
1740289
  ArithVar x_i = constraint->getVariable();
661
1740289
  const DeltaRational& c_i = constraint->getValue();
662
663
1740289
  Debug("arith") << "AssertUpper(" << x_i << " " << c_i << ")"<< std::endl;
664
665
666
  //Too strong because of rounding with integers
667
  //Assert(!constraint->hasLiteral() || original == constraint->getLiteral());
668
1740289
  Assert(!isInteger(x_i) || c_i.isIntegral());
669
670
1740289
  Debug("arith") << "AssertUpper(" << x_i << " " << c_i << ")"<< std::endl;
671
672
1740289
  if(d_partialModel.greaterThanUpperBound(x_i, c_i) ){ // \upperbound(x_i) <= c_i
673
743093
    return false; //sat
674
  }
675
676
  // cmpToLb =  \lowerbound(x_i).cmp(c_i)
677
997196
  int cmpToLB = d_partialModel.cmpToLowerBound(x_i, c_i);
678
997196
  if( cmpToLB < 0 ){ //  \upperbound(x_i) < \lowerbound(x_i)
679
    // l_i <= x_i and c_i < l_i |= c_i < x_i
680
    // or ... |= not (x_i <= c_i)
681
2067
    ConstraintP lbc = d_partialModel.getLowerBoundConstraint(x_i);
682
2067
    ConstraintP negConstraint = constraint->getNegation();
683
2067
    negConstraint->impliedByUnate(lbc, true);
684
2067
    raiseConflict(constraint, InferenceId::ARITH_CONF_UPPER);
685
2067
    ++(d_statistics.d_statAssertUpperConflicts);
686
2067
    return true;
687
995129
  }else if(cmpToLB == 0){ // \lowerBound(x_i) == \upperbound(x_i)
688
130404
    if(isInteger(x_i)){
689
80863
      d_constantIntegerVariables.push_back(x_i);
690
80863
      Debug("dio::push") << "dio::push " << x_i << endl;
691
    }
692
693
130404
    const ValueCollection& vc = constraint->getValueCollection();
694
130404
    ConstraintP lb = d_partialModel.getLowerBoundConstraint(x_i);
695
130404
    if(d_cmEnabled){
696
130404
      if(!d_congruenceManager.isWatchedVariable(x_i) || c_i.sgn() != 0){
697
        // if it is not a watched variable report it
698
        // if it is is a watched variable and c_i == 0,
699
        // let zeroDifferenceDetected(x_i) catch this
700
68288
        d_congruenceManager.equalsConstant(lb, constraint);
701
      }
702
    }
703
704
130404
    if(vc.hasDisequality()){
705
97194
      Assert(vc.hasDisequality());
706
97194
      ConstraintP eq = vc.getEquality();
707
97194
      ConstraintP diseq = vc.getDisequality();
708
      // x <= b, x >= b |= x = b
709
      // (x > b or x < b or x = b)
710
97194
      Debug("arith::eq") << "lb == ub, propagate eq" << eq << endl;
711
97194
      bool triConflict = diseq->isTrue();
712
97194
      if(!eq->isTrue()){
713
74340
        eq->impliedByTrichotomy(constraint, lb, triConflict);
714
74340
        eq->tryToPropagate();
715
      }
716
97194
      if(triConflict){
717
3
        ++(d_statistics.d_statDisequalityConflicts);
718
3
        raiseConflict(eq, InferenceId::ARITH_CONF_TRICHOTOMY);
719
3
        return true;
720
      }
721
    }
722
864725
  }else if(cmpToLB > 0){
723
    // l <= x <= u and l < u
724
864725
    Assert(cmpToLB > 0);
725
864725
    const ValueCollection& vc = constraint->getValueCollection();
726
727
864725
    if(vc.hasDisequality()){
728
341650
      const ConstraintP diseq = vc.getDisequality();
729
341650
      if(diseq->isTrue()){
730
30025
        const ConstraintP lb = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), LowerBound);
731
30025
        ConstraintP negLb = lb->getNegation();
732
733
        // x <= u, u != x |= u < x
734
        // |= not (u >= x)
735
30025
        bool lbInConflict = lb->hasProof();
736
30025
        bool learnNegLb = !(negLb->hasProof());
737
30025
        if(learnNegLb){
738
30025
          negLb->impliedByTrichotomy(constraint, diseq, lbInConflict);
739
30025
          negLb->tryToPropagate();
740
        }
741
30025
        if(lbInConflict){
742
          raiseConflict(lb, InferenceId::ARITH_CONF_TRICHOTOMY);
743
          return true;
744
30025
        }else if(learnNegLb){
745
30025
          d_learnedBounds.push_back(negLb);
746
        }
747
      }
748
    }
749
  }
750
751
995126
  d_currentPropagationList.push_back(constraint);
752
995126
  d_currentPropagationList.push_back(d_partialModel.getUpperBoundConstraint(x_i));
753
  //It is fine if this is NullConstraint
754
755
995126
  d_partialModel.setUpperBoundConstraint(constraint);
756
757
995126
  if(d_cmEnabled){
758
995126
    if(d_congruenceManager.isWatchedVariable(x_i)){
759
692664
      int sgn = c_i.sgn();
760
692664
      if(sgn < 0){
761
309474
        d_congruenceManager.watchedVariableCannotBeZero(constraint);
762
383190
      }else if(sgn == 0 && d_partialModel.lowerBoundIsZero(x_i)){
763
62116
        zeroDifferenceDetected(x_i);
764
      }
765
    }
766
  }
767
768
995126
  d_updatedBounds.softAdd(x_i);
769
770
995126
  if(Debug.isOn("model")) {
771
    Debug("model") << "before" << endl;
772
    d_partialModel.printModel(x_i);
773
    d_tableau.debugPrintIsBasic(x_i);
774
  }
775
776
995126
  if(!d_tableau.isBasic(x_i)){
777
400687
    if(d_partialModel.getAssignment(x_i) > c_i){
778
47207
      d_linEq.update(x_i, c_i);
779
    }
780
  }else{
781
594439
    d_errorSet.signalVariable(x_i);
782
  }
783
784
995126
  if(Debug.isOn("model")) {
785
    Debug("model") << "after" << endl;
786
    d_partialModel.printModel(x_i);
787
    d_tableau.debugPrintIsBasic(x_i);
788
  }
789
790
995126
  return false; //sat
791
}
792
793
794
/* procedure AssertEquality( x_i == c_i ) */
795
733854
bool TheoryArithPrivate::AssertEquality(ConstraintP constraint){
796
733854
  Assert(constraint != NullConstraint);
797
733854
  Assert(constraint->isEquality());
798
733854
  Assert(constraint->isTrue());
799
733854
  Assert(!constraint->negationHasProof());
800
801
733854
  ArithVar x_i = constraint->getVariable();
802
733854
  const DeltaRational& c_i = constraint->getValue();
803
804
733854
  Debug("arith") << "AssertEquality(" << x_i << " " << c_i << ")"<< std::endl;
805
806
  //Should be fine in integers
807
733854
  Assert(!isInteger(x_i) || c_i.isIntegral());
808
809
733854
  int cmpToLB = d_partialModel.cmpToLowerBound(x_i, c_i);
810
733854
  int cmpToUB = d_partialModel.cmpToUpperBound(x_i, c_i);
811
812
  // u_i <= c_i <= l_i
813
  // This can happen if both c_i <= x_i and x_i <= c_i are in the system.
814
733854
  if(cmpToUB >= 0 && cmpToLB <= 0){
815
37799
    return false; //sat
816
  }
817
818
696055
  if(cmpToUB > 0 || cmpToLB < 0){
819
3132
    ConstraintP cb = (cmpToUB > 0) ?  d_partialModel.getUpperBoundConstraint(x_i) :
820
3132
      d_partialModel.getLowerBoundConstraint(x_i);
821
2055
    ConstraintP diseq = constraint->getNegation();
822
2055
    Assert(!diseq->isTrue());
823
2055
    diseq->impliedByUnate(cb, true);
824
2055
    raiseConflict(constraint, InferenceId::ARITH_CONF_EQ);
825
2055
    return true;
826
  }
827
828
694000
  Assert(cmpToUB <= 0);
829
694000
  Assert(cmpToLB >= 0);
830
694000
  Assert(cmpToUB < 0 || cmpToLB > 0);
831
832
694000
  if(isInteger(x_i)){
833
647836
    d_constantIntegerVariables.push_back(x_i);
834
647836
    Debug("dio::push") << "dio::push " << x_i << endl;
835
  }
836
837
  // Don't bother to check whether x_i != c_i is in d_diseq
838
  // The a and (not a) should never be on the fact queue
839
694000
  d_currentPropagationList.push_back(constraint);
840
694000
  d_currentPropagationList.push_back(d_partialModel.getLowerBoundConstraint(x_i));
841
694000
  d_currentPropagationList.push_back(d_partialModel.getUpperBoundConstraint(x_i));
842
843
694000
  d_partialModel.setUpperBoundConstraint(constraint);
844
694000
  d_partialModel.setLowerBoundConstraint(constraint);
845
846
694000
  if(d_cmEnabled){
847
694000
    if(d_congruenceManager.isWatchedVariable(x_i)){
848
188519
      int sgn = c_i.sgn();
849
188519
      if(sgn == 0){
850
162817
        zeroDifferenceDetected(x_i);
851
      }else{
852
25702
        d_congruenceManager.watchedVariableCannotBeZero(constraint);
853
25702
        d_congruenceManager.equalsConstant(constraint);
854
      }
855
    }else{
856
505481
      d_congruenceManager.equalsConstant(constraint);
857
    }
858
  }
859
860
694000
  d_updatedBounds.softAdd(x_i);
861
862
694000
  if(Debug.isOn("model")) {
863
    Debug("model") << "before" << endl;
864
    d_partialModel.printModel(x_i);
865
    d_tableau.debugPrintIsBasic(x_i);
866
  }
867
868
694000
  if(!d_tableau.isBasic(x_i)){
869
396837
    if(!(d_partialModel.getAssignment(x_i) == c_i)){
870
50536
      d_linEq.update(x_i, c_i);
871
    }
872
  }else{
873
297163
    d_errorSet.signalVariable(x_i);
874
  }
875
876
694000
  if(Debug.isOn("model")) {
877
    Debug("model") << "after" << endl;
878
    d_partialModel.printModel(x_i);
879
    d_tableau.debugPrintIsBasic(x_i);
880
  }
881
882
694000
  return false;
883
}
884
885
886
/* procedure AssertDisequality( x_i != c_i ) */
887
595939
bool TheoryArithPrivate::AssertDisequality(ConstraintP constraint){
888
595939
  Assert(constraint != NullConstraint);
889
595939
  Assert(constraint->isDisequality());
890
595939
  Assert(constraint->isTrue());
891
595939
  Assert(!constraint->negationHasProof());
892
893
595939
  ArithVar x_i = constraint->getVariable();
894
595939
  const DeltaRational& c_i = constraint->getValue();
895
595939
  Debug("arith") << "AssertDisequality(" << x_i << " " << c_i << ")"<< std::endl;
896
897
  //Should be fine in integers
898
595939
  Assert(!isInteger(x_i) || c_i.isIntegral());
899
900
595939
  if(d_cmEnabled){
901
595939
    if(d_congruenceManager.isWatchedVariable(x_i)){
902
121129
      int sgn = c_i.sgn();
903
121129
      if(sgn == 0){
904
103309
        d_congruenceManager.watchedVariableCannotBeZero(constraint);
905
      }
906
    }
907
  }
908
909
595939
  const ValueCollection& vc = constraint->getValueCollection();
910
595939
  if(vc.hasLowerBound() && vc.hasUpperBound()){
911
267030
    const ConstraintP lb = vc.getLowerBound();
912
267030
    const ConstraintP ub = vc.getUpperBound();
913
267030
    if(lb->isTrue() && ub->isTrue()){
914
82
      ConstraintP eq = constraint->getNegation();
915
82
      eq->impliedByTrichotomy(lb, ub, true);
916
82
      raiseConflict(constraint, InferenceId::ARITH_CONF_TRICHOTOMY);
917
      //in conflict
918
82
      ++(d_statistics.d_statDisequalityConflicts);
919
82
      return true;
920
    }
921
  }
922
595857
  if(vc.hasLowerBound() ){
923
302587
    const ConstraintP lb = vc.getLowerBound();
924
302587
    if(lb->isTrue()){
925
90358
      const ConstraintP ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound);
926
90358
      Assert(!ub->isTrue());
927
90358
      Debug("arith::eq") << "propagate UpperBound " << constraint << lb << ub << endl;
928
90358
      const ConstraintP negUb = ub->getNegation();
929
90358
      if(!negUb->isTrue()){
930
48519
        negUb->impliedByTrichotomy(constraint, lb, false);
931
48519
        negUb->tryToPropagate();
932
48519
        d_learnedBounds.push_back(negUb);
933
      }
934
    }
935
  }
936
595857
  if(vc.hasUpperBound()){
937
300504
    const ConstraintP ub = vc.getUpperBound();
938
300504
    if(ub->isTrue()){
939
63774
      const ConstraintP lb = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), LowerBound);
940
63774
      Assert(!lb->isTrue());
941
942
63774
      Debug("arith::eq") << "propagate LowerBound " << constraint << lb << ub << endl;
943
63774
      const ConstraintP negLb = lb->getNegation();
944
63774
      if(!negLb->isTrue()){
945
14986
        negLb->impliedByTrichotomy(constraint, ub, false);
946
14986
        negLb->tryToPropagate();
947
14986
        d_learnedBounds.push_back(negLb);
948
      }
949
    }
950
  }
951
952
595857
  bool split = constraint->isSplit();
953
954
595857
  if(!split && c_i == d_partialModel.getAssignment(x_i)){
955
13542
    Debug("arith::eq") << "lemma now! " << constraint << endl;
956
13542
    outputTrustedLemma(constraint->split(), InferenceId::ARITH_SPLIT_DEQ);
957
13542
    return false;
958
582315
  }else if(d_partialModel.strictlyLessThanLowerBound(x_i, c_i)){
959
164183
    Debug("arith::eq") << "can drop as less than lb" << constraint << endl;
960
418132
  }else if(d_partialModel.strictlyGreaterThanUpperBound(x_i, c_i)){
961
152860
    Debug("arith::eq") << "can drop as less than ub" << constraint << endl;
962
265272
  }else if(!split){
963
149568
    Debug("arith::eq") << "push back" << constraint << endl;
964
149568
    d_diseqQueue.push(constraint);
965
149568
    d_partialModel.invalidateDelta();
966
  }else{
967
115704
    Debug("arith::eq") << "skipping already split " << constraint << endl;
968
  }
969
582315
  return false;
970
}
971
972
582302
void TheoryArithPrivate::notifySharedTerm(TNode n)
973
{
974
582302
  Debug("arith::notifySharedTerm") << "notifySharedTerm: " << n << endl;
975
582302
  if(n.isConst()){
976
73410
    d_partialModel.invalidateDelta();
977
  }
978
582302
  if(!n.isConst() && !isSetup(n)){
979
443692
    Polynomial poly = Polynomial::parsePolynomial(n);
980
443692
    Polynomial::iterator it = poly.begin();
981
443692
    Polynomial::iterator it_end = poly.end();
982
1223252
    for (; it != it_end; ++ it) {
983
1001406
      Monomial m = *it;
984
500703
      if (!m.isConstant() && !isSetup(m.getVarList().getNode())) {
985
5475
        setupVariableList(m.getVarList());
986
      }
987
    }
988
  }
989
582302
}
990
991
2876
Node TheoryArithPrivate::getModelValue(TNode term) {
992
  try{
993
5752
    const DeltaRational drv = getDeltaValue(term);
994
2876
    const Rational& delta = d_partialModel.getDelta();
995
5752
    const Rational qmodel = drv.substituteDelta( delta );
996
2876
    return mkRationalNode( qmodel );
997
  } catch (DeltaRationalException& dr) {
998
    return Node::null();
999
  } catch (ModelException& me) {
1000
    return Node::null();
1001
  }
1002
}
1003
1004
11527
Theory::PPAssertStatus TheoryArithPrivate::ppAssert(
1005
    TrustNode tin, TrustSubstitutionMap& outSubstitutions)
1006
{
1007
23054
  TimerStat::CodeTimer codeTimer(d_statistics.d_simplifyTimer);
1008
23054
  TNode in = tin.getNode();
1009
11527
  Debug("simplify") << "TheoryArithPrivate::solve(" << in << ")" << endl;
1010
1011
1012
  // Solve equalities
1013
23054
  Rational minConstant = 0;
1014
23054
  Node minMonomial;
1015
23054
  Node minVar;
1016
28322
  if (in.getKind() == kind::EQUAL &&
1017
16795
      Theory::theoryOf(in[0].getType()) == THEORY_ARITH) {
1018
4089
    Comparison cmp = Comparison::parseNormalForm(in);
1019
1020
4089
    Polynomial left = cmp.getLeft();
1021
1022
4089
    Monomial m = left.getHead();
1023
2634
    if (m.getVarList().singleton()){
1024
5146
      VarList vl = m.getVarList();
1025
5146
      Node var = vl.getNode();
1026
2573
      if (var.isVar())
1027
      {
1028
        // if vl.isIntegral then m.getConstant().isOne()
1029
1390
        if(!vl.isIntegral() || m.getConstant().isOne()){
1030
1378
          minVar = var;
1031
        }
1032
      }
1033
    }
1034
1035
    // Solve for variable
1036
2634
    if (!minVar.isNull()) {
1037
1577
      Polynomial right = cmp.getRight();
1038
1577
      Node elim = right.getNode();
1039
      // ax + p = c -> (ax + p) -ax - c = -ax
1040
      // x = (p - ax - c) * -1/a
1041
      // Add the substitution if not recursive
1042
1378
      Assert(elim == Rewriter::rewrite(elim));
1043
1044
2756
      if (right.size() > options::ppAssertMaxSubSize())
1045
      {
1046
218
        Debug("simplify")
1047
            << "TheoryArithPrivate::solve(): did not substitute due to the "
1048
109
               "right hand side containing too many terms: "
1049
109
            << minVar << ":" << elim << endl;
1050
109
        Debug("simplify") << right.size() << endl;
1051
      }
1052
1269
      else if (d_containing.isLegalElimination(minVar, elim))
1053
      {
1054
        // cannot eliminate integers here unless we know the resulting
1055
        // substitution is integral
1056
2358
        Debug("simplify") << "TheoryArithPrivate::solve(): substitution "
1057
1179
                          << minVar << " |-> " << elim << endl;
1058
1059
1179
        outSubstitutions.addSubstitutionSolved(minVar, elim, tin);
1060
1179
        return Theory::PP_ASSERT_STATUS_SOLVED;
1061
      }
1062
      else
1063
      {
1064
180
        Debug("simplify") << "TheoryArithPrivate::solve(): can't substitute "
1065
180
                          << minVar << ":" << minVar.getType() << " |-> "
1066
90
                          << elim << ":" << elim.getType() << endl;
1067
      }
1068
    }
1069
  }
1070
1071
  // If a relation, remember the bound
1072
10348
  switch(in.getKind()) {
1073
5743
  case kind::LEQ:
1074
  case kind::LT:
1075
  case kind::GEQ:
1076
  case kind::GT:
1077
5743
    if (in[0].isVar()) {
1078
2466
      d_learner.addBound(in);
1079
    }
1080
5743
    break;
1081
4605
  default:
1082
    // Do nothing
1083
4605
    break;
1084
  }
1085
1086
10348
  return Theory::PP_ASSERT_STATUS_UNSOLVED;
1087
}
1088
1089
104072
void TheoryArithPrivate::ppStaticLearn(TNode n, NodeBuilder& learned)
1090
{
1091
208144
  TimerStat::CodeTimer codeTimer(d_statistics.d_staticLearningTimer);
1092
1093
104072
  d_learner.staticLearning(n, learned);
1094
104072
}
1095
1096
ArithVar TheoryArithPrivate::findShortestBasicRow(ArithVar variable){
1097
  ArithVar bestBasic = ARITHVAR_SENTINEL;
1098
  uint64_t bestRowLength = std::numeric_limits<uint64_t>::max();
1099
1100
  Tableau::ColIterator basicIter = d_tableau.colIterator(variable);
1101
  for(; !basicIter.atEnd(); ++basicIter){
1102
    const Tableau::Entry& entry = *basicIter;
1103
    Assert(entry.getColVar() == variable);
1104
    RowIndex ridx = entry.getRowIndex();
1105
    ArithVar basic = d_tableau.rowIndexToBasic(ridx);
1106
    uint32_t rowLength = d_tableau.getRowLength(ridx);
1107
    if((rowLength < bestRowLength) ||
1108
       (rowLength == bestRowLength && basic < bestBasic)){
1109
      bestBasic = basic;
1110
      bestRowLength = rowLength;
1111
    }
1112
  }
1113
  Assert(bestBasic == ARITHVAR_SENTINEL
1114
         || bestRowLength < std::numeric_limits<uint32_t>::max());
1115
  return bestBasic;
1116
}
1117
1118
60774
void TheoryArithPrivate::setupVariable(const Variable& x){
1119
121548
  Node n = x.getNode();
1120
1121
60774
  Assert(!isSetup(n));
1122
1123
60774
  ++(d_statistics.d_statUserVariables);
1124
60774
  requestArithVar(n, false,  false);
1125
  //ArithVar varN = requestArithVar(n,false);
1126
  //setupInitialValue(varN);
1127
1128
60774
  markSetup(n);
1129
60774
}
1130
1131
62292
void TheoryArithPrivate::setupVariableList(const VarList& vl){
1132
62292
  Assert(!vl.empty());
1133
1134
124584
  TNode vlNode = vl.getNode();
1135
62292
  Assert(!isSetup(vlNode));
1136
62292
  Assert(!d_partialModel.hasArithVar(vlNode));
1137
1138
130862
  for(VarList::iterator i = vl.begin(), end = vl.end(); i != end; ++i){
1139
137140
    Variable var = *i;
1140
1141
68570
    if(!isSetup(var.getNode())){
1142
60774
      setupVariable(var);
1143
    }
1144
  }
1145
1146
62292
  if(!vl.singleton()){
1147
    // vl is the product of at least 2 variables
1148
    // vl : (* v1 v2 ...)
1149
2450
    if(getLogicInfo().isLinear()){
1150
1
      throw LogicException("A non-linear fact was asserted to arithmetic in a linear logic.");
1151
    }
1152
2449
    d_foundNl = true;
1153
1154
2449
    ++(d_statistics.d_statUserVariables);
1155
2449
    requestArithVar(vlNode, false, false);
1156
    //ArithVar av = requestArithVar(vlNode, false);
1157
    //setupInitialValue(av);
1158
1159
2449
    markSetup(vlNode);
1160
  }
1161
119684
  else if (vlNode.getKind() == kind::EXPONENTIAL
1162
59794
           || vlNode.getKind() == kind::SINE || vlNode.getKind() == kind::COSINE
1163
119187
           || vlNode.getKind() == kind::TANGENT)
1164
  {
1165
497
    d_foundNl = true;
1166
  }
1167
1168
  /* Note:
1169
   * Only call markSetup if the VarList is not a singleton.
1170
   * See the comment in setupPolynomail for more.
1171
   */
1172
62291
}
1173
1174
void TheoryArithPrivate::cautiousSetupPolynomial(const Polynomial& p){
1175
  if(p.containsConstant()){
1176
    if(!p.isConstant()){
1177
      Polynomial noConstant = p.getTail();
1178
      if(!isSetup(noConstant.getNode())){
1179
        setupPolynomial(noConstant);
1180
      }
1181
    }
1182
  }else if(!isSetup(p.getNode())){
1183
    setupPolynomial(p);
1184
  }
1185
}
1186
1187
1188
108595
void TheoryArithPrivate::setupPolynomial(const Polynomial& poly) {
1189
108595
  Assert(!poly.containsConstant());
1190
217190
  TNode polyNode = poly.getNode();
1191
108595
  Assert(!isSetup(polyNode));
1192
108595
  Assert(!d_partialModel.hasArithVar(polyNode));
1193
1194
327616
  for(Polynomial::iterator i = poly.begin(), end = poly.end(); i != end; ++i){
1195
438042
    Monomial mono = *i;
1196
219021
    const VarList& vl = mono.getVarList();
1197
219021
    if(!isSetup(vl.getNode())){
1198
56817
      setupVariableList(vl);
1199
    }
1200
  }
1201
1202
108594
  if(polyNode.getKind() == PLUS){
1203
84690
    d_tableauSizeHasBeenModified = true;
1204
1205
169380
    vector<ArithVar> variables;
1206
169380
    vector<Rational> coefficients;
1207
84690
    asVectors(poly, coefficients, variables);
1208
1209
84690
    ArithVar varSlack = requestArithVar(polyNode, true, false);
1210
84690
    d_tableau.addRow(varSlack, coefficients, variables);
1211
84690
    setupBasicValue(varSlack);
1212
84690
    d_linEq.trackRowIndex(d_tableau.basicToRowIndex(varSlack));
1213
1214
    //Add differences to the difference manager
1215
169380
    Polynomial::iterator i = poly.begin(), end = poly.end();
1216
84690
    if(i != end){
1217
169380
      Monomial first = *i;
1218
84690
      ++i;
1219
84690
      if(i != end){
1220
169380
        Monomial second = *i;
1221
84690
        ++i;
1222
84690
        if(i == end){
1223
68164
          if(first.getConstant().isOne() && second.getConstant().getValue() == -1){
1224
115660
            VarList vl0 = first.getVarList();
1225
115660
            VarList vl1 = second.getVarList();
1226
57830
            if(vl0.singleton() && vl1.singleton()){
1227
55619
              d_congruenceManager.addWatchedPair(varSlack, vl0.getNode(), vl1.getNode());
1228
            }
1229
          }
1230
        }
1231
      }
1232
    }
1233
1234
84690
    ++(d_statistics.d_statAuxiliaryVariables);
1235
84690
    markSetup(polyNode);
1236
  }
1237
1238
  /* Note:
1239
   * It is worth documenting that polyNode should only be marked as
1240
   * being setup by this function if it has kind PLUS.
1241
   * Other kinds will be marked as being setup by lower levels of setup
1242
   * specifically setupVariableList.
1243
   */
1244
108594
}
1245
1246
242625
void TheoryArithPrivate::setupAtom(TNode atom) {
1247
242625
  Assert(isRelationOperator(atom.getKind())) << atom;
1248
242625
  Assert(Comparison::isNormalAtom(atom));
1249
242625
  Assert(!isSetup(atom));
1250
242625
  Assert(!d_constraintDatabase.hasLiteral(atom));
1251
1252
485250
  Comparison cmp = Comparison::parseNormalForm(atom);
1253
485250
  Polynomial nvp = cmp.normalizedVariablePart();
1254
242625
  Assert(!nvp.isZero());
1255
1256
242625
  if(!isSetup(nvp.getNode())){
1257
108595
    setupPolynomial(nvp);
1258
  }
1259
1260
242624
  d_constraintDatabase.addLiteral(atom);
1261
1262
242624
  markSetup(atom);
1263
242624
}
1264
1265
730660
void TheoryArithPrivate::preRegisterTerm(TNode n) {
1266
730660
  Debug("arith::preregister") <<"begin arith::preRegisterTerm("<< n <<")"<< endl;
1267
1268
730660
  d_preregisteredNodes.insert(n);
1269
1270
  try {
1271
730660
    if(isRelationOperator(n.getKind())){
1272
371713
      if(!isSetup(n)){
1273
195260
        setupAtom(n);
1274
      }
1275
371712
      ConstraintP c = d_constraintDatabase.lookup(n);
1276
371712
      Assert(c != NullConstraint);
1277
1278
371712
      Debug("arith::preregister") << "setup constraint" << c << endl;
1279
371712
      Assert(!c->canBePropagated());
1280
371712
      c->setPreregistered();
1281
    }
1282
2
  } catch(LogicException& le) {
1283
2
    std::stringstream ss;
1284
1
    ss << le.getMessage() << endl << "The fact in question: " << n << endl;
1285
1
    throw LogicException(ss.str());
1286
  }
1287
1288
730659
  Debug("arith::preregister") << "end arith::preRegisterTerm("<< n <<")" << endl;
1289
730659
}
1290
1291
void TheoryArithPrivate::releaseArithVar(ArithVar v){
1292
  //Assert(d_partialModel.hasNode(v));
1293
1294
  d_constraintDatabase.removeVariable(v);
1295
  d_partialModel.releaseArithVar(v);
1296
}
1297
1298
147913
ArithVar TheoryArithPrivate::requestArithVar(TNode x, bool aux, bool internal){
1299
  //TODO : The VarList trick is good enough?
1300
147913
  Assert(isLeaf(x) || VarList::isMember(x) || x.getKind() == PLUS || internal);
1301
147913
  if(getLogicInfo().isLinear() && Variable::isDivMember(x)){
1302
    stringstream ss;
1303
    ss << "A non-linear fact (involving div/mod/divisibility) was asserted to "
1304
          "arithmetic in a linear logic: "
1305
       << x << std::endl;
1306
    throw LogicException(ss.str());
1307
  }
1308
147913
  Assert(!d_partialModel.hasArithVar(x));
1309
147913
  Assert(x.getType().isReal());  // real or integer
1310
1311
147913
  ArithVar max = d_partialModel.getNumberOfVariables();
1312
147913
  ArithVar varX = d_partialModel.allocate(x, aux);
1313
1314
147913
  bool reclaim =  max >= d_partialModel.getNumberOfVariables();;
1315
1316
147913
  if(!reclaim){
1317
147913
    d_dualSimplex.increaseMax();
1318
1319
147913
    d_tableau.increaseSize();
1320
147913
    d_tableauSizeHasBeenModified = true;
1321
  }
1322
147913
  d_constraintDatabase.addVariable(varX);
1323
1324
295826
  Debug("arith::arithvar") << "@" << getSatContext()->getLevel()
1325
147913
                           << " " << x << " |-> " << varX
1326
147913
                           << "(relaiming " << reclaim << ")" << endl;
1327
1328
147913
  Assert(!d_partialModel.hasUpperBound(varX));
1329
147913
  Assert(!d_partialModel.hasLowerBound(varX));
1330
1331
147913
  return varX;
1332
}
1333
1334
84690
void TheoryArithPrivate::asVectors(const Polynomial& p, std::vector<Rational>& coeffs, std::vector<ArithVar>& variables) {
1335
279806
  for(Polynomial::iterator i = p.begin(), end = p.end(); i != end; ++i){
1336
390232
    const Monomial& mono = *i;
1337
195116
    const Constant& constant = mono.getConstant();
1338
195116
    const VarList& variable = mono.getVarList();
1339
1340
390232
    Node n = variable.getNode();
1341
1342
195116
    Debug("arith::asVectors") << "should be var: " << n << endl;
1343
1344
    // TODO: This VarList::isMember(n) can be stronger
1345
195116
    Assert(isLeaf(n) || VarList::isMember(n));
1346
195116
    Assert(theoryOf(n) != THEORY_ARITH || d_partialModel.hasArithVar(n));
1347
1348
195116
    Assert(d_partialModel.hasArithVar(n));
1349
195116
    ArithVar av = d_partialModel.asArithVar(n);
1350
1351
195116
    coeffs.push_back(constant.getValue());
1352
195116
    variables.push_back(av);
1353
  }
1354
84690
}
1355
1356
/* Requirements:
1357
 * For basic variables the row must have been added to the tableau.
1358
 */
1359
84690
void TheoryArithPrivate::setupBasicValue(ArithVar x){
1360
84690
  Assert(d_tableau.isBasic(x));
1361
  //If the variable is basic, assertions may have already happened and updates
1362
  //may have occured before setting this variable up.
1363
1364
  //This can go away if the tableau creation is done at preregister
1365
  //time instead of register
1366
169380
  DeltaRational safeAssignment = d_linEq.computeRowValue(x, true);
1367
169380
  DeltaRational assignment = d_linEq.computeRowValue(x, false);
1368
84690
  d_partialModel.setAssignment(x,safeAssignment,assignment);
1369
1370
84690
  Debug("arith") << "setupVariable("<<x<<")"<<std::endl;
1371
84690
}
1372
1373
ArithVar TheoryArithPrivate::determineArithVar(const Polynomial& p) const{
1374
  Assert(!p.containsConstant());
1375
  Assert(p.getHead().constantIsPositive());
1376
  TNode n = p.getNode();
1377
  Debug("determineArithVar") << "determineArithVar(" << n << ")" << endl;
1378
  return d_partialModel.asArithVar(n);
1379
}
1380
1381
ArithVar TheoryArithPrivate::determineArithVar(TNode assertion) const{
1382
  Debug("determineArithVar") << "determineArithVar " << assertion << endl;
1383
  Comparison cmp = Comparison::parseNormalForm(assertion);
1384
  Polynomial variablePart = cmp.normalizedVariablePart();
1385
  return determineArithVar(variablePart);
1386
}
1387
1388
1389
bool TheoryArithPrivate::canSafelyAvoidEqualitySetup(TNode equality){
1390
  Assert(equality.getKind() == EQUAL);
1391
  return d_partialModel.hasArithVar(equality[0]);
1392
}
1393
1394
38998
Comparison TheoryArithPrivate::mkIntegerEqualityFromAssignment(ArithVar v){
1395
38998
  const DeltaRational& beta = d_partialModel.getAssignment(v);
1396
1397
38998
  Assert(beta.isIntegral());
1398
77996
  Polynomial betaAsPolynomial = Polynomial::mkPolynomial( Constant::mkConstant(beta.floor()) );
1399
1400
77996
  TNode var = d_partialModel.asNode(v);
1401
77996
  Polynomial varAsPolynomial = Polynomial::parsePolynomial(var);
1402
77996
  return Comparison::mkComparison(EQUAL, varAsPolynomial, betaAsPolynomial);
1403
}
1404
1405
1820
TrustNode TheoryArithPrivate::dioCutting()
1406
{
1407
3640
  context::Context::ScopedPush speculativePush(getSatContext());
1408
  //DO NOT TOUCH THE OUTPUTSTREAM
1409
1410
80364
  for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
1411
78544
    ArithVar v = *vi;
1412
78544
    if(isInteger(v)){
1413
125639
      if(d_partialModel.cmpAssignmentUpperBound(v) == 0 ||
1414
48609
         d_partialModel.cmpAssignmentLowerBound(v) == 0){
1415
36784
        if(!d_partialModel.boundsAreEqual(v)){
1416
          // If the bounds are equal this is already in the dioSolver
1417
          //Add v = dr as a speculation.
1418
31250
          Comparison eq = mkIntegerEqualityFromAssignment(v);
1419
15625
          Debug("dio::push") << "dio::push " << v << " " <<  eq.getNode() << endl;
1420
15625
          Assert(!eq.isBoolean());
1421
15625
          d_diosolver.pushInputConstraint(eq, eq.getNode());
1422
          // It does not matter what the explanation of eq is.
1423
          // It cannot be used in a conflict
1424
        }
1425
      }
1426
    }
1427
  }
1428
1429
3640
  SumPair plane = d_diosolver.processEquationsForCut();
1430
1820
  if(plane.isZero()){
1431
450
    return TrustNode::null();
1432
  }else{
1433
2740
    Polynomial p = plane.getPolynomial();
1434
2740
    Polynomial c = Polynomial::mkPolynomial(plane.getConstant() * Constant::mkConstant(-1));
1435
2740
    Integer gcd = p.gcd();
1436
1370
    Assert(p.isIntegral());
1437
1370
    Assert(c.isIntegral());
1438
1370
    Assert(gcd > 1);
1439
1370
    Assert(!gcd.divides(c.asConstant().getNumerator()));
1440
2740
    Comparison leq = Comparison::mkComparison(LEQ, p, c);
1441
2740
    Comparison geq = Comparison::mkComparison(GEQ, p, c);
1442
2740
    Node lemma = NodeManager::currentNM()->mkNode(OR, leq.getNode(), geq.getNode());
1443
2740
    Node rewrittenLemma = Rewriter::rewrite(lemma);
1444
1370
    Debug("arith::dio::ex") << "dioCutting found the plane: " << plane.getNode() << endl;
1445
1370
    Debug("arith::dio::ex") << "resulting in the cut: " << lemma << endl;
1446
1370
    Debug("arith::dio::ex") << "rewritten " << rewrittenLemma << endl;
1447
1370
    Debug("arith::dio") << "dioCutting found the plane: " << plane.getNode() << endl;
1448
1370
    Debug("arith::dio") << "resulting in the cut: " << lemma << endl;
1449
1370
    Debug("arith::dio") << "rewritten " << rewrittenLemma << endl;
1450
1370
    if (proofsEnabled())
1451
    {
1452
208
      NodeManager* nm = NodeManager::currentNM();
1453
416
      Node gt = nm->mkNode(kind::GT, p.getNode(), c.getNode());
1454
416
      Node lt = nm->mkNode(kind::LT, p.getNode(), c.getNode());
1455
1456
416
      Pf pfNotLeq = d_pnm->mkAssume(leq.getNode().negate());
1457
      Pf pfGt =
1458
416
          d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM, {pfNotLeq}, {gt});
1459
416
      Pf pfNotGeq = d_pnm->mkAssume(geq.getNode().negate());
1460
      Pf pfLt =
1461
416
          d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM, {pfNotGeq}, {lt});
1462
      Pf pfSum =
1463
208
          d_pnm->mkNode(PfRule::MACRO_ARITH_SCALE_SUM_UB,
1464
                        {pfGt, pfLt},
1465
416
                        {nm->mkConst<Rational>(-1), nm->mkConst<Rational>(1)});
1466
208
      Pf pfBot = d_pnm->mkNode(
1467
416
          PfRule::MACRO_SR_PRED_TRANSFORM, {pfSum}, {nm->mkConst<bool>(false)});
1468
208
      std::vector<Node> assumptions = {leq.getNode().negate(),
1469
416
                                       geq.getNode().negate()};
1470
416
      Pf pfNotAndNot = d_pnm->mkScope(pfBot, assumptions);
1471
416
      Pf pfOr = d_pnm->mkNode(PfRule::NOT_AND, {pfNotAndNot}, {});
1472
208
      Pf pfRewritten = d_pnm->mkNode(
1473
416
          PfRule::MACRO_SR_PRED_TRANSFORM, {pfOr}, {rewrittenLemma});
1474
208
      return d_pfGen->mkTrustNode(rewrittenLemma, pfRewritten);
1475
    }
1476
    else
1477
    {
1478
1162
      return TrustNode::mkTrustLemma(rewrittenLemma, nullptr);
1479
    }
1480
  }
1481
}
1482
1483
25986
Node TheoryArithPrivate::callDioSolver(){
1484
49359
  while(!d_constantIntegerVariables.empty()){
1485
23373
    ArithVar v = d_constantIntegerVariables.front();
1486
23373
    d_constantIntegerVariables.pop();
1487
1488
23373
    Debug("arith::dio")  << "callDioSolver " << v << endl;
1489
1490
23373
    Assert(isInteger(v));
1491
23373
    Assert(d_partialModel.boundsAreEqual(v));
1492
1493
23373
    ConstraintP lb = d_partialModel.getLowerBoundConstraint(v);
1494
23373
    ConstraintP ub = d_partialModel.getUpperBoundConstraint(v);
1495
1496
46746
    Node orig = Node::null();
1497
23373
    if(lb->isEquality()){
1498
21540
      orig = Constraint::externalExplainByAssertions({lb});
1499
1833
    }else if(ub->isEquality()){
1500
      orig = Constraint::externalExplainByAssertions({ub});
1501
    }else {
1502
1833
      orig = Constraint::externalExplainByAssertions(ub, lb);
1503
    }
1504
1505
23373
    Assert(d_partialModel.assignmentIsConsistent(v));
1506
1507
46746
    Comparison eq = mkIntegerEqualityFromAssignment(v);
1508
1509
23373
    if(eq.isBoolean()){
1510
      //This can only be a conflict
1511
      Assert(!eq.getNode().getConst<bool>());
1512
1513
      //This should be handled by the normal form earlier in the case of equality
1514
      Assert(orig.getKind() != EQUAL);
1515
      return orig;
1516
    }else{
1517
23373
      Debug("dio::push") << "dio::push " << v << " " << eq.getNode() << " with reason " << orig << endl;
1518
23373
      d_diosolver.pushInputConstraint(eq, orig);
1519
    }
1520
  }
1521
1522
2613
  return d_diosolver.processEquationsForConflict();
1523
}
1524
1525
5005301
ConstraintP TheoryArithPrivate::constraintFromFactQueue(TNode assertion)
1526
{
1527
5005301
  Kind simpleKind = Comparison::comparisonKind(assertion);
1528
5005301
  ConstraintP constraint = d_constraintDatabase.lookup(assertion);
1529
5005301
  if(constraint == NullConstraint){
1530
537637
    Assert(simpleKind == EQUAL || simpleKind == DISTINCT);
1531
537637
    bool isDistinct = simpleKind == DISTINCT;
1532
1065645
    Node eq = (simpleKind == DISTINCT) ? assertion[0] : assertion;
1533
537637
    Assert(!isSetup(eq));
1534
1065645
    Node reEq = Rewriter::rewrite(eq);
1535
537637
    Debug("arith::distinct::const") << "Assertion: " << assertion << std::endl;
1536
537637
    Debug("arith::distinct::const") << "Eq       : " << eq << std::endl;
1537
537637
    Debug("arith::distinct::const") << "reEq     : " << reEq << std::endl;
1538
537637
    if(reEq.getKind() == CONST_BOOLEAN){
1539
9629
      if(reEq.getConst<bool>() == isDistinct){
1540
        // if is (not true), or false
1541
        Assert((reEq.getConst<bool>() && isDistinct)
1542
               || (!reEq.getConst<bool>() && !isDistinct));
1543
        if (proofsEnabled())
1544
        {
1545
          Pf assume = d_pnm->mkAssume(assertion);
1546
          std::vector<Node> assumptions = {assertion};
1547
          Pf pf = d_pnm->mkScope(d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
1548
                                               {d_pnm->mkAssume(assertion)},
1549
                                               {}),
1550
                                 assumptions);
1551
          raiseBlackBoxConflict(assertion, pf);
1552
        }
1553
        else
1554
        {
1555
          raiseBlackBoxConflict(assertion);
1556
        }
1557
      }
1558
9629
      return NullConstraint;
1559
    }
1560
528008
    Assert(reEq.getKind() != CONST_BOOLEAN);
1561
528008
    if(!isSetup(reEq)){
1562
30756
      setupAtom(reEq);
1563
    }
1564
1056016
    Node reAssertion = isDistinct ? reEq.notNode() : reEq;
1565
528008
    constraint = d_constraintDatabase.lookup(reAssertion);
1566
1567
528008
    if(assertion != reAssertion){
1568
511674
      Debug("arith::nf") << "getting non-nf assertion " << assertion << " |-> " <<  reAssertion << endl;
1569
511674
      Assert(constraint != NullConstraint);
1570
511674
      d_assertionsThatDoNotMatchTheirLiterals.insert(assertion, constraint);
1571
    }
1572
  }
1573
1574
4995672
  Assert(constraint != NullConstraint);
1575
1576
4995672
  if(constraint->assertedToTheTheory()){
1577
    //Do nothing
1578
167968
    return NullConstraint;
1579
  }
1580
4827704
  Assert(!constraint->assertedToTheTheory());
1581
4827704
  bool inConflict = constraint->negationHasProof();
1582
4827704
  constraint->setAssertedToTheTheory(assertion, inConflict);
1583
1584
4827704
  if(!constraint->hasProof()){
1585
4119438
    Debug("arith::constraint") << "marking as constraint as self explaining " << endl;
1586
4119438
    constraint->setAssumption(inConflict);
1587
  } else {
1588
1416532
    Debug("arith::constraint")
1589
708266
        << "already has proof: "
1590
708266
        << Constraint::externalExplainByAssertions({constraint});
1591
  }
1592
1593
4827704
  if(Debug.isOn("arith::negatedassumption") && inConflict){
1594
    ConstraintP negation = constraint->getNegation();
1595
    if(Debug.isOn("arith::negatedassumption") && negation->isAssumption()){
1596
      debugPrintFacts();
1597
    }
1598
    Debug("arith::eq") << "negation has proof" << endl;
1599
    Debug("arith::eq") << constraint << endl;
1600
    Debug("arith::eq") << negation << endl;
1601
  }
1602
1603
4827704
  if(inConflict){
1604
3371
    ConstraintP negation = constraint->getNegation();
1605
3371
    if(Debug.isOn("arith::negatedassumption") && negation->isAssumption()){
1606
      debugPrintFacts();
1607
    }
1608
3371
    Debug("arith::eq") << "negation has proof" << endl;
1609
3371
    Debug("arith::eq") << constraint << endl;
1610
3371
    Debug("arith::eq") << negation << endl;
1611
3371
    raiseConflict(negation, InferenceId::UNKNOWN);
1612
3371
    return NullConstraint;
1613
  }else{
1614
4824333
    return constraint;
1615
  }
1616
}
1617
1618
4926584
bool TheoryArithPrivate::assertionCases(ConstraintP constraint){
1619
4926584
  Assert(constraint->hasProof());
1620
4926584
  Assert(!constraint->negationHasProof());
1621
1622
4926584
  ArithVar x_i = constraint->getVariable();
1623
1624
4926584
  switch(constraint->getType()){
1625
1742932
  case UpperBound:
1626
1742932
    if(isInteger(x_i) && constraint->isStrictUpperBound()){
1627
1016884
      ConstraintP floorConstraint = constraint->getFloor();
1628
1016884
      if(!floorConstraint->isTrue()){
1629
871835
        bool inConflict = floorConstraint->negationHasProof();
1630
871835
        if (Debug.isOn("arith::intbound")) {
1631
          Debug("arith::intbound") << "literal, before: " << constraint->getLiteral() << std::endl;
1632
          Debug("arith::intbound") << "constraint, after: " << floorConstraint << std::endl;
1633
        }
1634
871835
        floorConstraint->impliedByIntTighten(constraint, inConflict);
1635
871835
        floorConstraint->tryToPropagate();
1636
871835
        if(inConflict){
1637
2643
          raiseConflict(floorConstraint, InferenceId::ARITH_TIGHTEN_FLOOR);
1638
2643
          return true;
1639
        }
1640
      }
1641
1014241
      return AssertUpper(floorConstraint);
1642
    }else{
1643
726048
      return AssertUpper(constraint);
1644
    }
1645
1853859
  case LowerBound:
1646
1853859
    if(isInteger(x_i) && constraint->isStrictLowerBound()){
1647
54375
      ConstraintP ceilingConstraint = constraint->getCeiling();
1648
54375
      if(!ceilingConstraint->isTrue()){
1649
33999
        bool inConflict = ceilingConstraint->negationHasProof();
1650
33999
        if (Debug.isOn("arith::intbound")) {
1651
          Debug("arith::intbound") << "literal, before: " << constraint->getLiteral() << std::endl;
1652
          Debug("arith::intbound") << "constraint, after: " << ceilingConstraint << std::endl;
1653
        }
1654
33999
        ceilingConstraint->impliedByIntTighten(constraint, inConflict);
1655
33999
        ceilingConstraint->tryToPropagate();
1656
33999
        if(inConflict){
1657
29
          raiseConflict(ceilingConstraint, InferenceId::ARITH_TIGHTEN_CEIL);
1658
29
          return true;
1659
        }
1660
      }
1661
54346
      return AssertLower(ceilingConstraint);
1662
    }else{
1663
1799484
      return AssertLower(constraint);
1664
    }
1665
733854
  case Equality:
1666
733854
    return AssertEquality(constraint);
1667
595939
  case Disequality:
1668
595939
    return AssertDisequality(constraint);
1669
  default:
1670
    Unreachable();
1671
    return false;
1672
  }
1673
}
1674
/**
1675
 * Looks for through the variables starting at d_nextIntegerCheckVar
1676
 * for the first integer variable that is between its upper and lower bounds
1677
 * that has a non-integer assignment.
1678
 *
1679
 * If assumeBounds is true, skip the check that the variable is in bounds.
1680
 *
1681
 * If there is no such variable, returns ARITHVAR_SENTINEL;
1682
 */
1683
2682747
ArithVar TheoryArithPrivate::nextIntegerViolation(bool assumeBounds) const
1684
{
1685
2682747
  ArithVar numVars = d_partialModel.getNumberOfVariables();
1686
2682747
  ArithVar v = d_nextIntegerCheckVar;
1687
2682747
  if (numVars > 0)
1688
  {
1689
2648913
    const ArithVar rrEnd = d_nextIntegerCheckVar;
1690
443257640
    do
1691
    {
1692
445906553
      if (isIntegerInput(v))
1693
      {
1694
107612635
        if (!d_partialModel.integralAssignment(v))
1695
        {
1696
123551
          if (assumeBounds || d_partialModel.assignmentIsConsistent(v))
1697
          {
1698
123551
            return v;
1699
          }
1700
        }
1701
      }
1702
445783002
      v = (1 + v == numVars) ? 0 : (1 + v);
1703
445783002
    } while (v != rrEnd);
1704
  }
1705
2559196
  return ARITHVAR_SENTINEL;
1706
}
1707
1708
/**
1709
 * Checks the set of integer variables I to see if each variable
1710
 * in I has an integer assignment.
1711
 */
1712
2682747
bool TheoryArithPrivate::hasIntegerModel()
1713
{
1714
2682747
  ArithVar next = nextIntegerViolation(true);
1715
2682747
  if (next != ARITHVAR_SENTINEL)
1716
  {
1717
123551
    d_nextIntegerCheckVar = next;
1718
123551
    if (Debug.isOn("arith::hasIntegerModel"))
1719
    {
1720
      Debug("arith::hasIntegerModel") << "has int model? " << next << endl;
1721
      d_partialModel.printModel(next, Debug("arith::hasIntegerModel"));
1722
    }
1723
123551
    return false;
1724
  }
1725
  else
1726
  {
1727
2559196
    return true;
1728
  }
1729
}
1730
1731
Node flattenAndSort(Node n){
1732
  Kind k = n.getKind();
1733
  switch(k){
1734
  case kind::OR:
1735
  case kind::AND:
1736
  case kind::PLUS:
1737
  case kind::MULT:
1738
    break;
1739
  default:
1740
    return n;
1741
  }
1742
1743
  std::vector<Node> out;
1744
  std::vector<Node> process;
1745
  process.push_back(n);
1746
  while(!process.empty()){
1747
    Node b = process.back();
1748
    process.pop_back();
1749
    if(b.getKind() == k){
1750
      for(Node::iterator i=b.begin(), end=b.end(); i!=end; ++i){
1751
        process.push_back(*i);
1752
      }
1753
    } else {
1754
      out.push_back(b);
1755
    }
1756
  }
1757
  Assert(out.size() >= 2);
1758
  std::sort(out.begin(), out.end());
1759
  return NodeManager::currentNM()->mkNode(k, out);
1760
}
1761
1762
1763
1764
/** Outputs conflicts to the output channel. */
1765
49477
void TheoryArithPrivate::outputConflicts(){
1766
49477
  Debug("arith::conflict") << "outputting conflicts" << std::endl;
1767
49477
  Assert(anyConflict());
1768
  static unsigned int conflicts = 0;
1769
1770
49477
  if(!conflictQueueEmpty()){
1771
47393
    Assert(!d_conflicts.empty());
1772
114565
    for(size_t i = 0, i_end = d_conflicts.size(); i < i_end; ++i){
1773
67172
      const std::pair<ConstraintCP, InferenceId>& conf = d_conflicts[i];
1774
67172
      const ConstraintCP& confConstraint = conf.first;
1775
67172
      bool hasProof = confConstraint->hasProof();
1776
67172
      Assert(confConstraint->inConflict());
1777
67172
      const ConstraintRule& pf = confConstraint->getConstraintRule();
1778
67172
      if (Debug.isOn("arith::conflict"))
1779
      {
1780
        pf.print(std::cout);
1781
        std::cout << std::endl;
1782
      }
1783
67172
      if (Debug.isOn("arith::pf::tree"))
1784
      {
1785
        Debug("arith::pf::tree") << "\n\nTree:\n";
1786
        confConstraint->printProofTree(Debug("arith::pf::tree"));
1787
        confConstraint->getNegation()->printProofTree(Debug("arith::pf::tree"));
1788
      }
1789
1790
134344
      TrustNode trustedConflict = confConstraint->externalExplainConflict();
1791
134344
      Node conflict = trustedConflict.getNode();
1792
1793
67172
      ++conflicts;
1794
134344
      Debug("arith::conflict") << "d_conflicts[" << i << "] " << conflict
1795
67172
                               << " has proof: " << hasProof << endl;
1796
67172
      if(Debug.isOn("arith::normalize::external")){
1797
        conflict = flattenAndSort(conflict);
1798
        Debug("arith::conflict") << "(normalized to) " << conflict << endl;
1799
      }
1800
1801
67172
      if (isProofEnabled())
1802
      {
1803
11087
        outputTrustedConflict(trustedConflict, conf.second);
1804
      }
1805
      else
1806
      {
1807
56085
        outputConflict(conflict, conf.second);
1808
      }
1809
    }
1810
  }
1811
49477
  if(!d_blackBoxConflict.get().isNull()){
1812
4180
    Node bb = d_blackBoxConflict.get();
1813
2090
    ++conflicts;
1814
4180
    Debug("arith::conflict") << "black box conflict" << bb
1815
      //<< "("<<conflicts<<")"
1816
2090
                             << endl;
1817
2090
    if(Debug.isOn("arith::normalize::external")){
1818
      bb = flattenAndSort(bb);
1819
      Debug("arith::conflict") << "(normalized to) " << bb << endl;
1820
    }
1821
2090
    if (isProofEnabled() && d_blackBoxConflictPf.get())
1822
    {
1823
756
      auto confPf = d_blackBoxConflictPf.get();
1824
378
      outputTrustedConflict(d_pfGen->mkTrustNode(bb, confPf, true), InferenceId::ARITH_BLACK_BOX);
1825
    }
1826
    else
1827
    {
1828
1712
      outputConflict(bb, InferenceId::ARITH_BLACK_BOX);
1829
    }
1830
  }
1831
49477
}
1832
1833
69412
void TheoryArithPrivate::outputTrustedLemma(TrustNode lemma, InferenceId id)
1834
{
1835
69412
  Debug("arith::channel") << "Arith trusted lemma: " << lemma << std::endl;
1836
69412
  d_containing.d_im.trustedLemma(lemma, id);
1837
69412
}
1838
1839
75154
void TheoryArithPrivate::outputLemma(TNode lem, InferenceId id) {
1840
75154
  Debug("arith::channel") << "Arith lemma: " << lem << std::endl;
1841
75154
  d_containing.d_im.lemma(lem, id);
1842
75154
}
1843
1844
11465
void TheoryArithPrivate::outputTrustedConflict(TrustNode conf, InferenceId id)
1845
{
1846
11465
  Debug("arith::channel") << "Arith trusted conflict: " << conf << std::endl;
1847
11465
  d_containing.d_im.trustedConflict(conf, id);
1848
11465
}
1849
1850
57797
void TheoryArithPrivate::outputConflict(TNode lit, InferenceId id) {
1851
57797
  Debug("arith::channel") << "Arith conflict: " << lit << std::endl;
1852
57797
  d_containing.d_im.conflict(lit, id);
1853
57797
}
1854
1855
994529
void TheoryArithPrivate::outputPropagate(TNode lit) {
1856
994529
  Debug("arith::channel") << "Arith propagation: " << lit << std::endl;
1857
  // call the propagate lit method of the
1858
994529
  d_containing.d_im.propagateLit(lit);
1859
994529
}
1860
1861
void TheoryArithPrivate::outputRestart() {
1862
  Debug("arith::channel") << "Arith restart!" << std::endl;
1863
  (d_containing.d_out)->demandRestart();
1864
}
1865
1866
1315471
bool TheoryArithPrivate::attemptSolveInteger(Theory::Effort effortLevel, bool emmmittedLemmaOrSplit){
1867
1315471
  int level = getSatContext()->getLevel();
1868
2630942
  Debug("approx")
1869
1315471
    << "attemptSolveInteger " << d_qflraStatus
1870
1315471
    << " " << emmmittedLemmaOrSplit
1871
1315471
    << " " << effortLevel
1872
1315471
    << " " << d_lastContextIntegerAttempted
1873
1315471
    << " " << level
1874
2630942
    << " " << hasIntegerModel()
1875
1315471
    << endl;
1876
1877
1315471
  if(d_qflraStatus == Result::UNSAT){ return false; }
1878
1279043
  if(emmmittedLemmaOrSplit){ return false; }
1879
5093642
  if(!options::useApprox()){ return false; }
1880
  if(!ApproximateSimplex::enabled()){ return false; }
1881
1882
  if(Theory::fullEffort(effortLevel)){
1883
    if(hasIntegerModel()){
1884
      return false;
1885
    }else{
1886
      return getSolveIntegerResource();
1887
    }
1888
  }
1889
1890
  if(d_lastContextIntegerAttempted <= 0){
1891
    if(hasIntegerModel()){
1892
      d_lastContextIntegerAttempted = getSatContext()->getLevel();
1893
      return false;
1894
    }else{
1895
      return getSolveIntegerResource();
1896
    }
1897
  }
1898
1899
1900
  if(!options::trySolveIntStandardEffort()){ return false; }
1901
1902
  if (d_lastContextIntegerAttempted <= (level >> 2))
1903
  {
1904
    double d = (double)(d_solveIntMaybeHelp + 1)
1905
               / (d_solveIntAttempts + 1 + level * level);
1906
    if (Random::getRandom().pickWithProb(d))
1907
    {
1908
      return getSolveIntegerResource();
1909
    }
1910
  }
1911
  return false;
1912
}
1913
1914
bool TheoryArithPrivate::replayLog(ApproximateSimplex* approx){
1915
  TimerStat::CodeTimer codeTimer(d_statistics.d_replayLogTimer);
1916
1917
  ++d_statistics.d_mipProofsAttempted;
1918
1919
  Assert(d_replayVariables.empty());
1920
  Assert(d_replayConstraints.empty());
1921
1922
  size_t enteringPropN = d_currentPropagationList.size();
1923
  Assert(conflictQueueEmpty());
1924
  TreeLog& tl = getTreeLog();
1925
  //tl.applySelected(); /* set row ids */
1926
1927
  d_replayedLemmas = false;
1928
1929
  /* use the try block for the purpose of pushing the sat context */
1930
  context::Context::ScopedPush speculativePush(getSatContext());
1931
  d_cmEnabled = false;
1932
  std::vector<ConstraintCPVec> res =
1933
      replayLogRec(approx, tl.getRootId(), NullConstraint, 1);
1934
1935
  if(res.empty()){
1936
    ++d_statistics.d_replayAttemptFailed;
1937
  }else{
1938
    unsigned successes = 0;
1939
    for(size_t i =0, N = res.size(); i < N; ++i){
1940
      ConstraintCPVec& vec = res[i];
1941
      Assert(vec.size() >= 2);
1942
      for(size_t j=0, M = vec.size(); j < M; ++j){
1943
        ConstraintCP at_j = vec[j];
1944
        Assert(at_j->isTrue());
1945
        if(!at_j->negationHasProof()){
1946
          successes++;
1947
          vec[j] = vec.back();
1948
          vec.pop_back();
1949
          ConstraintP neg_at_j = at_j->getNegation();
1950
1951
          Debug("approx::replayLog") << "Setting the proof for the replayLog conflict on:" << endl
1952
                                     << "  (" << neg_at_j->isTrue() <<") " << neg_at_j << endl
1953
                                     << "  (" << at_j->isTrue() <<") " << at_j << endl;
1954
          neg_at_j->impliedByIntHole(vec, true);
1955
          raiseConflict(at_j, InferenceId::UNKNOWN);
1956
          break;
1957
        }
1958
      }
1959
    }
1960
    if(successes > 0){
1961
      ++d_statistics.d_mipProofsSuccessful;
1962
    }
1963
  }
1964
1965
  if(d_currentPropagationList.size() > enteringPropN){
1966
    d_currentPropagationList.resize(enteringPropN);
1967
  }
1968
1969
  /* It is not clear what the d_qflraStatus is at this point */
1970
  d_qflraStatus = Result::SAT_UNKNOWN;
1971
1972
  Assert(d_replayVariables.empty());
1973
  Assert(d_replayConstraints.empty());
1974
1975
  return !conflictQueueEmpty();
1976
}
1977
1978
std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(const DenseMap<Rational>& lhs, Kind k, const Rational& rhs, bool branch)
1979
{
1980
  ArithVar added = ARITHVAR_SENTINEL;
1981
  Node sum = toSumNode(d_partialModel, lhs);
1982
  if(sum.isNull()){ return make_pair(NullConstraint, added); }
1983
1984
  Debug("approx::constraint") << "replayGetConstraint " << sum
1985
                              << " " << k
1986
                              << " " << rhs
1987
                              << endl;
1988
1989
  Assert(k == kind::LEQ || k == kind::GEQ);
1990
1991
  Node comparison = NodeManager::currentNM()->mkNode(k, sum, mkRationalNode(rhs));
1992
  Node rewritten = Rewriter::rewrite(comparison);
1993
  if(!(Comparison::isNormalAtom(rewritten))){
1994
    return make_pair(NullConstraint, added);
1995
  }
1996
1997
  Comparison cmp = Comparison::parseNormalForm(rewritten);
1998
  if(cmp.isBoolean()){ return make_pair(NullConstraint, added); }
1999
2000
  Polynomial nvp =  cmp.normalizedVariablePart();
2001
  if(nvp.isZero()){ return make_pair(NullConstraint, added); }
2002
2003
  Node norm = nvp.getNode();
2004
2005
  ConstraintType t = Constraint::constraintTypeOfComparison(cmp);
2006
  DeltaRational dr = cmp.normalizedDeltaRational();
2007
2008
  Debug("approx::constraint") << "rewriting " << rewritten << endl
2009
                              << " |-> " << norm << " " << t << " " << dr << endl;
2010
2011
  Assert(!branch || d_partialModel.hasArithVar(norm));
2012
  ArithVar v = ARITHVAR_SENTINEL;
2013
  if(d_partialModel.hasArithVar(norm)){
2014
2015
    v = d_partialModel.asArithVar(norm);
2016
    Debug("approx::constraint") << "replayGetConstraint found "
2017
                                << norm << " |-> " << v << " @ " << getSatContext()->getLevel() << endl;
2018
    Assert(!branch || d_partialModel.isIntegerInput(v));
2019
  }else{
2020
    v = requestArithVar(norm, true, true);
2021
    d_replayVariables.push_back(v);
2022
2023
    added = v;
2024
2025
    Debug("approx::constraint") << "replayGetConstraint adding "
2026
                                << norm << " |-> " << v << " @ " << getSatContext()->getLevel() << endl;
2027
2028
    Polynomial poly = Polynomial::parsePolynomial(norm);
2029
    vector<ArithVar> variables;
2030
    vector<Rational> coefficients;
2031
    asVectors(poly, coefficients, variables);
2032
    d_tableau.addRow(v, coefficients, variables);
2033
    setupBasicValue(v);
2034
    d_linEq.trackRowIndex(d_tableau.basicToRowIndex(v));
2035
  }
2036
  Assert(d_partialModel.hasArithVar(norm));
2037
  Assert(d_partialModel.asArithVar(norm) == v);
2038
  Assert(d_constraintDatabase.variableDatabaseIsSetup(v));
2039
2040
  ConstraintP imp = d_constraintDatabase.getBestImpliedBound(v, t, dr);
2041
  if(imp != NullConstraint){
2042
    if(imp->getValue() == dr){
2043
      Assert(added == ARITHVAR_SENTINEL);
2044
      return make_pair(imp, added);
2045
    }
2046
  }
2047
2048
  ConstraintP newc = d_constraintDatabase.getConstraint(v, t, dr);
2049
  d_replayConstraints.push_back(newc);
2050
  return make_pair(newc, added);
2051
}
2052
2053
std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(
2054
    ApproximateSimplex* approx, const NodeLog& nl)
2055
{
2056
  Assert(nl.isBranch());
2057
  Assert(d_lhsTmp.empty());
2058
2059
  ArithVar v = approx->getBranchVar(nl);
2060
  if(v != ARITHVAR_SENTINEL && d_partialModel.isIntegerInput(v)){
2061
    if(d_partialModel.hasNode(v)){
2062
      d_lhsTmp.set(v, Rational(1));
2063
      double dval = nl.branchValue();
2064
      Maybe<Rational> maybe_value = ApproximateSimplex::estimateWithCFE(dval);
2065
      if (!maybe_value)
2066
      {
2067
        return make_pair(NullConstraint, ARITHVAR_SENTINEL);
2068
      }
2069
      Rational fl(maybe_value.value().floor());
2070
      pair<ConstraintP, ArithVar> p;
2071
      p = replayGetConstraint(d_lhsTmp, kind::LEQ, fl, true);
2072
      d_lhsTmp.purge();
2073
      return p;
2074
    }
2075
  }
2076
  return make_pair(NullConstraint, ARITHVAR_SENTINEL);
2077
}
2078
2079
std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(const CutInfo& ci) {
2080
  Assert(ci.reconstructed());
2081
  const DenseMap<Rational>& lhs = ci.getReconstruction().lhs;
2082
  const Rational& rhs = ci.getReconstruction().rhs;
2083
  Kind k = ci.getKind();
2084
2085
  return replayGetConstraint(lhs, k, rhs, ci.getKlass() == BranchCutKlass);
2086
}
2087
2088
// Node denseVectorToLiteral(const ArithVariables& vars, const DenseVector& dv, Kind k){
2089
//   NodeManager* nm = NodeManager::currentNM();
2090
//   Node sumLhs = toSumNode(vars, dv.lhs);
2091
//   Node ineq = nm->mkNode(k, sumLhs, mkRationalNode(dv.rhs) );
2092
//   Node lit = Rewriter::rewrite(ineq);
2093
//   return lit;
2094
// }
2095
2096
Node toSumNode(const ArithVariables& vars, const DenseMap<Rational>& sum){
2097
  Debug("arith::toSumNode") << "toSumNode() begin" << endl;
2098
  NodeBuilder nb(kind::PLUS);
2099
  NodeManager* nm = NodeManager::currentNM();
2100
  DenseMap<Rational>::const_iterator iter, end;
2101
  iter = sum.begin(), end = sum.end();
2102
  for(; iter != end; ++iter){
2103
    ArithVar x = *iter;
2104
    if(!vars.hasNode(x)){ return Node::null(); }
2105
    Node xNode = vars.asNode(x);
2106
    const Rational& q = sum[x];
2107
    Node mult = nm->mkNode(kind::MULT, mkRationalNode(q), xNode);
2108
    Debug("arith::toSumNode") << "toSumNode() " << x << " " << mult << endl;
2109
    nb << mult;
2110
  }
2111
  Debug("arith::toSumNode") << "toSumNode() end" << endl;
2112
  return safeConstructNary(nb);
2113
}
2114
2115
ConstraintCP TheoryArithPrivate::vectorToIntHoleConflict(const ConstraintCPVec& conflict){
2116
  Assert(conflict.size() >= 2);
2117
  ConstraintCPVec exp(conflict.begin(), conflict.end()-1);
2118
  ConstraintCP back = conflict.back();
2119
  Assert(back->hasProof());
2120
  ConstraintP negBack = back->getNegation();
2121
  // This can select negBack multiple times so we need to test if negBack has a proof.
2122
  if(negBack->hasProof()){
2123
    // back is in conflict already
2124
  } else {
2125
    negBack->impliedByIntHole(exp, true);
2126
  }
2127
2128
  return back;
2129
}
2130
2131
void TheoryArithPrivate::intHoleConflictToVector(ConstraintCP conflicting, ConstraintCPVec& conflict){
2132
  ConstraintCP negConflicting = conflicting->getNegation();
2133
  Assert(conflicting->hasProof());
2134
  Assert(negConflicting->hasProof());
2135
2136
  conflict.push_back(conflicting);
2137
  conflict.push_back(negConflicting);
2138
2139
  Constraint::assertionFringe(conflict);
2140
}
2141
2142
void TheoryArithPrivate::tryBranchCut(ApproximateSimplex* approx, int nid, BranchCutInfo& bci){
2143
  Assert(conflictQueueEmpty());
2144
  std::vector< ConstraintCPVec > conflicts;
2145
2146
  approx->tryCut(nid, bci);
2147
  Debug("approx::branch") << "tryBranchCut" << bci << endl;
2148
  Assert(bci.reconstructed());
2149
  Assert(!bci.proven());
2150
  pair<ConstraintP, ArithVar> p = replayGetConstraint(bci);
2151
  Assert(p.second == ARITHVAR_SENTINEL);
2152
  ConstraintP bc = p.first;
2153
  Assert(bc != NullConstraint);
2154
  if(bc->hasProof()){
2155
    return;
2156
  }
2157
2158
  ConstraintP bcneg = bc->getNegation();
2159
  {
2160
    context::Context::ScopedPush speculativePush(getSatContext());
2161
    replayAssert(bcneg);
2162
    if(conflictQueueEmpty()){
2163
      TimerStat::CodeTimer codeTimer(d_statistics.d_replaySimplexTimer);
2164
2165
      //test for linear feasibility
2166
      d_partialModel.stopQueueingBoundCounts();
2167
      UpdateTrackingCallback utcb(&d_linEq);
2168
      d_partialModel.processBoundsQueue(utcb);
2169
      d_linEq.startTrackingBoundCounts();
2170
2171
      SimplexDecisionProcedure& simplex = selectSimplex(true);
2172
      simplex.findModel(false);
2173
      // Can change d_qflraStatus
2174
2175
      d_linEq.stopTrackingBoundCounts();
2176
      d_partialModel.startQueueingBoundCounts();
2177
    }
2178
    for(size_t i = 0, N = d_conflicts.size(); i < N; ++i){
2179
2180
      conflicts.push_back(ConstraintCPVec());
2181
      intHoleConflictToVector(d_conflicts[i].first, conflicts.back());
2182
      Constraint::assertionFringe(conflicts.back());
2183
2184
      // ConstraintCP conflicting = d_conflicts[i];
2185
      // ConstraintCP negConflicting = conflicting->getNegation();
2186
      // Assert(conflicting->hasProof());
2187
      // Assert(negConflicting->hasProof());
2188
2189
      // conflicts.push_back(ConstraintCPVec());
2190
      // ConstraintCPVec& back = conflicts.back();
2191
      // back.push_back(conflicting);
2192
      // back.push_back(negConflicting);
2193
2194
      // // remove the floor/ceiling contraint implied by bcneg
2195
      // Constraint::assertionFringe(back);
2196
    }
2197
2198
    if(Debug.isOn("approx::branch")){
2199
      if(d_conflicts.empty()){
2200
        entireStateIsConsistent("branchfailure");
2201
      }
2202
    }
2203
  }
2204
2205
  Debug("approx::branch") << "branch constraint " << bc << endl;
2206
  for(size_t i = 0, N = conflicts.size(); i < N; ++i){
2207
    ConstraintCPVec& conf = conflicts[i];
2208
2209
    // make sure to be working on the assertion fringe!
2210
    if(!contains(conf, bcneg)){
2211
      Debug("approx::branch") << "reraise " << conf  << endl;
2212
      ConstraintCP conflicting = vectorToIntHoleConflict(conf);
2213
      raiseConflict(conflicting, InferenceId::UNKNOWN);
2214
    }else if(!bci.proven()){
2215
      drop(conf, bcneg);
2216
      bci.setExplanation(conf);
2217
      Debug("approx::branch") << "dropped " << bci  << endl;
2218
    }
2219
  }
2220
}
2221
2222
void TheoryArithPrivate::replayAssert(ConstraintP c) {
2223
  if(!c->assertedToTheTheory()){
2224
    bool inConflict = c->negationHasProof();
2225
    if(!c->hasProof()){
2226
      c->setInternalAssumption(inConflict);
2227
      Debug("approx::replayAssert") << "replayAssert " << c << " set internal" << endl;
2228
    }else{
2229
      Debug("approx::replayAssert") << "replayAssert " << c << " has explanation" << endl;
2230
    }
2231
    Debug("approx::replayAssert") << "replayAssertion " << c << endl;
2232
    if(inConflict){
2233
      raiseConflict(c, InferenceId::UNKNOWN);
2234
    }else{
2235
      assertionCases(c);
2236
    }
2237
  }else{
2238
    Debug("approx::replayAssert")
2239
        << "replayAssert " << c << " already asserted" << endl;
2240
  }
2241
}
2242
2243
2244
void TheoryArithPrivate::resolveOutPropagated(std::vector<ConstraintCPVec>& confs, const std::set<ConstraintCP>& propagated) const {
2245
  Debug("arith::resolveOutPropagated")
2246
    << "starting resolveOutPropagated() " << confs.size() << endl;
2247
  for(size_t i =0, N = confs.size(); i < N; ++i){
2248
    ConstraintCPVec& conf = confs[i];
2249
    size_t orig = conf.size();
2250
    Constraint::assertionFringe(conf);
2251
    Debug("arith::resolveOutPropagated")
2252
      << "  conf["<<i<<"] " << orig << " to " << conf.size() << endl;
2253
  }
2254
  Debug("arith::resolveOutPropagated")
2255
    << "ending resolveOutPropagated() " << confs.size() << endl;
2256
}
2257
2258
struct SizeOrd {
2259
  bool operator()(const ConstraintCPVec& a, const ConstraintCPVec& b) const{
2260
    return a.size() < b.size();
2261
  }
2262
};
2263
2264
void TheoryArithPrivate::subsumption(
2265
    std::vector<ConstraintCPVec> &confs) const {
2266
  int checks CVC5_UNUSED = 0;
2267
  int subsumed CVC5_UNUSED = 0;
2268
2269
  for (size_t i = 0, N = confs.size(); i < N; ++i) {
2270
    ConstraintCPVec &conf = confs[i];
2271
    std::sort(conf.begin(), conf.end());
2272
  }
2273
2274
  std::sort(confs.begin(), confs.end(), SizeOrd());
2275
  for (size_t i = 0; i < confs.size(); i++) {
2276
    // i is not subsumed
2277
    for (size_t j = i + 1; j < confs.size();) {
2278
      ConstraintCPVec& a = confs[i];
2279
      ConstraintCPVec& b = confs[j];
2280
      checks++;
2281
      bool subsumes = std::includes(a.begin(), a.end(), b.begin(), b.end());
2282
      if (subsumes) {
2283
        ConstraintCPVec& back = confs.back();
2284
        b.swap(back);
2285
        confs.pop_back();
2286
        subsumed++;
2287
      } else {
2288
        j++;
2289
      }
2290
    }
2291
  }
2292
  Debug("arith::subsumption") << "subsumed " << subsumed << "/" << checks
2293
                              << endl;
2294
}
2295
2296
std::vector<ConstraintCPVec> TheoryArithPrivate::replayLogRec(ApproximateSimplex* approx, int nid, ConstraintP bc, int depth){
2297
  ++(d_statistics.d_replayLogRecCount);
2298
  Debug("approx::replayLogRec") << "replayLogRec()" << std::endl;
2299
2300
  size_t rpvars_size = d_replayVariables.size();
2301
  size_t rpcons_size = d_replayConstraints.size();
2302
  std::vector<ConstraintCPVec> res;
2303
2304
  { /* create a block for the purpose of pushing the sat context */
2305
    context::Context::ScopedPush speculativePush(getSatContext());
2306
    Assert(!anyConflict());
2307
    Assert(conflictQueueEmpty());
2308
    set<ConstraintCP> propagated;
2309
2310
    TreeLog& tl = getTreeLog();
2311
2312
    if(bc != NullConstraint){
2313
      replayAssert(bc);
2314
    }
2315
2316
    const NodeLog& nl = tl.getNode(nid);
2317
    NodeLog::const_iterator iter = nl.begin(), end = nl.end();
2318
    for(; conflictQueueEmpty() && iter != end; ++iter){
2319
      CutInfo* ci = *iter;
2320
      bool reject = false;
2321
      //cout << "  trying " << *ci << endl;
2322
      if(ci->getKlass() == RowsDeletedKlass){
2323
        RowsDeleted* rd = dynamic_cast<RowsDeleted*>(ci);
2324
2325
        tl.applyRowsDeleted(nid, *rd);
2326
        // The previous line modifies nl
2327
2328
        ++d_statistics.d_applyRowsDeleted;
2329
      }else if(ci->getKlass() == BranchCutKlass){
2330
        BranchCutInfo* bci = dynamic_cast<BranchCutInfo*>(ci);
2331
        Assert(bci != NULL);
2332
        tryBranchCut(approx, nid, *bci);
2333
2334
        ++d_statistics.d_branchCutsAttempted;
2335
        if(!(conflictQueueEmpty() || ci->reconstructed())){
2336
          ++d_statistics.d_numBranchesFailed;
2337
        }
2338
      }else{
2339
        approx->tryCut(nid, *ci);
2340
        if(ci->getKlass() == GmiCutKlass){
2341
          ++d_statistics.d_gmiCutsAttempted;
2342
        }else if(ci->getKlass() == MirCutKlass){
2343
          ++d_statistics.d_mirCutsAttempted;
2344
        }
2345
2346
        if(ci->reconstructed() && ci->proven()){
2347
          const DenseMap<Rational>& row = ci->getReconstruction().lhs;
2348
          reject = !complexityBelow(row, options::replayRejectCutSize());
2349
        }
2350
      }
2351
      if(conflictQueueEmpty()){
2352
        if(reject){
2353
          ++d_statistics.d_cutsRejectedDuringReplay;
2354
        }else if(ci->reconstructed()){
2355
          // success
2356
          ++d_statistics.d_cutsReconstructed;
2357
2358
          pair<ConstraintP, ArithVar> p = replayGetConstraint(*ci);
2359
          if(p.second != ARITHVAR_SENTINEL){
2360
            Assert(ci->getRowId() >= 1);
2361
            tl.mapRowId(nl.getNodeId(), ci->getRowId(), p.second);
2362
          }
2363
          ConstraintP con = p.first;
2364
          if(Debug.isOn("approx::replayLogRec")){
2365
            Debug("approx::replayLogRec") << "cut was remade " << con << " " << *ci << endl;
2366
          }
2367
2368
          if(ci->proven()){
2369
            ++d_statistics.d_cutsProven;
2370
2371
            const ConstraintCPVec& exp = ci->getExplanation();
2372
            // success
2373
            if(con->isTrue()){
2374
              Debug("approx::replayLogRec") << "not asserted?" << endl;
2375
            }else if(!con->negationHasProof()){
2376
              con->impliedByIntHole(exp, false);
2377
              replayAssert(con);
2378
              Debug("approx::replayLogRec") << "cut prop" << endl;
2379
            }else {
2380
              con->impliedByIntHole(exp, true);
2381
              Debug("approx::replayLogRec") << "cut into conflict " << con << endl;
2382
              raiseConflict(con, InferenceId::UNKNOWN);
2383
            }
2384
          }else{
2385
            ++d_statistics.d_cutsProofFailed;
2386
            Debug("approx::replayLogRec") << "failed to get proof " << *ci << endl;
2387
          }
2388
        }else if(ci->getKlass() != RowsDeletedKlass){
2389
          ++d_statistics.d_cutsReconstructionFailed;
2390
        }
2391
      }
2392
    }
2393
2394
    /* check if the system is feasible under with the cuts */
2395
    if(conflictQueueEmpty()){
2396
      Assert(options::replayEarlyCloseDepths() >= 1);
2397
      if(!nl.isBranch() || depth % options::replayEarlyCloseDepths() == 0 ){
2398
        TimerStat::CodeTimer codeTimer(d_statistics.d_replaySimplexTimer);
2399
        //test for linear feasibility
2400
        d_partialModel.stopQueueingBoundCounts();
2401
        UpdateTrackingCallback utcb(&d_linEq);
2402
        d_partialModel.processBoundsQueue(utcb);
2403
        d_linEq.startTrackingBoundCounts();
2404
2405
        SimplexDecisionProcedure& simplex = selectSimplex(true);
2406
        simplex.findModel(false);
2407
        // can change d_qflraStatus
2408
2409
        d_linEq.stopTrackingBoundCounts();
2410
        d_partialModel.startQueueingBoundCounts();
2411
      }
2412
    }else{
2413
      ++d_statistics.d_replayLogRecConflictEscalation;
2414
    }
2415
2416
    if(!conflictQueueEmpty()){
2417
      /* if a conflict has been found stop */
2418
      for(size_t i = 0, N = d_conflicts.size(); i < N; ++i){
2419
        res.push_back(ConstraintCPVec());
2420
        intHoleConflictToVector(d_conflicts[i].first, res.back());
2421
      }
2422
      ++d_statistics.d_replayLogRecEarlyExit;
2423
    }else if(nl.isBranch()){
2424
      /* if it is a branch try the branch */
2425
      pair<ConstraintP, ArithVar> p = replayGetConstraint(approx, nl);
2426
      Assert(p.second == ARITHVAR_SENTINEL);
2427
      ConstraintP dnc = p.first;
2428
      if(dnc != NullConstraint){
2429
        ConstraintP upc = dnc->getNegation();
2430
2431
        int dnid = nl.getDownId();
2432
        int upid = nl.getUpId();
2433
2434
        NodeLog& dnlog = tl.getNode(dnid);
2435
        NodeLog& uplog = tl.getNode(upid);
2436
        dnlog.copyParentRowIds();
2437
        uplog.copyParentRowIds();
2438
2439
        std::vector<ConstraintCPVec> dnres;
2440
        std::vector<ConstraintCPVec> upres;
2441
        std::vector<size_t> containsdn;
2442
        std::vector<size_t> containsup;
2443
        if(res.empty()){
2444
          dnres = replayLogRec(approx, dnid, dnc, depth+1);
2445
          for(size_t i = 0, N = dnres.size(); i < N; ++i){
2446
            ConstraintCPVec& conf = dnres[i];
2447
            if(contains(conf, dnc)){
2448
              containsdn.push_back(i);
2449
            }else{
2450
              res.push_back(conf);
2451
            }
2452
          }
2453
        }else{
2454
          Debug("approx::replayLogRec") << "replayLogRec() skipping" << dnlog << std::endl;
2455
          ++d_statistics.d_replayBranchSkips;
2456
        }
2457
2458
        if(res.empty()){
2459
          upres = replayLogRec(approx, upid, upc, depth+1);
2460
2461
          for(size_t i = 0, N = upres.size(); i < N; ++i){
2462
            ConstraintCPVec& conf = upres[i];
2463
            if(contains(conf, upc)){
2464
              containsup.push_back(i);
2465
            }else{
2466
              res.push_back(conf);
2467
            }
2468
          }
2469
        }else{
2470
          Debug("approx::replayLogRec") << "replayLogRec() skipping" << uplog << std::endl;
2471
          ++d_statistics.d_replayBranchSkips;
2472
        }
2473
2474
        if(res.empty()){
2475
          for(size_t i = 0, N = containsdn.size(); i < N; ++i){
2476
            ConstraintCPVec& dnconf = dnres[containsdn[i]];
2477
            for(size_t j = 0, M = containsup.size(); j < M; ++j){
2478
              ConstraintCPVec& upconf = upres[containsup[j]];
2479
2480
              res.push_back(ConstraintCPVec());
2481
              ConstraintCPVec& back = res.back();
2482
              resolve(back, dnc, dnconf, upconf);
2483
            }
2484
          }
2485
          if(res.size() >= 2u){
2486
            subsumption(res);
2487
2488
            if(res.size() > 100u){
2489
              res.resize(100u);
2490
            }
2491
          }
2492
        }else{
2493
          Debug("approx::replayLogRec") << "replayLogRec() skipping resolving" << nl << std::endl;
2494
        }
2495
        Debug("approx::replayLogRec") << "found #"<<res.size()<<" conflicts on branch " << nid << endl;
2496
        if(res.empty()){
2497
          ++d_statistics.d_replayBranchCloseFailures;
2498
        }
2499
2500
      }else{
2501
        Debug("approx::replayLogRec") << "failed to make a branch " << nid << endl;
2502
      }
2503
    }else{
2504
      ++d_statistics.d_replayLeafCloseFailures;
2505
      Debug("approx::replayLogRec") << "failed on node " << nid << endl;
2506
      Assert(res.empty());
2507
    }
2508
    resolveOutPropagated(res, propagated);
2509
    Debug("approx::replayLogRec") << "replayLogRec() ending" << std::endl;
2510
2511
2512
    if(options::replayFailureLemma()){
2513
      // must be done inside the sat context to get things
2514
      // propagated at this level
2515
      if(res.empty() && nid == getTreeLog().getRootId()){
2516
        Assert(!d_replayedLemmas);
2517
        d_replayedLemmas = replayLemmas(approx);
2518
        Assert(d_acTmp.empty());
2519
        while(!d_approxCuts.empty()){
2520
          TrustNode lem = d_approxCuts.front();
2521
          d_approxCuts.pop();
2522
          d_acTmp.push_back(lem);
2523
        }
2524
      }
2525
    }
2526
  } /* pop the sat context */
2527
2528
  /* move into the current context. */
2529
  while(!d_acTmp.empty()){
2530
    TrustNode lem = d_acTmp.back();
2531
    d_acTmp.pop_back();
2532
    d_approxCuts.push_back(lem);
2533
  }
2534
  Assert(d_acTmp.empty());
2535
2536
  /* Garbage collect the constraints from this call */
2537
  while(d_replayConstraints.size() > rpcons_size){
2538
    ConstraintP c = d_replayConstraints.back();
2539
    d_replayConstraints.pop_back();
2540
    d_constraintDatabase.deleteConstraintAndNegation(c);
2541
  }
2542
2543
  /* Garbage collect the ArithVars made by this call */
2544
  if(d_replayVariables.size() > rpvars_size){
2545
    d_partialModel.stopQueueingBoundCounts();
2546
    UpdateTrackingCallback utcb(&d_linEq);
2547
    d_partialModel.processBoundsQueue(utcb);
2548
    d_linEq.startTrackingBoundCounts();
2549
    while(d_replayVariables.size() > rpvars_size){
2550
      ArithVar v = d_replayVariables.back();
2551
      d_replayVariables.pop_back();
2552
      Assert(d_partialModel.canBeReleased(v));
2553
      if(!d_tableau.isBasic(v)){
2554
        /* if it is not basic make it basic. */
2555
        ArithVar b = ARITHVAR_SENTINEL;
2556
        for(Tableau::ColIterator ci = d_tableau.colIterator(v); !ci.atEnd(); ++ci){
2557
          const Tableau::Entry& e = *ci;
2558
          b = d_tableau.rowIndexToBasic(e.getRowIndex());
2559
          break;
2560
        }
2561
        Assert(b != ARITHVAR_SENTINEL);
2562
        DeltaRational cp = d_partialModel.getAssignment(b);
2563
        if(d_partialModel.cmpAssignmentLowerBound(b) < 0){
2564
          cp = d_partialModel.getLowerBound(b);
2565
        }else if(d_partialModel.cmpAssignmentUpperBound(b) > 0){
2566
          cp = d_partialModel.getUpperBound(b);
2567
        }
2568
        d_linEq.pivotAndUpdate(b, v, cp);
2569
      }
2570
      Assert(d_tableau.isBasic(v));
2571
      d_linEq.stopTrackingRowIndex(d_tableau.basicToRowIndex(v));
2572
      d_tableau.removeBasicRow(v);
2573
2574
      releaseArithVar(v);
2575
      Debug("approx::vars") << "releasing " << v << endl;
2576
    }
2577
    d_linEq.stopTrackingBoundCounts();
2578
    d_partialModel.startQueueingBoundCounts();
2579
    d_partialModel.attemptToReclaimReleased();
2580
  }
2581
  return res;
2582
}
2583
2584
TreeLog& TheoryArithPrivate::getTreeLog(){
2585
  if(d_treeLog == NULL){
2586
    d_treeLog = new TreeLog();
2587
  }
2588
  return *d_treeLog;
2589
}
2590
2591
ApproximateStatistics& TheoryArithPrivate::getApproxStats(){
2592
  if(d_approxStats == NULL){
2593
    d_approxStats = new ApproximateStatistics();
2594
  }
2595
  return *d_approxStats;
2596
}
2597
2598
Node TheoryArithPrivate::branchToNode(ApproximateSimplex* approx,
2599
                                      const NodeLog& bn) const
2600
{
2601
  Assert(bn.isBranch());
2602
  ArithVar v = approx->getBranchVar(bn);
2603
  if(v != ARITHVAR_SENTINEL && d_partialModel.isIntegerInput(v)){
2604
    if(d_partialModel.hasNode(v)){
2605
      Node n = d_partialModel.asNode(v);
2606
      double dval = bn.branchValue();
2607
      Maybe<Rational> maybe_value = ApproximateSimplex::estimateWithCFE(dval);
2608
      if (!maybe_value)
2609
      {
2610
        return Node::null();
2611
      }
2612
      Rational fl(maybe_value.value().floor());
2613
      NodeManager* nm = NodeManager::currentNM();
2614
      Node leq = nm->mkNode(kind::LEQ, n, mkRationalNode(fl));
2615
      Node norm = Rewriter::rewrite(leq);
2616
      return norm;
2617
    }
2618
  }
2619
  return Node::null();
2620
}
2621
2622
Node TheoryArithPrivate::cutToLiteral(ApproximateSimplex* approx, const CutInfo& ci) const{
2623
  Assert(ci.reconstructed());
2624
2625
  const DenseMap<Rational>& lhs = ci.getReconstruction().lhs;
2626
  Node sum = toSumNode(d_partialModel, lhs);
2627
  if(!sum.isNull()){
2628
    Kind k = ci.getKind();
2629
    Assert(k == kind::LEQ || k == kind::GEQ);
2630
    Node rhs = mkRationalNode(ci.getReconstruction().rhs);
2631
2632
    NodeManager* nm = NodeManager::currentNM();
2633
    Node ineq = nm->mkNode(k, sum, rhs);
2634
    return Rewriter::rewrite(ineq);
2635
  }
2636
  return Node::null();
2637
}
2638
2639
bool TheoryArithPrivate::replayLemmas(ApproximateSimplex* approx){
2640
    ++(d_statistics.d_mipReplayLemmaCalls);
2641
    bool anythingnew = false;
2642
2643
    TreeLog& tl = getTreeLog();
2644
    NodeLog& root = tl.getRootNode();
2645
    root.applySelected(); /* set row ids */
2646
2647
    vector<const CutInfo*> cuts = approx->getValidCuts(root);
2648
    for(size_t i =0, N =cuts.size(); i < N; ++i){
2649
      const CutInfo* cut = cuts[i];
2650
      Assert(cut->reconstructed());
2651
      Assert(cut->proven());
2652
2653
      const DenseMap<Rational>& row =  cut->getReconstruction().lhs;
2654
      if(!complexityBelow(row, options::lemmaRejectCutSize())){
2655
        ++(d_statistics.d_cutsRejectedDuringLemmas);
2656
        continue;
2657
      }
2658
2659
      Node cutConstraint = cutToLiteral(approx, *cut);
2660
      if(!cutConstraint.isNull()){
2661
        const ConstraintCPVec& exp = cut->getExplanation();
2662
        Node asLemma = Constraint::externalExplainByAssertions(exp);
2663
2664
        Node implied = Rewriter::rewrite(cutConstraint);
2665
        anythingnew = anythingnew || !isSatLiteral(implied);
2666
2667
        Node implication = asLemma.impNode(implied);
2668
        // DO NOT CALL OUTPUT LEMMA!
2669
        // TODO (project #37): justify
2670
        d_approxCuts.push_back(TrustNode::mkTrustLemma(implication, nullptr));
2671
        Debug("approx::lemmas") << "cut["<<i<<"] " << implication << endl;
2672
        ++(d_statistics.d_mipExternalCuts);
2673
      }
2674
    }
2675
    if(root.isBranch()){
2676
      Node lit = branchToNode(approx, root);
2677
      if(!lit.isNull()){
2678
        anythingnew = anythingnew || !isSatLiteral(lit);
2679
        Node branch = lit.orNode(lit.notNode());
2680
        if (proofsEnabled())
2681
        {
2682
          d_pfGen->mkTrustNode(branch, PfRule::SPLIT, {}, {lit});
2683
        }
2684
        else
2685
        {
2686
          d_approxCuts.push_back(TrustNode::mkTrustLemma(branch, nullptr));
2687
        }
2688
        ++(d_statistics.d_mipExternalBranch);
2689
        Debug("approx::lemmas") << "branching "<< root <<" as " << branch << endl;
2690
      }
2691
    }
2692
    return anythingnew;
2693
}
2694
2695
void TheoryArithPrivate::turnOffApproxFor(int32_t rounds){
2696
  d_attemptSolveIntTurnedOff = d_attemptSolveIntTurnedOff + rounds;
2697
  ++(d_statistics.d_approxDisabled);
2698
}
2699
2700
1267778
bool TheoryArithPrivate::safeToCallApprox() const{
2701
1267778
  unsigned numRows = 0;
2702
1267778
  unsigned numCols = 0;
2703
1267778
  var_iterator vi = var_begin(), vi_end = var_end();
2704
  // Assign each variable to a row and column variable as it appears in the input
2705
20062714
  for(; vi != vi_end && !(numRows > 0 && numCols > 0); ++vi){
2706
9397468
    ArithVar v = *vi;
2707
2708
9397468
    if(d_partialModel.isAuxiliary(v)){
2709
1251840
      ++numRows;
2710
    }else{
2711
8145628
      ++numCols;
2712
    }
2713
  }
2714
1267778
  return (numRows > 0 && numCols > 0);
2715
}
2716
2717
// solve()
2718
//   res = solveRealRelaxation(effortLevel);
2719
//   switch(res){
2720
//   case LinFeas:
2721
//   case LinInfeas:
2722
//     return replay()
2723
//   case Unknown:
2724
//   case Error
2725
//     if()
2726
void TheoryArithPrivate::solveInteger(Theory::Effort effortLevel){
2727
  if(!safeToCallApprox()) { return; }
2728
2729
  Assert(safeToCallApprox());
2730
  TimerStat::CodeTimer codeTimer0(d_statistics.d_solveIntTimer);
2731
2732
  ++(d_statistics.d_solveIntCalls);
2733
  d_statistics.d_inSolveInteger = 1;
2734
2735
  if(!Theory::fullEffort(effortLevel)){
2736
    d_solveIntAttempts++;
2737
    ++(d_statistics.d_solveStandardEffort);
2738
  }
2739
2740
  // if integers are attempted,
2741
  Assert(options::useApprox());
2742
  Assert(ApproximateSimplex::enabled());
2743
2744
  int level = getSatContext()->getLevel();
2745
  d_lastContextIntegerAttempted = level;
2746
2747
2748
  static const int32_t mipLimit = 200000;
2749
2750
  TreeLog& tl = getTreeLog();
2751
  ApproximateStatistics& stats = getApproxStats();
2752
  ApproximateSimplex* approx =
2753
    ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel, tl, stats);
2754
2755
    approx->setPivotLimit(mipLimit);
2756
    if(!d_guessedCoeffSet){
2757
      d_guessedCoeffs = approx->heuristicOptCoeffs();
2758
      d_guessedCoeffSet = true;
2759
    }
2760
    if(!d_guessedCoeffs.empty()){
2761
      approx->setOptCoeffs(d_guessedCoeffs);
2762
    }
2763
    static const int32_t depthForLikelyInfeasible = 10;
2764
    int maxDepthPass1 = d_likelyIntegerInfeasible ?
2765
      depthForLikelyInfeasible : options::maxApproxDepth();
2766
    approx->setBranchingDepth(maxDepthPass1);
2767
    approx->setBranchOnVariableLimit(100);
2768
    LinResult relaxRes = approx->solveRelaxation();
2769
    if( relaxRes == LinFeasible ){
2770
      MipResult mipRes = MipUnknown;
2771
      {
2772
        TimerStat::CodeTimer codeTimer1(d_statistics.d_mipTimer);
2773
        mipRes = approx->solveMIP(false);
2774
      }
2775
2776
      Debug("arith::solveInteger") << "mipRes " << mipRes << endl;
2777
      switch(mipRes) {
2778
      case MipBingo:
2779
        // attempt the solution
2780
        {
2781
          ++(d_statistics.d_solveIntModelsAttempts);
2782
2783
          d_partialModel.stopQueueingBoundCounts();
2784
          UpdateTrackingCallback utcb(&d_linEq);
2785
          d_partialModel.processBoundsQueue(utcb);
2786
          d_linEq.startTrackingBoundCounts();
2787
2788
          ApproximateSimplex::Solution mipSolution;
2789
          mipSolution = approx->extractMIP();
2790
          importSolution(mipSolution);
2791
          solveRelaxationOrPanic(effortLevel);
2792
2793
          if (d_qflraStatus == Result::SAT)
2794
          {
2795
            if (!anyConflict())
2796
            {
2797
              if (ARITHVAR_SENTINEL == nextIntegerViolation(false))
2798
              {
2799
                ++(d_statistics.d_solveIntModelsSuccessful);
2800
              }
2801
            }
2802
          }
2803
2804
          // shutdown simplex
2805
          d_linEq.stopTrackingBoundCounts();
2806
          d_partialModel.startQueueingBoundCounts();
2807
        }
2808
        break;
2809
      case MipClosed:
2810
        /* All integer branches closed */
2811
        approx->setPivotLimit(2*mipLimit);
2812
        {
2813
          TimerStat::CodeTimer codeTimer2(d_statistics.d_mipTimer);
2814
          mipRes = approx->solveMIP(true);
2815
        }
2816
2817
        if(mipRes == MipClosed){
2818
          d_likelyIntegerInfeasible = true;
2819
          replayLog(approx);
2820
          AlwaysAssert(anyConflict() || d_qflraStatus != Result::SAT);
2821
2822
          if (!anyConflict())
2823
          {
2824
            solveRealRelaxation(effortLevel);
2825
          }
2826
        }
2827
        if(!(anyConflict() || !d_approxCuts.empty())){
2828
          turnOffApproxFor(options::replayNumericFailurePenalty());
2829
        }
2830
        break;
2831
      case BranchesExhausted:
2832
      case ExecExhausted:
2833
      case PivotsExhauasted:
2834
        if(mipRes == BranchesExhausted){
2835
          ++d_statistics.d_branchesExhausted;
2836
        }else if(mipRes == ExecExhausted){
2837
          ++d_statistics.d_execExhausted;
2838
        }else if(mipRes == PivotsExhauasted){
2839
          ++d_statistics.d_pivotsExhausted;
2840
        }
2841
2842
        approx->setPivotLimit(2*mipLimit);
2843
        approx->setBranchingDepth(2);
2844
        {
2845
          TimerStat::CodeTimer codeTimer3(d_statistics.d_mipTimer);
2846
          mipRes = approx->solveMIP(true);
2847
        }
2848
        replayLemmas(approx);
2849
        break;
2850
      case MipUnknown:
2851
        break;
2852
      }
2853
    }
2854
  delete approx;
2855
2856
  if(!Theory::fullEffort(effortLevel)){
2857
    if(anyConflict() || !d_approxCuts.empty()){
2858
      d_solveIntMaybeHelp++;
2859
    }
2860
  }
2861
2862
  d_statistics.d_inSolveInteger = 0;
2863
}
2864
2865
1267778
SimplexDecisionProcedure& TheoryArithPrivate::selectSimplex(bool pass1){
2866
1267778
  if(pass1){
2867
1267778
    if(d_pass1SDP == NULL){
2868
1327577
      if(options::useFC()){
2869
        d_pass1SDP = (SimplexDecisionProcedure*)(&d_fcSimplex);
2870
12106
      }else if(options::useSOI()){
2871
        d_pass1SDP = (SimplexDecisionProcedure*)(&d_soiSimplex);
2872
      }else{
2873
6053
        d_pass1SDP = (SimplexDecisionProcedure*)(&d_dualSimplex);
2874
      }
2875
    }
2876
1267778
    Assert(d_pass1SDP != NULL);
2877
1267778
    return *d_pass1SDP;
2878
  }else{
2879
     if(d_otherSDP == NULL){
2880
      if(options::useFC()){
2881
        d_otherSDP  = (SimplexDecisionProcedure*)(&d_fcSimplex);
2882
      }else if(options::useSOI()){
2883
        d_otherSDP = (SimplexDecisionProcedure*)(&d_soiSimplex);
2884
      }else{
2885
        d_otherSDP = (SimplexDecisionProcedure*)(&d_soiSimplex);
2886
      }
2887
    }
2888
    Assert(d_otherSDP != NULL);
2889
    return *d_otherSDP;
2890
  }
2891
}
2892
2893
void TheoryArithPrivate::importSolution(const ApproximateSimplex::Solution& solution){
2894
  if(Debug.isOn("arith::importSolution")){
2895
    Debug("arith::importSolution") << "importSolution before " << d_qflraStatus << endl;
2896
    d_partialModel.printEntireModel(Debug("arith::importSolution"));
2897
  }
2898
2899
  d_qflraStatus = d_attemptSolSimplex.attempt(solution);
2900
2901
  if(Debug.isOn("arith::importSolution")){
2902
    Debug("arith::importSolution") << "importSolution intermediate " << d_qflraStatus << endl;
2903
    d_partialModel.printEntireModel(Debug("arith::importSolution"));
2904
  }
2905
2906
  if(d_qflraStatus != Result::UNSAT){
2907
    static const int32_t pass2Limit = 20;
2908
    int16_t oldCap = options::arithStandardCheckVarOrderPivots();
2909
    Options::current().set(options::arithStandardCheckVarOrderPivots, pass2Limit);
2910
    SimplexDecisionProcedure& simplex = selectSimplex(false);
2911
    d_qflraStatus = simplex.findModel(false);
2912
    Options::current().set(options::arithStandardCheckVarOrderPivots, oldCap);
2913
  }
2914
2915
  if(Debug.isOn("arith::importSolution")){
2916
    Debug("arith::importSolution") << "importSolution after " << d_qflraStatus << endl;
2917
    d_partialModel.printEntireModel(Debug("arith::importSolution"));
2918
  }
2919
}
2920
2921
1267778
bool TheoryArithPrivate::solveRelaxationOrPanic(Theory::Effort effortLevel)
2922
{
2923
  // if at this point the linear relaxation is still unknown,
2924
  //  attempt to branch an integer variable as a last ditch effort on full check
2925
1267778
  if (d_qflraStatus == Result::SAT_UNKNOWN)
2926
  {
2927
    d_qflraStatus = selectSimplex(true).findModel(false);
2928
  }
2929
2930
1267778
  if (Theory::fullEffort(effortLevel) && d_qflraStatus == Result::SAT_UNKNOWN)
2931
  {
2932
    ArithVar canBranch = nextIntegerViolation(false);
2933
    if (canBranch != ARITHVAR_SENTINEL)
2934
    {
2935
      ++d_statistics.d_panicBranches;
2936
      TrustNode branch = branchIntegerVariable(canBranch);
2937
      Assert(branch.getNode().getKind() == kind::OR);
2938
      Node rwbranch = Rewriter::rewrite(branch.getNode()[0]);
2939
      if (!isSatLiteral(rwbranch))
2940
      {
2941
        d_approxCuts.push_back(branch);
2942
        return true;
2943
      }
2944
    }
2945
    d_qflraStatus = selectSimplex(false).findModel(true);
2946
  }
2947
1267778
  return false;
2948
}
2949
2950
1267778
bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
2951
2535556
  TimerStat::CodeTimer codeTimer0(d_statistics.d_solveRealRelaxTimer);
2952
1267778
  Assert(d_qflraStatus != Result::SAT);
2953
2954
1267778
  d_partialModel.stopQueueingBoundCounts();
2955
2535556
  UpdateTrackingCallback utcb(&d_linEq);
2956
1267778
  d_partialModel.processBoundsQueue(utcb);
2957
1267778
  d_linEq.startTrackingBoundCounts();
2958
2959
2529119
  bool noPivotLimit = Theory::fullEffort(effortLevel) ||
2960
3790460
    !options::restrictedPivots();
2961
2962
1267778
  SimplexDecisionProcedure& simplex = selectSimplex(true);
2963
2964
1267778
  bool useApprox = options::useApprox() && ApproximateSimplex::enabled() && getSolveIntegerResource();
2965
2966
2535556
  Debug("TheoryArithPrivate::solveRealRelaxation")
2967
1267778
    << "solveRealRelaxation() approx"
2968
2535556
    << " " <<  options::useApprox()
2969
2535556
    << " " << ApproximateSimplex::enabled()
2970
1267778
    << " " << useApprox
2971
2535556
    << " " << safeToCallApprox()
2972
1267778
    << endl;
2973
2974
1267778
  bool noPivotLimitPass1 = noPivotLimit && !useApprox;
2975
1267778
  d_qflraStatus = simplex.findModel(noPivotLimitPass1);
2976
2977
2535556
  Debug("TheoryArithPrivate::solveRealRelaxation")
2978
1267778
    << "solveRealRelaxation()" << " pass1 " << d_qflraStatus << endl;
2979
2980
1267778
  if(d_qflraStatus == Result::SAT_UNKNOWN && useApprox && safeToCallApprox()){
2981
    // pass2: fancy-final
2982
    static const int32_t relaxationLimit = 10000;
2983
    Assert(ApproximateSimplex::enabled());
2984
2985
    TreeLog& tl = getTreeLog();
2986
    ApproximateStatistics& stats = getApproxStats();
2987
    ApproximateSimplex* approxSolver =
2988
      ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel, tl, stats);
2989
2990
    approxSolver->setPivotLimit(relaxationLimit);
2991
2992
    if(!d_guessedCoeffSet){
2993
      d_guessedCoeffs = approxSolver->heuristicOptCoeffs();
2994
      d_guessedCoeffSet = true;
2995
    }
2996
    if(!d_guessedCoeffs.empty()){
2997
      approxSolver->setOptCoeffs(d_guessedCoeffs);
2998
    }
2999
3000
    ++d_statistics.d_relaxCalls;
3001
3002
    ApproximateSimplex::Solution relaxSolution;
3003
    LinResult relaxRes = LinUnknown;
3004
    {
3005
      TimerStat::CodeTimer codeTimer1(d_statistics.d_lpTimer);
3006
      relaxRes = approxSolver->solveRelaxation();
3007
    }
3008
      Debug("solveRealRelaxation") << "solve relaxation? " << endl;
3009
      switch(relaxRes){
3010
      case LinFeasible:
3011
        Debug("solveRealRelaxation") << "lin feasible? " << endl;
3012
        ++d_statistics.d_relaxLinFeas;
3013
        relaxSolution = approxSolver->extractRelaxation();
3014
        importSolution(relaxSolution);
3015
        if(d_qflraStatus != Result::SAT){
3016
          ++d_statistics.d_relaxLinFeasFailures;
3017
        }
3018
        break;
3019
      case LinInfeasible:
3020
        // todo attempt to recreate approximate conflict
3021
        ++d_statistics.d_relaxLinInfeas;
3022
        Debug("solveRealRelaxation") << "lin infeasible " << endl;
3023
        relaxSolution = approxSolver->extractRelaxation();
3024
        importSolution(relaxSolution);
3025
        if(d_qflraStatus != Result::UNSAT){
3026
          ++d_statistics.d_relaxLinInfeasFailures;
3027
        }
3028
        break;
3029
      case LinExhausted:
3030
        ++d_statistics.d_relaxLinExhausted;
3031
        Debug("solveRealRelaxation") << "exhuasted " << endl;
3032
        break;
3033
      case LinUnknown:
3034
      default:
3035
        ++d_statistics.d_relaxOthers;
3036
        break;
3037
      }
3038
    delete approxSolver;
3039
3040
  }
3041
3042
1267778
  bool emmittedConflictOrSplit = solveRelaxationOrPanic(effortLevel);
3043
3044
  // TODO Save zeroes with no conflicts
3045
1267778
  d_linEq.stopTrackingBoundCounts();
3046
1267778
  d_partialModel.startQueueingBoundCounts();
3047
3048
2535556
  return emmittedConflictOrSplit;
3049
}
3050
3051
bool TheoryArithPrivate::hasFreshArithLiteral(Node n) const{
3052
  switch(n.getKind()){
3053
  case kind::LEQ:
3054
  case kind::GEQ:
3055
  case kind::GT:
3056
  case kind::LT:
3057
    return !isSatLiteral(n);
3058
  case kind::EQUAL:
3059
    if(n[0].getType().isReal()){
3060
      return !isSatLiteral(n);
3061
    }else if(n[0].getType().isBoolean()){
3062
      return hasFreshArithLiteral(n[0]) ||
3063
        hasFreshArithLiteral(n[1]);
3064
    }else{
3065
      return false;
3066
    }
3067
  case kind::IMPLIES:
3068
    // try the rhs first
3069
    return hasFreshArithLiteral(n[1]) ||
3070
      hasFreshArithLiteral(n[0]);
3071
  default:
3072
    if(n.getType().isBoolean()){
3073
      for(Node::iterator ni=n.begin(), nend=n.end(); ni!=nend; ++ni){
3074
        Node child = *ni;
3075
        if(hasFreshArithLiteral(child)){
3076
          return true;
3077
        }
3078
      }
3079
    }
3080
    return false;
3081
  }
3082
}
3083
3084
1331402
bool TheoryArithPrivate::preCheck(Theory::Effort level)
3085
{
3086
1331402
  Assert(d_currentPropagationList.empty());
3087
1331402
  if(Debug.isOn("arith::consistency")){
3088
    Assert(unenqueuedVariablesAreConsistent());
3089
  }
3090
3091
1331402
  d_newFacts = !done();
3092
  // If d_previousStatus == SAT, then reverts on conflicts are safe
3093
  // Otherwise, they are not and must be committed.
3094
1331402
  d_previousStatus = d_qflraStatus;
3095
1331402
  if (d_newFacts)
3096
  {
3097
1277793
    d_qflraStatus = Result::SAT_UNKNOWN;
3098
1277793
    d_hasDoneWorkSinceCut = true;
3099
  }
3100
1331402
  return false;
3101
}
3102
3103
5005301
void TheoryArithPrivate::preNotifyFact(TNode atom, bool pol, TNode fact)
3104
{
3105
5005301
  ConstraintP curr = constraintFromFactQueue(fact);
3106
5005301
  if (curr != NullConstraint)
3107
  {
3108
4824333
    bool res CVC5_UNUSED = assertionCases(curr);
3109
4824333
    Assert(!res || anyConflict());
3110
  }
3111
5005301
}
3112
3113
1328373
bool TheoryArithPrivate::postCheck(Theory::Effort effortLevel)
3114
{
3115
1328373
  if(!anyConflict()){
3116
1519928
    while(!d_learnedBounds.empty()){
3117
      // we may attempt some constraints twice.  this is okay!
3118
102251
      ConstraintP curr = d_learnedBounds.front();
3119
102251
      d_learnedBounds.pop();
3120
102251
      Debug("arith::learned") << curr << endl;
3121
3122
102251
      bool res CVC5_UNUSED = assertionCases(curr);
3123
102251
      Assert(!res || anyConflict());
3124
3125
102251
      if(anyConflict()){ break; }
3126
    }
3127
  }
3128
3129
1328373
  if(anyConflict()){
3130
12902
    d_qflraStatus = Result::UNSAT;
3131
25804
    if (options::revertArithModels() && d_previousStatus == Result::SAT)
3132
    {
3133
      ++d_statistics.d_revertsOnConflicts;
3134
      Debug("arith::bt") << "clearing here "
3135
                         << " " << d_newFacts << " " << d_previousStatus << " "
3136
                         << d_qflraStatus << endl;
3137
      revertOutOfConflict();
3138
      d_errorSet.clear();
3139
    }else{
3140
12902
      ++d_statistics.d_commitsOnConflicts;
3141
25804
      Debug("arith::bt") << "committing here "
3142
12902
                         << " " << d_newFacts << " " << d_previousStatus << " "
3143
12902
                         << d_qflraStatus << endl;
3144
12902
      d_partialModel.commitAssignmentChanges();
3145
12902
      revertOutOfConflict();
3146
    }
3147
12902
    outputConflicts();
3148
    //cout << "unate conflict 1 " << effortLevel << std::endl;
3149
12902
    return true;
3150
  }
3151
3152
3153
1315471
  if(Debug.isOn("arith::print_assertions")) {
3154
    debugPrintAssertions(Debug("arith::print_assertions"));
3155
  }
3156
3157
1315471
  bool emmittedConflictOrSplit = false;
3158
1315471
  Assert(d_conflicts.empty());
3159
3160
1315471
  bool useSimplex = d_qflraStatus != Result::SAT;
3161
2630942
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3162
1315471
                      << "pre realRelax" << endl;
3163
3164
1315471
  if(useSimplex){
3165
1267778
    emmittedConflictOrSplit = solveRealRelaxation(effortLevel);
3166
  }
3167
2630942
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3168
1315471
                      << "post realRelax" << endl;
3169
3170
3171
2630942
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3172
1315471
                      << "pre solveInteger" << endl;
3173
3174
1315471
  if(attemptSolveInteger(effortLevel, emmittedConflictOrSplit)){
3175
    solveInteger(effortLevel);
3176
    if(anyConflict()){
3177
      ++d_statistics.d_commitsOnConflicts;
3178
      Debug("arith::bt") << "committing here "
3179
                         << " " << d_newFacts << " " << d_previousStatus << " "
3180
                         << d_qflraStatus << endl;
3181
      revertOutOfConflict();
3182
      d_errorSet.clear();
3183
      outputConflicts();
3184
      return true;
3185
    }
3186
  }
3187
3188
2630942
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3189
1315471
                      << "post solveInteger" << endl;
3190
3191
1315471
  switch(d_qflraStatus){
3192
1279043
  case Result::SAT:
3193
1279043
    if (d_newFacts)
3194
    {
3195
1228463
      ++d_statistics.d_nontrivialSatChecks;
3196
    }
3197
3198
2558086
    Debug("arith::bt") << "committing sap inConflit"
3199
1279043
                       << " " << d_newFacts << " " << d_previousStatus << " "
3200
1279043
                       << d_qflraStatus << endl;
3201
1279043
    d_partialModel.commitAssignmentChanges();
3202
1279043
    d_unknownsInARow = 0;
3203
1279043
    if(Debug.isOn("arith::consistency")){
3204
      Assert(entireStateIsConsistent("sat comit"));
3205
    }
3206
2546821
    if(useSimplex && options::collectPivots()){
3207
      if(options::useFC()){
3208
        d_statistics.d_satPivots << d_fcSimplex.getPivots();
3209
      }else{
3210
        d_statistics.d_satPivots << d_dualSimplex.getPivots();
3211
      }
3212
    }
3213
1279043
    break;
3214
  case Result::SAT_UNKNOWN:
3215
    ++d_unknownsInARow;
3216
    ++(d_statistics.d_unknownChecks);
3217
    Assert(!Theory::fullEffort(effortLevel));
3218
    Debug("arith::bt") << "committing unknown"
3219
                       << " " << d_newFacts << " " << d_previousStatus << " "
3220
                       << d_qflraStatus << endl;
3221
    d_partialModel.commitAssignmentChanges();
3222
    d_statistics.d_maxUnknownsInARow.maxAssign(d_unknownsInARow);
3223
3224
    if(useSimplex && options::collectPivots()){
3225
      if(options::useFC()){
3226
        d_statistics.d_unknownPivots << d_fcSimplex.getPivots();
3227
      }else{
3228
        d_statistics.d_unknownPivots << d_dualSimplex.getPivots();
3229
      }
3230
    }
3231
    break;
3232
36428
  case Result::UNSAT:
3233
36428
    d_unknownsInARow = 0;
3234
3235
36428
    ++d_statistics.d_commitsOnConflicts;
3236
3237
72856
    Debug("arith::bt") << "committing on conflict"
3238
36428
                       << " " << d_newFacts << " " << d_previousStatus << " "
3239
36428
                       << d_qflraStatus << endl;
3240
36428
    d_partialModel.commitAssignmentChanges();
3241
36428
    revertOutOfConflict();
3242
3243
36428
    if(Debug.isOn("arith::consistency::comitonconflict")){
3244
      entireStateIsConsistent("commit on conflict");
3245
    }
3246
36428
    outputConflicts();
3247
36428
    emmittedConflictOrSplit = true;
3248
36428
    Debug("arith::conflict") << "simplex conflict" << endl;
3249
3250
36428
    if(useSimplex && options::collectPivots()){
3251
      if(options::useFC()){
3252
        d_statistics.d_unsatPivots << d_fcSimplex.getPivots();
3253
      }else{
3254
        d_statistics.d_unsatPivots << d_dualSimplex.getPivots();
3255
      }
3256
    }
3257
36428
    break;
3258
  default:
3259
    Unimplemented();
3260
  }
3261
1315471
  d_statistics.d_avgUnknownsInARow << d_unknownsInARow;
3262
3263
  size_t nPivots =
3264
1315471
      options::useFC() ? d_fcSimplex.getPivots() : d_dualSimplex.getPivots();
3265
1512335
  for (std::size_t i = 0; i < nPivots; ++i)
3266
  {
3267
393728
    d_containing.d_out->spendResource(
3268
196864
        Resource::ArithPivotStep);
3269
  }
3270
3271
2630942
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3272
1315471
                      << "pre approx cuts" << endl;
3273
1315471
  if(!d_approxCuts.empty()){
3274
    bool anyFresh = false;
3275
    while(!d_approxCuts.empty()){
3276
      TrustNode lem = d_approxCuts.front();
3277
      d_approxCuts.pop();
3278
      Debug("arith::approx::cuts") << "approximate cut:" << lem << endl;
3279
      anyFresh = anyFresh || hasFreshArithLiteral(lem.getNode());
3280
      Debug("arith::lemma") << "approximate cut:" << lem << endl;
3281
      outputTrustedLemma(lem, InferenceId::ARITH_APPROX_CUT);
3282
    }
3283
    if(anyFresh){
3284
      emmittedConflictOrSplit = true;
3285
    }
3286
  }
3287
3288
2630942
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3289
1315471
                      << "post approx cuts" << endl;
3290
3291
  // This should be fine if sat or unknown
3292
2630942
  if (!emmittedConflictOrSplit
3293
9434438
      && (options::arithPropagationMode()
3294
              == options::ArithPropagationMode::UNATE_PROP
3295
1279043
          || options::arithPropagationMode()
3296
                 == options::ArithPropagationMode::BOTH_PROP))
3297
  {
3298
2558086
    TimerStat::CodeTimer codeTimer0(d_statistics.d_newPropTime);
3299
1279043
    Assert(d_qflraStatus != Result::UNSAT);
3300
3301
6494507
    while(!d_currentPropagationList.empty()  && !anyConflict()){
3302
2607732
      ConstraintP curr = d_currentPropagationList.front();
3303
2607732
      d_currentPropagationList.pop_front();
3304
3305
2607732
      ConstraintType t = curr->getType();
3306
2607732
      Assert(t != Disequality)
3307
          << "Disequalities are not allowed in d_currentPropagation";
3308
3309
2607732
      switch(t){
3310
1017227
      case LowerBound:
3311
        {
3312
1017227
          ConstraintP prev = d_currentPropagationList.front();
3313
1017227
          d_currentPropagationList.pop_front();
3314
1017227
          d_constraintDatabase.unatePropLowerBound(curr, prev);
3315
1017227
          break;
3316
        }
3317
941139
      case UpperBound:
3318
        {
3319
941139
          ConstraintP prev = d_currentPropagationList.front();
3320
941139
          d_currentPropagationList.pop_front();
3321
941139
          d_constraintDatabase.unatePropUpperBound(curr, prev);
3322
941139
          break;
3323
        }
3324
649366
      case Equality:
3325
        {
3326
649366
          ConstraintP prevLB = d_currentPropagationList.front();
3327
649366
          d_currentPropagationList.pop_front();
3328
649366
          ConstraintP prevUB = d_currentPropagationList.front();
3329
649366
          d_currentPropagationList.pop_front();
3330
649366
          d_constraintDatabase.unatePropEquality(curr, prevLB, prevUB);
3331
649366
          break;
3332
        }
3333
        default: Unhandled() << curr->getType();
3334
      }
3335
    }
3336
3337
1279043
    if(anyConflict()){
3338
      Debug("arith::unate") << "unate conflict" << endl;
3339
      revertOutOfConflict();
3340
      d_qflraStatus = Result::UNSAT;
3341
      outputConflicts();
3342
      emmittedConflictOrSplit = true;
3343
      //cout << "unate conflict " << endl;
3344
      Debug("arith::bt") << "committing on unate conflict"
3345
                         << " " << d_newFacts << " " << d_previousStatus << " "
3346
                         << d_qflraStatus << endl;
3347
3348
      Debug("arith::conflict") << "unate arith conflict" << endl;
3349
    }
3350
  }
3351
  else
3352
  {
3353
72856
    TimerStat::CodeTimer codeTimer1(d_statistics.d_newPropTime);
3354
36428
    d_currentPropagationList.clear();
3355
  }
3356
1315471
  Assert(d_currentPropagationList.empty());
3357
3358
2630942
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3359
1315471
                      << "post unate" << endl;
3360
3361
1315471
  if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel)){
3362
50856
    ++d_fullCheckCounter;
3363
  }
3364
1315471
  if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel)){
3365
50856
    emmittedConflictOrSplit = splitDisequalities();
3366
  }
3367
2630942
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3368
1315471
                      << "pos splitting" << endl;
3369
3370
3371
2630942
  Debug("arith") << "integer? "
3372
1315471
       << " conf/split " << emmittedConflictOrSplit
3373
2630942
       << " fulleffort " << Theory::fullEffort(effortLevel)
3374
1315471
       << " hasintmodel " << hasIntegerModel() << endl;
3375
3376
1315471
  if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel) && !hasIntegerModel()){
3377
5226
    Node possibleConflict = Node::null();
3378
7692
    if(!emmittedConflictOrSplit && options::arithDioSolver()){
3379
2613
      possibleConflict = callDioSolver();
3380
2613
      if(possibleConflict != Node::null()){
3381
147
        revertOutOfConflict();
3382
147
        Debug("arith::conflict") << "dio conflict   " << possibleConflict << endl;
3383
        // TODO (project #37): justify (proofs in the DIO solver)
3384
147
        raiseBlackBoxConflict(possibleConflict);
3385
147
        outputConflicts();
3386
147
        emmittedConflictOrSplit = true;
3387
      }
3388
    }
3389
3390
2613
    if(!emmittedConflictOrSplit && d_hasDoneWorkSinceCut && options::arithDioSolver()){
3391
2466
      if(getDioCuttingResource()){
3392
3640
        TrustNode possibleLemma = dioCutting();
3393
1820
        if(!possibleLemma.isNull()){
3394
1370
          emmittedConflictOrSplit = true;
3395
1370
          d_hasDoneWorkSinceCut = false;
3396
1370
          d_cutCount = d_cutCount + 1;
3397
1370
          Debug("arith::lemma") << "dio cut   " << possibleLemma << endl;
3398
1370
          outputTrustedLemma(possibleLemma, InferenceId::ARITH_DIO_CUT);
3399
        }
3400
      }
3401
    }
3402
3403
2613
    if(!emmittedConflictOrSplit) {
3404
2192
      TrustNode possibleLemma = roundRobinBranch();
3405
1096
      if (!possibleLemma.getNode().isNull())
3406
      {
3407
1096
        ++(d_statistics.d_externalBranchAndBounds);
3408
1096
        d_cutCount = d_cutCount + 1;
3409
1096
        emmittedConflictOrSplit = true;
3410
2192
        Debug("arith::lemma") << "rrbranch lemma"
3411
1096
                              << possibleLemma << endl;
3412
1096
        outputTrustedLemma(possibleLemma, InferenceId::ARITH_BB_LEMMA);
3413
      }
3414
    }
3415
3416
5226
    if(options::maxCutsInContext() <= d_cutCount){
3417
      if(d_diosolver.hasMoreDecompositionLemmas()){
3418
        while(d_diosolver.hasMoreDecompositionLemmas()){
3419
          Node decompositionLemma = d_diosolver.nextDecompositionLemma();
3420
          Debug("arith::lemma") << "dio decomposition lemma "
3421
                                << decompositionLemma << endl;
3422
          outputLemma(decompositionLemma, InferenceId::ARITH_DIO_DECOMPOSITION);
3423
        }
3424
      }else{
3425
        Debug("arith::restart") << "arith restart!" << endl;
3426
        outputRestart();
3427
      }
3428
    }
3429
  }//if !emmittedConflictOrSplit && fullEffort(effortLevel) && !hasIntegerModel()
3430
3431
1315471
  if(Theory::fullEffort(effortLevel)){
3432
54130
    if(Debug.isOn("arith::consistency::final")){
3433
      entireStateIsConsistent("arith::consistency::final");
3434
    }
3435
  }
3436
3437
1315471
  if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
3438
1315471
  if(Debug.isOn("arith::print_model")) {
3439
    debugPrintModel(Debug("arith::print_model"));
3440
  }
3441
1315471
  Debug("arith") << "TheoryArithPrivate::check end" << std::endl;
3442
1315471
  return emmittedConflictOrSplit;
3443
}
3444
3445
21672
bool TheoryArithPrivate::foundNonlinear() const { return d_foundNl; }
3446
3447
1096
TrustNode TheoryArithPrivate::branchIntegerVariable(ArithVar x) const
3448
{
3449
1096
  const DeltaRational& d = d_partialModel.getAssignment(x);
3450
1096
  Assert(!d.isIntegral());
3451
1096
  const Rational& r = d.getNoninfinitesimalPart();
3452
1096
  const Rational& i = d.getInfinitesimalPart();
3453
1096
  Trace("integers") << "integers: assignment to [[" << d_partialModel.asNode(x) << "]] is " << r << "[" << i << "]" << endl;
3454
3455
1096
  Assert(!(r.getDenominator() == 1 && i.getNumerator() == 0));
3456
1096
  Assert(!d.isIntegral());
3457
2192
  TNode var = d_partialModel.asNode(x);
3458
2192
  Integer floor_d = d.floor();
3459
3460
1096
  TrustNode lem = TrustNode::null();
3461
1096
  NodeManager* nm = NodeManager::currentNM();
3462
2196
  if (options::brabTest())
3463
  {
3464
1092
    Trace("integers") << "branch-round-and-bound enabled" << endl;
3465
2184
    Integer ceil_d = d.ceiling();
3466
2184
    Rational f = r - floor_d;
3467
    // Multiply by -1 to get abs value.
3468
2184
    Rational c = (r - ceil_d) * (-1);
3469
2184
    Integer nearest = (c > f) ? floor_d : ceil_d;
3470
3471
    // Prioritize trying a simple rounding of the real solution first,
3472
    // it that fails, fall back on original branch and bound strategy.
3473
    Node ub = Rewriter::rewrite(
3474
2184
        nm->mkNode(kind::LEQ, var, mkRationalNode(nearest - 1)));
3475
    Node lb = Rewriter::rewrite(
3476
2184
        nm->mkNode(kind::GEQ, var, mkRationalNode(nearest + 1)));
3477
2184
    Node right = nm->mkNode(kind::OR, ub, lb);
3478
2184
    Node rawEq = nm->mkNode(kind::EQUAL, var, mkRationalNode(nearest));
3479
2184
    Node eq = Rewriter::rewrite(rawEq);
3480
    // Also preprocess it before we send it out. This is important since
3481
    // arithmetic may prefer eliminating equalities.
3482
2184
    TrustNode teq;
3483
1092
    if (Theory::theoryOf(eq) == THEORY_ARITH)
3484
    {
3485
973
      teq = d_containing.ppRewriteEq(eq);
3486
973
      eq = teq.isNull() ? eq : teq.getNode();
3487
    }
3488
2184
    Node literal = d_containing.getValuation().ensureLiteral(eq);
3489
1092
    Trace("integers") << "eq: " << eq << "\nto: " << literal << endl;
3490
1092
    d_containing.getOutputChannel().requirePhase(literal, true);
3491
2184
    Node l = nm->mkNode(kind::OR, literal, right);
3492
1092
    Trace("integers") << "l: " << l << endl;
3493
1092
    if (proofsEnabled())
3494
    {
3495
244
      Node less = nm->mkNode(kind::LT, var, mkRationalNode(nearest));
3496
244
      Node greater = nm->mkNode(kind::GT, var, mkRationalNode(nearest));
3497
      // TODO (project #37): justify. Thread proofs through *ensureLiteral*.
3498
122
      Debug("integers::pf") << "less: " << less << endl;
3499
122
      Debug("integers::pf") << "greater: " << greater << endl;
3500
122
      Debug("integers::pf") << "literal: " << literal << endl;
3501
122
      Debug("integers::pf") << "eq: " << eq << endl;
3502
122
      Debug("integers::pf") << "rawEq: " << rawEq << endl;
3503
244
      Pf pfNotLit = d_pnm->mkAssume(literal.negate());
3504
      // rewrite notLiteral to notRawEq, using teq.
3505
      Pf pfNotRawEq =
3506
122
          literal == rawEq
3507
              ? pfNotLit
3508
              : d_pnm->mkNode(
3509
                  PfRule::MACRO_SR_PRED_TRANSFORM,
3510
122
                  {pfNotLit, teq.getGenerator()->getProofFor(teq.getProven())},
3511
366
                  {rawEq.negate()});
3512
      Pf pfBot =
3513
122
          d_pnm->mkNode(PfRule::CONTRA,
3514
122
                        {d_pnm->mkNode(PfRule::ARITH_TRICHOTOMY,
3515
244
                                       {d_pnm->mkAssume(less.negate()), pfNotRawEq},
3516
366
                                       {greater}),
3517
244
                         d_pnm->mkAssume(greater.negate())},
3518
1098
                        {});
3519
      std::vector<Node> assumptions = {
3520
244
          literal.negate(), less.negate(), greater.negate()};
3521
      // Proof of (not (and (not (= v i)) (not (< v i)) (not (> v i))))
3522
244
      Pf pfNotAnd = d_pnm->mkScope(pfBot, assumptions);
3523
122
      Pf pfL = d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
3524
244
                             {d_pnm->mkNode(PfRule::NOT_AND, {pfNotAnd}, {})},
3525
488
                             {l});
3526
122
      lem = d_pfGen->mkTrustNode(l, pfL);
3527
    }
3528
    else
3529
    {
3530
970
      lem = TrustNode::mkTrustLemma(l, nullptr);
3531
    }
3532
  }
3533
  else
3534
  {
3535
    Node ub =
3536
8
        Rewriter::rewrite(nm->mkNode(kind::LEQ, var, mkRationalNode(floor_d)));
3537
8
    Node lb = ub.notNode();
3538
4
    if (proofsEnabled())
3539
    {
3540
      lem = d_pfGen->mkTrustNode(
3541
          nm->mkNode(kind::OR, ub, lb), PfRule::SPLIT, {}, {ub});
3542
    }
3543
    else
3544
    {
3545
4
      lem = TrustNode::mkTrustLemma(nm->mkNode(kind::OR, ub, lb), nullptr);
3546
    }
3547
  }
3548
3549
1096
  Trace("integers") << "integers: branch & bound: " << lem << endl;
3550
1096
  if (Debug.isOn("integers"))
3551
  {
3552
    Node l = lem.getNode();
3553
    if (isSatLiteral(l[0]))
3554
    {
3555
      Debug("integers") << "    " << l[0] << " == " << getSatValue(l[0])
3556
                        << endl;
3557
    }
3558
    else
3559
    {
3560
      Debug("integers") << "    " << l[0] << " is not assigned a SAT literal"
3561
                        << endl;
3562
    }
3563
    if (isSatLiteral(l[1]))
3564
    {
3565
      Debug("integers") << "    " << l[1] << " == " << getSatValue(l[1])
3566
                        << endl;
3567
    }
3568
    else
3569
    {
3570
      Debug("integers") << "    " << l[1] << " is not assigned a SAT literal"
3571
                        << endl;
3572
    }
3573
  }
3574
2192
  return lem;
3575
}
3576
3577
std::vector<ArithVar> TheoryArithPrivate::cutAllBounded() const{
3578
  vector<ArithVar> lemmas;
3579
  ArithVar max = d_partialModel.getNumberOfVariables();
3580
3581
  if(options::doCutAllBounded() && max > 0){
3582
    for(ArithVar iter = 0; iter != max; ++iter){
3583
    //Do not include slack variables
3584
      const DeltaRational& d = d_partialModel.getAssignment(iter);
3585
      if(isIntegerInput(iter) &&
3586
         !d_cutInContext.contains(iter) &&
3587
         d_partialModel.hasUpperBound(iter) &&
3588
         d_partialModel.hasLowerBound(iter) &&
3589
         !d.isIntegral()){
3590
        lemmas.push_back(iter);
3591
      }
3592
    }
3593
  }
3594
  return lemmas;
3595
}
3596
3597
/** Returns true if the roundRobinBranching() issues a lemma. */
3598
1096
TrustNode TheoryArithPrivate::roundRobinBranch()
3599
{
3600
1096
  if(hasIntegerModel()){
3601
    return TrustNode::null();
3602
  }else{
3603
1096
    ArithVar v = d_nextIntegerCheckVar;
3604
3605
1096
    Assert(isInteger(v));
3606
1096
    Assert(!isAuxiliaryVariable(v));
3607
1096
    return branchIntegerVariable(v);
3608
  }
3609
}
3610
3611
50856
bool TheoryArithPrivate::splitDisequalities(){
3612
50856
  bool splitSomething = false;
3613
3614
101712
  vector<ConstraintP> save;
3615
3616
366862
  while(!d_diseqQueue.empty()){
3617
158003
    ConstraintP front = d_diseqQueue.front();
3618
158003
    d_diseqQueue.pop();
3619
3620
158003
    if(front->isSplit()){
3621
161
      Debug("arith::eq") << "split already" << endl;
3622
    }else{
3623
157842
      Debug("arith::eq") << "not split already" << endl;
3624
3625
157842
      ArithVar lhsVar = front->getVariable();
3626
3627
157842
      const DeltaRational& lhsValue = d_partialModel.getAssignment(lhsVar);
3628
157842
      const DeltaRational& rhsValue = front->getValue();
3629
157842
      if(lhsValue == rhsValue){
3630
189
        Debug("arith::lemma") << "Splitting on " << front << endl;
3631
189
        Debug("arith::lemma") << "LHS value = " << lhsValue << endl;
3632
189
        Debug("arith::lemma") << "RHS value = " << rhsValue << endl;
3633
378
        TrustNode lemma = front->split();
3634
189
        ++(d_statistics.d_statDisequalitySplits);
3635
3636
378
        Debug("arith::lemma")
3637
189
            << "Now " << Rewriter::rewrite(lemma.getNode()) << endl;
3638
189
        outputTrustedLemma(lemma, InferenceId::ARITH_SPLIT_DEQ);
3639
        //cout << "Now " << Rewriter::rewrite(lemma) << endl;
3640
189
        splitSomething = true;
3641
157653
      }else if(d_partialModel.strictlyLessThanLowerBound(lhsVar, rhsValue)){
3642
30434
        Debug("arith::eq") << "can drop as less than lb" << front << endl;
3643
127219
      }else if(d_partialModel.strictlyGreaterThanUpperBound(lhsVar, rhsValue)){
3644
19060
        Debug("arith::eq") << "can drop as greater than ub" << front << endl;
3645
      }else{
3646
108159
        Debug("arith::eq") << "save" << front << ": " <<lhsValue << " != " << rhsValue << endl;
3647
108159
        save.push_back(front);
3648
      }
3649
    }
3650
  }
3651
50856
  vector<ConstraintP>::const_iterator i=save.begin(), i_end = save.end();
3652
267174
  for(; i != i_end; ++i){
3653
108159
    d_diseqQueue.push(*i);
3654
  }
3655
101712
  return splitSomething;
3656
}
3657
3658
/**
3659
 * Should be guarded by at least Debug.isOn("arith::print_assertions").
3660
 * Prints to Debug("arith::print_assertions")
3661
 */
3662
void TheoryArithPrivate::debugPrintAssertions(std::ostream& out) const {
3663
  out << "Assertions:" << endl;
3664
  for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
3665
    ArithVar i = *vi;
3666
    if (d_partialModel.hasLowerBound(i)) {
3667
      ConstraintP lConstr = d_partialModel.getLowerBoundConstraint(i);
3668
      out << lConstr << endl;
3669
    }
3670
3671
    if (d_partialModel.hasUpperBound(i)) {
3672
      ConstraintP uConstr = d_partialModel.getUpperBoundConstraint(i);
3673
      out << uConstr << endl;
3674
    }
3675
  }
3676
  context::CDQueue<ConstraintP>::const_iterator it = d_diseqQueue.begin();
3677
  context::CDQueue<ConstraintP>::const_iterator it_end = d_diseqQueue.end();
3678
  for(; it != it_end; ++ it) {
3679
    out << *it << endl;
3680
  }
3681
}
3682
3683
void TheoryArithPrivate::debugPrintModel(std::ostream& out) const{
3684
  out << "Model:" << endl;
3685
  for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
3686
    ArithVar i = *vi;
3687
    if(d_partialModel.hasNode(i)){
3688
      out << d_partialModel.asNode(i) << " : " <<
3689
        d_partialModel.getAssignment(i);
3690
      if(d_tableau.isBasic(i)){
3691
        out << " (basic)";
3692
      }
3693
      out << endl;
3694
    }
3695
  }
3696
}
3697
3698
21670
TrustNode TheoryArithPrivate::explain(TNode n)
3699
{
3700
21670
  Debug("arith::explain") << "explain @" << getSatContext()->getLevel() << ": " << n << endl;
3701
3702
21670
  ConstraintP c = d_constraintDatabase.lookup(n);
3703
21670
  TrustNode exp;
3704
21670
  if(c != NullConstraint){
3705
8423
    Assert(!c->isAssumption());
3706
8423
    exp = c->externalExplainForPropagation(n);
3707
8423
    Debug("arith::explain") << "constraint explanation" << n << ":" << exp << endl;
3708
13247
  }else if(d_assertionsThatDoNotMatchTheirLiterals.find(n) != d_assertionsThatDoNotMatchTheirLiterals.end()){
3709
9648
    c = d_assertionsThatDoNotMatchTheirLiterals[n];
3710
9648
    if(!c->isAssumption()){
3711
2893
      exp = c->externalExplainForPropagation(n);
3712
2893
      Debug("arith::explain") << "assertions explanation" << n << ":" << exp << endl;
3713
    }else{
3714
6755
      Debug("arith::explain") << "this is a strange mismatch" << n << endl;
3715
6755
      Assert(d_congruenceManager.canExplain(n));
3716
6755
      exp = d_congruenceManager.explain(n);
3717
    }
3718
  }else{
3719
3599
    Assert(d_congruenceManager.canExplain(n));
3720
3599
    Debug("arith::explain") << "dm explanation" << n << endl;
3721
3599
    exp = d_congruenceManager.explain(n);
3722
  }
3723
21670
  return exp;
3724
}
3725
3726
2163161
void TheoryArithPrivate::propagate(Theory::Effort e) {
3727
  // This uses model values for safety. Disable for now.
3728
4326322
  if (d_qflraStatus == Result::SAT
3729
2140919
      && (options::arithPropagationMode()
3730
              == options::ArithPropagationMode::BOUND_INFERENCE_PROP
3731
2140919
          || options::arithPropagationMode()
3732
                 == options::ArithPropagationMode::BOTH_PROP)
3733
4304080
      && hasAnyUpdates())
3734
  {
3735
1615816
    if(options::newProp()){
3736
805352
      propagateCandidatesNew();
3737
    }else{
3738
2552
      propagateCandidates();
3739
    }
3740
  }
3741
  else
3742
  {
3743
1355257
    clearUpdates();
3744
  }
3745
3746
3251051
  while(d_constraintDatabase.hasMorePropagations()){
3747
543945
    ConstraintCP c = d_constraintDatabase.nextPropagation();
3748
543945
    Debug("arith::prop") << "next prop" << getSatContext()->getLevel() << ": " << c << endl;
3749
3750
543945
    if(c->negationHasProof()){
3751
      Debug("arith::prop") << "negation has proof " << c->getNegation() << endl;
3752
      Debug("arith::prop") << c->getNegation()->externalExplainByAssertions()
3753
                           << endl;
3754
    }
3755
543945
    Assert(!c->negationHasProof())
3756
        << "A constraint has been propagated on the constraint propagation "
3757
           "queue, but the negation has been set to true.  Contact Tim now!";
3758
3759
543945
    if(!c->assertedToTheTheory()){
3760
1059052
      Node literal = c->getLiteral();
3761
529526
      Debug("arith::prop") << "propagating @" << getSatContext()->getLevel() << " " << literal << endl;
3762
3763
529526
      outputPropagate(literal);
3764
    }else{
3765
14419
      Debug("arith::prop") << "already asserted to the theory " <<  c->getLiteral() << endl;
3766
    }
3767
  }
3768
3769
3093167
  while(d_congruenceManager.hasMorePropagations()){
3770
930006
    TNode toProp = d_congruenceManager.getNextPropagation();
3771
3772
    //Currently if the flag is set this came from an equality detected by the
3773
    //equality engine in the the difference manager.
3774
930006
    Node normalized = Rewriter::rewrite(toProp);
3775
3776
465003
    ConstraintP constraint = d_constraintDatabase.lookup(normalized);
3777
465003
    if(constraint == NullConstraint){
3778
100
      Debug("arith::prop") << "propagating on non-constraint? "  << toProp << endl;
3779
3780
100
      outputPropagate(toProp);
3781
464903
    }else if(constraint->negationHasProof()){
3782
      // The congruence manager can prove: antecedents => toProp,
3783
      // ergo. antecedents ^ ~toProp is a conflict.
3784
      TrustNode exp = d_congruenceManager.explain(toProp);
3785
      Node notNormalized = normalized.negate();
3786
      std::vector<Node> ants(exp.getNode().begin(), exp.getNode().end());
3787
      ants.push_back(notNormalized);
3788
      Node lp = safeConstructNary(kind::AND, ants);
3789
      Debug("arith::prop") << "propagate conflict" <<  lp << endl;
3790
      if (proofsEnabled())
3791
      {
3792
        // Assume all of antecedents and ~toProp (rewritten)
3793
        std::vector<Pf> pfAntList;
3794
        for (size_t i = 0; i < ants.size(); ++i)
3795
        {
3796
          pfAntList.push_back(d_pnm->mkAssume(ants[i]));
3797
        }
3798
        Pf pfAnt = pfAntList.size() > 1
3799
                       ? d_pnm->mkNode(PfRule::AND_INTRO, pfAntList, {})
3800
                       : pfAntList[0];
3801
        // Use modus ponens to get toProp (un rewritten)
3802
        Pf pfConc = d_pnm->mkNode(
3803
            PfRule::MODUS_PONENS,
3804
            {pfAnt, exp.getGenerator()->getProofFor(exp.getProven())},
3805
            {});
3806
        // prove toProp (rewritten)
3807
        Pf pfConcRewritten = d_pnm->mkNode(
3808
            PfRule::MACRO_SR_PRED_TRANSFORM, {pfConc}, {normalized});
3809
        Pf pfNotNormalized = d_pnm->mkAssume(notNormalized);
3810
        // prove bottom from toProp and ~toProp
3811
        Pf pfBot;
3812
        if (normalized.getKind() == kind::NOT)
3813
        {
3814
          pfBot = d_pnm->mkNode(
3815
              PfRule::CONTRA, {pfNotNormalized, pfConcRewritten}, {});
3816
        }
3817
        else
3818
        {
3819
          pfBot = d_pnm->mkNode(
3820
              PfRule::CONTRA, {pfConcRewritten, pfNotNormalized}, {});
3821
        }
3822
        // close scope
3823
        Pf pfNotAnd = d_pnm->mkScope(pfBot, ants);
3824
        raiseBlackBoxConflict(lp, pfNotAnd);
3825
      }
3826
      else
3827
      {
3828
        raiseBlackBoxConflict(lp);
3829
      }
3830
      outputConflicts();
3831
      return;
3832
    }else{
3833
464903
      Debug("arith::prop") << "propagating still?" <<  toProp << endl;
3834
464903
      outputPropagate(toProp);
3835
    }
3836
  }
3837
}
3838
3839
5442285
DeltaRational TheoryArithPrivate::getDeltaValue(TNode term) const
3840
{
3841
5442285
  AlwaysAssert(d_qflraStatus != Result::SAT_UNKNOWN);
3842
5442285
  Debug("arith::value") << term << std::endl;
3843
3844
5442285
  if (d_partialModel.hasArithVar(term)) {
3845
1734696
    ArithVar var = d_partialModel.asArithVar(term);
3846
1734696
    return d_partialModel.getAssignment(var);
3847
  }
3848
3849
3707589
  switch (Kind kind = term.getKind()) {
3850
2056229
    case kind::CONST_RATIONAL:
3851
2056229
      return term.getConst<Rational>();
3852
3853
1184115
    case kind::PLUS: {  // 2+ args
3854
2368230
      DeltaRational value(0);
3855
3820750
      for (TNode::iterator i = term.begin(), iend = term.end(); i != iend;
3856
           ++i) {
3857
2636635
        value = value + getDeltaValue(*i);
3858
      }
3859
1184115
      return value;
3860
    }
3861
3862
467245
    case kind::NONLINEAR_MULT:
3863
    case kind::MULT: {  // 2+ args
3864
467245
      Assert(!isSetup(term));
3865
934490
      DeltaRational value(1);
3866
1401735
      for (TNode::iterator i = term.begin(), iend = term.end(); i != iend;
3867
           ++i) {
3868
934490
        value = value * getDeltaValue(*i);
3869
      }
3870
467245
      return value;
3871
    }
3872
    case kind::MINUS: {  // 2 args
3873
      return getDeltaValue(term[0]) - getDeltaValue(term[1]);
3874
    }
3875
    case kind::UMINUS: {  // 1 arg
3876
      return (-getDeltaValue(term[0]));
3877
    }
3878
3879
    case kind::DIVISION: {  // 2 args
3880
      Assert(!isSetup(term));
3881
      return getDeltaValue(term[0]) / getDeltaValue(term[1]);
3882
    }
3883
    case kind::DIVISION_TOTAL:
3884
    case kind::INTS_DIVISION_TOTAL:
3885
    case kind::INTS_MODULUS_TOTAL: {  // 2 args
3886
      Assert(!isSetup(term));
3887
      DeltaRational denominator = getDeltaValue(term[1]);
3888
      if (denominator.isZero()) {
3889
        return DeltaRational(0, 0);
3890
      }
3891
      DeltaRational numerator = getDeltaValue(term[0]);
3892
      if (kind == kind::DIVISION_TOTAL) {
3893
        return numerator / denominator;
3894
      } else if (kind == kind::INTS_DIVISION_TOTAL) {
3895
        return Rational(numerator.euclidianDivideQuotient(denominator));
3896
      } else {
3897
        Assert(kind == kind::INTS_MODULUS_TOTAL);
3898
        return Rational(numerator.euclidianDivideRemainder(denominator));
3899
      }
3900
    }
3901
3902
    default:
3903
      throw ModelException(term, "No model assignment.");
3904
  }
3905
}
3906
3907
11891
Rational TheoryArithPrivate::deltaValueForTotalOrder() const{
3908
23782
  Rational min(2);
3909
23782
  std::set<DeltaRational> relevantDeltaValues;
3910
11891
  context::CDQueue<ConstraintP>::const_iterator qiter = d_diseqQueue.begin();
3911
11891
  context::CDQueue<ConstraintP>::const_iterator qiter_end = d_diseqQueue.end();
3912
3913
61235
  for(; qiter != qiter_end; ++qiter){
3914
24672
    ConstraintP curr = *qiter;
3915
3916
24672
    const DeltaRational& rhsValue = curr->getValue();
3917
24672
    relevantDeltaValues.insert(rhsValue);
3918
  }
3919
3920
11891
  Theory::shared_terms_iterator shared_iter = d_containing.shared_terms_begin();
3921
11891
  Theory::shared_terms_iterator shared_end = d_containing.shared_terms_end();
3922
516915
  for(; shared_iter != shared_end; ++shared_iter){
3923
505024
    Node sharedCurr = *shared_iter;
3924
3925
    // ModelException is fatal as this point. Don't catch!
3926
    // DeltaRationalException is fatal as this point. Don't catch!
3927
505024
    DeltaRational val = getDeltaValue(sharedCurr);
3928
252512
    relevantDeltaValues.insert(val);
3929
  }
3930
3931
542594
  for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
3932
530703
    ArithVar v = *vi;
3933
530703
    const DeltaRational& value = d_partialModel.getAssignment(v);
3934
530703
    relevantDeltaValues.insert(value);
3935
530703
    if( d_partialModel.hasLowerBound(v)){
3936
326296
      const DeltaRational& lb = d_partialModel.getLowerBound(v);
3937
326296
      relevantDeltaValues.insert(lb);
3938
    }
3939
530703
    if( d_partialModel.hasUpperBound(v)){
3940
258357
      const DeltaRational& ub = d_partialModel.getUpperBound(v);
3941
258357
      relevantDeltaValues.insert(ub);
3942
    }
3943
  }
3944
3945
11891
  if(relevantDeltaValues.size() >= 2){
3946
10069
    std::set<DeltaRational>::const_iterator iter = relevantDeltaValues.begin();
3947
10069
    std::set<DeltaRational>::const_iterator iter_end = relevantDeltaValues.end();
3948
20138
    DeltaRational prev = *iter;
3949
10069
    ++iter;
3950
282439
    for(; iter != iter_end; ++iter){
3951
136185
      const DeltaRational& curr = *iter;
3952
3953
136185
      Assert(prev < curr);
3954
3955
136185
      DeltaRational::seperatingDelta(min, prev, curr);
3956
136185
      prev = curr;
3957
    }
3958
  }
3959
3960
11891
  Assert(min.sgn() > 0);
3961
11891
  Rational belowMin = min/Rational(2);
3962
23782
  return belowMin;
3963
}
3964
3965
13422
void TheoryArithPrivate::collectModelValues(const std::set<Node>& termSet,
3966
                                            std::map<Node, Node>& arithModel)
3967
{
3968
13422
  AlwaysAssert(d_qflraStatus == Result::SAT);
3969
3970
13422
  if(Debug.isOn("arith::collectModelInfo")){
3971
    debugPrintFacts();
3972
  }
3973
3974
13422
  Debug("arith::collectModelInfo") << "collectModelInfo() begin " << endl;
3975
3976
  // Delta lasts at least the duration of the function call
3977
13422
  const Rational& delta = d_partialModel.getDelta();
3978
26844
  std::unordered_set<TNode> shared = d_containing.currentlySharedTerms();
3979
3980
  // TODO:
3981
  // This is not very good for user push/pop....
3982
  // Revisit when implementing push/pop
3983
538391
  for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
3984
524969
    ArithVar v = *vi;
3985
3986
524969
    if(!isAuxiliaryVariable(v)){
3987
460710
      Node term = d_partialModel.asNode(v);
3988
3989
855796
      if((theoryOf(term) == THEORY_ARITH || shared.find(term) != shared.end())
3990
917577
         && termSet.find(term) != termSet.end()){
3991
3992
223263
        const DeltaRational& mod = d_partialModel.getAssignment(v);
3993
446526
        Rational qmodel = mod.substituteDelta(delta);
3994
3995
446526
        Node qNode = mkRationalNode(qmodel);
3996
223263
        Debug("arith::collectModelInfo") << "m->assertEquality(" << term << ", " << qmodel << ", true)" << endl;
3997
        // Add to the map
3998
223263
        arithModel[term] = qNode;
3999
      }else{
4000
7092
        Debug("arith::collectModelInfo") << "Skipping m->assertEquality(" << term << ", true)" << endl;
4001
4002
      }
4003
    }
4004
  }
4005
4006
  // Iterate over equivalence classes in LinearEqualityModule
4007
  // const eq::EqualityEngine& ee = d_congruenceManager.getEqualityEngine();
4008
  // m->assertEqualityEngine(&ee);
4009
4010
13422
  Debug("arith::collectModelInfo") << "collectModelInfo() end " << endl;
4011
13422
}
4012
4013
bool TheoryArithPrivate::safeToReset() const {
4014
  Assert(!d_tableauSizeHasBeenModified);
4015
  Assert(d_errorSet.noSignals());
4016
4017
  ErrorSet::error_iterator error_iter = d_errorSet.errorBegin();
4018
  ErrorSet::error_iterator error_end = d_errorSet.errorEnd();
4019
  for(; error_iter != error_end; ++error_iter){
4020
    ArithVar basic = *error_iter;
4021
    if(!d_smallTableauCopy.isBasic(basic)){
4022
      return false;
4023
    }
4024
  }
4025
4026
  return true;
4027
}
4028
4029
1629
void TheoryArithPrivate::notifyRestart(){
4030
3258
  TimerStat::CodeTimer codeTimer(d_statistics.d_restartTimer);
4031
4032
1629
  if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
4033
4034
1629
  ++d_restartsCounter;
4035
1629
  d_solveIntMaybeHelp = 0;
4036
1629
  d_solveIntAttempts = 0;
4037
1629
}
4038
4039
bool TheoryArithPrivate::entireStateIsConsistent(const string& s){
4040
  bool result = true;
4041
  for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
4042
    ArithVar var = *vi;
4043
    //ArithVar var = d_partialModel.asArithVar(*i);
4044
    if(!d_partialModel.assignmentIsConsistent(var)){
4045
      d_partialModel.printModel(var);
4046
      Warning() << s << ":" << "Assignment is not consistent for " << var << d_partialModel.asNode(var);
4047
      if(d_tableau.isBasic(var)){
4048
        Warning() << " (basic)";
4049
      }
4050
      Warning() << endl;
4051
      result = false;
4052
    }else if(d_partialModel.isInteger(var) && !d_partialModel.integralAssignment(var)){
4053
      d_partialModel.printModel(var);
4054
      Warning() << s << ":" << "Assignment is not integer for integer variable " << var << d_partialModel.asNode(var);
4055
      if(d_tableau.isBasic(var)){
4056
        Warning() << " (basic)";
4057
      }
4058
      Warning() << endl;
4059
      result = false;
4060
    }
4061
  }
4062
  return result;
4063
}
4064
4065
bool TheoryArithPrivate::unenqueuedVariablesAreConsistent(){
4066
  bool result = true;
4067
  for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
4068
    ArithVar var = *vi;
4069
    if(!d_partialModel.assignmentIsConsistent(var)){
4070
      if(!d_errorSet.inError(var)){
4071
4072
        d_partialModel.printModel(var);
4073
        Warning() << "Unenqueued var is not consistent for " << var <<  d_partialModel.asNode(var);
4074
        if(d_tableau.isBasic(var)){
4075
          Warning() << " (basic)";
4076
        }
4077
        Warning() << endl;
4078
        result = false;
4079
      } else if(Debug.isOn("arith::consistency::initial")){
4080
        d_partialModel.printModel(var);
4081
        Warning() << "Initial var is not consistent for " << var <<  d_partialModel.asNode(var);
4082
        if(d_tableau.isBasic(var)){
4083
          Warning() << " (basic)";
4084
        }
4085
        Warning() << endl;
4086
      }
4087
     }
4088
  }
4089
  return result;
4090
}
4091
4092
14306
void TheoryArithPrivate::presolve(){
4093
28612
  TimerStat::CodeTimer codeTimer(d_statistics.d_presolveTime);
4094
4095
14306
  d_statistics.d_initialTableauSize = d_tableau.size();
4096
4097
14306
  if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
4098
4099
  static thread_local unsigned callCount = 0;
4100
14306
  if(Debug.isOn("arith::presolve")) {
4101
    Debug("arith::presolve") << "TheoryArithPrivate::presolve #" << callCount << endl;
4102
    callCount = callCount + 1;
4103
  }
4104
4105
28612
  vector<TrustNode> lemmas;
4106
14306
  if(!options::incrementalSolving()) {
4107
14724
    switch(options::arithUnateLemmaMode()){
4108
      case options::ArithUnateLemmaMode::NO: break;
4109
      case options::ArithUnateLemmaMode::INEQUALITY:
4110
        d_constraintDatabase.outputUnateInequalityLemmas(lemmas);
4111
        break;
4112
      case options::ArithUnateLemmaMode::EQUALITY:
4113
        d_constraintDatabase.outputUnateEqualityLemmas(lemmas);
4114
        break;
4115
7362
      case options::ArithUnateLemmaMode::ALL:
4116
7362
        d_constraintDatabase.outputUnateInequalityLemmas(lemmas);
4117
7362
        d_constraintDatabase.outputUnateEqualityLemmas(lemmas);
4118
7362
        break;
4119
      default: Unhandled() << options::arithUnateLemmaMode();
4120
    }
4121
  }
4122
4123
14306
  vector<TrustNode>::const_iterator i = lemmas.begin(), i_end = lemmas.end();
4124
92510
  for(; i != i_end; ++i){
4125
78204
    TrustNode lem = *i;
4126
39102
    Debug("arith::oldprop") << " lemma lemma duck " <<lem << endl;
4127
39102
    outputTrustedLemma(lem, InferenceId::ARITH_UNATE);
4128
  }
4129
14306
}
4130
4131
807886
EqualityStatus TheoryArithPrivate::getEqualityStatus(TNode a, TNode b) {
4132
807886
  if(d_qflraStatus == Result::SAT_UNKNOWN){
4133
    return EQUALITY_UNKNOWN;
4134
  }else{
4135
    try {
4136
807886
      if (getDeltaValue(a) == getDeltaValue(b)) {
4137
74908
        return EQUALITY_TRUE_IN_MODEL;
4138
      } else {
4139
732978
        return EQUALITY_FALSE_IN_MODEL;
4140
      }
4141
    } catch (DeltaRationalException& dr) {
4142
      return EQUALITY_UNKNOWN;
4143
    } catch (ModelException& me) {
4144
      return EQUALITY_UNKNOWN;
4145
    }
4146
  }
4147
}
4148
4149
1746
bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound){
4150
1746
  ++d_statistics.d_boundComputations;
4151
4152
1746
  RowIndex ridx = d_tableau.basicToRowIndex(basic);
4153
3492
  DeltaRational bound = d_linEq.computeRowBound(ridx, upperBound, basic);
4154
4155
4504
  if((upperBound && d_partialModel.strictlyLessThanUpperBound(basic, bound)) ||
4156
2048
     (!upperBound && d_partialModel.strictlyGreaterThanLowerBound(basic, bound))){
4157
4158
    // TODO: "Policy point"
4159
    //We are only going to recreate the functionality for now.
4160
    //In the future this can be improved to generate a temporary constraint
4161
    //if none exists.
4162
    //Experiment with doing this every time or only when the new constraint
4163
    //implies an unknown fact.
4164
4165
1730
    ConstraintType t = upperBound ? UpperBound : LowerBound;
4166
1730
    ConstraintP bestImplied = d_constraintDatabase.getBestImpliedBound(basic, t, bound);
4167
4168
    // Node bestImplied = upperBound ?
4169
    //   d_apm.getBestImpliedUpperBound(basic, bound):
4170
    //   d_apm.getBestImpliedLowerBound(basic, bound);
4171
4172
1730
    if(bestImplied != NullConstraint){
4173
      //This should be stronger
4174
1272
      Assert(!upperBound || bound <= bestImplied->getValue());
4175
1272
      Assert(
4176
          !upperBound
4177
          || d_partialModel.lessThanUpperBound(basic, bestImplied->getValue()));
4178
4179
1272
      Assert(upperBound || bound >= bestImplied->getValue());
4180
1272
      Assert(upperBound
4181
             || d_partialModel.greaterThanLowerBound(basic,
4182
                                                     bestImplied->getValue()));
4183
      //slightly changed
4184
4185
      // ConstraintP c = d_constraintDatabase.lookup(bestImplied);
4186
      // Assert(c != NullConstraint);
4187
4188
1272
      bool assertedToTheTheory = bestImplied->assertedToTheTheory();
4189
1272
      bool canBePropagated = bestImplied->canBePropagated();
4190
1272
      bool hasProof = bestImplied->hasProof();
4191
4192
2544
      Debug("arith::prop") << "arith::prop" << basic
4193
1272
                           << " " << assertedToTheTheory
4194
1272
                           << " " << canBePropagated
4195
1272
                           << " " << hasProof
4196
1272
                           << endl;
4197
4198
1272
      if(bestImplied->negationHasProof()){
4199
        Warning() << "the negation of " <<  bestImplied << " : " << endl
4200
                  << "has proof " << bestImplied->getNegation() << endl
4201
                  << bestImplied->getNegation()->externalExplainByAssertions()
4202
                  << endl;
4203
      }
4204
4205
1272
      if(!assertedToTheTheory && canBePropagated && !hasProof ){
4206
232
        d_linEq.propagateBasicFromRow(bestImplied);
4207
        // I think this can be skipped if canBePropagated is true
4208
        //d_learnedBounds.push(bestImplied);
4209
232
        if(Debug.isOn("arith::prop")){
4210
          Debug("arith::prop") << "success " << bestImplied << endl;
4211
          d_partialModel.printModel(basic, Debug("arith::prop"));
4212
        }
4213
232
        return true;
4214
      }
4215
1040
      if(Debug.isOn("arith::prop")){
4216
        Debug("arith::prop") << "failed " << basic
4217
                             << " " << bound
4218
                             << " " << assertedToTheTheory
4219
                             << " " << canBePropagated
4220
                             << " " << hasProof << endl;
4221
        d_partialModel.printModel(basic, Debug("arith::prop"));
4222
      }
4223
    }
4224
16
  }else if(Debug.isOn("arith::prop")){
4225
    Debug("arith::prop") << "false " << bound << " ";
4226
    d_partialModel.printModel(basic, Debug("arith::prop"));
4227
  }
4228
1514
  return false;
4229
}
4230
4231
4434
void TheoryArithPrivate::propagateCandidate(ArithVar basic){
4232
4434
  bool success = false;
4233
4434
  RowIndex ridx = d_tableau.basicToRowIndex(basic);
4234
4235
  bool tryLowerBound =
4236
8480
    d_partialModel.strictlyAboveLowerBound(basic) &&
4237
8480
    d_linEq.rowLacksBound(ridx, false, basic) == NULL;
4238
4239
  bool tryUpperBound =
4240
8446
    d_partialModel.strictlyBelowUpperBound(basic) &&
4241
8446
    d_linEq.rowLacksBound(ridx, true, basic) == NULL;
4242
4243
4434
  if(tryLowerBound){
4244
1020
    success |= propagateCandidateLowerBound(basic);
4245
  }
4246
4434
  if(tryUpperBound){
4247
726
    success |= propagateCandidateUpperBound(basic);
4248
  }
4249
4434
  if(success){
4250
226
    ++d_statistics.d_boundPropagations;
4251
  }
4252
4434
}
4253
4254
2552
void TheoryArithPrivate::propagateCandidates(){
4255
5104
  TimerStat::CodeTimer codeTimer(d_statistics.d_boundComputationTime);
4256
4257
2552
  Debug("arith::prop") << "propagateCandidates begin" << endl;
4258
4259
2552
  Assert(d_candidateBasics.empty());
4260
4261
2552
  if(d_updatedBounds.empty()){ return; }
4262
4263
2552
  DenseSet::const_iterator i = d_updatedBounds.begin();
4264
2552
  DenseSet::const_iterator end = d_updatedBounds.end();
4265
9200
  for(; i != end; ++i){
4266
3324
    ArithVar var = *i;
4267
4098
    if(d_tableau.isBasic(var) &&
4268
9190621
       d_tableau.basicRowLength(var) <= options::arithPropagateMaxLength()){
4269
702
      d_candidateBasics.softAdd(var);
4270
    }else{
4271
2622
      Tableau::ColIterator basicIter = d_tableau.colIterator(var);
4272
15002
      for(; !basicIter.atEnd(); ++basicIter){
4273
6190
        const Tableau::Entry& entry = *basicIter;
4274
6190
        RowIndex ridx = entry.getRowIndex();
4275
6190
        ArithVar rowVar = d_tableau.rowIndexToBasic(ridx);
4276
6190
        Assert(entry.getColVar() == var);
4277
6190
        Assert(d_tableau.isBasic(rowVar));
4278
6190
        if(d_tableau.getRowLength(ridx) <= options::arithPropagateMaxLength()){
4279
4576
          d_candidateBasics.softAdd(rowVar);
4280
        }
4281
      }
4282
    }
4283
  }
4284
2552
  d_updatedBounds.purge();
4285
4286
11420
  while(!d_candidateBasics.empty()){
4287
4434
    ArithVar candidate = d_candidateBasics.back();
4288
4434
    d_candidateBasics.pop_back();
4289
4434
    Assert(d_tableau.isBasic(candidate));
4290
4434
    propagateCandidate(candidate);
4291
  }
4292
2552
  Debug("arith::prop") << "propagateCandidates end" << endl << endl << endl;
4293
}
4294
4295
805352
void TheoryArithPrivate::propagateCandidatesNew(){
4296
  /* Four criteria must be met for progagation on a variable to happen using a row:
4297
   * 0: A new bound has to have been added to the row.
4298
   * 1: The hasBoundsCount for the row must be "full" or be full minus one variable
4299
   *    (This is O(1) to check, but requires book keeping.)
4300
   * 2: The current assignment must be strictly smaller/greater than the current bound.
4301
   *    assign(x) < upper(x)
4302
   *    (This is O(1) to compute.)
4303
   * 3: There is a bound that is strictly smaller/greater than the current assignment.
4304
   *    assign(x) < c for some x <= c literal
4305
   *    (This is O(log n) to compute.)
4306
   * 4: The implied bound on x is strictly smaller/greater than the current bound.
4307
   *    (This is O(n) to compute.)
4308
   */
4309
4310
1610704
  TimerStat::CodeTimer codeTimer(d_statistics.d_boundComputationTime);
4311
805352
  Debug("arith::prop") << "propagateCandidatesNew begin" << endl;
4312
4313
805352
  Assert(d_qflraStatus == Result::SAT);
4314
805352
  if(d_updatedBounds.empty()){ return; }
4315
805352
  dumpUpdatedBoundsToRows();
4316
805352
  Assert(d_updatedBounds.empty());
4317
4318
805352
  if(!d_candidateRows.empty()){
4319
1521896
    UpdateTrackingCallback utcb(&d_linEq);
4320
760948
    d_partialModel.processBoundsQueue(utcb);
4321
  }
4322
4323
16300334
  while(!d_candidateRows.empty()){
4324
7747491
    RowIndex candidate = d_candidateRows.back();
4325
7747491
    d_candidateRows.pop_back();
4326
7747491
    propagateCandidateRow(candidate);
4327
  }
4328
805352
  Debug("arith::prop") << "propagateCandidatesNew end" << endl << endl << endl;
4329
}
4330
4331
11997892
bool TheoryArithPrivate::propagateMightSucceed(ArithVar v, bool ub) const{
4332
18117578
  int cmp = ub ? d_partialModel.cmpAssignmentUpperBound(v)
4333
18117578
    : d_partialModel.cmpAssignmentLowerBound(v);
4334
11997892
  bool hasSlack = ub ? cmp < 0 : cmp > 0;
4335
11997892
  if(hasSlack){
4336
5779900
    ConstraintType t = ub ? UpperBound : LowerBound;
4337
5779900
    const DeltaRational& a = d_partialModel.getAssignment(v);
4338
4339
5779900
    if(isInteger(v) && !a.isIntegral()){
4340
63906
      return true;
4341
    }
4342
4343
5715994
    ConstraintP strongestPossible = d_constraintDatabase.getBestImpliedBound(v, t, a);
4344
5715994
    if(strongestPossible == NullConstraint){
4345
3171049
      return false;
4346
    }else{
4347
2544945
      bool assertedToTheTheory = strongestPossible->assertedToTheTheory();
4348
2544945
      bool canBePropagated = strongestPossible->canBePropagated();
4349
2544945
      bool hasProof = strongestPossible->hasProof();
4350
4351
2544945
      return !assertedToTheTheory && canBePropagated && !hasProof;
4352
    }
4353
  }else{
4354
6217992
    return false;
4355
  }
4356
}
4357
4358
3002504
bool TheoryArithPrivate::attemptSingleton(RowIndex ridx, bool rowUp){
4359
3002504
  Debug("arith::prop") << "  attemptSingleton" << ridx;
4360
4361
  const Tableau::Entry* ep;
4362
3002504
  ep = d_linEq.rowLacksBound(ridx, rowUp, ARITHVAR_SENTINEL);
4363
3002504
  Assert(ep != NULL);
4364
4365
3002504
  ArithVar v = ep->getColVar();
4366
3002504
  const Rational& coeff = ep->getCoefficient();
4367
4368
  // 0 = c * v + \sum rest
4369
  // Suppose rowUp
4370
  // - c * v = \sum rest \leq D
4371
  // if c > 0, v \geq -D/c so !vUp
4372
  // if c < 0, v \leq -D/c so  vUp
4373
  // Suppose not rowUp
4374
  // - c * v = \sum rest \geq D
4375
  // if c > 0, v \leq -D/c so  vUp
4376
  // if c < 0, v \geq -D/c so !vUp
4377
3002504
  bool vUp = (rowUp == ( coeff.sgn() < 0));
4378
4379
3002504
  Debug("arith::prop") << "  " << rowUp << " " << v << " " << coeff << " " << vUp << endl;
4380
3002504
  Debug("arith::prop") << "  " << propagateMightSucceed(v, vUp) << endl;
4381
4382
3002504
  if(propagateMightSucceed(v, vUp)){
4383
552416
    DeltaRational dr = d_linEq.computeRowBound(ridx, rowUp, v);
4384
552416
    DeltaRational bound = dr / (- coeff);
4385
276208
    return tryToPropagate(ridx, rowUp, v, vUp, bound);
4386
  }
4387
2726296
  return false;
4388
}
4389
4390
1170907
bool TheoryArithPrivate::attemptFull(RowIndex ridx, bool rowUp){
4391
1170907
  Debug("arith::prop") << "  attemptFull" << ridx << endl;
4392
4393
2341814
  vector<const Tableau::Entry*> candidates;
4394
4395
7163791
  for(Tableau::RowIterator i = d_tableau.ridRowIterator(ridx); !i.atEnd(); ++i){
4396
5992884
    const Tableau::Entry& e =*i;
4397
5992884
    const Rational& c = e.getCoefficient();
4398
5992884
    ArithVar v = e.getColVar();
4399
5992884
    bool vUp = (rowUp == (c.sgn() < 0));
4400
5992884
    if(propagateMightSucceed(v, vUp)){
4401
154626
      candidates.push_back(&e);
4402
    }
4403
  }
4404
1170907
  if(candidates.empty()){ return false; }
4405
4406
  const DeltaRational slack =
4407
275496
    d_linEq.computeRowBound(ridx, rowUp, ARITHVAR_SENTINEL);
4408
137748
  bool any = false;
4409
137748
  vector<const Tableau::Entry*>::const_iterator i, iend;
4410
292374
  for(i = candidates.begin(), iend = candidates.end(); i != iend; ++i){
4411
154626
    const Tableau::Entry* ep = *i;
4412
154626
    const Rational& c = ep->getCoefficient();
4413
154626
    ArithVar v = ep->getColVar();
4414
4415
    // See the comment for attemptSingleton()
4416
154626
    bool activeUp = (rowUp == (c.sgn() > 0));
4417
154626
    bool vUb = (rowUp == (c.sgn() < 0));
4418
4419
309252
    const DeltaRational& activeBound = activeUp ?
4420
120182
      d_partialModel.getUpperBound(v):
4421
189070
      d_partialModel.getLowerBound(v);
4422
4423
309252
    DeltaRational contribution = activeBound * c;
4424
309252
    DeltaRational impliedBound = (slack - contribution)/(-c);
4425
4426
154626
    bool success = tryToPropagate(ridx, rowUp, v, vUb, impliedBound);
4427
154626
    any |= success;
4428
  }
4429
137748
  return any;
4430
}
4431
4432
430834
bool TheoryArithPrivate::tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, bool vUb, const DeltaRational& bound){
4433
4434
736961
  bool weaker = vUb ? d_partialModel.strictlyLessThanUpperBound(v, bound):
4435
736961
    d_partialModel.strictlyGreaterThanLowerBound(v, bound);
4436
430834
  if(weaker){
4437
279923
    ConstraintType t = vUb ? UpperBound : LowerBound;
4438
4439
279923
    ConstraintP implied = d_constraintDatabase.getBestImpliedBound(v, t, bound);
4440
279923
    if(implied != NullConstraint){
4441
142897
      return rowImplicationCanBeApplied(ridx, rowUp, implied);
4442
    }
4443
  }
4444
287937
  return false;
4445
}
4446
4447
89267
Node flattenImplication(Node imp){
4448
178534
  NodeBuilder nb(kind::OR);
4449
178534
  std::unordered_set<Node> included;
4450
178534
  Node left = imp[0];
4451
178534
  Node right = imp[1];
4452
4453
89267
  if(left.getKind() == kind::AND){
4454
400469
    for(Node::iterator i = left.begin(), iend = left.end(); i != iend; ++i) {
4455
311202
      if (!included.count((*i).negate()))
4456
      {
4457
311199
        nb << (*i).negate();
4458
311199
        included.insert((*i).negate());
4459
      }
4460
    }
4461
  }else{
4462
    if (!included.count(left.negate()))
4463
    {
4464
      nb << left.negate();
4465
      included.insert(left.negate());
4466
    }
4467
  }
4468
4469
89267
  if(right.getKind() == kind::OR){
4470
    for(Node::iterator i = right.begin(), iend = right.end(); i != iend; ++i) {
4471
      if (!included.count(*i))
4472
      {
4473
        nb << *i;
4474
        included.insert(*i);
4475
      }
4476
    }
4477
  }else{
4478
89267
    if (!included.count(right))
4479
    {
4480
89267
      nb << right;
4481
89267
      included.insert(right);
4482
    }
4483
  }
4484
4485
178534
  return nb;
4486
}
4487
4488
142897
bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, ConstraintP implied){
4489
142897
  Assert(implied != NullConstraint);
4490
142897
  ArithVar v = implied->getVariable();
4491
4492
142897
  bool assertedToTheTheory = implied->assertedToTheTheory();
4493
142897
  bool canBePropagated = implied->canBePropagated();
4494
142897
  bool hasProof = implied->hasProof();
4495
4496
285794
  Debug("arith::prop") << "arith::prop" << v
4497
142897
                       << " " << assertedToTheTheory
4498
142897
                       << " " << canBePropagated
4499
142897
                       << " " << hasProof
4500
142897
                       << endl;
4501
4502
4503
142897
  if( !assertedToTheTheory && canBePropagated && !hasProof ){
4504
234570
    ConstraintCPVec explain;
4505
117285
    ARITH_PROOF(d_farkasBuffer.clear());
4506
117285
    RationalVectorP coeffs = ARITH_NULLPROOF(&d_farkasBuffer);
4507
4508
    // After invoking `propegateRow`:
4509
    //   * coeffs[0] is for implied
4510
    //   * coeffs[i+1] is for explain[i]
4511
117285
    d_linEq.propagateRow(explain, ridx, rowUp, implied, coeffs);
4512
234570
    if(d_tableau.getRowLength(ridx) <= options::arithPropAsLemmaLength()){
4513
89267
      if (Debug.isOn("arith::prop::pf")) {
4514
        for (const auto & constraint : explain) {
4515
          Assert(constraint->hasProof());
4516
          constraint->printProofTree(Debug("arith::prop::pf"));
4517
        }
4518
      }
4519
178534
      Node implication = implied->externalImplication(explain);
4520
178534
      Node clause = flattenImplication(implication);
4521
178534
      std::shared_ptr<ProofNode> clausePf{nullptr};
4522
4523
89267
      if (isProofEnabled())
4524
      {
4525
        // We can prove this lemma from Farkas...
4526
28226
        std::vector<std::shared_ptr<ProofNode>> conflictPfs;
4527
        // Assume the negated getLiteral version of the implied constaint
4528
        // then rewrite it into proof normal form.
4529
14113
        conflictPfs.push_back(
4530
84678
            d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
4531
28226
                          {d_pnm->mkAssume(implied->getLiteral().negate())},
4532
28226
                          {implied->getNegation()->getProofLiteral()}));
4533
        // Add the explaination proofs.
4534
61849
        for (const auto constraint : explain)
4535
        {
4536
95472
          NodeBuilder nb;
4537
47736
          conflictPfs.push_back(constraint->externalExplainByAssertions(nb));
4538
        }
4539
        // Collect the farkas coefficients, as nodes.
4540
28226
        std::vector<Node> farkasCoefficients;
4541
14113
        farkasCoefficients.reserve(coeffs->size());
4542
14113
        auto nm = NodeManager::currentNM();
4543
14113
        std::transform(
4544
            coeffs->begin(),
4545
            coeffs->end(),
4546
            std::back_inserter(farkasCoefficients),
4547
75962
            [nm](const Rational& r) { return nm->mkConst<Rational>(r); });
4548
4549
        // Prove bottom.
4550
14113
        auto sumPf = d_pnm->mkNode(
4551
28226
            PfRule::MACRO_ARITH_SCALE_SUM_UB, conflictPfs, farkasCoefficients);
4552
14113
        auto botPf = d_pnm->mkNode(
4553
28226
            PfRule::MACRO_SR_PRED_TRANSFORM, {sumPf}, {nm->mkConst(false)});
4554
4555
        // Prove the conflict
4556
28226
        std::vector<Node> assumptions;
4557
14113
        assumptions.reserve(clause.getNumChildren());
4558
14113
        std::transform(clause.begin(),
4559
                       clause.end(),
4560
                       std::back_inserter(assumptions),
4561
76586
                       [](TNode r) { return r.negate(); });
4562
28226
        auto notAndNotPf = d_pnm->mkScope(botPf, assumptions);
4563
4564
        // Convert it to a clause
4565
28226
        auto orNotNotPf = d_pnm->mkNode(PfRule::NOT_AND, {notAndNotPf}, {});
4566
42339
        clausePf = d_pnm->mkNode(
4567
28226
            PfRule::MACRO_SR_PRED_TRANSFORM, {orNotNotPf}, {clause});
4568
4569
        // Output it
4570
28226
        TrustNode trustedClause = d_pfGen->mkTrustNode(clause, clausePf);
4571
14113
        outputTrustedLemma(trustedClause, InferenceId::ARITH_ROW_IMPL);
4572
      }
4573
      else
4574
      {
4575
75154
        outputLemma(clause, InferenceId::ARITH_ROW_IMPL);
4576
      }
4577
    }else{
4578
28018
      Assert(!implied->negationHasProof());
4579
28018
      implied->impliedByFarkas(explain, coeffs, false);
4580
28018
      implied->tryToPropagate();
4581
    }
4582
117285
    return true;
4583
  }
4584
4585
25612
  if(Debug.isOn("arith::prop")){
4586
    Debug("arith::prop")
4587
      << "failed " << v << " " << assertedToTheTheory << " "
4588
      << canBePropagated << " " << hasProof << " " << implied << endl;
4589
    d_partialModel.printModel(v, Debug("arith::prop"));
4590
  }
4591
25612
  return false;
4592
}
4593
4594
7747491
bool TheoryArithPrivate::propagateCandidateRow(RowIndex ridx){
4595
7747491
  BoundCounts hasCount = d_linEq.hasBoundCount(ridx);
4596
7747491
  uint32_t rowLength = d_tableau.getRowLength(ridx);
4597
4598
7747491
  bool success = false;
4599
  static int instance = 0;
4600
7747491
  ++instance;
4601
4602
15494982
  Debug("arith::prop")
4603
7747491
    << "propagateCandidateRow " << instance << " attempt " << rowLength << " " <<  hasCount << endl;
4604
4605
15494982
  if (rowLength >= options::arithPropagateMaxLength()
4606
9182883
      && Random::getRandom().pickWithProb(
4607
1435392
             1.0 - double(options::arithPropagateMaxLength()) / rowLength))
4608
  {
4609
299337
    return false;
4610
  }
4611
4612
7448154
  if(hasCount.lowerBoundCount() == rowLength){
4613
502740
    success |= attemptFull(ridx, false);
4614
6945414
  }else if(hasCount.lowerBoundCount() + 1 == rowLength){
4615
1555899
    success |= attemptSingleton(ridx, false);
4616
  }
4617
4618
7448154
  if(hasCount.upperBoundCount() == rowLength){
4619
668167
    success |= attemptFull(ridx, true);
4620
6779987
  }else if(hasCount.upperBoundCount() + 1 == rowLength){
4621
1446605
    success |= attemptSingleton(ridx, true);
4622
  }
4623
7448154
  return success;
4624
}
4625
4626
805352
void TheoryArithPrivate::dumpUpdatedBoundsToRows(){
4627
805352
  Assert(d_candidateRows.empty());
4628
805352
  DenseSet::const_iterator i = d_updatedBounds.begin();
4629
805352
  DenseSet::const_iterator end = d_updatedBounds.end();
4630
5104866
  for(; i != end; ++i){
4631
2149757
    ArithVar var = *i;
4632
2149757
    if(d_tableau.isBasic(var)){
4633
1194505
      RowIndex ridx = d_tableau.basicToRowIndex(var);
4634
1194505
      d_candidateRows.softAdd(ridx);
4635
    }else{
4636
955252
      Tableau::ColIterator basicIter = d_tableau.colIterator(var);
4637
21501680
      for(; !basicIter.atEnd(); ++basicIter){
4638
10273214
        const Tableau::Entry& entry = *basicIter;
4639
10273214
        RowIndex ridx = entry.getRowIndex();
4640
10273214
        d_candidateRows.softAdd(ridx);
4641
      }
4642
    }
4643
  }
4644
805352
  d_updatedBounds.purge();
4645
805352
}
4646
4647
const BoundsInfo& TheoryArithPrivate::boundsInfo(ArithVar basic) const{
4648
  RowIndex ridx = d_tableau.basicToRowIndex(basic);
4649
  return d_rowTracking[ridx];
4650
}
4651
4652
4830
std::pair<bool, Node> TheoryArithPrivate::entailmentCheck(TNode lit, const ArithEntailmentCheckParameters& params, ArithEntailmentCheckSideEffects& out){
4653
  using namespace inferbounds;
4654
4655
  // l k r
4656
  // diff : (l - r) k 0
4657
4830
  Debug("arith::entailCheck") << "TheoryArithPrivate::entailmentCheck(" << lit << ")"<< endl;
4658
  Kind k;
4659
  int primDir;
4660
9660
  Rational lm, rm, dm;
4661
9660
  Node lp, rp, dp;
4662
9660
  DeltaRational sep;
4663
4830
  bool successful = decomposeLiteral(lit, k, primDir, lm, lp, rm, rp, dm, dp, sep);
4664
4830
  if(!successful) { return make_pair(false, Node::null()); }
4665
4666
4830
  if(dp.getKind() == CONST_RATIONAL){
4667
    Node eval = Rewriter::rewrite(lit);
4668
    Assert(eval.getKind() == kind::CONST_BOOLEAN);
4669
    // if true, true is an acceptable explaination
4670
    // if false, the node is uninterpreted and eval can be forgotten
4671
    return make_pair(eval.getConst<bool>(), eval);
4672
  }
4673
4830
  Assert(dm != Rational(0));
4674
4830
  Assert(primDir == 1 || primDir == -1);
4675
4676
4830
  int negPrim = -primDir;
4677
4678
4830
  int secDir = (k == EQUAL || k == DISTINCT) ? negPrim: 0;
4679
4830
  int negSecDir = (k == EQUAL || k == DISTINCT) ? primDir: 0;
4680
4681
  // primDir*[lm*( lp )] k primDir*[ [rm*( rp )] + sep ]
4682
  // primDir*[lm*( lp ) - rm*( rp ) ] k primDir*sep
4683
  // primDir*[dm * dp] k primDir*sep
4684
4685
9660
  std::pair<Node, DeltaRational> bestPrimLeft, bestNegPrimRight, bestPrimDiff, tmp;
4686
9660
  std::pair<Node, DeltaRational> bestSecLeft, bestNegSecRight, bestSecDiff;
4687
4830
  bestPrimLeft.first = Node::null(); bestNegPrimRight.first = Node::null(); bestPrimDiff.first = Node::null();
4688
4830
  bestSecLeft.first = Node::null(); bestNegSecRight.first = Node::null(); bestSecDiff.first = Node::null();
4689
4690
4691
4692
4830
  ArithEntailmentCheckParameters::const_iterator alg, alg_end;
4693
13437
  for( alg = params.begin(), alg_end = params.end(); alg != alg_end; ++alg ){
4694
9578
    const inferbounds::InferBoundAlgorithm& ibalg = *alg;
4695
4696
9578
    Debug("arith::entailCheck") << "entailmentCheck trying " << (inferbounds::Algorithms) ibalg.getAlgorithm() << endl;
4697
9578
    switch(ibalg.getAlgorithm()){
4698
    case inferbounds::None:
4699
      break;
4700
9578
    case inferbounds::Lookup:
4701
    case inferbounds::RowSum:
4702
      {
4703
        typedef void (TheoryArithPrivate::*EntailmentCheckFunc)(std::pair<Node, DeltaRational>&, int, TNode) const;
4704
4705
        EntailmentCheckFunc ecfunc =
4706
9578
          (ibalg.getAlgorithm() == inferbounds::Lookup)
4707
          ? (&TheoryArithPrivate::entailmentCheckBoundLookup)
4708
9578
          : (&TheoryArithPrivate::entailmentCheckRowSum);
4709
4710
9578
        (*this.*ecfunc)(tmp, primDir * lm.sgn(), lp);
4711
9578
        setToMin(primDir * lm.sgn(), bestPrimLeft, tmp);
4712
4713
9578
        (*this.*ecfunc)(tmp, negPrim * rm.sgn(), rp);
4714
9578
        setToMin(negPrim * rm.sgn(), bestNegPrimRight, tmp);
4715
4716
9578
        (*this.*ecfunc)(tmp, secDir * lm.sgn(), lp);
4717
9578
        setToMin(secDir * lm.sgn(), bestSecLeft, tmp);
4718
4719
9578
        (*this.*ecfunc)(tmp, negSecDir * rm.sgn(), rp);
4720
9578
        setToMin(negSecDir * rm.sgn(), bestNegSecRight, tmp);
4721
4722
9578
        (*this.*ecfunc)(tmp, primDir * dm.sgn(), dp);
4723
9578
        setToMin(primDir * dm.sgn(), bestPrimDiff, tmp);
4724
4725
9578
        (*this.*ecfunc)(tmp, secDir * dm.sgn(), dp);
4726
9578
        setToMin(secDir * dm.sgn(), bestSecDiff, tmp);
4727
      }
4728
9578
      break;
4729
    default:
4730
      Unhandled();
4731
    }
4732
4733
    // turn bounds on prim * left and -prim * right into bounds on prim * diff
4734
9578
    if(!bestPrimLeft.first.isNull() && !bestNegPrimRight.first.isNull()){
4735
      //  primDir*lm* lp <= primDir*lm*L
4736
      // -primDir*rm* rp <= -primDir*rm*R
4737
      // primDir*lm* lp -primDir*rm* rp <=  primDir*lm*L - primDir*rm*R
4738
      // primDir [lm* lp -rm* rp] <= primDir[lm*L - *rm*R]
4739
      // primDir [dm * dp] <= primDir[lm*L - *rm*R]
4740
      // primDir [dm * dp] <= primDir * dm * ([lm*L - *rm*R]/dm)
4741
1535
      tmp.second = ((bestPrimLeft.second * lm) - (bestNegPrimRight.second * rm)) / dm;
4742
1535
      tmp.first = (bestPrimLeft.first).andNode(bestNegPrimRight.first);
4743
1535
      setToMin(primDir, bestPrimDiff, tmp);
4744
    }
4745
4746
    // turn bounds on sec * left and sec * right into bounds on sec * diff
4747
9578
    if(secDir != 0 && !bestSecLeft.first.isNull() && !bestNegSecRight.first.isNull()){
4748
      //  secDir*lm* lp <= secDir*lm*L
4749
      // -secDir*rm* rp <= -secDir*rm*R
4750
      // secDir*lm* lp -secDir*rm* rp <=  secDir*lm*L - secDir*rm*R
4751
      // secDir [lm* lp -rm* rp] <= secDir[lm*L - *rm*R]
4752
      // secDir [dm * dp] <= secDir[lm*L - *rm*R]
4753
      // secDir [dm * dp] <= secDir * dm * ([lm*L - *rm*R]/dm)
4754
      tmp.second = ((bestSecLeft.second * lm) - (bestNegSecRight.second * rm)) / dm;
4755
      tmp.first = (bestSecLeft.first).andNode(bestNegSecRight.first);
4756
      setToMin(secDir, bestSecDiff, tmp);
4757
    }
4758
4759
9578
    switch(k){
4760
9534
    case LEQ:
4761
9534
      if(!bestPrimDiff.first.isNull()){
4762
2099
        DeltaRational d = (bestPrimDiff.second * dm);
4763
1535
        if((primDir > 0 && d <= sep) || (primDir < 0 && d >= sep) ){
4764
1942
          Debug("arith::entailCheck") << "entailmentCheck found "
4765
971
                                      << primDir << "*" << dm << "*(" << dp<<")"
4766
971
                                      << " <= " << primDir << "*" << dm << "*" << bestPrimDiff.second
4767
971
                                      << " <= " << primDir << "*" << sep << endl
4768
971
                                      << " by " << bestPrimDiff.first << endl;
4769
971
          Assert(bestPrimDiff.second * (Rational(primDir) * dm)
4770
                 <= (sep * Rational(primDir)));
4771
971
          return make_pair(true, bestPrimDiff.first);
4772
        }
4773
      }
4774
8563
      break;
4775
22
    case EQUAL:
4776
22
      if(!bestPrimDiff.first.isNull() && !bestSecDiff.first.isNull()){
4777
        // Is primDir [dm * dp] == primDir * sep entailed?
4778
        // Iff [dm * dp] == sep entailed?
4779
        // Iff dp == sep / dm entailed?
4780
        // Iff dp <= sep / dm and dp >= sep / dm entailed?
4781
4782
        // primDir [dm * dp] <= primDir * dm * U
4783
        // secDir [dm * dp] <= secDir * dm * L
4784
4785
        // Suppose primDir * dm > 0
4786
        // then secDir * dm < 0
4787
        //   dp >= (secDir * L) / secDir * dm
4788
        //   dp >= (primDir * L) / primDir * dm
4789
        //
4790
        //   dp <= U / dm
4791
        //   dp >= L / dm
4792
        //   dp == sep / dm entailed iff U == L == sep
4793
        // Suppose primDir * dm < 0
4794
        // then secDir * dm > 0
4795
        //   dp >= U / dm
4796
        //   dp <= L / dm
4797
        //   dp == sep / dm entailed iff U == L == sep
4798
        if(bestPrimDiff.second == bestSecDiff.second){
4799
          if(bestPrimDiff.second == sep){
4800
            return make_pair(true, (bestPrimDiff.first).andNode(bestSecDiff.first));
4801
          }
4802
        }
4803
      }
4804
      // intentionally fall through to DISTINCT case!
4805
      // entailments of negations are eager exit cases for EQUAL
4806
      CVC5_FALLTHROUGH;
4807
    case DISTINCT:
4808
44
      if(!bestPrimDiff.first.isNull()){
4809
        // primDir [dm * dp] <= primDir * dm * U < primDir * sep
4810
        if((primDir > 0 && (bestPrimDiff.second * dm  < sep)) ||
4811
           (primDir < 0 && (bestPrimDiff.second * dm  > sep))){
4812
          // entailment of negation
4813
          if(k == DISTINCT){
4814
            return make_pair(true, bestPrimDiff.first);
4815
          }else{
4816
            Assert(k == EQUAL);
4817
            return make_pair(false, Node::null());
4818
          }
4819
        }
4820
      }
4821
44
      if(!bestSecDiff.first.isNull()){
4822
        // If primDir [dm * dp] > primDir * sep, then this is not entailed.
4823
        // If primDir [dm * dp] >= primDir * dm * L > primDir * sep
4824
        // -primDir * dm * L < -primDir * sep
4825
        // secDir * dm * L < secDir * sep
4826
        if((secDir > 0 && (bestSecDiff.second * dm < sep)) ||
4827
           (secDir < 0 && (bestSecDiff.second * dm > sep))){
4828
          if(k == DISTINCT){
4829
            return make_pair(true, bestSecDiff.first);
4830
          }else{
4831
            Assert(k == EQUAL);
4832
            return make_pair(false, Node::null());
4833
          }
4834
        }
4835
      }
4836
4837
44
      break;
4838
    default:
4839
      Unreachable();
4840
      break;
4841
    }
4842
  }
4843
3859
  return make_pair(false, Node::null());
4844
}
4845
4846
14490
bool TheoryArithPrivate::decomposeTerm(Node term, Rational& m, Node& p, Rational& c){
4847
28980
  Node t = Rewriter::rewrite(term);
4848
14490
  if(!Polynomial::isMember(t)){
4849
    return false;
4850
  }
4851
4852
  // TODO Speed up
4853
28980
  preprocessing::util::ContainsTermITEVisitor ctv;
4854
14490
  if(ctv.containsTermITE(t)){
4855
    return false;
4856
  }
4857
4858
28980
  Polynomial poly = Polynomial::parsePolynomial(t);
4859
14490
  if(poly.isConstant()){
4860
4808
    c = poly.getHead().getConstant().getValue();
4861
4808
    p = mkRationalNode(Rational(0));
4862
4808
    m = Rational(1);
4863
4808
    return true;
4864
9682
  }else if(poly.containsConstant()){
4865
2307
    c = poly.getHead().getConstant().getValue();
4866
2307
    poly = poly.getTail();
4867
  }else{
4868
7375
    c = Rational(0);
4869
  }
4870
9682
  Assert(!poly.isConstant());
4871
9682
  Assert(!poly.containsConstant());
4872
4873
9682
  const bool intVars = poly.allIntegralVariables();
4874
4875
9682
  if(intVars){
4876
9682
    m = Rational(1);
4877
9682
    if(!poly.isIntegral()){
4878
      Integer denom = poly.denominatorLCM();
4879
      m /= denom;
4880
      poly = poly * denom;
4881
    }
4882
19364
    Integer g = poly.gcd();
4883
9682
    m *= g;
4884
9682
    poly = poly * Rational(1,g);
4885
9682
    Assert(poly.isIntegral());
4886
9682
    Assert(poly.leadingCoefficientIsPositive());
4887
  }else{
4888
    Assert(!intVars);
4889
    m = poly.getHead().getConstant().getValue();
4890
    poly = poly * m.inverse();
4891
    Assert(poly.leadingCoefficientIsAbsOne());
4892
  }
4893
9682
  p = poly.getNode();
4894
9682
  return true;
4895
}
4896
4897
59003
void TheoryArithPrivate::setToMin(int sgn, std::pair<Node, DeltaRational>& min, const std::pair<Node, DeltaRational>& e){
4898
59003
  if(sgn != 0){
4899
30401
    if(min.first.isNull() && !e.first.isNull()){
4900
7870
      min = e;
4901
22531
    }else if(!min.first.isNull() && !e.first.isNull()){
4902
1535
      if(sgn > 0 && min.second > e.second){
4903
        min = e;
4904
1535
      }else if(sgn < 0 &&  min.second < e.second){
4905
        min = e;
4906
      }
4907
    }
4908
  }
4909
59003
}
4910
4911
// std::pair<bool, Node> TheoryArithPrivate::entailmentUpperCheck(const Rational& lm, Node lp, const Rational& rm, Node rp, const DeltaRational& sep, const ArithEntailmentCheckParameters& params, ArithEntailmentCheckSideEffects& out){
4912
4913
//   Rational negRM = -rm;
4914
//   Node diff = NodeManager::currentNM()->mkNode(MULT, mkRationalConstan(lm), lp) + (negRM * rp);
4915
4916
//   Rational diffm;
4917
//   Node diffp;
4918
//   decompose(diff, diffm, diffNode);
4919
4920
4921
//   std::pair<Node, DeltaRational> bestUbLeft, bestLbRight, bestUbDiff, tmp;
4922
//   bestUbLeft = bestLbRight = bestUbDiff = make_pair(Node::Null(), DeltaRational());
4923
4924
//   return make_pair(false, Node::null());
4925
// }
4926
4927
/**
4928
 * Decomposes a literal into the form:
4929
 *   dir*[lm*( lp )] k dir*[ [rm*( rp )] + sep ]
4930
 *   dir*[dm* dp]  k dir *sep
4931
 *   dir is either 1 or -1
4932
 */
4933
4830
bool TheoryArithPrivate::decomposeLiteral(Node lit, Kind& k, int& dir, Rational& lm,  Node& lp, Rational& rm, Node& rp, Rational& dm, Node& dp, DeltaRational& sep){
4934
4830
  bool negated = (lit.getKind() == kind::NOT);
4935
9660
  TNode atom = negated ? lit[0] : lit;
4936
4937
9660
  TNode left = atom[0];
4938
9660
  TNode right = atom[1];
4939
4940
  // left : lm*( lp ) + lc
4941
  // right: rm*( rp ) + rc
4942
9660
  Rational lc, rc;
4943
4830
  bool success = decomposeTerm(left, lm, lp, lc);
4944
4830
  if(!success){ return false; }
4945
4830
  success = decomposeTerm(right, rm, rp, rc);
4946
4830
  if(!success){ return false; }
4947
4948
9660
  Node diff = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::MINUS, left, right));
4949
9660
  Rational dc;
4950
4830
  success = decomposeTerm(diff, dm, dp, dc);
4951
4830
  Assert(success);
4952
4953
  // reduce the kind of the to not include literals
4954
  // GT, NOT LEQ
4955
  // GEQ, NOT LT
4956
  // LT, NOT GEQ
4957
  // LEQ, NOT LT
4958
4830
  Kind atomKind = atom.getKind();
4959
4830
  Kind normKind = negated ? negateKind(atomKind) : atomKind;
4960
4961
4830
  if(normKind == GEQ || normKind == GT){
4962
2307
    dir = -1;
4963
2307
    normKind = (normKind == GEQ) ? LEQ : LT;
4964
  }else{
4965
2523
    dir = 1;
4966
  }
4967
4968
9660
  Debug("arith::decomp") << "arith::decomp "
4969
4830
                         << lit << "(" << normKind << "*" << dir << ")"<< endl
4970
4830
                         << "  left:" << lc << " + " << lm << "*(" <<  lp << ") : " <<left << endl
4971
4830
                         << "  right:" << rc << " + " << rm << "*(" <<  rp << ") : " << right << endl
4972
4830
                         << "  diff: " << dc << " + " << dm << "*("<< dp <<"): " << diff << endl
4973
4830
                         << "  sep: " << sep << endl;
4974
4975
4976
  // k in LT, LEQ, EQUAL, DISEQUAL
4977
  // [dir*lm*( lp ) + dir*lc] k [dir*rm*( rp ) + dir*rc]
4978
9660
  Rational change = rc - lc;
4979
4830
  Assert(change == (-dc));
4980
  // [dir*lm*( lp )] k [dir*rm*( rp ) + dir*(rc - lc)]
4981
4830
  if(normKind == LT){
4982
2501
    sep = DeltaRational(change, Rational(-1));
4983
2501
    k = LEQ;
4984
  }else{
4985
2329
    sep = DeltaRational(change);
4986
2329
    k = normKind;
4987
  }
4988
  // k in LEQ, EQUAL, DISEQUAL
4989
  // dir*lm*( lp ) k [dir*rm*( rp )] + dir*(sep + d * delta)
4990
4830
  return true;
4991
}
4992
4993
/**
4994
 *  Precondition:
4995
 *   tp is a polynomial not containing an ite.
4996
 *   either tp is constant or contains no constants.
4997
 *  Post:
4998
 *    if tmp.first is not null, then
4999
 *      sgn * tp <= sgn * tmp.second
5000
 */
5001
28980
void TheoryArithPrivate::entailmentCheckBoundLookup(std::pair<Node, DeltaRational>& tmp, int sgn, TNode tp) const {
5002
28980
  tmp.first = Node::null();
5003
28980
  if(sgn == 0){ return; }
5004
5005
14556
  Assert(Polynomial::isMember(tp));
5006
14556
  if(tp.getKind() == CONST_RATIONAL){
5007
4808
    tmp.first = mkBoolNode(true);
5008
4808
    tmp.second = DeltaRational(tp.getConst<Rational>());
5009
9748
  }else if(d_partialModel.hasArithVar(tp)){
5010
7628
    Assert(tp.getKind() != CONST_RATIONAL);
5011
7628
    ArithVar v = d_partialModel.asArithVar(tp);
5012
7628
    Assert(v != ARITHVAR_SENTINEL);
5013
    ConstraintP c = (sgn > 0)
5014
11338
      ? d_partialModel.getUpperBoundConstraint(v)
5015
11338
      : d_partialModel.getLowerBoundConstraint(v);
5016
7628
    if(c != NullConstraint){
5017
172
      tmp.first = Constraint::externalExplainByAssertions({c});
5018
172
      tmp.second = c->getValue();
5019
    }
5020
  }
5021
}
5022
5023
28488
void TheoryArithPrivate::entailmentCheckRowSum(std::pair<Node, DeltaRational>& tmp, int sgn, TNode tp) const {
5024
28488
  tmp.first = Node::null();
5025
54086
  if(sgn == 0){ return; }
5026
14310
  if(tp.getKind() != PLUS){ return; }
5027
9464
  Assert(Polynomial::isMember(tp));
5028
5029
9464
  tmp.second = DeltaRational(0);
5030
12354
  NodeBuilder nb(kind::AND);
5031
5032
12354
  Polynomial p = Polynomial::parsePolynomial(tp);
5033
18672
  for(Polynomial::iterator i = p.begin(), iend = p.end(); i != iend; ++i) {
5034
24990
    Monomial m = *i;
5035
24990
    Node x = m.getVarList().getNode();
5036
15782
    if(d_partialModel.hasArithVar(x)){
5037
15738
      ArithVar v = d_partialModel.asArithVar(x);
5038
15738
      const Rational& coeff = m.getConstant().getValue();
5039
15738
      int dir = sgn * coeff.sgn();
5040
      ConstraintP c = (dir > 0)
5041
22056
        ? d_partialModel.getUpperBoundConstraint(v)
5042
22056
        : d_partialModel.getLowerBoundConstraint(v);
5043
15738
      if(c != NullConstraint){
5044
9208
        tmp.second += c->getValue() * coeff;
5045
9208
        c->externalExplainByAssertions(nb);
5046
      }else{
5047
        //failed
5048
6530
        return;
5049
      }
5050
    }else{
5051
      // failed
5052
44
      return;
5053
    }
5054
  }
5055
  // success
5056
2890
  tmp.first = nb;
5057
}
5058
5059
3600
ArithProofRuleChecker* TheoryArithPrivate::getProofChecker()
5060
{
5061
3600
  return &d_checker;
5062
}
5063
5064
}  // namespace arith
5065
}  // namespace theory
5066
28191
}  // namespace cvc5