GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/theory_arith_private.cpp Lines: 1752 2957 59.2 %
Date: 2021-08-19 Branches: 3412 12470 27.4 %

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