GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/theory_arith_private.cpp Lines: 1715 2923 58.7 %
Date: 2021-09-17 Branches: 3442 12528 27.5 %

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