GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/theory_arith_private.cpp Lines: 1715 2921 58.7 %
Date: 2021-09-18 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
9940
TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing,
89
                                       Env& env,
90
9940
                                       BranchAndBound& bab)
91
    : EnvObj(env),
92
      d_containing(containing),
93
      d_foundNl(false),
94
      d_rowTracking(),
95
      d_bab(bab),
96
9940
      d_pnm(d_env.isTheoryProofProducing() ? d_env.getProofNodeManager()
97
                                           : nullptr),
98
      d_checker(),
99
19880
      d_pfGen(new EagerProofGenerator(d_pnm, userContext())),
100
      d_constraintDatabase(context(),
101
9940
                           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
9940
      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
19880
      d_partialModel(context(), DeltaComputeCallback(*this)),
119
      d_errorSet(
120
9940
          d_partialModel, TableauSizes(&d_tableau), BoundCountingLookup(*this)),
121
      d_tableau(),
122
      d_linEq(d_partialModel,
123
              d_tableau,
124
              d_rowTracking,
125
19880
              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
19880
      d_blackBoxConflict(context(), Node::null()),
133
19880
      d_blackBoxConflictPf(context(), std::shared_ptr<ProofNode>(nullptr)),
134
      d_congruenceManager(context(),
135
                          userContext(),
136
                          d_constraintDatabase,
137
19880
                          SetupLiteralCallBack(*this),
138
                          d_partialModel,
139
                          RaiseEqualityEngineConflict(*this),
140
                          d_pnm),
141
9940
      d_cmEnabled(context(), options().arith.arithCongMan),
142
143
      d_dualSimplex(
144
19880
          d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
145
      d_fcSimplex(
146
19880
          d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
147
      d_soiSimplex(
148
19880
          d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
149
      d_attemptSolSimplex(
150
19880
          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
9940
      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
268380
      d_statistics(statisticsRegistry(), "theory::arith::")
175
{
176
9940
}
177
178
29811
TheoryArithPrivate::~TheoryArithPrivate(){
179
9937
  if(d_treeLog != NULL){ delete d_treeLog; }
180
9937
  if(d_approxStats != NULL) { delete d_approxStats; }
181
19874
}
182
183
9901
bool TheoryArithPrivate::needsEqualityEngine(EeSetupInfo& esi)
184
{
185
9901
  if (!d_cmEnabled)
186
  {
187
    return false;
188
  }
189
9901
  return d_congruenceManager.needsEqualityEngine(esi);
190
}
191
9940
void TheoryArithPrivate::finishInit()
192
{
193
9940
  if (d_cmEnabled)
194
  {
195
9901
    eq::EqualityEngine* ee = d_containing.getEqualityEngine();
196
9901
    Assert(ee != nullptr);
197
9901
    d_congruenceManager.finishInit(ee);
198
  }
199
9940
}
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
9940
TheoryArithPrivate::Statistics::Statistics(StatisticsRegistry& reg,
264
9940
                                           const std::string& name)
265
    : d_statAssertUpperConflicts(
266
19880
        reg.registerInt(name + "AssertUpperConflicts")),
267
      d_statAssertLowerConflicts(
268
19880
          reg.registerInt(name + "AssertLowerConflicts")),
269
19880
      d_statUserVariables(reg.registerInt(name + "UserVariables")),
270
19880
      d_statAuxiliaryVariables(reg.registerInt(name + "AuxiliaryVariables")),
271
19880
      d_statDisequalitySplits(reg.registerInt(name + "DisequalitySplits")),
272
      d_statDisequalityConflicts(
273
19880
          reg.registerInt(name + "DisequalityConflicts")),
274
19880
      d_simplifyTimer(reg.registerTimer(name + "simplifyTimer")),
275
19880
      d_staticLearningTimer(reg.registerTimer(name + "staticLearningTimer")),
276
19880
      d_presolveTime(reg.registerTimer(name + "presolveTime")),
277
19880
      d_newPropTime(reg.registerTimer(name + "newPropTimer")),
278
      d_externalBranchAndBounds(
279
19880
          reg.registerInt(name + "externalBranchAndBounds")),
280
19880
      d_initialTableauSize(reg.registerInt(name + "initialTableauSize")),
281
19880
      d_currSetToSmaller(reg.registerInt(name + "currSetToSmaller")),
282
19880
      d_smallerSetToCurr(reg.registerInt(name + "smallerSetToCurr")),
283
19880
      d_restartTimer(reg.registerTimer(name + "restartTimer")),
284
19880
      d_boundComputationTime(reg.registerTimer(name + "bound::time")),
285
19880
      d_boundComputations(reg.registerInt(name + "bound::boundComputations")),
286
19880
      d_boundPropagations(reg.registerInt(name + "bound::boundPropagations")),
287
19880
      d_unknownChecks(reg.registerInt(name + "status::unknowns")),
288
19880
      d_maxUnknownsInARow(reg.registerInt(name + "status::maxUnknownsInARow")),
289
      d_avgUnknownsInARow(
290
19880
          reg.registerAverage(name + "status::avgUnknownsInARow")),
291
      d_revertsOnConflicts(
292
19880
          reg.registerInt(name + "status::revertsOnConflicts")),
293
      d_commitsOnConflicts(
294
19880
          reg.registerInt(name + "status::commitsOnConflicts")),
295
      d_nontrivialSatChecks(
296
19880
          reg.registerInt(name + "status::nontrivialSatChecks")),
297
19880
      d_replayLogRecCount(reg.registerInt(name + "z::approx::replay::rec")),
298
      d_replayLogRecConflictEscalation(
299
19880
          reg.registerInt(name + "z::approx::replay::rec::escalation")),
300
      d_replayLogRecEarlyExit(
301
19880
          reg.registerInt(name + "z::approx::replay::rec::earlyexit")),
302
      d_replayBranchCloseFailures(reg.registerInt(
303
19880
          name + "z::approx::replay::rec::branch::closefailures")),
304
      d_replayLeafCloseFailures(reg.registerInt(
305
19880
          name + "z::approx::replay::rec::leaf::closefailures")),
306
      d_replayBranchSkips(
307
19880
          reg.registerInt(name + "z::approx::replay::rec::branch::skips")),
308
      d_mirCutsAttempted(
309
19880
          reg.registerInt(name + "z::approx::cuts::mir::attempted")),
310
      d_gmiCutsAttempted(
311
19880
          reg.registerInt(name + "z::approx::cuts::gmi::attempted")),
312
      d_branchCutsAttempted(
313
19880
          reg.registerInt(name + "z::approx::cuts::branch::attempted")),
314
      d_cutsReconstructed(
315
19880
          reg.registerInt(name + "z::approx::cuts::reconstructed")),
316
      d_cutsReconstructionFailed(
317
19880
          reg.registerInt(name + "z::approx::cuts::reconstructed::failed")),
318
19880
      d_cutsProven(reg.registerInt(name + "z::approx::cuts::proofs")),
319
      d_cutsProofFailed(
320
19880
          reg.registerInt(name + "z::approx::cuts::proofs::failed")),
321
      d_mipReplayLemmaCalls(
322
19880
          reg.registerInt(name + "z::approx::external::calls")),
323
19880
      d_mipExternalCuts(reg.registerInt(name + "z::approx::external::cuts")),
324
      d_mipExternalBranch(
325
19880
          reg.registerInt(name + "z::approx::external::branches")),
326
19880
      d_inSolveInteger(reg.registerInt(name + "z::approx::inSolverInteger")),
327
      d_branchesExhausted(
328
19880
          reg.registerInt(name + "z::approx::exhausted::branches")),
329
19880
      d_execExhausted(reg.registerInt(name + "z::approx::exhausted::exec")),
330
19880
      d_pivotsExhausted(reg.registerInt(name + "z::approx::exhausted::pivots")),
331
19880
      d_panicBranches(reg.registerInt(name + "z::arith::paniclemmas")),
332
19880
      d_relaxCalls(reg.registerInt(name + "z::arith::relax::calls")),
333
19880
      d_relaxLinFeas(reg.registerInt(name + "z::arith::relax::feasible::res")),
334
      d_relaxLinFeasFailures(
335
19880
          reg.registerInt(name + "z::arith::relax::feasible::failures")),
336
19880
      d_relaxLinInfeas(reg.registerInt(name + "z::arith::relax::infeasible")),
337
      d_relaxLinInfeasFailures(
338
19880
          reg.registerInt(name + "z::arith::relax::infeasible::failures")),
339
19880
      d_relaxLinExhausted(reg.registerInt(name + "z::arith::relax::exhausted")),
340
19880
      d_relaxOthers(reg.registerInt(name + "z::arith::relax::other")),
341
      d_applyRowsDeleted(
342
19880
          reg.registerInt(name + "z::arith::cuts::applyRowsDeleted")),
343
      d_replaySimplexTimer(
344
19880
          reg.registerTimer(name + "z::approx::replay::simplex::timer")),
345
      d_replayLogTimer(
346
19880
          reg.registerTimer(name + "z::approx::replay::log::timer")),
347
19880
      d_solveIntTimer(reg.registerTimer(name + "z::solveInt::timer")),
348
      d_solveRealRelaxTimer(
349
19880
          reg.registerTimer(name + "z::solveRealRelax::timer")),
350
19880
      d_solveIntCalls(reg.registerInt(name + "z::solveInt::calls")),
351
      d_solveStandardEffort(
352
19880
          reg.registerInt(name + "z::solveInt::calls::standardEffort")),
353
19880
      d_approxDisabled(reg.registerInt(name + "z::approxDisabled")),
354
19880
      d_replayAttemptFailed(reg.registerInt(name + "z::replayAttemptFailed")),
355
      d_cutsRejectedDuringReplay(
356
19880
          reg.registerInt(name + "z::approx::replay::cuts::rejected")),
357
      d_cutsRejectedDuringLemmas(
358
19880
          reg.registerInt(name + "z::approx::external::cuts::rejected")),
359
19880
      d_satPivots(reg.registerHistogram<uint32_t>(name + "pivots::sat")),
360
19880
      d_unsatPivots(reg.registerHistogram<uint32_t>(name + "pivots::unsat")),
361
      d_unknownPivots(
362
19880
          reg.registerHistogram<uint32_t>(name + "pivots::unknown")),
363
      d_solveIntModelsAttempts(
364
19880
          reg.registerInt(name + "z::solveInt::models::attempts")),
365
      d_solveIntModelsSuccessful(
366
19880
          reg.registerInt(name + "zzz::solveInt::models::successful")),
367
19880
      d_mipTimer(reg.registerTimer(name + "z::approx::mip::timer")),
368
19880
      d_lpTimer(reg.registerTimer(name + "z::approx::lp::timer")),
369
19880
      d_mipProofsAttempted(reg.registerInt(name + "z::mip::proofs::attempted")),
370
      d_mipProofsSuccessful(
371
19880
          reg.registerInt(name + "z::mip::proofs::successful")),
372
      d_numBranchesFailed(
373
725620
          reg.registerInt(name + "z::mip::branch::proof::failed"))
374
{
375
9940
}
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
194186
bool TheoryArithPrivate::isProofEnabled() const
390
{
391
194186
  return d_pnm != nullptr;
392
}
393
394
78910
void TheoryArithPrivate::raiseConflict(ConstraintCP a, InferenceId id){
395
78910
  Assert(a->inConflict());
396
157820
  d_conflicts.push_back(std::make_pair(a, id));
397
78910
}
398
399
2258
void TheoryArithPrivate::raiseBlackBoxConflict(Node bb,
400
                                               std::shared_ptr<ProofNode> pf)
401
{
402
2258
  Debug("arith::bb") << "raiseBlackBoxConflict: " << bb << std::endl;
403
2258
  if (d_blackBoxConflict.get().isNull())
404
  {
405
2258
    if (isProofEnabled())
406
    {
407
413
      Debug("arith::bb") << "  with proof " << pf << std::endl;
408
413
      d_blackBoxConflictPf.set(pf);
409
    }
410
2258
    d_blackBoxConflict = bb;
411
  }
412
2258
}
413
414
17699695
bool TheoryArithPrivate::anyConflict() const
415
{
416
17699695
  return !conflictQueueEmpty() || !d_blackBoxConflict.get().isNull();
417
}
418
419
55212
void TheoryArithPrivate::revertOutOfConflict(){
420
55212
  d_partialModel.revertAssignmentChanges();
421
55212
  clearUpdates();
422
55212
  d_currentPropagationList.clear();
423
55212
}
424
425
1688837
void TheoryArithPrivate::clearUpdates(){
426
1688837
  d_updatedBounds.purge();
427
1688837
}
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
487576
void TheoryArithPrivate::zeroDifferenceDetected(ArithVar x){
445
487576
  if(d_cmEnabled){
446
487576
    Assert(d_congruenceManager.isWatchedVariable(x));
447
487576
    Assert(d_partialModel.upperBoundIsZero(x));
448
487576
    Assert(d_partialModel.lowerBoundIsZero(x));
449
450
487576
    ConstraintP lb = d_partialModel.getLowerBoundConstraint(x);
451
487576
    ConstraintP ub = d_partialModel.getUpperBoundConstraint(x);
452
453
487576
    if(lb->isEquality()){
454
244571
      d_congruenceManager.watchedVariableIsZero(lb);
455
243005
    }else if(ub->isEquality()){
456
      d_congruenceManager.watchedVariableIsZero(ub);
457
    }else{
458
243005
      d_congruenceManager.watchedVariableIsZero(lb, ub);
459
    }
460
  }
461
487576
}
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
1961478
bool TheoryArithPrivate::AssertLower(ConstraintP constraint){
490
1961478
  Assert(constraint != NullConstraint);
491
1961478
  Assert(constraint->isLowerBound());
492
1961478
  Assert(constraint->isTrue());
493
1961478
  Assert(!constraint->negationHasProof());
494
495
1961478
  ArithVar x_i = constraint->getVariable();
496
1961478
  const DeltaRational& c_i = constraint->getValue();
497
498
1961478
  Debug("arith") << "AssertLower(" << x_i << " " << c_i << ")"<< std::endl;
499
500
1961478
  Assert(!isInteger(x_i) || c_i.isIntegral());
501
502
  //TODO Relax to less than?
503
1961478
  if(d_partialModel.lessThanLowerBound(x_i, c_i)){
504
805873
    return false; //sat
505
  }
506
507
1155605
  int cmpToUB = d_partialModel.cmpToUpperBound(x_i, c_i);
508
1155605
  if(cmpToUB > 0){ //  c_i < \lowerbound(x_i)
509
702
    ConstraintP ubc = d_partialModel.getUpperBoundConstraint(x_i);
510
702
    ConstraintP negation = constraint->getNegation();
511
702
    negation->impliedByUnate(ubc, true);
512
513
702
    raiseConflict(constraint, InferenceId::ARITH_CONF_LOWER);
514
515
702
    ++(d_statistics.d_statAssertLowerConflicts);
516
702
    return true;
517
1154903
  }else if(cmpToUB == 0){
518
275160
    if(isInteger(x_i)){
519
77164
      d_constantIntegerVariables.push_back(x_i);
520
77164
      Debug("dio::push") << "dio::push " << x_i << endl;
521
    }
522
275160
    ConstraintP ub = d_partialModel.getUpperBoundConstraint(x_i);
523
524
275160
    if(d_cmEnabled){
525
275160
      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
93188
        d_congruenceManager.equalsConstant(constraint, ub);
530
      }
531
    }
532
533
275160
    const ValueCollection& vc = constraint->getValueCollection();
534
275160
    if(vc.hasEquality()){
535
194471
      Assert(vc.hasDisequality());
536
194471
      ConstraintP eq = vc.getEquality();
537
194471
      ConstraintP diseq = vc.getDisequality();
538
      // x <= b, x >= b |= x = b
539
      // (x > b or x < b or x = b)
540
194471
      Debug("arith::eq") << "lb == ub, propagate eq" << eq << endl;
541
194471
      bool triConflict = diseq->isTrue();
542
543
194471
      if(!eq->isTrue()){
544
188712
        eq->impliedByTrichotomy(constraint, ub, triConflict);
545
188712
        eq->tryToPropagate();
546
      }
547
194471
      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
879743
    Assert(cmpToUB < 0);
556
879743
    const ValueCollection& vc = constraint->getValueCollection();
557
558
879743
    if(vc.hasDisequality()){
559
235978
      const ConstraintP diseq = vc.getDisequality();
560
235978
      if(diseq->isTrue()){
561
15183
        const ConstraintP ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound);
562
15183
        ConstraintP negUb = ub->getNegation();
563
564
        // l <= x, l != x |= l < x
565
        // |= not (l >= x)
566
15183
        bool ubInConflict = ub->hasProof();
567
15183
        bool learnNegUb = !(negUb->hasProof());
568
15183
        if(learnNegUb){
569
15183
          negUb->impliedByTrichotomy(constraint, diseq, ubInConflict);
570
15183
          negUb->tryToPropagate();
571
        }
572
15183
        if(ubInConflict){
573
          raiseConflict(ub, InferenceId::ARITH_CONF_TRICHOTOMY);
574
          return true;
575
15183
        }else if(learnNegUb){
576
15183
          d_learnedBounds.push_back(negUb);
577
        }
578
      }
579
    }
580
  }
581
582
1154903
  d_currentPropagationList.push_back(constraint);
583
1154903
  d_currentPropagationList.push_back(d_partialModel.getLowerBoundConstraint(x_i));
584
585
1154903
  d_partialModel.setLowerBoundConstraint(constraint);
586
587
1154903
  if(d_cmEnabled){
588
1154612
    if(d_congruenceManager.isWatchedVariable(x_i)){
589
656709
      int sgn = c_i.sgn();
590
656709
      if(sgn > 0){
591
181937
        d_congruenceManager.watchedVariableCannotBeZero(constraint);
592
474772
      }else if(sgn == 0 && d_partialModel.upperBoundIsZero(x_i)){
593
181972
        zeroDifferenceDetected(x_i);
594
      }
595
    }
596
  }
597
598
1154903
  d_updatedBounds.softAdd(x_i);
599
600
1154903
  if(Debug.isOn("model")) {
601
    Debug("model") << "before" << endl;
602
    d_partialModel.printModel(x_i);
603
    d_tableau.debugPrintIsBasic(x_i);
604
  }
605
606
1154903
  if(!d_tableau.isBasic(x_i)){
607
396041
    if(d_partialModel.getAssignment(x_i) < c_i){
608
59010
      d_linEq.update(x_i, c_i);
609
    }
610
  }else{
611
758862
    d_errorSet.signalVariable(x_i);
612
  }
613
614
1154903
  if(Debug.isOn("model")) {
615
    Debug("model") << "after" << endl;
616
    d_partialModel.printModel(x_i);
617
    d_tableau.debugPrintIsBasic(x_i);
618
 }
619
620
1154903
  return false; //sat
621
}
622
623
/* procedure AssertUpper( x_i <= c_i) */
624
1918598
bool TheoryArithPrivate::AssertUpper(ConstraintP constraint){
625
1918598
  Assert(constraint != NullConstraint);
626
1918598
  Assert(constraint->isUpperBound());
627
1918598
  Assert(constraint->isTrue());
628
1918598
  Assert(!constraint->negationHasProof());
629
630
1918598
  ArithVar x_i = constraint->getVariable();
631
1918598
  const DeltaRational& c_i = constraint->getValue();
632
633
1918598
  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
1918598
  Assert(!isInteger(x_i) || c_i.isIntegral());
639
640
1918598
  Debug("arith") << "AssertUpper(" << x_i << " " << c_i << ")"<< std::endl;
641
642
1918598
  if(d_partialModel.greaterThanUpperBound(x_i, c_i) ){ // \upperbound(x_i) <= c_i
643
899039
    return false; //sat
644
  }
645
646
  // cmpToLb =  \lowerbound(x_i).cmp(c_i)
647
1019559
  int cmpToLB = d_partialModel.cmpToLowerBound(x_i, c_i);
648
1019559
  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
2118
    ConstraintP lbc = d_partialModel.getLowerBoundConstraint(x_i);
652
2118
    ConstraintP negConstraint = constraint->getNegation();
653
2118
    negConstraint->impliedByUnate(lbc, true);
654
2118
    raiseConflict(constraint, InferenceId::ARITH_CONF_UPPER);
655
2118
    ++(d_statistics.d_statAssertUpperConflicts);
656
2118
    return true;
657
1017441
  }else if(cmpToLB == 0){ // \lowerBound(x_i) == \upperbound(x_i)
658
134507
    if(isInteger(x_i)){
659
84398
      d_constantIntegerVariables.push_back(x_i);
660
84398
      Debug("dio::push") << "dio::push " << x_i << endl;
661
    }
662
663
134507
    const ValueCollection& vc = constraint->getValueCollection();
664
134507
    ConstraintP lb = d_partialModel.getLowerBoundConstraint(x_i);
665
134507
    if(d_cmEnabled){
666
134507
      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
73474
        d_congruenceManager.equalsConstant(lb, constraint);
671
      }
672
    }
673
674
134507
    if(vc.hasDisequality()){
675
104071
      Assert(vc.hasDisequality());
676
104071
      ConstraintP eq = vc.getEquality();
677
104071
      ConstraintP diseq = vc.getDisequality();
678
      // x <= b, x >= b |= x = b
679
      // (x > b or x < b or x = b)
680
104071
      Debug("arith::eq") << "lb == ub, propagate eq" << eq << endl;
681
104071
      bool triConflict = diseq->isTrue();
682
104071
      if(!eq->isTrue()){
683
74898
        eq->impliedByTrichotomy(constraint, lb, triConflict);
684
74898
        eq->tryToPropagate();
685
      }
686
104071
      if(triConflict){
687
4
        ++(d_statistics.d_statDisequalityConflicts);
688
4
        raiseConflict(eq, InferenceId::ARITH_CONF_TRICHOTOMY);
689
4
        return true;
690
      }
691
    }
692
882934
  }else if(cmpToLB > 0){
693
    // l <= x <= u and l < u
694
882934
    Assert(cmpToLB > 0);
695
882934
    const ValueCollection& vc = constraint->getValueCollection();
696
697
882934
    if(vc.hasDisequality()){
698
330866
      const ConstraintP diseq = vc.getDisequality();
699
330866
      if(diseq->isTrue()){
700
40463
        const ConstraintP lb = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), LowerBound);
701
40463
        ConstraintP negLb = lb->getNegation();
702
703
        // x <= u, u != x |= u < x
704
        // |= not (u >= x)
705
40463
        bool lbInConflict = lb->hasProof();
706
40463
        bool learnNegLb = !(negLb->hasProof());
707
40463
        if(learnNegLb){
708
40463
          negLb->impliedByTrichotomy(constraint, diseq, lbInConflict);
709
40463
          negLb->tryToPropagate();
710
        }
711
40463
        if(lbInConflict){
712
          raiseConflict(lb, InferenceId::ARITH_CONF_TRICHOTOMY);
713
          return true;
714
40463
        }else if(learnNegLb){
715
40463
          d_learnedBounds.push_back(negLb);
716
        }
717
      }
718
    }
719
  }
720
721
1017437
  d_currentPropagationList.push_back(constraint);
722
1017437
  d_currentPropagationList.push_back(d_partialModel.getUpperBoundConstraint(x_i));
723
  //It is fine if this is NullConstraint
724
725
1017437
  d_partialModel.setUpperBoundConstraint(constraint);
726
727
1017437
  if(d_cmEnabled){
728
1017122
    if(d_congruenceManager.isWatchedVariable(x_i)){
729
625699
      int sgn = c_i.sgn();
730
625699
      if(sgn < 0){
731
288577
        d_congruenceManager.watchedVariableCannotBeZero(constraint);
732
337122
      }else if(sgn == 0 && d_partialModel.lowerBoundIsZero(x_i)){
733
61033
        zeroDifferenceDetected(x_i);
734
      }
735
    }
736
  }
737
738
1017437
  d_updatedBounds.softAdd(x_i);
739
740
1017437
  if(Debug.isOn("model")) {
741
    Debug("model") << "before" << endl;
742
    d_partialModel.printModel(x_i);
743
    d_tableau.debugPrintIsBasic(x_i);
744
  }
745
746
1017437
  if(!d_tableau.isBasic(x_i)){
747
393854
    if(d_partialModel.getAssignment(x_i) > c_i){
748
45521
      d_linEq.update(x_i, c_i);
749
    }
750
  }else{
751
623583
    d_errorSet.signalVariable(x_i);
752
  }
753
754
1017437
  if(Debug.isOn("model")) {
755
    Debug("model") << "after" << endl;
756
    d_partialModel.printModel(x_i);
757
    d_tableau.debugPrintIsBasic(x_i);
758
  }
759
760
1017437
  return false; //sat
761
}
762
763
764
/* procedure AssertEquality( x_i == c_i ) */
765
1058381
bool TheoryArithPrivate::AssertEquality(ConstraintP constraint){
766
1058381
  Assert(constraint != NullConstraint);
767
1058381
  Assert(constraint->isEquality());
768
1058381
  Assert(constraint->isTrue());
769
1058381
  Assert(!constraint->negationHasProof());
770
771
1058381
  ArithVar x_i = constraint->getVariable();
772
1058381
  const DeltaRational& c_i = constraint->getValue();
773
774
1058381
  Debug("arith") << "AssertEquality(" << x_i << " " << c_i << ")"<< std::endl;
775
776
  //Should be fine in integers
777
1058381
  Assert(!isInteger(x_i) || c_i.isIntegral());
778
779
1058381
  int cmpToLB = d_partialModel.cmpToLowerBound(x_i, c_i);
780
1058381
  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
1058381
  if(cmpToUB >= 0 && cmpToLB <= 0){
785
46706
    return false; //sat
786
  }
787
788
1011675
  if(cmpToUB > 0 || cmpToLB < 0){
789
3261
    ConstraintP cb = (cmpToUB > 0) ?  d_partialModel.getUpperBoundConstraint(x_i) :
790
3261
      d_partialModel.getLowerBoundConstraint(x_i);
791
2096
    ConstraintP diseq = constraint->getNegation();
792
2096
    Assert(!diseq->isTrue());
793
2096
    diseq->impliedByUnate(cb, true);
794
2096
    raiseConflict(constraint, InferenceId::ARITH_CONF_EQ);
795
2096
    return true;
796
  }
797
798
1009579
  Assert(cmpToUB <= 0);
799
1009579
  Assert(cmpToLB >= 0);
800
1009579
  Assert(cmpToUB < 0 || cmpToLB > 0);
801
802
1009579
  if(isInteger(x_i)){
803
964192
    d_constantIntegerVariables.push_back(x_i);
804
964192
    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
1009579
  d_currentPropagationList.push_back(constraint);
810
1009579
  d_currentPropagationList.push_back(d_partialModel.getLowerBoundConstraint(x_i));
811
1009579
  d_currentPropagationList.push_back(d_partialModel.getUpperBoundConstraint(x_i));
812
813
1009579
  d_partialModel.setUpperBoundConstraint(constraint);
814
1009579
  d_partialModel.setLowerBoundConstraint(constraint);
815
816
1009579
  if(d_cmEnabled){
817
1008746
    if(d_congruenceManager.isWatchedVariable(x_i)){
818
279706
      int sgn = c_i.sgn();
819
279706
      if(sgn == 0){
820
244571
        zeroDifferenceDetected(x_i);
821
      }else{
822
35135
        d_congruenceManager.watchedVariableCannotBeZero(constraint);
823
35135
        d_congruenceManager.equalsConstant(constraint);
824
      }
825
    }else{
826
729040
      d_congruenceManager.equalsConstant(constraint);
827
    }
828
  }
829
830
1009579
  d_updatedBounds.softAdd(x_i);
831
832
1009579
  if(Debug.isOn("model")) {
833
    Debug("model") << "before" << endl;
834
    d_partialModel.printModel(x_i);
835
    d_tableau.debugPrintIsBasic(x_i);
836
  }
837
838
1009579
  if(!d_tableau.isBasic(x_i)){
839
546805
    if(!(d_partialModel.getAssignment(x_i) == c_i)){
840
53623
      d_linEq.update(x_i, c_i);
841
    }
842
  }else{
843
462774
    d_errorSet.signalVariable(x_i);
844
  }
845
846
1009579
  if(Debug.isOn("model")) {
847
    Debug("model") << "after" << endl;
848
    d_partialModel.printModel(x_i);
849
    d_tableau.debugPrintIsBasic(x_i);
850
  }
851
852
1009579
  return false;
853
}
854
855
856
/* procedure AssertDisequality( x_i != c_i ) */
857
814855
bool TheoryArithPrivate::AssertDisequality(ConstraintP constraint){
858
814855
  Assert(constraint != NullConstraint);
859
814855
  Assert(constraint->isDisequality());
860
814855
  Assert(constraint->isTrue());
861
814855
  Assert(!constraint->negationHasProof());
862
863
814855
  ArithVar x_i = constraint->getVariable();
864
814855
  const DeltaRational& c_i = constraint->getValue();
865
814855
  Debug("arith") << "AssertDisequality(" << x_i << " " << c_i << ")"<< std::endl;
866
867
  //Should be fine in integers
868
814855
  Assert(!isInteger(x_i) || c_i.isIntegral());
869
870
814855
  if(d_cmEnabled){
871
814576
    if(d_congruenceManager.isWatchedVariable(x_i)){
872
178440
      int sgn = c_i.sgn();
873
178440
      if(sgn == 0){
874
158775
        d_congruenceManager.watchedVariableCannotBeZero(constraint);
875
      }
876
    }
877
  }
878
879
814855
  const ValueCollection& vc = constraint->getValueCollection();
880
814855
  if(vc.hasLowerBound() && vc.hasUpperBound()){
881
355820
    const ConstraintP lb = vc.getLowerBound();
882
355820
    const ConstraintP ub = vc.getUpperBound();
883
355820
    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
814768
  if(vc.hasLowerBound() ){
893
403870
    const ConstraintP lb = vc.getLowerBound();
894
403870
    if(lb->isTrue()){
895
138036
      const ConstraintP ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound);
896
138036
      Assert(!ub->isTrue());
897
138036
      Debug("arith::eq") << "propagate UpperBound " << constraint << lb << ub << endl;
898
138036
      const ConstraintP negUb = ub->getNegation();
899
138036
      if(!negUb->isTrue()){
900
76023
        negUb->impliedByTrichotomy(constraint, lb, false);
901
76023
        negUb->tryToPropagate();
902
76023
        d_learnedBounds.push_back(negUb);
903
      }
904
    }
905
  }
906
814768
  if(vc.hasUpperBound()){
907
412421
    const ConstraintP ub = vc.getUpperBound();
908
412421
    if(ub->isTrue()){
909
82137
      const ConstraintP lb = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), LowerBound);
910
82137
      Assert(!lb->isTrue());
911
912
82137
      Debug("arith::eq") << "propagate LowerBound " << constraint << lb << ub << endl;
913
82137
      const ConstraintP negLb = lb->getNegation();
914
82137
      if(!negLb->isTrue()){
915
16668
        negLb->impliedByTrichotomy(constraint, ub, false);
916
16668
        negLb->tryToPropagate();
917
16668
        d_learnedBounds.push_back(negLb);
918
      }
919
    }
920
  }
921
922
814768
  bool split = constraint->isSplit();
923
924
814768
  if(!split && c_i == d_partialModel.getAssignment(x_i)){
925
15511
    Debug("arith::eq") << "lemma now! " << constraint << endl;
926
15511
    outputTrustedLemma(constraint->split(), InferenceId::ARITH_SPLIT_DEQ);
927
15511
    return false;
928
799257
  }else if(d_partialModel.strictlyLessThanLowerBound(x_i, c_i)){
929
244527
    Debug("arith::eq") << "can drop as less than lb" << constraint << endl;
930
554730
  }else if(d_partialModel.strictlyGreaterThanUpperBound(x_i, c_i)){
931
186199
    Debug("arith::eq") << "can drop as less than ub" << constraint << endl;
932
368531
  }else if(!split){
933
216664
    Debug("arith::eq") << "push back" << constraint << endl;
934
216664
    d_diseqQueue.push(constraint);
935
216664
    d_partialModel.invalidateDelta();
936
  }else{
937
151867
    Debug("arith::eq") << "skipping already split " << constraint << endl;
938
  }
939
799257
  return false;
940
}
941
942
643018
void TheoryArithPrivate::notifySharedTerm(TNode n)
943
{
944
643018
  Debug("arith::notifySharedTerm") << "notifySharedTerm: " << n << endl;
945
643018
  if(n.isConst()){
946
74677
    d_partialModel.invalidateDelta();
947
  }
948
643018
  if(!n.isConst() && !isSetup(n)){
949
473344
    Polynomial poly = Polynomial::parsePolynomial(n);
950
473344
    Polynomial::iterator it = poly.begin();
951
473344
    Polynomial::iterator it_end = poly.end();
952
1317378
    for (; it != it_end; ++ it) {
953
1080706
      Monomial m = *it;
954
540353
      if (!m.isConstant() && !isSetup(m.getVarList().getNode())) {
955
5562
        setupVariableList(m.getVarList());
956
      }
957
    }
958
  }
959
643018
}
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
105458
void TheoryArithPrivate::ppStaticLearn(TNode n, NodeBuilder& learned)
1060
{
1061
210916
  TimerStat::CodeTimer codeTimer(d_statistics.d_staticLearningTimer);
1062
1063
105458
  d_learner.staticLearning(n, learned);
1064
105458
}
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
67870
void TheoryArithPrivate::setupVariable(const Variable& x){
1089
135740
  Node n = x.getNode();
1090
1091
67870
  Assert(!isSetup(n));
1092
1093
67870
  ++(d_statistics.d_statUserVariables);
1094
67870
  requestArithVar(n, false,  false);
1095
  //ArithVar varN = requestArithVar(n,false);
1096
  //setupInitialValue(varN);
1097
1098
67870
  markSetup(n);
1099
67870
}
1100
1101
69388
void TheoryArithPrivate::setupVariableList(const VarList& vl){
1102
69388
  Assert(!vl.empty());
1103
1104
138776
  TNode vlNode = vl.getNode();
1105
69388
  Assert(!isSetup(vlNode));
1106
69388
  Assert(!d_partialModel.hasArithVar(vlNode));
1107
1108
145074
  for(VarList::iterator i = vl.begin(), end = vl.end(); i != end; ++i){
1109
151372
    Variable var = *i;
1110
1111
75686
    if(!isSetup(var.getNode())){
1112
67870
      setupVariable(var);
1113
    }
1114
  }
1115
1116
69388
  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
133696
  else if (vlNode.getKind() == kind::EXPONENTIAL
1133
66800
           || vlNode.getKind() == kind::SINE || vlNode.getKind() == kind::COSINE
1134
133203
           || 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
69387
}
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
123895
void TheoryArithPrivate::setupPolynomial(const Polynomial& poly) {
1160
123895
  Assert(!poly.containsConstant());
1161
247790
  TNode polyNode = poly.getNode();
1162
123895
  Assert(!isSetup(polyNode));
1163
123895
  Assert(!d_partialModel.hasArithVar(polyNode));
1164
1165
372903
  for(Polynomial::iterator i = poly.begin(), end = poly.end(); i != end; ++i){
1166
498016
    Monomial mono = *i;
1167
249008
    const VarList& vl = mono.getVarList();
1168
249008
    if(!isSetup(vl.getNode())){
1169
63826
      setupVariableList(vl);
1170
    }
1171
  }
1172
1173
123894
  if(polyNode.getKind() == PLUS){
1174
94873
    d_tableauSizeHasBeenModified = true;
1175
1176
189746
    vector<ArithVar> variables;
1177
189746
    vector<Rational> coefficients;
1178
94873
    asVectors(poly, coefficients, variables);
1179
1180
94873
    ArithVar varSlack = requestArithVar(polyNode, true, false);
1181
94873
    d_tableau.addRow(varSlack, coefficients, variables);
1182
94873
    setupBasicValue(varSlack);
1183
94873
    d_linEq.trackRowIndex(d_tableau.basicToRowIndex(varSlack));
1184
1185
    //Add differences to the difference manager
1186
189746
    Polynomial::iterator i = poly.begin(), end = poly.end();
1187
94873
    if(i != end){
1188
189746
      Monomial first = *i;
1189
94873
      ++i;
1190
94873
      if(i != end){
1191
189746
        Monomial second = *i;
1192
94873
        ++i;
1193
94873
        if(i == end){
1194
75373
          if(first.getConstant().isOne() && second.getConstant().getValue() == -1){
1195
129502
            VarList vl0 = first.getVarList();
1196
129502
            VarList vl1 = second.getVarList();
1197
64751
            if(vl0.singleton() && vl1.singleton()){
1198
62283
              d_congruenceManager.addWatchedPair(varSlack, vl0.getNode(), vl1.getNode());
1199
            }
1200
          }
1201
        }
1202
      }
1203
    }
1204
1205
94873
    ++(d_statistics.d_statAuxiliaryVariables);
1206
94873
    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
123894
}
1216
1217
271079
void TheoryArithPrivate::setupAtom(TNode atom) {
1218
271079
  Assert(isRelationOperator(atom.getKind())) << atom;
1219
271079
  Assert(Comparison::isNormalAtom(atom));
1220
271079
  Assert(!isSetup(atom));
1221
271079
  Assert(!d_constraintDatabase.hasLiteral(atom));
1222
1223
542158
  Comparison cmp = Comparison::parseNormalForm(atom);
1224
542158
  Polynomial nvp = cmp.normalizedVariablePart();
1225
271079
  Assert(!nvp.isZero());
1226
1227
271079
  if(!isSetup(nvp.getNode())){
1228
123895
    setupPolynomial(nvp);
1229
  }
1230
1231
271078
  d_constraintDatabase.addLiteral(atom);
1232
1233
271078
  markSetup(atom);
1234
271078
}
1235
1236
818899
void TheoryArithPrivate::preRegisterTerm(TNode n) {
1237
818899
  Debug("arith::preregister") <<"begin arith::preRegisterTerm("<< n <<")"<< endl;
1238
1239
818899
  d_preregisteredNodes.insert(n);
1240
1241
  try {
1242
818899
    if(isRelationOperator(n.getKind())){
1243
425255
      if(!isSetup(n)){
1244
212925
        setupAtom(n);
1245
      }
1246
425254
      ConstraintP c = d_constraintDatabase.lookup(n);
1247
425254
      Assert(c != NullConstraint);
1248
1249
425254
      Debug("arith::preregister") << "setup constraint" << c << endl;
1250
425254
      Assert(!c->canBePropagated());
1251
425254
      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
818898
  Debug("arith::preregister") << "end arith::preRegisterTerm("<< n <<")" << endl;
1260
818898
}
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
165282
ArithVar TheoryArithPrivate::requestArithVar(TNode x, bool aux, bool internal){
1270
  //TODO : The VarList trick is good enough?
1271
165282
  Assert(isLeaf(x) || VarList::isMember(x) || x.getKind() == PLUS || internal);
1272
165282
  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
165282
  Assert(!d_partialModel.hasArithVar(x));
1281
165282
  Assert(x.getType().isReal());  // real or integer
1282
1283
165282
  ArithVar max = d_partialModel.getNumberOfVariables();
1284
165282
  ArithVar varX = d_partialModel.allocate(x, aux);
1285
1286
165282
  bool reclaim =  max >= d_partialModel.getNumberOfVariables();;
1287
1288
165282
  if(!reclaim){
1289
165282
    d_dualSimplex.increaseMax();
1290
1291
165282
    d_tableau.increaseSize();
1292
165282
    d_tableauSizeHasBeenModified = true;
1293
  }
1294
165282
  d_constraintDatabase.addVariable(varX);
1295
1296
330564
  Debug("arith::arithvar") << "@" << context()->getLevel() << " " << x
1297
165282
                           << " |-> " << varX << "(relaiming " << reclaim << ")"
1298
165282
                           << endl;
1299
1300
165282
  Assert(!d_partialModel.hasUpperBound(varX));
1301
165282
  Assert(!d_partialModel.hasLowerBound(varX));
1302
1303
165282
  return varX;
1304
}
1305
1306
94873
void TheoryArithPrivate::asVectors(const Polynomial& p, std::vector<Rational>& coeffs, std::vector<ArithVar>& variables) {
1307
314859
  for(Polynomial::iterator i = p.begin(), end = p.end(); i != end; ++i){
1308
439972
    const Monomial& mono = *i;
1309
219986
    const Constant& constant = mono.getConstant();
1310
219986
    const VarList& variable = mono.getVarList();
1311
1312
439972
    Node n = variable.getNode();
1313
1314
219986
    Debug("arith::asVectors") << "should be var: " << n << endl;
1315
1316
    // TODO: This VarList::isMember(n) can be stronger
1317
219986
    Assert(isLeaf(n) || VarList::isMember(n));
1318
219986
    Assert(theoryOf(n) != THEORY_ARITH || d_partialModel.hasArithVar(n));
1319
1320
219986
    Assert(d_partialModel.hasArithVar(n));
1321
219986
    ArithVar av = d_partialModel.asArithVar(n);
1322
1323
219986
    coeffs.push_back(constant.getValue());
1324
219986
    variables.push_back(av);
1325
  }
1326
94873
}
1327
1328
/* Requirements:
1329
 * For basic variables the row must have been added to the tableau.
1330
 */
1331
94873
void TheoryArithPrivate::setupBasicValue(ArithVar x){
1332
94873
  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
189746
  DeltaRational safeAssignment = d_linEq.computeRowValue(x, true);
1339
189746
  DeltaRational assignment = d_linEq.computeRowValue(x, false);
1340
94873
  d_partialModel.setAssignment(x,safeAssignment,assignment);
1341
1342
94873
  Debug("arith") << "setupVariable("<<x<<")"<<std::endl;
1343
94873
}
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
38191
Comparison TheoryArithPrivate::mkIntegerEqualityFromAssignment(ArithVar v){
1367
38191
  const DeltaRational& beta = d_partialModel.getAssignment(v);
1368
1369
38191
  Assert(beta.isIntegral());
1370
76382
  Polynomial betaAsPolynomial = Polynomial::mkPolynomial( Constant::mkConstant(beta.floor()) );
1371
1372
76382
  TNode var = d_partialModel.asNode(v);
1373
76382
  Polynomial varAsPolynomial = Polynomial::parsePolynomial(var);
1374
76382
  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
24746
Node TheoryArithPrivate::callDioSolver(){
1456
46725
  while(!d_constantIntegerVariables.empty()){
1457
21979
    ArithVar v = d_constantIntegerVariables.front();
1458
21979
    d_constantIntegerVariables.pop();
1459
1460
21979
    Debug("arith::dio")  << "callDioSolver " << v << endl;
1461
1462
21979
    Assert(isInteger(v));
1463
21979
    Assert(d_partialModel.boundsAreEqual(v));
1464
1465
21979
    ConstraintP lb = d_partialModel.getLowerBoundConstraint(v);
1466
21979
    ConstraintP ub = d_partialModel.getUpperBoundConstraint(v);
1467
1468
43958
    Node orig = Node::null();
1469
21979
    if(lb->isEquality()){
1470
20203
      orig = Constraint::externalExplainByAssertions({lb});
1471
1776
    }else if(ub->isEquality()){
1472
      orig = Constraint::externalExplainByAssertions({ub});
1473
    }else {
1474
1776
      orig = Constraint::externalExplainByAssertions(ub, lb);
1475
    }
1476
1477
21979
    Assert(d_partialModel.assignmentIsConsistent(v));
1478
1479
43958
    Comparison eq = mkIntegerEqualityFromAssignment(v);
1480
1481
21979
    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
21979
      Debug("dio::push") << "dio::push " << v << " " << eq.getNode() << " with reason " << orig << endl;
1490
21979
      d_diosolver.pushInputConstraint(eq, orig);
1491
    }
1492
  }
1493
1494
2767
  return d_diosolver.processEquationsForConflict();
1495
}
1496
1497
5893236
ConstraintP TheoryArithPrivate::constraintFromFactQueue(TNode assertion)
1498
{
1499
5893236
  Kind simpleKind = Comparison::comparisonKind(assertion);
1500
5893236
  ConstraintP constraint = d_constraintDatabase.lookup(assertion);
1501
5893236
  if(constraint == NullConstraint){
1502
773519
    Assert(simpleKind == EQUAL || simpleKind == DISTINCT);
1503
773519
    bool isDistinct = simpleKind == DISTINCT;
1504
1537436
    Node eq = (simpleKind == DISTINCT) ? assertion[0] : assertion;
1505
773519
    Assert(!isSetup(eq));
1506
1537436
    Node reEq = Rewriter::rewrite(eq);
1507
773519
    Debug("arith::distinct::const") << "Assertion: " << assertion << std::endl;
1508
773519
    Debug("arith::distinct::const") << "Eq       : " << eq << std::endl;
1509
773519
    Debug("arith::distinct::const") << "reEq     : " << reEq << std::endl;
1510
773519
    if(reEq.getKind() == CONST_BOOLEAN){
1511
9602
      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
9602
      return NullConstraint;
1531
    }
1532
763917
    Assert(reEq.getKind() != CONST_BOOLEAN);
1533
763917
    if(!isSetup(reEq)){
1534
37923
      setupAtom(reEq);
1535
    }
1536
1527834
    Node reAssertion = isDistinct ? reEq.notNode() : reEq;
1537
763917
    constraint = d_constraintDatabase.lookup(reAssertion);
1538
1539
763917
    if(assertion != reAssertion){
1540
744140
      Debug("arith::nf") << "getting non-nf assertion " << assertion << " |-> " <<  reAssertion << endl;
1541
744140
      Assert(constraint != NullConstraint);
1542
744140
      d_assertionsThatDoNotMatchTheirLiterals.insert(assertion, constraint);
1543
    }
1544
  }
1545
1546
5883634
  Assert(constraint != NullConstraint);
1547
1548
5883634
  if(constraint->assertedToTheTheory()){
1549
    //Do nothing
1550
272042
    return NullConstraint;
1551
  }
1552
5611592
  Assert(!constraint->assertedToTheTheory());
1553
5611592
  bool inConflict = constraint->negationHasProof();
1554
5611592
  constraint->setAssertedToTheTheory(assertion, inConflict);
1555
1556
5611592
  if(!constraint->hasProof()){
1557
4605485
    Debug("arith::constraint") << "marking as constraint as self explaining " << endl;
1558
4605485
    constraint->setAssumption(inConflict);
1559
  } else {
1560
2012214
    Debug("arith::constraint")
1561
1006107
        << "already has proof: "
1562
1006107
        << Constraint::externalExplainByAssertions({constraint});
1563
  }
1564
1565
5611592
  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
5611592
  if(inConflict){
1576
3057
    ConstraintP negation = constraint->getNegation();
1577
3057
    if(Debug.isOn("arith::negatedassumption") && negation->isAssumption()){
1578
      debugPrintFacts();
1579
    }
1580
3057
    Debug("arith::eq") << "negation has proof" << endl;
1581
3057
    Debug("arith::eq") << constraint << endl;
1582
3057
    Debug("arith::eq") << negation << endl;
1583
3057
    raiseConflict(negation, InferenceId::ARITH_CONF_FACT_QUEUE);
1584
3057
    return NullConstraint;
1585
  }else{
1586
5608535
    return constraint;
1587
  }
1588
}
1589
1590
5755710
bool TheoryArithPrivate::assertionCases(ConstraintP constraint){
1591
5755710
  Assert(constraint->hasProof());
1592
5755710
  Assert(!constraint->negationHasProof());
1593
1594
5755710
  ArithVar x_i = constraint->getVariable();
1595
1596
5755710
  switch(constraint->getType()){
1597
1920948
  case UpperBound:
1598
1920948
    if(isInteger(x_i) && constraint->isStrictUpperBound()){
1599
1190253
      ConstraintP floorConstraint = constraint->getFloor();
1600
1190253
      if(!floorConstraint->isTrue()){
1601
1000276
        bool inConflict = floorConstraint->negationHasProof();
1602
1000276
        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
1000276
        floorConstraint->impliedByIntTighten(constraint, inConflict);
1607
1000276
        floorConstraint->tryToPropagate();
1608
1000276
        if(inConflict){
1609
2350
          raiseConflict(floorConstraint, InferenceId::ARITH_TIGHTEN_FLOOR);
1610
2350
          return true;
1611
        }
1612
      }
1613
1187903
      return AssertUpper(floorConstraint);
1614
    }else{
1615
730695
      return AssertUpper(constraint);
1616
    }
1617
1961526
  case LowerBound:
1618
1961526
    if(isInteger(x_i) && constraint->isStrictLowerBound()){
1619
86873
      ConstraintP ceilingConstraint = constraint->getCeiling();
1620
86873
      if(!ceilingConstraint->isTrue()){
1621
52663
        bool inConflict = ceilingConstraint->negationHasProof();
1622
52663
        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
52663
        ceilingConstraint->impliedByIntTighten(constraint, inConflict);
1627
52663
        ceilingConstraint->tryToPropagate();
1628
52663
        if(inConflict){
1629
48
          raiseConflict(ceilingConstraint, InferenceId::ARITH_TIGHTEN_CEIL);
1630
48
          return true;
1631
        }
1632
      }
1633
86825
      return AssertLower(ceilingConstraint);
1634
    }else{
1635
1874653
      return AssertLower(constraint);
1636
    }
1637
1058381
  case Equality:
1638
1058381
    return AssertEquality(constraint);
1639
814855
  case Disequality:
1640
814855
    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
3644323
ArithVar TheoryArithPrivate::nextIntegerViolation(bool assumeBounds) const
1656
{
1657
3644323
  ArithVar numVars = d_partialModel.getNumberOfVariables();
1658
3644323
  ArithVar v = d_nextIntegerCheckVar;
1659
3644323
  if (numVars > 0)
1660
  {
1661
3603502
    const ArithVar rrEnd = d_nextIntegerCheckVar;
1662
745915022
    do
1663
    {
1664
749518524
      if (isIntegerInput(v))
1665
      {
1666
209806038
        if (!d_partialModel.integralAssignment(v))
1667
        {
1668
129140
          if (assumeBounds || d_partialModel.assignmentIsConsistent(v))
1669
          {
1670
129140
            return v;
1671
          }
1672
        }
1673
      }
1674
749389384
      v = (1 + v == numVars) ? 0 : (1 + v);
1675
749389384
    } while (v != rrEnd);
1676
  }
1677
3515183
  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
3644323
bool TheoryArithPrivate::hasIntegerModel()
1685
{
1686
3644323
  ArithVar next = nextIntegerViolation(true);
1687
3644323
  if (next != ARITHVAR_SENTINEL)
1688
  {
1689
129140
    d_nextIntegerCheckVar = next;
1690
129140
    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
129140
    return false;
1696
  }
1697
  else
1698
  {
1699
3515183
    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
55212
void TheoryArithPrivate::outputConflicts(){
1738
55212
  Debug("arith::conflict") << "outputting conflicts" << std::endl;
1739
55212
  Assert(anyConflict());
1740
  static unsigned int conflicts = 0;
1741
1742
55212
  if(!conflictQueueEmpty()){
1743
52963
    Assert(!d_conflicts.empty());
1744
131873
    for(size_t i = 0, i_end = d_conflicts.size(); i < i_end; ++i){
1745
78910
      const std::pair<ConstraintCP, InferenceId>& conf = d_conflicts[i];
1746
78910
      const ConstraintCP& confConstraint = conf.first;
1747
78910
      bool hasProof = confConstraint->hasProof();
1748
78910
      Assert(confConstraint->inConflict());
1749
78910
      const ConstraintRule& pf = confConstraint->getConstraintRule();
1750
78910
      if (Debug.isOn("arith::conflict"))
1751
      {
1752
        pf.print(std::cout);
1753
        std::cout << std::endl;
1754
      }
1755
78910
      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
157820
      TrustNode trustedConflict = confConstraint->externalExplainConflict();
1763
157820
      Node conflict = trustedConflict.getNode();
1764
1765
78910
      ++conflicts;
1766
157820
      Debug("arith::conflict") << "d_conflicts[" << i << "] " << conflict
1767
78910
                               << " has proof: " << hasProof << endl;
1768
78910
      if(Debug.isOn("arith::normalize::external")){
1769
        conflict = flattenAndSort(conflict);
1770
        Debug("arith::conflict") << "(normalized to) " << conflict << endl;
1771
      }
1772
1773
78910
      if (isProofEnabled())
1774
      {
1775
13028
        outputTrustedConflict(trustedConflict, conf.second);
1776
      }
1777
      else
1778
      {
1779
65882
        outputConflict(conflict, conf.second);
1780
      }
1781
    }
1782
  }
1783
55212
  if(!d_blackBoxConflict.get().isNull()){
1784
4516
    Node bb = d_blackBoxConflict.get();
1785
2258
    ++conflicts;
1786
4516
    Debug("arith::conflict") << "black box conflict" << bb
1787
      //<< "("<<conflicts<<")"
1788
2258
                             << endl;
1789
2258
    if(Debug.isOn("arith::normalize::external")){
1790
      bb = flattenAndSort(bb);
1791
      Debug("arith::conflict") << "(normalized to) " << bb << endl;
1792
    }
1793
2258
    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
1882
      outputConflict(bb, InferenceId::ARITH_BLACK_BOX);
1801
    }
1802
  }
1803
55212
}
1804
1805
71282
bool TheoryArithPrivate::outputTrustedLemma(TrustNode lemma, InferenceId id)
1806
{
1807
71282
  Debug("arith::channel") << "Arith trusted lemma: " << lemma << std::endl;
1808
71282
  return d_containing.d_im.trustedLemma(lemma, id);
1809
}
1810
1811
94961
bool TheoryArithPrivate::outputLemma(TNode lem, InferenceId id) {
1812
94961
  Debug("arith::channel") << "Arith lemma: " << lem << std::endl;
1813
94961
  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
67764
void TheoryArithPrivate::outputConflict(TNode lit, InferenceId id) {
1823
67764
  Debug("arith::channel") << "Arith conflict: " << lit << std::endl;
1824
67764
  d_containing.d_im.conflict(lit, id);
1825
67764
}
1826
1827
1490324
void TheoryArithPrivate::outputPropagate(TNode lit) {
1828
1490324
  Debug("arith::channel") << "Arith propagation: " << lit << std::endl;
1829
  // call the propagate lit method of the
1830
1490324
  d_containing.d_im.propagateLit(lit);
1831
1490324
}
1832
1833
void TheoryArithPrivate::outputRestart() {
1834
  Debug("arith::channel") << "Arith restart!" << std::endl;
1835
  (d_containing.d_out)->demandRestart();
1836
}
1837
1838
1789149
bool TheoryArithPrivate::attemptSolveInteger(Theory::Effort effortLevel, bool emmmittedLemmaOrSplit){
1839
1789149
  int level = context()->getLevel();
1840
3578298
  Debug("approx")
1841
1789149
    << "attemptSolveInteger " << d_qflraStatus
1842
1789149
    << " " << emmmittedLemmaOrSplit
1843
1789149
    << " " << effortLevel
1844
1789149
    << " " << d_lastContextIntegerAttempted
1845
1789149
    << " " << level
1846
3578298
    << " " << hasIntegerModel()
1847
1789149
    << endl;
1848
1849
1789149
  if(d_qflraStatus == Result::UNSAT){ return false; }
1850
1746648
  if(emmmittedLemmaOrSplit){ return false; }
1851
1746648
  if (!options().arith.useApprox)
1852
  {
1853
1746648
    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
1730336
bool TheoryArithPrivate::safeToCallApprox() const{
2684
1730336
  unsigned numRows = 0;
2685
1730336
  unsigned numCols = 0;
2686
1730336
  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
28309488
  for(; vi != vi_end && !(numRows > 0 && numCols > 0); ++vi){
2689
13289576
    ArithVar v = *vi;
2690
2691
13289576
    if(d_partialModel.isAuxiliary(v)){
2692
1712961
      ++numRows;
2693
    }else{
2694
11576615
      ++numCols;
2695
    }
2696
  }
2697
1730336
  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
1730336
SimplexDecisionProcedure& TheoryArithPrivate::selectSimplex(bool pass1){
2850
1730336
  if(pass1){
2851
1730336
    if(d_pass1SDP == NULL){
2852
6368
      if (options().arith.useFC)
2853
      {
2854
        d_pass1SDP = (SimplexDecisionProcedure*)(&d_fcSimplex);
2855
      }
2856
6368
      else if (options().arith.useSOI)
2857
      {
2858
        d_pass1SDP = (SimplexDecisionProcedure*)(&d_soiSimplex);
2859
      }
2860
      else
2861
      {
2862
6368
        d_pass1SDP = (SimplexDecisionProcedure*)(&d_dualSimplex);
2863
      }
2864
    }
2865
1730336
    Assert(d_pass1SDP != NULL);
2866
1730336
    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
    SimplexDecisionProcedure& simplex = selectSimplex(false);
2903
    simplex.setVarOrderPivotLimit(pass2Limit);
2904
    d_qflraStatus = simplex.findModel(false);
2905
  }
2906
2907
  if(Debug.isOn("arith::importSolution")){
2908
    Debug("arith::importSolution") << "importSolution after " << d_qflraStatus << endl;
2909
    d_partialModel.printEntireModel(Debug("arith::importSolution"));
2910
  }
2911
}
2912
2913
1730336
bool TheoryArithPrivate::solveRelaxationOrPanic(Theory::Effort effortLevel)
2914
{
2915
  // if at this point the linear relaxation is still unknown,
2916
  //  attempt to branch an integer variable as a last ditch effort on full check
2917
1730336
  if (d_qflraStatus == Result::SAT_UNKNOWN)
2918
  {
2919
    d_qflraStatus = selectSimplex(true).findModel(false);
2920
  }
2921
2922
1730336
  if (Theory::fullEffort(effortLevel) && d_qflraStatus == Result::SAT_UNKNOWN)
2923
  {
2924
    ArithVar canBranch = nextIntegerViolation(false);
2925
    if (canBranch != ARITHVAR_SENTINEL)
2926
    {
2927
      ++d_statistics.d_panicBranches;
2928
      TrustNode branch = branchIntegerVariable(canBranch);
2929
      Assert(branch.getNode().getKind() == kind::OR);
2930
      Node rwbranch = Rewriter::rewrite(branch.getNode()[0]);
2931
      if (!isSatLiteral(rwbranch))
2932
      {
2933
        d_approxCuts.push_back(branch);
2934
        return true;
2935
      }
2936
    }
2937
    d_qflraStatus = selectSimplex(false).findModel(true);
2938
  }
2939
1730336
  return false;
2940
}
2941
2942
1730336
bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
2943
3460672
  TimerStat::CodeTimer codeTimer0(d_statistics.d_solveRealRelaxTimer);
2944
1730336
  Assert(d_qflraStatus != Result::SAT);
2945
2946
1730336
  d_partialModel.stopQueueingBoundCounts();
2947
3460672
  UpdateTrackingCallback utcb(&d_linEq);
2948
1730336
  d_partialModel.processBoundsQueue(utcb);
2949
1730336
  d_linEq.startTrackingBoundCounts();
2950
2951
  bool noPivotLimit =
2952
1730336
      Theory::fullEffort(effortLevel) || !options().arith.restrictedPivots;
2953
2954
1730336
  SimplexDecisionProcedure& simplex = selectSimplex(true);
2955
2956
1730336
  bool useApprox = options().arith.useApprox && ApproximateSimplex::enabled()
2957
1730336
                   && getSolveIntegerResource();
2958
2959
3460672
  Debug("TheoryArithPrivate::solveRealRelaxation")
2960
1730336
      << "solveRealRelaxation() approx"
2961
1730336
      << " " << options().arith.useApprox << " "
2962
3460672
      << ApproximateSimplex::enabled() << " " << useApprox << " "
2963
1730336
      << safeToCallApprox() << endl;
2964
2965
1730336
  bool noPivotLimitPass1 = noPivotLimit && !useApprox;
2966
1730336
  d_qflraStatus = simplex.findModel(noPivotLimitPass1);
2967
2968
3460672
  Debug("TheoryArithPrivate::solveRealRelaxation")
2969
1730336
    << "solveRealRelaxation()" << " pass1 " << d_qflraStatus << endl;
2970
2971
1730336
  if(d_qflraStatus == Result::SAT_UNKNOWN && useApprox && safeToCallApprox()){
2972
    // pass2: fancy-final
2973
    static const int32_t relaxationLimit = 10000;
2974
    Assert(ApproximateSimplex::enabled());
2975
2976
    TreeLog& tl = getTreeLog();
2977
    ApproximateStatistics& stats = getApproxStats();
2978
    ApproximateSimplex* approxSolver =
2979
      ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel, tl, stats);
2980
2981
    approxSolver->setPivotLimit(relaxationLimit);
2982
2983
    if(!d_guessedCoeffSet){
2984
      d_guessedCoeffs = approxSolver->heuristicOptCoeffs();
2985
      d_guessedCoeffSet = true;
2986
    }
2987
    if(!d_guessedCoeffs.empty()){
2988
      approxSolver->setOptCoeffs(d_guessedCoeffs);
2989
    }
2990
2991
    ++d_statistics.d_relaxCalls;
2992
2993
    ApproximateSimplex::Solution relaxSolution;
2994
    LinResult relaxRes = LinUnknown;
2995
    {
2996
      TimerStat::CodeTimer codeTimer1(d_statistics.d_lpTimer);
2997
      relaxRes = approxSolver->solveRelaxation();
2998
    }
2999
      Debug("solveRealRelaxation") << "solve relaxation? " << endl;
3000
      switch(relaxRes){
3001
      case LinFeasible:
3002
        Debug("solveRealRelaxation") << "lin feasible? " << endl;
3003
        ++d_statistics.d_relaxLinFeas;
3004
        relaxSolution = approxSolver->extractRelaxation();
3005
        importSolution(relaxSolution);
3006
        if(d_qflraStatus != Result::SAT){
3007
          ++d_statistics.d_relaxLinFeasFailures;
3008
        }
3009
        break;
3010
      case LinInfeasible:
3011
        // todo attempt to recreate approximate conflict
3012
        ++d_statistics.d_relaxLinInfeas;
3013
        Debug("solveRealRelaxation") << "lin infeasible " << endl;
3014
        relaxSolution = approxSolver->extractRelaxation();
3015
        importSolution(relaxSolution);
3016
        if(d_qflraStatus != Result::UNSAT){
3017
          ++d_statistics.d_relaxLinInfeasFailures;
3018
        }
3019
        break;
3020
      case LinExhausted:
3021
        ++d_statistics.d_relaxLinExhausted;
3022
        Debug("solveRealRelaxation") << "exhuasted " << endl;
3023
        break;
3024
      case LinUnknown:
3025
      default:
3026
        ++d_statistics.d_relaxOthers;
3027
        break;
3028
      }
3029
    delete approxSolver;
3030
3031
  }
3032
3033
1730336
  bool emmittedConflictOrSplit = solveRelaxationOrPanic(effortLevel);
3034
3035
  // TODO Save zeroes with no conflicts
3036
1730336
  d_linEq.stopTrackingBoundCounts();
3037
1730336
  d_partialModel.startQueueingBoundCounts();
3038
3039
3460672
  return emmittedConflictOrSplit;
3040
}
3041
3042
bool TheoryArithPrivate::hasFreshArithLiteral(Node n) const{
3043
  switch(n.getKind()){
3044
  case kind::LEQ:
3045
  case kind::GEQ:
3046
  case kind::GT:
3047
  case kind::LT:
3048
    return !isSatLiteral(n);
3049
  case kind::EQUAL:
3050
    if(n[0].getType().isReal()){
3051
      return !isSatLiteral(n);
3052
    }else if(n[0].getType().isBoolean()){
3053
      return hasFreshArithLiteral(n[0]) ||
3054
        hasFreshArithLiteral(n[1]);
3055
    }else{
3056
      return false;
3057
    }
3058
  case kind::IMPLIES:
3059
    // try the rhs first
3060
    return hasFreshArithLiteral(n[1]) ||
3061
      hasFreshArithLiteral(n[0]);
3062
  default:
3063
    if(n.getType().isBoolean()){
3064
      for(Node::iterator ni=n.begin(), nend=n.end(); ni!=nend; ++ni){
3065
        Node child = *ni;
3066
        if(hasFreshArithLiteral(child)){
3067
          return true;
3068
        }
3069
      }
3070
    }
3071
    return false;
3072
  }
3073
}
3074
3075
1805002
bool TheoryArithPrivate::preCheck(Theory::Effort level)
3076
{
3077
1805002
  Assert(d_currentPropagationList.empty());
3078
1805002
  if(Debug.isOn("arith::consistency")){
3079
    Assert(unenqueuedVariablesAreConsistent());
3080
  }
3081
3082
1805002
  d_newFacts = !done();
3083
  // If d_previousStatus == SAT, then reverts on conflicts are safe
3084
  // Otherwise, they are not and must be committed.
3085
1805002
  d_previousStatus = d_qflraStatus;
3086
1805002
  if (d_newFacts)
3087
  {
3088
1739901
    d_qflraStatus = Result::SAT_UNKNOWN;
3089
1739901
    d_hasDoneWorkSinceCut = true;
3090
  }
3091
1805002
  return false;
3092
}
3093
3094
5893236
void TheoryArithPrivate::preNotifyFact(TNode atom, bool pol, TNode fact)
3095
{
3096
5893236
  ConstraintP curr = constraintFromFactQueue(fact);
3097
5893236
  if (curr != NullConstraint)
3098
  {
3099
5608535
    bool res CVC5_UNUSED = assertionCases(curr);
3100
5608535
    Assert(!res || anyConflict());
3101
  }
3102
5893236
}
3103
3104
1801705
bool TheoryArithPrivate::postCheck(Theory::Effort effortLevel)
3105
{
3106
1801705
  if(!anyConflict()){
3107
2083427
    while(!d_learnedBounds.empty()){
3108
      // we may attempt some constraints twice.  this is okay!
3109
147175
      ConstraintP curr = d_learnedBounds.front();
3110
147175
      d_learnedBounds.pop();
3111
147175
      Debug("arith::learned") << curr << endl;
3112
3113
147175
      bool res CVC5_UNUSED = assertionCases(curr);
3114
147175
      Assert(!res || anyConflict());
3115
3116
147175
      if(anyConflict()){ break; }
3117
    }
3118
  }
3119
3120
1801705
  if(anyConflict()){
3121
12556
    d_qflraStatus = Result::UNSAT;
3122
12556
    if (options().arith.revertArithModels && d_previousStatus == Result::SAT)
3123
    {
3124
      ++d_statistics.d_revertsOnConflicts;
3125
      Debug("arith::bt") << "clearing here "
3126
                         << " " << d_newFacts << " " << d_previousStatus << " "
3127
                         << d_qflraStatus << endl;
3128
      revertOutOfConflict();
3129
      d_errorSet.clear();
3130
    }else{
3131
12556
      ++d_statistics.d_commitsOnConflicts;
3132
25112
      Debug("arith::bt") << "committing here "
3133
12556
                         << " " << d_newFacts << " " << d_previousStatus << " "
3134
12556
                         << d_qflraStatus << endl;
3135
12556
      d_partialModel.commitAssignmentChanges();
3136
12556
      revertOutOfConflict();
3137
    }
3138
12556
    outputConflicts();
3139
    //cout << "unate conflict 1 " << effortLevel << std::endl;
3140
12556
    return true;
3141
  }
3142
3143
3144
1789149
  if(Debug.isOn("arith::print_assertions")) {
3145
    debugPrintAssertions(Debug("arith::print_assertions"));
3146
  }
3147
3148
1789149
  bool emmittedConflictOrSplit = false;
3149
1789149
  Assert(d_conflicts.empty());
3150
3151
1789149
  bool useSimplex = d_qflraStatus != Result::SAT;
3152
3578298
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3153
1789149
                      << "pre realRelax" << endl;
3154
3155
1789149
  if(useSimplex){
3156
1730336
    emmittedConflictOrSplit = solveRealRelaxation(effortLevel);
3157
  }
3158
3578298
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3159
1789149
                      << "post realRelax" << endl;
3160
3161
3162
3578298
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3163
1789149
                      << "pre solveInteger" << endl;
3164
3165
1789149
  if(attemptSolveInteger(effortLevel, emmittedConflictOrSplit)){
3166
    solveInteger(effortLevel);
3167
    if(anyConflict()){
3168
      ++d_statistics.d_commitsOnConflicts;
3169
      Debug("arith::bt") << "committing here "
3170
                         << " " << d_newFacts << " " << d_previousStatus << " "
3171
                         << d_qflraStatus << endl;
3172
      revertOutOfConflict();
3173
      d_errorSet.clear();
3174
      outputConflicts();
3175
      return true;
3176
    }
3177
  }
3178
3179
3578298
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3180
1789149
                      << "post solveInteger" << endl;
3181
3182
1789149
  switch(d_qflraStatus){
3183
1746648
  case Result::SAT:
3184
1746648
    if (d_newFacts)
3185
    {
3186
1684844
      ++d_statistics.d_nontrivialSatChecks;
3187
    }
3188
3189
3493296
    Debug("arith::bt") << "committing sap inConflit"
3190
1746648
                       << " " << d_newFacts << " " << d_previousStatus << " "
3191
1746648
                       << d_qflraStatus << endl;
3192
1746648
    d_partialModel.commitAssignmentChanges();
3193
1746648
    d_unknownsInARow = 0;
3194
1746648
    if(Debug.isOn("arith::consistency")){
3195
      Assert(entireStateIsConsistent("sat comit"));
3196
    }
3197
1746648
    if (useSimplex && options().arith.collectPivots)
3198
    {
3199
      if (options().arith.useFC)
3200
      {
3201
        d_statistics.d_satPivots << d_fcSimplex.getPivots();
3202
      }
3203
      else
3204
      {
3205
        d_statistics.d_satPivots << d_dualSimplex.getPivots();
3206
      }
3207
    }
3208
1746648
    break;
3209
  case Result::SAT_UNKNOWN:
3210
    ++d_unknownsInARow;
3211
    ++(d_statistics.d_unknownChecks);
3212
    Assert(!Theory::fullEffort(effortLevel));
3213
    Debug("arith::bt") << "committing unknown"
3214
                       << " " << d_newFacts << " " << d_previousStatus << " "
3215
                       << d_qflraStatus << endl;
3216
    d_partialModel.commitAssignmentChanges();
3217
    d_statistics.d_maxUnknownsInARow.maxAssign(d_unknownsInARow);
3218
3219
    if (useSimplex && options().arith.collectPivots)
3220
    {
3221
      if (options().arith.useFC)
3222
      {
3223
        d_statistics.d_unknownPivots << d_fcSimplex.getPivots();
3224
      }
3225
      else
3226
      {
3227
        d_statistics.d_unknownPivots << d_dualSimplex.getPivots();
3228
      }
3229
    }
3230
    break;
3231
42501
  case Result::UNSAT:
3232
42501
    d_unknownsInARow = 0;
3233
3234
42501
    ++d_statistics.d_commitsOnConflicts;
3235
3236
85002
    Debug("arith::bt") << "committing on conflict"
3237
42501
                       << " " << d_newFacts << " " << d_previousStatus << " "
3238
42501
                       << d_qflraStatus << endl;
3239
42501
    d_partialModel.commitAssignmentChanges();
3240
42501
    revertOutOfConflict();
3241
3242
42501
    if(Debug.isOn("arith::consistency::comitonconflict")){
3243
      entireStateIsConsistent("commit on conflict");
3244
    }
3245
42501
    outputConflicts();
3246
42501
    emmittedConflictOrSplit = true;
3247
42501
    Debug("arith::conflict") << "simplex conflict" << endl;
3248
3249
42501
    if (useSimplex && options().arith.collectPivots)
3250
    {
3251
      if (options().arith.useFC)
3252
      {
3253
        d_statistics.d_unsatPivots << d_fcSimplex.getPivots();
3254
      }
3255
      else
3256
      {
3257
        d_statistics.d_unsatPivots << d_dualSimplex.getPivots();
3258
      }
3259
    }
3260
42501
    break;
3261
  default:
3262
    Unimplemented();
3263
  }
3264
1789149
  d_statistics.d_avgUnknownsInARow << d_unknownsInARow;
3265
3266
3578298
  size_t nPivots = options().arith.useFC ? d_fcSimplex.getPivots()
3267
3578298
                                         : d_dualSimplex.getPivots();
3268
2003048
  for (std::size_t i = 0; i < nPivots; ++i)
3269
  {
3270
427798
    d_containing.d_out->spendResource(
3271
213899
        Resource::ArithPivotStep);
3272
  }
3273
3274
3578298
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3275
1789149
                      << "pre approx cuts" << endl;
3276
1789149
  if(!d_approxCuts.empty()){
3277
    bool anyFresh = false;
3278
    while(!d_approxCuts.empty()){
3279
      TrustNode lem = d_approxCuts.front();
3280
      d_approxCuts.pop();
3281
      Debug("arith::approx::cuts") << "approximate cut:" << lem << endl;
3282
      anyFresh = anyFresh || hasFreshArithLiteral(lem.getNode());
3283
      Debug("arith::lemma") << "approximate cut:" << lem << endl;
3284
      outputTrustedLemma(lem, InferenceId::ARITH_APPROX_CUT);
3285
    }
3286
    if(anyFresh){
3287
      emmittedConflictOrSplit = true;
3288
    }
3289
  }
3290
3291
3578298
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3292
1789149
                      << "post approx cuts" << endl;
3293
3294
  // This should be fine if sat or unknown
3295
3578298
  if (!emmittedConflictOrSplit
3296
3535797
      && (options().arith.arithPropagationMode
3297
              == options::ArithPropagationMode::UNATE_PROP
3298
1746648
          || options().arith.arithPropagationMode
3299
                 == options::ArithPropagationMode::BOTH_PROP))
3300
  {
3301
3493296
    TimerStat::CodeTimer codeTimer0(d_statistics.d_newPropTime);
3302
1746648
    Assert(d_qflraStatus != Result::UNSAT);
3303
3304
7751526
    while(!d_currentPropagationList.empty()  && !anyConflict()){
3305
3002439
      ConstraintP curr = d_currentPropagationList.front();
3306
3002439
      d_currentPropagationList.pop_front();
3307
3308
3002439
      ConstraintType t = curr->getType();
3309
3002439
      Assert(t != Disequality)
3310
          << "Disequalities are not allowed in d_currentPropagation";
3311
3312
3002439
      switch(t){
3313
1083852
      case LowerBound:
3314
        {
3315
1083852
          ConstraintP prev = d_currentPropagationList.front();
3316
1083852
          d_currentPropagationList.pop_front();
3317
1083852
          d_constraintDatabase.unatePropLowerBound(curr, prev);
3318
1083852
          break;
3319
        }
3320
960546
      case UpperBound:
3321
        {
3322
960546
          ConstraintP prev = d_currentPropagationList.front();
3323
960546
          d_currentPropagationList.pop_front();
3324
960546
          d_constraintDatabase.unatePropUpperBound(curr, prev);
3325
960546
          break;
3326
        }
3327
958041
      case Equality:
3328
        {
3329
958041
          ConstraintP prevLB = d_currentPropagationList.front();
3330
958041
          d_currentPropagationList.pop_front();
3331
958041
          ConstraintP prevUB = d_currentPropagationList.front();
3332
958041
          d_currentPropagationList.pop_front();
3333
958041
          d_constraintDatabase.unatePropEquality(curr, prevLB, prevUB);
3334
958041
          break;
3335
        }
3336
        default: Unhandled() << curr->getType();
3337
      }
3338
    }
3339
3340
1746648
    if(anyConflict()){
3341
      Debug("arith::unate") << "unate conflict" << endl;
3342
      revertOutOfConflict();
3343
      d_qflraStatus = Result::UNSAT;
3344
      outputConflicts();
3345
      emmittedConflictOrSplit = true;
3346
      //cout << "unate conflict " << endl;
3347
      Debug("arith::bt") << "committing on unate conflict"
3348
                         << " " << d_newFacts << " " << d_previousStatus << " "
3349
                         << d_qflraStatus << endl;
3350
3351
      Debug("arith::conflict") << "unate arith conflict" << endl;
3352
    }
3353
  }
3354
  else
3355
  {
3356
85002
    TimerStat::CodeTimer codeTimer1(d_statistics.d_newPropTime);
3357
42501
    d_currentPropagationList.clear();
3358
  }
3359
1789149
  Assert(d_currentPropagationList.empty());
3360
3361
3578298
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3362
1789149
                      << "post unate" << endl;
3363
3364
1789149
  if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel)){
3365
65057
    ++d_fullCheckCounter;
3366
  }
3367
1789149
  if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel)){
3368
65057
    emmittedConflictOrSplit = splitDisequalities();
3369
  }
3370
3578298
  Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3371
1789149
                      << "pos splitting" << endl;
3372
3373
3374
3578298
  Debug("arith") << "integer? "
3375
1789149
       << " conf/split " << emmittedConflictOrSplit
3376
3578298
       << " fulleffort " << Theory::fullEffort(effortLevel)
3377
1789149
       << " hasintmodel " << hasIntegerModel() << endl;
3378
3379
1789149
  if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel) && !hasIntegerModel()){
3380
5534
    Node possibleConflict = Node::null();
3381
2767
    if (!emmittedConflictOrSplit && options().arith.arithDioSolver)
3382
    {
3383
2767
      possibleConflict = callDioSolver();
3384
2767
      if(possibleConflict != Node::null()){
3385
155
        revertOutOfConflict();
3386
155
        Debug("arith::conflict") << "dio conflict   " << possibleConflict << endl;
3387
        // TODO (project #37): justify (proofs in the DIO solver)
3388
155
        raiseBlackBoxConflict(possibleConflict);
3389
155
        outputConflicts();
3390
155
        emmittedConflictOrSplit = true;
3391
      }
3392
    }
3393
3394
8146
    if (!emmittedConflictOrSplit && d_hasDoneWorkSinceCut
3395
5379
        && options().arith.arithDioSolver)
3396
    {
3397
2612
      if(getDioCuttingResource()){
3398
3862
        TrustNode possibleLemma = dioCutting();
3399
1931
        if(!possibleLemma.isNull()){
3400
1471
          d_hasDoneWorkSinceCut = false;
3401
1471
          d_cutCount = d_cutCount + 1;
3402
1471
          Debug("arith::lemma") << "dio cut   " << possibleLemma << endl;
3403
1471
          if (outputTrustedLemma(possibleLemma, InferenceId::ARITH_DIO_CUT))
3404
          {
3405
1471
            emmittedConflictOrSplit = true;
3406
          }
3407
        }
3408
      }
3409
    }
3410
3411
2767
    if(!emmittedConflictOrSplit) {
3412
2282
      TrustNode possibleLemma = roundRobinBranch();
3413
1141
      if (!possibleLemma.getNode().isNull())
3414
      {
3415
1141
        ++(d_statistics.d_externalBranchAndBounds);
3416
1141
        d_cutCount = d_cutCount + 1;
3417
2282
        Debug("arith::lemma") << "rrbranch lemma"
3418
1141
                              << possibleLemma << endl;
3419
1141
        if (outputTrustedLemma(possibleLemma, InferenceId::ARITH_BB_LEMMA))
3420
        {
3421
1141
          emmittedConflictOrSplit = true;
3422
        }
3423
      }
3424
    }
3425
3426
2767
    if (options().arith.maxCutsInContext <= d_cutCount)
3427
    {
3428
      if(d_diosolver.hasMoreDecompositionLemmas()){
3429
        while(d_diosolver.hasMoreDecompositionLemmas()){
3430
          Node decompositionLemma = d_diosolver.nextDecompositionLemma();
3431
          Debug("arith::lemma") << "dio decomposition lemma "
3432
                                << decompositionLemma << endl;
3433
          outputLemma(decompositionLemma, InferenceId::ARITH_DIO_DECOMPOSITION);
3434
        }
3435
      }else{
3436
        Debug("arith::restart") << "arith restart!" << endl;
3437
        outputRestart();
3438
      }
3439
    }
3440
  }//if !emmittedConflictOrSplit && fullEffort(effortLevel) && !hasIntegerModel()
3441
3442
1789149
  if(Theory::fullEffort(effortLevel)){
3443
70279
    if(Debug.isOn("arith::consistency::final")){
3444
      entireStateIsConsistent("arith::consistency::final");
3445
    }
3446
  }
3447
3448
1789149
  if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
3449
1789149
  if(Debug.isOn("arith::print_model")) {
3450
    debugPrintModel(Debug("arith::print_model"));
3451
  }
3452
1789149
  Debug("arith") << "TheoryArithPrivate::check end" << std::endl;
3453
1789149
  return emmittedConflictOrSplit;
3454
}
3455
3456
27667
bool TheoryArithPrivate::foundNonlinear() const { return d_foundNl; }
3457
3458
1141
TrustNode TheoryArithPrivate::branchIntegerVariable(ArithVar x) const
3459
{
3460
1141
  const DeltaRational& d = d_partialModel.getAssignment(x);
3461
1141
  Assert(!d.isIntegral());
3462
1141
  const Rational& r = d.getNoninfinitesimalPart();
3463
1141
  const Rational& i = d.getInfinitesimalPart();
3464
1141
  Trace("integers") << "integers: assignment to [[" << d_partialModel.asNode(x) << "]] is " << r << "[" << i << "]" << endl;
3465
1141
  Assert(!(r.getDenominator() == 1 && i.getNumerator() == 0));
3466
2282
  TNode var = d_partialModel.asNode(x);
3467
1141
  TrustNode lem = d_bab.branchIntegerVariable(var, r);
3468
1141
  if (Debug.isOn("integers"))
3469
  {
3470
    Node l = lem.getNode();
3471
    if (isSatLiteral(l[0]))
3472
    {
3473
      Debug("integers") << "    " << l[0] << " == " << getSatValue(l[0])
3474
                        << endl;
3475
    }
3476
    else
3477
    {
3478
      Debug("integers") << "    " << l[0] << " is not assigned a SAT literal"
3479
                        << endl;
3480
    }
3481
    if (isSatLiteral(l[1]))
3482
    {
3483
      Debug("integers") << "    " << l[1] << " == " << getSatValue(l[1])
3484
                        << endl;
3485
    }
3486
    else
3487
    {
3488
      Debug("integers") << "    " << l[1] << " is not assigned a SAT literal"
3489
                        << endl;
3490
    }
3491
  }
3492
2282
  return lem;
3493
}
3494
3495
std::vector<ArithVar> TheoryArithPrivate::cutAllBounded() const{
3496
  vector<ArithVar> lemmas;
3497
  ArithVar max = d_partialModel.getNumberOfVariables();
3498
3499
  if (options().arith.doCutAllBounded && max > 0)
3500
  {
3501
    for(ArithVar iter = 0; iter != max; ++iter){
3502
    //Do not include slack variables
3503
      const DeltaRational& d = d_partialModel.getAssignment(iter);
3504
      if(isIntegerInput(iter) &&
3505
         !d_cutInContext.contains(iter) &&
3506
         d_partialModel.hasUpperBound(iter) &&
3507
         d_partialModel.hasLowerBound(iter) &&
3508
         !d.isIntegral()){
3509
        lemmas.push_back(iter);
3510
      }
3511
    }
3512
  }
3513
  return lemmas;
3514
}
3515
3516
/** Returns true if the roundRobinBranching() issues a lemma. */
3517
1141
TrustNode TheoryArithPrivate::roundRobinBranch()
3518
{
3519
1141
  if(hasIntegerModel()){
3520
    return TrustNode::null();
3521
  }else{
3522
1141
    ArithVar v = d_nextIntegerCheckVar;
3523
3524
1141
    Assert(isInteger(v));
3525
1141
    Assert(!isAuxiliaryVariable(v));
3526
1141
    return branchIntegerVariable(v);
3527
  }
3528
}
3529
3530
65057
bool TheoryArithPrivate::splitDisequalities(){
3531
65057
  bool splitSomething = false;
3532
3533
130114
  vector<ConstraintP> save;
3534
3535
592221
  while(!d_diseqQueue.empty()){
3536
263582
    ConstraintP front = d_diseqQueue.front();
3537
263582
    d_diseqQueue.pop();
3538
3539
263582
    if(front->isSplit()){
3540
212
      Debug("arith::eq") << "split already" << endl;
3541
    }else{
3542
263370
      Debug("arith::eq") << "not split already" << endl;
3543
3544
263370
      ArithVar lhsVar = front->getVariable();
3545
3546
263370
      const DeltaRational& lhsValue = d_partialModel.getAssignment(lhsVar);
3547
263370
      const DeltaRational& rhsValue = front->getValue();
3548
263370
      if(lhsValue == rhsValue){
3549
220
        Debug("arith::lemma") << "Splitting on " << front << endl;
3550
220
        Debug("arith::lemma") << "LHS value = " << lhsValue << endl;
3551
220
        Debug("arith::lemma") << "RHS value = " << rhsValue << endl;
3552
440
        TrustNode lemma = front->split();
3553
220
        ++(d_statistics.d_statDisequalitySplits);
3554
3555
440
        Debug("arith::lemma")
3556
220
            << "Now " << Rewriter::rewrite(lemma.getNode()) << endl;
3557
220
        outputTrustedLemma(lemma, InferenceId::ARITH_SPLIT_DEQ);
3558
        //cout << "Now " << Rewriter::rewrite(lemma) << endl;
3559
220
        splitSomething = true;
3560
263150
      }else if(d_partialModel.strictlyLessThanLowerBound(lhsVar, rhsValue)){
3561
52536
        Debug("arith::eq") << "can drop as less than lb" << front << endl;
3562
210614
      }else if(d_partialModel.strictlyGreaterThanUpperBound(lhsVar, rhsValue)){
3563
20342
        Debug("arith::eq") << "can drop as greater than ub" << front << endl;
3564
      }else{
3565
190272
        Debug("arith::eq") << "save" << front << ": " <<lhsValue << " != " << rhsValue << endl;
3566
190272
        save.push_back(front);
3567
      }
3568
    }
3569
  }
3570
65057
  vector<ConstraintP>::const_iterator i=save.begin(), i_end = save.end();
3571
445601
  for(; i != i_end; ++i){
3572
190272
    d_diseqQueue.push(*i);
3573
  }
3574
130114
  return splitSomething;
3575
}
3576
3577
/**
3578
 * Should be guarded by at least Debug.isOn("arith::print_assertions").
3579
 * Prints to Debug("arith::print_assertions")
3580
 */
3581
void TheoryArithPrivate::debugPrintAssertions(std::ostream& out) const {
3582
  out << "Assertions:" << endl;
3583
  for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
3584
    ArithVar i = *vi;
3585
    if (d_partialModel.hasLowerBound(i)) {
3586
      ConstraintP lConstr = d_partialModel.getLowerBoundConstraint(i);
3587
      out << lConstr << endl;
3588
    }
3589
3590
    if (d_partialModel.hasUpperBound(i)) {
3591
      ConstraintP uConstr = d_partialModel.getUpperBoundConstraint(i);
3592
      out << uConstr << endl;
3593
    }
3594
  }
3595
  context::CDQueue<ConstraintP>::const_iterator it = d_diseqQueue.begin();
3596
  context::CDQueue<ConstraintP>::const_iterator it_end = d_diseqQueue.end();
3597
  for(; it != it_end; ++ it) {
3598
    out << *it << endl;
3599
  }
3600
}
3601
3602
void TheoryArithPrivate::debugPrintModel(std::ostream& out) const{
3603
  out << "Model:" << endl;
3604
  for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
3605
    ArithVar i = *vi;
3606
    if(d_partialModel.hasNode(i)){
3607
      out << d_partialModel.asNode(i) << " : " <<
3608
        d_partialModel.getAssignment(i);
3609
      if(d_tableau.isBasic(i)){
3610
        out << " (basic)";
3611
      }
3612
      out << endl;
3613
    }
3614
  }
3615
}
3616
3617
25918
TrustNode TheoryArithPrivate::explain(TNode n)
3618
{
3619
51836
  Debug("arith::explain") << "explain @" << context()->getLevel() << ": " << n
3620
25918
                          << endl;
3621
3622
25918
  ConstraintP c = d_constraintDatabase.lookup(n);
3623
25918
  TrustNode exp;
3624
25918
  if(c != NullConstraint){
3625
11461
    Assert(!c->isAssumption());
3626
11461
    exp = c->externalExplainForPropagation(n);
3627
11461
    Debug("arith::explain") << "constraint explanation" << n << ":" << exp << endl;
3628
14457
  }else if(d_assertionsThatDoNotMatchTheirLiterals.find(n) != d_assertionsThatDoNotMatchTheirLiterals.end()){
3629
11089
    c = d_assertionsThatDoNotMatchTheirLiterals[n];
3630
11089
    if(!c->isAssumption()){
3631
4475
      exp = c->externalExplainForPropagation(n);
3632
4475
      Debug("arith::explain") << "assertions explanation" << n << ":" << exp << endl;
3633
    }else{
3634
6614
      Debug("arith::explain") << "this is a strange mismatch" << n << endl;
3635
6614
      Assert(d_congruenceManager.canExplain(n));
3636
6614
      exp = d_congruenceManager.explain(n);
3637
    }
3638
  }else{
3639
3368
    Assert(d_congruenceManager.canExplain(n));
3640
3368
    Debug("arith::explain") << "dm explanation" << n << endl;
3641
3368
    exp = d_congruenceManager.explain(n);
3642
  }
3643
25918
  return exp;
3644
}
3645
3646
2744243
void TheoryArithPrivate::propagate(Theory::Effort e) {
3647
  // This uses model values for safety. Disable for now.
3648
5488486
  if (d_qflraStatus == Result::SAT
3649
2717706
      && (options().arith.arithPropagationMode
3650
              == options::ArithPropagationMode::BOUND_INFERENCE_PROP
3651
2717706
          || options().arith.arithPropagationMode
3652
                 == options::ArithPropagationMode::BOTH_PROP)
3653
5461949
      && hasAnyUpdates())
3654
  {
3655
1110618
    if (options().arith.newProp)
3656
    {
3657
1108066
      propagateCandidatesNew();
3658
    }
3659
    else
3660
    {
3661
2552
      propagateCandidates();
3662
    }
3663
  }
3664
  else
3665
  {
3666
1633625
    clearUpdates();
3667
  }
3668
3669
4343235
  while(d_constraintDatabase.hasMorePropagations()){
3670
799496
    ConstraintCP c = d_constraintDatabase.nextPropagation();
3671
1598992
    Debug("arith::prop") << "next prop" << context()->getLevel() << ": " << c
3672
799496
                         << endl;
3673
3674
799496
    if(c->negationHasProof()){
3675
      Debug("arith::prop") << "negation has proof " << c->getNegation() << endl;
3676
      Debug("arith::prop") << c->getNegation()->externalExplainByAssertions()
3677
                           << endl;
3678
    }
3679
799496
    Assert(!c->negationHasProof())
3680
        << "A constraint has been propagated on the constraint propagation "
3681
           "queue, but the negation has been set to true.  Contact Tim now!";
3682
3683
799496
    if(!c->assertedToTheTheory()){
3684
1560658
      Node literal = c->getLiteral();
3685
1560658
      Debug("arith::prop") << "propagating @" << context()->getLevel() << " "
3686
780329
                           << literal << endl;
3687
3688
780329
      outputPropagate(literal);
3689
    }else{
3690
19167
      Debug("arith::prop") << "already asserted to the theory " <<  c->getLiteral() << endl;
3691
    }
3692
  }
3693
3694
4164233
  while(d_congruenceManager.hasMorePropagations()){
3695
1419990
    TNode toProp = d_congruenceManager.getNextPropagation();
3696
3697
    //Currently if the flag is set this came from an equality detected by the
3698
    //equality engine in the the difference manager.
3699
1419990
    Node normalized = Rewriter::rewrite(toProp);
3700
3701
709995
    ConstraintP constraint = d_constraintDatabase.lookup(normalized);
3702
709995
    if(constraint == NullConstraint){
3703
147
      Debug("arith::prop") << "propagating on non-constraint? "  << toProp << endl;
3704
3705
147
      outputPropagate(toProp);
3706
709848
    }else if(constraint->negationHasProof()){
3707
      // The congruence manager can prove: antecedents => toProp,
3708
      // ergo. antecedents ^ ~toProp is a conflict.
3709
      TrustNode exp = d_congruenceManager.explain(toProp);
3710
      Node notNormalized = normalized.negate();
3711
      std::vector<Node> ants(exp.getNode().begin(), exp.getNode().end());
3712
      ants.push_back(notNormalized);
3713
      Node lp = safeConstructNary(kind::AND, ants);
3714
      Debug("arith::prop") << "propagate conflict" <<  lp << endl;
3715
      if (proofsEnabled())
3716
      {
3717
        // Assume all of antecedents and ~toProp (rewritten)
3718
        std::vector<Pf> pfAntList;
3719
        for (size_t i = 0; i < ants.size(); ++i)
3720
        {
3721
          pfAntList.push_back(d_pnm->mkAssume(ants[i]));
3722
        }
3723
        Pf pfAnt = pfAntList.size() > 1
3724
                       ? d_pnm->mkNode(PfRule::AND_INTRO, pfAntList, {})
3725
                       : pfAntList[0];
3726
        // Use modus ponens to get toProp (un rewritten)
3727
        Pf pfConc = d_pnm->mkNode(
3728
            PfRule::MODUS_PONENS,
3729
            {pfAnt, exp.getGenerator()->getProofFor(exp.getProven())},
3730
            {});
3731
        // prove toProp (rewritten)
3732
        Pf pfConcRewritten = d_pnm->mkNode(
3733
            PfRule::MACRO_SR_PRED_TRANSFORM, {pfConc}, {normalized});
3734
        Pf pfNotNormalized = d_pnm->mkAssume(notNormalized);
3735
        // prove bottom from toProp and ~toProp
3736
        Pf pfBot;
3737
        if (normalized.getKind() == kind::NOT)
3738
        {
3739
          pfBot = d_pnm->mkNode(
3740
              PfRule::CONTRA, {pfNotNormalized, pfConcRewritten}, {});
3741
        }
3742
        else
3743
        {
3744
          pfBot = d_pnm->mkNode(
3745
              PfRule::CONTRA, {pfConcRewritten, pfNotNormalized}, {});
3746
        }
3747
        // close scope
3748
        Pf pfNotAnd = d_pnm->mkScope(pfBot, ants);
3749
        raiseBlackBoxConflict(lp, pfNotAnd);
3750
      }
3751
      else
3752
      {
3753
        raiseBlackBoxConflict(lp);
3754
      }
3755
      outputConflicts();
3756
      return;
3757
    }else{
3758
709848
      Debug("arith::prop") << "propagating still?" <<  toProp << endl;
3759
709848
      outputPropagate(toProp);
3760
    }
3761
  }
3762
}
3763
3764
5873151
DeltaRational TheoryArithPrivate::getDeltaValue(TNode term) const
3765
{
3766
5873151
  AlwaysAssert(d_qflraStatus != Result::SAT_UNKNOWN);
3767
5873151
  Debug("arith::value") << term << std::endl;
3768
3769
5873151
  if (d_partialModel.hasArithVar(term)) {
3770
2179271
    ArithVar var = d_partialModel.asArithVar(term);
3771
2179271
    return d_partialModel.getAssignment(var);
3772
  }
3773
3774
3693880
  switch (Kind kind = term.getKind()) {
3775
2075793
    case kind::CONST_RATIONAL:
3776
2075793
      return term.getConst<Rational>();
3777
3778
1167045
    case kind::PLUS: {  // 2+ args
3779
2334090
      DeltaRational value(0);
3780
3769597
      for (TNode::iterator i = term.begin(), iend = term.end(); i != iend;
3781
           ++i) {
3782
2602552
        value = value + getDeltaValue(*i);
3783
      }
3784
1167045
      return value;
3785
    }
3786
3787
451042
    case kind::NONLINEAR_MULT:
3788
    case kind::MULT: {  // 2+ args
3789
451042
      Assert(!isSetup(term));
3790
902084
      DeltaRational value(1);
3791
1353126
      for (TNode::iterator i = term.begin(), iend = term.end(); i != iend;
3792
           ++i) {
3793
902084
        value = value * getDeltaValue(*i);
3794
      }
3795
451042
      return value;
3796
    }
3797
    case kind::MINUS: {  // 2 args
3798
      return getDeltaValue(term[0]) - getDeltaValue(term[1]);
3799
    }
3800
    case kind::UMINUS: {  // 1 arg
3801
      return (-getDeltaValue(term[0]));
3802
    }
3803
3804
    case kind::DIVISION: {  // 2 args
3805
      Assert(!isSetup(term));
3806
      return getDeltaValue(term[0]) / getDeltaValue(term[1]);
3807
    }
3808
    case kind::DIVISION_TOTAL:
3809
    case kind::INTS_DIVISION_TOTAL:
3810
    case kind::INTS_MODULUS_TOTAL: {  // 2 args
3811
      Assert(!isSetup(term));
3812
      DeltaRational denominator = getDeltaValue(term[1]);
3813
      if (denominator.isZero()) {
3814
        return DeltaRational(0, 0);
3815
      }
3816
      DeltaRational numerator = getDeltaValue(term[0]);
3817
      if (kind == kind::DIVISION_TOTAL) {
3818
        return numerator / denominator;
3819
      } else if (kind == kind::INTS_DIVISION_TOTAL) {
3820
        return Rational(numerator.euclidianDivideQuotient(denominator));
3821
      } else {
3822
        Assert(kind == kind::INTS_MODULUS_TOTAL);
3823
        return Rational(numerator.euclidianDivideRemainder(denominator));
3824
      }
3825
    }
3826
3827
    default:
3828
      throw ModelException(term, "No model assignment.");
3829
  }
3830
}
3831
3832
27884
Rational TheoryArithPrivate::deltaValueForTotalOrder() const{
3833
55768
  Rational min(2);
3834
55768
  std::set<DeltaRational> relevantDeltaValues;
3835
27884
  context::CDQueue<ConstraintP>::const_iterator qiter = d_diseqQueue.begin();
3836
27884
  context::CDQueue<ConstraintP>::const_iterator qiter_end = d_diseqQueue.end();
3837
3838
189296
  for(; qiter != qiter_end; ++qiter){
3839
80706
    ConstraintP curr = *qiter;
3840
3841
80706
    const DeltaRational& rhsValue = curr->getValue();
3842
80706
    relevantDeltaValues.insert(rhsValue);
3843
  }
3844
3845
27884
  Theory::shared_terms_iterator shared_iter = d_containing.shared_terms_begin();
3846
27884
  Theory::shared_terms_iterator shared_end = d_containing.shared_terms_end();
3847
1768704
  for(; shared_iter != shared_end; ++shared_iter){
3848
1740820
    Node sharedCurr = *shared_iter;
3849
3850
    // ModelException is fatal as this point. Don't catch!
3851
    // DeltaRationalException is fatal as this point. Don't catch!
3852
1740820
    DeltaRational val = getDeltaValue(sharedCurr);
3853
870410
    relevantDeltaValues.insert(val);
3854
  }
3855
3856
2042562
  for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
3857
2014678
    ArithVar v = *vi;
3858
2014678
    const DeltaRational& value = d_partialModel.getAssignment(v);
3859
2014678
    relevantDeltaValues.insert(value);
3860
2014678
    if( d_partialModel.hasLowerBound(v)){
3861
1260312
      const DeltaRational& lb = d_partialModel.getLowerBound(v);
3862
1260312
      relevantDeltaValues.insert(lb);
3863
    }
3864
2014678
    if( d_partialModel.hasUpperBound(v)){
3865
1050662
      const DeltaRational& ub = d_partialModel.getUpperBound(v);
3866
1050662
      relevantDeltaValues.insert(ub);
3867
    }
3868
  }
3869
3870
27884
  if(relevantDeltaValues.size() >= 2){
3871
25018
    std::set<DeltaRational>::const_iterator iter = relevantDeltaValues.begin();
3872
25018
    std::set<DeltaRational>::const_iterator iter_end = relevantDeltaValues.end();
3873
50036
    DeltaRational prev = *iter;
3874
25018
    ++iter;
3875
601898
    for(; iter != iter_end; ++iter){
3876
288440
      const DeltaRational& curr = *iter;
3877
3878
288440
      Assert(prev < curr);
3879
3880
288440
      DeltaRational::seperatingDelta(min, prev, curr);
3881
288440
      prev = curr;
3882
    }
3883
  }
3884
3885
27884
  Assert(min.sgn() > 0);
3886
27884
  Rational belowMin = min/Rational(2);
3887
55768
  return belowMin;
3888
}
3889
3890
42545
void TheoryArithPrivate::collectModelValues(const std::set<Node>& termSet,
3891
                                            std::map<Node, Node>& arithModel)
3892
{
3893
42545
  AlwaysAssert(d_qflraStatus == Result::SAT);
3894
3895
42545
  if(Debug.isOn("arith::collectModelInfo")){
3896
    debugPrintFacts();
3897
  }
3898
3899
42545
  Debug("arith::collectModelInfo") << "collectModelInfo() begin " << endl;
3900
3901
  // Delta lasts at least the duration of the function call
3902
42545
  const Rational& delta = d_partialModel.getDelta();
3903
85090
  std::unordered_set<TNode> shared = d_containing.currentlySharedTerms();
3904
3905
  // TODO:
3906
  // This is not very good for user push/pop....
3907
  // Revisit when implementing push/pop
3908
2499538
  for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
3909
2456993
    ArithVar v = *vi;
3910
3911
2456993
    if(!isAuxiliaryVariable(v)){
3912
2012376
      Node term = d_partialModel.asNode(v);
3913
3914
3881164
      if((theoryOf(term) == THEORY_ARITH || shared.find(term) != shared.end())
3915
3995015
         && termSet.find(term) != termSet.end()){
3916
3917
967976
        const DeltaRational& mod = d_partialModel.getAssignment(v);
3918
1935952
        Rational qmodel = mod.substituteDelta(delta);
3919
3920
1935952
        Node qNode = mkRationalNode(qmodel);
3921
967976
        Debug("arith::collectModelInfo") << "m->assertEquality(" << term << ", " << qmodel << ", true)" << endl;
3922
        // Add to the map
3923
967976
        arithModel[term] = qNode;
3924
      }else{
3925
38212
        Debug("arith::collectModelInfo") << "Skipping m->assertEquality(" << term << ", true)" << endl;
3926
3927
      }
3928
    }
3929
  }
3930
3931
  // Iterate over equivalence classes in LinearEqualityModule
3932
  // const eq::EqualityEngine& ee = d_congruenceManager.getEqualityEngine();
3933
  // m->assertEqualityEngine(&ee);
3934
3935
42545
  Debug("arith::collectModelInfo") << "collectModelInfo() end " << endl;
3936
42545
}
3937
3938
bool TheoryArithPrivate::safeToReset() const {
3939
  Assert(!d_tableauSizeHasBeenModified);
3940
  Assert(d_errorSet.noSignals());
3941
3942
  ErrorSet::error_iterator error_iter = d_errorSet.errorBegin();
3943
  ErrorSet::error_iterator error_end = d_errorSet.errorEnd();
3944
  for(; error_iter != error_end; ++error_iter){
3945
    ArithVar basic = *error_iter;
3946
    if(!d_smallTableauCopy.isBasic(basic)){
3947
      return false;
3948
    }
3949
  }
3950
3951
  return true;
3952
}
3953
3954
1687
void TheoryArithPrivate::notifyRestart(){
3955
3374
  TimerStat::CodeTimer codeTimer(d_statistics.d_restartTimer);
3956
3957
1687
  if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
3958
3959
1687
  ++d_restartsCounter;
3960
1687
  d_solveIntMaybeHelp = 0;
3961
1687
  d_solveIntAttempts = 0;
3962
1687
}
3963
3964
bool TheoryArithPrivate::entireStateIsConsistent(const string& s){
3965
  bool result = true;
3966
  for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
3967
    ArithVar var = *vi;
3968
    //ArithVar var = d_partialModel.asArithVar(*i);
3969
    if(!d_partialModel.assignmentIsConsistent(var)){
3970
      d_partialModel.printModel(var);
3971
      Warning() << s << ":" << "Assignment is not consistent for " << var << d_partialModel.asNode(var);
3972
      if(d_tableau.isBasic(var)){
3973
        Warning() << " (basic)";
3974
      }
3975
      Warning() << endl;
3976
      result = false;
3977
    }else if(d_partialModel.isInteger(var) && !d_partialModel.integralAssignment(var)){
3978
      d_partialModel.printModel(var);
3979
      Warning() << s << ":" << "Assignment is not integer for integer variable " << var << d_partialModel.asNode(var);
3980
      if(d_tableau.isBasic(var)){
3981
        Warning() << " (basic)";
3982
      }
3983
      Warning() << endl;
3984
      result = false;
3985
    }
3986
  }
3987
  return result;
3988
}
3989
3990
bool TheoryArithPrivate::unenqueuedVariablesAreConsistent(){
3991
  bool result = true;
3992
  for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
3993
    ArithVar var = *vi;
3994
    if(!d_partialModel.assignmentIsConsistent(var)){
3995
      if(!d_errorSet.inError(var)){
3996
3997
        d_partialModel.printModel(var);
3998
        Warning() << "Unenqueued var is not consistent for " << var <<  d_partialModel.asNode(var);
3999
        if(d_tableau.isBasic(var)){
4000
          Warning() << " (basic)";
4001
        }
4002
        Warning() << endl;
4003
        result = false;
4004
      } else if(Debug.isOn("arith::consistency::initial")){
4005
        d_partialModel.printModel(var);
4006
        Warning() << "Initial var is not consistent for " << var <<  d_partialModel.asNode(var);
4007
        if(d_tableau.isBasic(var)){
4008
          Warning() << " (basic)";
4009
        }
4010
        Warning() << endl;
4011
      }
4012
     }
4013
  }
4014
  return result;
4015
}
4016
4017
15262
void TheoryArithPrivate::presolve(){
4018
30524
  TimerStat::CodeTimer codeTimer(d_statistics.d_presolveTime);
4019
4020
15262
  d_statistics.d_initialTableauSize = d_tableau.size();
4021
4022
15262
  if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
4023
4024
  static thread_local unsigned callCount = 0;
4025
15262
  if(Debug.isOn("arith::presolve")) {
4026
    Debug("arith::presolve") << "TheoryArithPrivate::presolve #" << callCount << endl;
4027
    callCount = callCount + 1;
4028
  }
4029
4030
30524
  vector<TrustNode> lemmas;
4031
15262
  if (!options().base.incrementalSolving)
4032
  {
4033
7676
    switch (options().arith.arithUnateLemmaMode)
4034
    {
4035
      case options::ArithUnateLemmaMode::NO: break;
4036
      case options::ArithUnateLemmaMode::INEQUALITY:
4037
        d_constraintDatabase.outputUnateInequalityLemmas(lemmas);
4038
        break;
4039
      case options::ArithUnateLemmaMode::EQUALITY:
4040
        d_constraintDatabase.outputUnateEqualityLemmas(lemmas);
4041
        break;
4042
7676
      case options::ArithUnateLemmaMode::ALL:
4043
7676
        d_constraintDatabase.outputUnateInequalityLemmas(lemmas);
4044
7676
        d_constraintDatabase.outputUnateEqualityLemmas(lemmas);
4045
7676
        break;
4046
      default: Unhandled() << options().arith.arithUnateLemmaMode;
4047
    }
4048
  }
4049
4050
15262
  vector<TrustNode>::const_iterator i = lemmas.begin(), i_end = lemmas.end();
4051
89542
  for(; i != i_end; ++i){
4052
74280
    TrustNode lem = *i;
4053
37140
    Debug("arith::oldprop") << " lemma lemma duck " <<lem << endl;
4054
37140
    outputTrustedLemma(lem, InferenceId::ARITH_UNATE);
4055
  }
4056
15262
}
4057
4058
747572
EqualityStatus TheoryArithPrivate::getEqualityStatus(TNode a, TNode b) {
4059
747572
  if(d_qflraStatus == Result::SAT_UNKNOWN){
4060
    return EQUALITY_UNKNOWN;
4061
  }else{
4062
    try {
4063
747572
      if (getDeltaValue(a) == getDeltaValue(b)) {
4064
62468
        return EQUALITY_TRUE_IN_MODEL;
4065
      } else {
4066
685104
        return EQUALITY_FALSE_IN_MODEL;
4067
      }
4068
    } catch (DeltaRationalException& dr) {
4069
      return EQUALITY_UNKNOWN;
4070
    } catch (ModelException& me) {
4071
      return EQUALITY_UNKNOWN;
4072
    }
4073
  }
4074
}
4075
4076
1746
bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound){
4077
1746
  ++d_statistics.d_boundComputations;
4078
4079
1746
  RowIndex ridx = d_tableau.basicToRowIndex(basic);
4080
3492
  DeltaRational bound = d_linEq.computeRowBound(ridx, upperBound, basic);
4081
4082
4504
  if((upperBound && d_partialModel.strictlyLessThanUpperBound(basic, bound)) ||
4083
2048
     (!upperBound && d_partialModel.strictlyGreaterThanLowerBound(basic, bound))){
4084
4085
    // TODO: "Policy point"
4086
    //We are only going to recreate the functionality for now.
4087
    //In the future this can be improved to generate a temporary constraint
4088
    //if none exists.
4089
    //Experiment with doing this every time or only when the new constraint
4090
    //implies an unknown fact.
4091
4092
1730
    ConstraintType t = upperBound ? UpperBound : LowerBound;
4093
1730
    ConstraintP bestImplied = d_constraintDatabase.getBestImpliedBound(basic, t, bound);
4094
4095
    // Node bestImplied = upperBound ?
4096
    //   d_apm.getBestImpliedUpperBound(basic, bound):
4097
    //   d_apm.getBestImpliedLowerBound(basic, bound);
4098
4099
1730
    if(bestImplied != NullConstraint){
4100
      //This should be stronger
4101
1272
      Assert(!upperBound || bound <= bestImplied->getValue());
4102
1272
      Assert(
4103
          !upperBound
4104
          || d_partialModel.lessThanUpperBound(basic, bestImplied->getValue()));
4105
4106
1272
      Assert(upperBound || bound >= bestImplied->getValue());
4107
1272
      Assert(upperBound
4108
             || d_partialModel.greaterThanLowerBound(basic,
4109
                                                     bestImplied->getValue()));
4110
      //slightly changed
4111
4112
      // ConstraintP c = d_constraintDatabase.lookup(bestImplied);
4113
      // Assert(c != NullConstraint);
4114
4115
1272
      bool assertedToTheTheory = bestImplied->assertedToTheTheory();
4116
1272
      bool canBePropagated = bestImplied->canBePropagated();
4117
1272
      bool hasProof = bestImplied->hasProof();
4118
4119
2544
      Debug("arith::prop") << "arith::prop" << basic
4120
1272
                           << " " << assertedToTheTheory
4121
1272
                           << " " << canBePropagated
4122
1272
                           << " " << hasProof
4123
1272
                           << endl;
4124
4125
1272
      if(bestImplied->negationHasProof()){
4126
        Warning() << "the negation of " <<  bestImplied << " : " << endl
4127
                  << "has proof " << bestImplied->getNegation() << endl
4128
                  << bestImplied->getNegation()->externalExplainByAssertions()
4129
                  << endl;
4130
      }
4131
4132
1272
      if(!assertedToTheTheory && canBePropagated && !hasProof ){
4133
232
        d_linEq.propagateBasicFromRow(bestImplied);
4134
        // I think this can be skipped if canBePropagated is true
4135
        //d_learnedBounds.push(bestImplied);
4136
232
        if(Debug.isOn("arith::prop")){
4137
          Debug("arith::prop") << "success " << bestImplied << endl;
4138
          d_partialModel.printModel(basic, Debug("arith::prop"));
4139
        }
4140
232
        return true;
4141
      }
4142
1040
      if(Debug.isOn("arith::prop")){
4143
        Debug("arith::prop") << "failed " << basic
4144
                             << " " << bound
4145
                             << " " << assertedToTheTheory
4146
                             << " " << canBePropagated
4147
                             << " " << hasProof << endl;
4148
        d_partialModel.printModel(basic, Debug("arith::prop"));
4149
      }
4150
    }
4151
16
  }else if(Debug.isOn("arith::prop")){
4152
    Debug("arith::prop") << "false " << bound << " ";
4153
    d_partialModel.printModel(basic, Debug("arith::prop"));
4154
  }
4155
1514
  return false;
4156
}
4157
4158
4434
void TheoryArithPrivate::propagateCandidate(ArithVar basic){
4159
4434
  bool success = false;
4160
4434
  RowIndex ridx = d_tableau.basicToRowIndex(basic);
4161
4162
  bool tryLowerBound =
4163
8480
    d_partialModel.strictlyAboveLowerBound(basic) &&
4164
8480
    d_linEq.rowLacksBound(ridx, false, basic) == NULL;
4165
4166
  bool tryUpperBound =
4167
8446
    d_partialModel.strictlyBelowUpperBound(basic) &&
4168
8446
    d_linEq.rowLacksBound(ridx, true, basic) == NULL;
4169
4170
4434
  if(tryLowerBound){
4171
1020
    success |= propagateCandidateLowerBound(basic);
4172
  }
4173
4434
  if(tryUpperBound){
4174
726
    success |= propagateCandidateUpperBound(basic);
4175
  }
4176
4434
  if(success){
4177
226
    ++d_statistics.d_boundPropagations;
4178
  }
4179
4434
}
4180
4181
2552
void TheoryArithPrivate::propagateCandidates(){
4182
5104
  TimerStat::CodeTimer codeTimer(d_statistics.d_boundComputationTime);
4183
4184
2552
  Debug("arith::prop") << "propagateCandidates begin" << endl;
4185
4186
2552
  Assert(d_candidateBasics.empty());
4187
4188
2552
  if(d_updatedBounds.empty()){ return; }
4189
4190
2552
  DenseSet::const_iterator i = d_updatedBounds.begin();
4191
2552
  DenseSet::const_iterator end = d_updatedBounds.end();
4192
9200
  for(; i != end; ++i){
4193
3324
    ArithVar var = *i;
4194
6648
    if (d_tableau.isBasic(var)
4195
4098
        && d_tableau.basicRowLength(var)
4196
774
               <= options().arith.arithPropagateMaxLength)
4197
    {
4198
702
      d_candidateBasics.softAdd(var);
4199
    }
4200
    else
4201
    {
4202
2622
      Tableau::ColIterator basicIter = d_tableau.colIterator(var);
4203
15002
      for(; !basicIter.atEnd(); ++basicIter){
4204
6190
        const Tableau::Entry& entry = *basicIter;
4205
6190
        RowIndex ridx = entry.getRowIndex();
4206
6190
        ArithVar rowVar = d_tableau.rowIndexToBasic(ridx);
4207
6190
        Assert(entry.getColVar() == var);
4208
6190
        Assert(d_tableau.isBasic(rowVar));
4209
12380
        if (d_tableau.getRowLength(ridx)
4210
6190
            <= options().arith.arithPropagateMaxLength)
4211
        {
4212
4576
          d_candidateBasics.softAdd(rowVar);
4213
        }
4214
      }
4215
    }
4216
  }
4217
2552
  d_updatedBounds.purge();
4218
4219
11420
  while(!d_candidateBasics.empty()){
4220
4434
    ArithVar candidate = d_candidateBasics.back();
4221
4434
    d_candidateBasics.pop_back();
4222
4434
    Assert(d_tableau.isBasic(candidate));
4223
4434
    propagateCandidate(candidate);
4224
  }
4225
2552
  Debug("arith::prop") << "propagateCandidates end" << endl << endl << endl;
4226
}
4227
4228
1108066
void TheoryArithPrivate::propagateCandidatesNew(){
4229
  /* Four criteria must be met for progagation on a variable to happen using a row:
4230
   * 0: A new bound has to have been added to the row.
4231
   * 1: The hasBoundsCount for the row must be "full" or be full minus one variable
4232
   *    (This is O(1) to check, but requires book keeping.)
4233
   * 2: The current assignment must be strictly smaller/greater than the current bound.
4234
   *    assign(x) < upper(x)
4235
   *    (This is O(1) to compute.)
4236
   * 3: There is a bound that is strictly smaller/greater than the current assignment.
4237
   *    assign(x) < c for some x <= c literal
4238
   *    (This is O(log n) to compute.)
4239
   * 4: The implied bound on x is strictly smaller/greater than the current bound.
4240
   *    (This is O(n) to compute.)
4241
   */
4242
4243
2216132
  TimerStat::CodeTimer codeTimer(d_statistics.d_boundComputationTime);
4244
1108066
  Debug("arith::prop") << "propagateCandidatesNew begin" << endl;
4245
4246
1108066
  Assert(d_qflraStatus == Result::SAT);
4247
1108066
  if(d_updatedBounds.empty()){ return; }
4248
1108066
  dumpUpdatedBoundsToRows();
4249
1108066
  Assert(d_updatedBounds.empty());
4250
4251
1108066
  if(!d_candidateRows.empty()){
4252
2086576
    UpdateTrackingCallback utcb(&d_linEq);
4253
1043288
    d_partialModel.processBoundsQueue(utcb);
4254
  }
4255
4256
20778182
  while(!d_candidateRows.empty()){
4257
9835058
    RowIndex candidate = d_candidateRows.back();
4258
9835058
    d_candidateRows.pop_back();
4259
9835058
    propagateCandidateRow(candidate);
4260
  }
4261
1108066
  Debug("arith::prop") << "propagateCandidatesNew end" << endl << endl << endl;
4262
}
4263
4264
17234282
bool TheoryArithPrivate::propagateMightSucceed(ArithVar v, bool ub) const{
4265
26153302
  int cmp = ub ? d_partialModel.cmpAssignmentUpperBound(v)
4266
26153302
    : d_partialModel.cmpAssignmentLowerBound(v);
4267
17234282
  bool hasSlack = ub ? cmp < 0 : cmp > 0;
4268
17234282
  if(hasSlack){
4269
8555617
    ConstraintType t = ub ? UpperBound : LowerBound;
4270
8555617
    const DeltaRational& a = d_partialModel.getAssignment(v);
4271
4272
8555617
    if(isInteger(v) && !a.isIntegral()){
4273
95536
      return true;
4274
    }
4275
4276
8460081
    ConstraintP strongestPossible = d_constraintDatabase.getBestImpliedBound(v, t, a);
4277
8460081
    if(strongestPossible == NullConstraint){
4278
5411050
      return false;
4279
    }else{
4280
3049031
      bool assertedToTheTheory = strongestPossible->assertedToTheTheory();
4281
3049031
      bool canBePropagated = strongestPossible->canBePropagated();
4282
3049031
      bool hasProof = strongestPossible->hasProof();
4283
4284
3049031
      return !assertedToTheTheory && canBePropagated && !hasProof;
4285
    }
4286
  }else{
4287
8678665
    return false;
4288
  }
4289
}
4290
4291
4419048
bool TheoryArithPrivate::attemptSingleton(RowIndex ridx, bool rowUp){
4292
4419048
  Debug("arith::prop") << "  attemptSingleton" << ridx;
4293
4294
  const Tableau::Entry* ep;
4295
4419048
  ep = d_linEq.rowLacksBound(ridx, rowUp, ARITHVAR_SENTINEL);
4296
4419048
  Assert(ep != NULL);
4297
4298
4419048
  ArithVar v = ep->getColVar();
4299
4419048
  const Rational& coeff = ep->getCoefficient();
4300
4301
  // 0 = c * v + \sum rest
4302
  // Suppose rowUp
4303
  // - c * v = \sum rest \leq D
4304
  // if c > 0, v \geq -D/c so !vUp
4305
  // if c < 0, v \leq -D/c so  vUp
4306
  // Suppose not rowUp
4307
  // - c * v = \sum rest \geq D
4308
  // if c > 0, v \leq -D/c so  vUp
4309
  // if c < 0, v \geq -D/c so !vUp
4310
4419048
  bool vUp = (rowUp == ( coeff.sgn() < 0));
4311
4312
4419048
  Debug("arith::prop") << "  " << rowUp << " " << v << " " << coeff << " " << vUp << endl;
4313
4419048
  Debug("arith::prop") << "  " << propagateMightSucceed(v, vUp) << endl;
4314
4315
4419048
  if(propagateMightSucceed(v, vUp)){
4316
640044
    DeltaRational dr = d_linEq.computeRowBound(ridx, rowUp, v);
4317
640044
    DeltaRational bound = dr / (- coeff);
4318
320022
    return tryToPropagate(ridx, rowUp, v, vUp, bound);
4319
  }
4320
4099026
  return false;
4321
}
4322
4323
1563113
bool TheoryArithPrivate::attemptFull(RowIndex ridx, bool rowUp){
4324
1563113
  Debug("arith::prop") << "  attemptFull" << ridx << endl;
4325
4326
3126226
  vector<const Tableau::Entry*> candidates;
4327
4328
9959299
  for(Tableau::RowIterator i = d_tableau.ridRowIterator(ridx); !i.atEnd(); ++i){
4329
8396186
    const Tableau::Entry& e =*i;
4330
8396186
    const Rational& c = e.getCoefficient();
4331
8396186
    ArithVar v = e.getColVar();
4332
8396186
    bool vUp = (rowUp == (c.sgn() < 0));
4333
8396186
    if(propagateMightSucceed(v, vUp)){
4334
110243
      candidates.push_back(&e);
4335
    }
4336
  }
4337
1563113
  if(candidates.empty()){ return false; }
4338
4339
  const DeltaRational slack =
4340
185236
    d_linEq.computeRowBound(ridx, rowUp, ARITHVAR_SENTINEL);
4341
92618
  bool any = false;
4342
92618
  vector<const Tableau::Entry*>::const_iterator i, iend;
4343
202861
  for(i = candidates.begin(), iend = candidates.end(); i != iend; ++i){
4344
110243
    const Tableau::Entry* ep = *i;
4345
110243
    const Rational& c = ep->getCoefficient();
4346
110243
    ArithVar v = ep->getColVar();
4347
4348
    // See the comment for attemptSingleton()
4349
110243
    bool activeUp = (rowUp == (c.sgn() > 0));
4350
110243
    bool vUb = (rowUp == (c.sgn() < 0));
4351
4352
220486
    const DeltaRational& activeBound = activeUp ?
4353
73577
      d_partialModel.getUpperBound(v):
4354
146909
      d_partialModel.getLowerBound(v);
4355
4356
220486
    DeltaRational contribution = activeBound * c;
4357
220486
    DeltaRational impliedBound = (slack - contribution)/(-c);
4358
4359
110243
    bool success = tryToPropagate(ridx, rowUp, v, vUb, impliedBound);
4360
110243
    any |= success;
4361
  }
4362
92618
  return any;
4363
}
4364
4365
430265
bool TheoryArithPrivate::tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, bool vUb, const DeltaRational& bound){
4366
4367
726797
  bool weaker = vUb ? d_partialModel.strictlyLessThanUpperBound(v, bound):
4368
726797
    d_partialModel.strictlyGreaterThanLowerBound(v, bound);
4369
430265
  if(weaker){
4370
317749
    ConstraintType t = vUb ? UpperBound : LowerBound;
4371
4372
317749
    ConstraintP implied = d_constraintDatabase.getBestImpliedBound(v, t, bound);
4373
317749
    if(implied != NullConstraint){
4374
184607
      return rowImplicationCanBeApplied(ridx, rowUp, implied);
4375
    }
4376
  }
4377
245658
  return false;
4378
}
4379
4380
110760
Node flattenImplication(Node imp){
4381
221520
  NodeBuilder nb(kind::OR);
4382
221520
  std::unordered_set<Node> included;
4383
221520
  Node left = imp[0];
4384
221520
  Node right = imp[1];
4385
4386
110760
  if(left.getKind() == kind::AND){
4387
506857
    for(Node::iterator i = left.begin(), iend = left.end(); i != iend; ++i) {
4388
396097
      if (!included.count((*i).negate()))
4389
      {
4390
396097
        nb << (*i).negate();
4391
396097
        included.insert((*i).negate());
4392
      }
4393
    }
4394
  }else{
4395
    if (!included.count(left.negate()))
4396
    {
4397
      nb << left.negate();
4398
      included.insert(left.negate());
4399
    }
4400
  }
4401
4402
110760
  if(right.getKind() == kind::OR){
4403
    for(Node::iterator i = right.begin(), iend = right.end(); i != iend; ++i) {
4404
      if (!included.count(*i))
4405
      {
4406
        nb << *i;
4407
        included.insert(*i);
4408
      }
4409
    }
4410
  }else{
4411
110760
    if (!included.count(right))
4412
    {
4413
110760
      nb << right;
4414
110760
      included.insert(right);
4415
    }
4416
  }
4417
4418
221520
  return nb;
4419
}
4420
4421
184607
bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, ConstraintP implied){
4422
184607
  Assert(implied != NullConstraint);
4423
184607
  ArithVar v = implied->getVariable();
4424
4425
184607
  bool assertedToTheTheory = implied->assertedToTheTheory();
4426
184607
  bool canBePropagated = implied->canBePropagated();
4427
184607
  bool hasProof = implied->hasProof();
4428
4429
369214
  Debug("arith::prop") << "arith::prop" << v
4430
184607
                       << " " << assertedToTheTheory
4431
184607
                       << " " << canBePropagated
4432
184607
                       << " " << hasProof
4433
184607
                       << endl;
4434
4435
4436
184607
  if( !assertedToTheTheory && canBePropagated && !hasProof ){
4437
289530
    ConstraintCPVec explain;
4438
144765
    ARITH_PROOF(d_farkasBuffer.clear());
4439
144765
    RationalVectorP coeffs = ARITH_NULLPROOF(&d_farkasBuffer);
4440
4441
    // After invoking `propegateRow`:
4442
    //   * coeffs[0] is for implied
4443
    //   * coeffs[i+1] is for explain[i]
4444
144765
    d_linEq.propagateRow(explain, ridx, rowUp, implied, coeffs);
4445
144765
    if (d_tableau.getRowLength(ridx) <= options().arith.arithPropAsLemmaLength)
4446
    {
4447
110760
      if (Debug.isOn("arith::prop::pf")) {
4448
        for (const auto & constraint : explain) {
4449
          Assert(constraint->hasProof());
4450
          constraint->printProofTree(Debug("arith::prop::pf"));
4451
        }
4452
      }
4453
221520
      Node implication = implied->externalImplication(explain);
4454
221520
      Node clause = flattenImplication(implication);
4455
221520
      std::shared_ptr<ProofNode> clausePf{nullptr};
4456
4457
110760
      if (isProofEnabled())
4458
      {
4459
        // We can prove this lemma from Farkas...
4460
31598
        std::vector<std::shared_ptr<ProofNode>> conflictPfs;
4461
        // Assume the negated getLiteral version of the implied constaint
4462
        // then rewrite it into proof normal form.
4463
15799
        conflictPfs.push_back(
4464
94794
            d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
4465
31598
                          {d_pnm->mkAssume(implied->getLiteral().negate())},
4466
31598
                          {implied->getNegation()->getProofLiteral()}));
4467
        // Add the explaination proofs.
4468
68580
        for (const auto constraint : explain)
4469
        {
4470
105562
          NodeBuilder nb;
4471
52781
          conflictPfs.push_back(constraint->externalExplainByAssertions(nb));
4472
        }
4473
        // Collect the farkas coefficients, as nodes.
4474
31598
        std::vector<Node> farkasCoefficients;
4475
15799
        farkasCoefficients.reserve(coeffs->size());
4476
15799
        auto nm = NodeManager::currentNM();
4477
15799
        std::transform(
4478
            coeffs->begin(),
4479
            coeffs->end(),
4480
            std::back_inserter(farkasCoefficients),
4481
84379
            [nm](const Rational& r) { return nm->mkConst<Rational>(r); });
4482
4483
        // Prove bottom.
4484
15799
        auto sumPf = d_pnm->mkNode(
4485
31598
            PfRule::MACRO_ARITH_SCALE_SUM_UB, conflictPfs, farkasCoefficients);
4486
15799
        auto botPf = d_pnm->mkNode(
4487
31598
            PfRule::MACRO_SR_PRED_TRANSFORM, {sumPf}, {nm->mkConst(false)});
4488
4489
        // Prove the conflict
4490
31598
        std::vector<Node> assumptions;
4491
15799
        assumptions.reserve(clause.getNumChildren());
4492
15799
        std::transform(clause.begin(),
4493
                       clause.end(),
4494
                       std::back_inserter(assumptions),
4495
85274
                       [](TNode r) { return r.negate(); });
4496
31598
        auto notAndNotPf = d_pnm->mkScope(botPf, assumptions);
4497
4498
        // Convert it to a clause
4499
31598
        auto orNotNotPf = d_pnm->mkNode(PfRule::NOT_AND, {notAndNotPf}, {});
4500
47397
        clausePf = d_pnm->mkNode(
4501
31598
            PfRule::MACRO_SR_PRED_TRANSFORM, {orNotNotPf}, {clause});
4502
4503
        // Output it
4504
31598
        TrustNode trustedClause = d_pfGen->mkTrustNode(clause, clausePf);
4505
15799
        outputTrustedLemma(trustedClause, InferenceId::ARITH_ROW_IMPL);
4506
      }
4507
      else
4508
      {
4509
94961
        outputLemma(clause, InferenceId::ARITH_ROW_IMPL);
4510
      }
4511
    }
4512
    else
4513
    {
4514
34005
      Assert(!implied->negationHasProof());
4515
34005
      implied->impliedByFarkas(explain, coeffs, false);
4516
34005
      implied->tryToPropagate();
4517
    }
4518
144765
    return true;
4519
  }
4520
4521
39842
  if(Debug.isOn("arith::prop")){
4522
    Debug("arith::prop")
4523
      << "failed " << v << " " << assertedToTheTheory << " "
4524
      << canBePropagated << " " << hasProof << " " << implied << endl;
4525
    d_partialModel.printModel(v, Debug("arith::prop"));
4526
  }
4527
39842
  return false;
4528
}
4529
4530
9835058
bool TheoryArithPrivate::propagateCandidateRow(RowIndex ridx){
4531
9835058
  BoundCounts hasCount = d_linEq.hasBoundCount(ridx);
4532
9835058
  uint32_t rowLength = d_tableau.getRowLength(ridx);
4533
4534
9835058
  bool success = false;
4535
  static int instance = 0;
4536
9835058
  ++instance;
4537
4538
19670116
  Debug("arith::prop")
4539
9835058
    << "propagateCandidateRow " << instance << " attempt " << rowLength << " " <<  hasCount << endl;
4540
4541
19670116
  if (rowLength >= options().arith.arithPropagateMaxLength
4542
11437368
      && Random::getRandom().pickWithProb(
4543
1602310
          1.0 - double(options().arith.arithPropagateMaxLength) / rowLength))
4544
  {
4545
335663
    return false;
4546
  }
4547
4548
9499395
  if(hasCount.lowerBoundCount() == rowLength){
4549
650511
    success |= attemptFull(ridx, false);
4550
8848884
  }else if(hasCount.lowerBoundCount() + 1 == rowLength){
4551
2315038
    success |= attemptSingleton(ridx, false);
4552
  }
4553
4554
9499395
  if(hasCount.upperBoundCount() == rowLength){
4555
912602
    success |= attemptFull(ridx, true);
4556
8586793
  }else if(hasCount.upperBoundCount() + 1 == rowLength){
4557
2104010
    success |= attemptSingleton(ridx, true);
4558
  }
4559
9499395
  return success;
4560
}
4561
4562
1108066
void TheoryArithPrivate::dumpUpdatedBoundsToRows(){
4563
1108066
  Assert(d_candidateRows.empty());
4564
1108066
  DenseSet::const_iterator i = d_updatedBounds.begin();
4565
1108066
  DenseSet::const_iterator end = d_updatedBounds.end();
4566
6293366
  for(; i != end; ++i){
4567
2592650
    ArithVar var = *i;
4568
2592650
    if(d_tableau.isBasic(var)){
4569
1467337
      RowIndex ridx = d_tableau.basicToRowIndex(var);
4570
1467337
      d_candidateRows.softAdd(ridx);
4571
    }else{
4572
1125313
      Tableau::ColIterator basicIter = d_tableau.colIterator(var);
4573
26092773
      for(; !basicIter.atEnd(); ++basicIter){
4574
12483730
        const Tableau::Entry& entry = *basicIter;
4575
12483730
        RowIndex ridx = entry.getRowIndex();
4576
12483730
        d_candidateRows.softAdd(ridx);
4577
      }
4578
    }
4579
  }
4580
1108066
  d_updatedBounds.purge();
4581
1108066
}
4582
4583
const BoundsInfo& TheoryArithPrivate::boundsInfo(ArithVar basic) const{
4584
  RowIndex ridx = d_tableau.basicToRowIndex(basic);
4585
  return d_rowTracking[ridx];
4586
}
4587
4588
8517
std::pair<bool, Node> TheoryArithPrivate::entailmentCheck(TNode lit, const ArithEntailmentCheckParameters& params, ArithEntailmentCheckSideEffects& out){
4589
  using namespace inferbounds;
4590
4591
  // l k r
4592
  // diff : (l - r) k 0
4593
8517
  Debug("arith::entailCheck") << "TheoryArithPrivate::entailmentCheck(" << lit << ")"<< endl;
4594
  Kind k;
4595
  int primDir;
4596
17034
  Rational lm, rm, dm;
4597
17034
  Node lp, rp, dp;
4598
17034
  DeltaRational sep;
4599
8517
  bool successful = decomposeLiteral(lit, k, primDir, lm, lp, rm, rp, dm, dp, sep);
4600
8517
  if(!successful) { return make_pair(false, Node::null()); }
4601
4602
8517
  if(dp.getKind() == CONST_RATIONAL){
4603
    Node eval = Rewriter::rewrite(lit);
4604
    Assert(eval.getKind() == kind::CONST_BOOLEAN);
4605
    // if true, true is an acceptable explaination
4606
    // if false, the node is uninterpreted and eval can be forgotten
4607
    return make_pair(eval.getConst<bool>(), eval);
4608
  }
4609
8517
  Assert(dm != Rational(0));
4610
8517
  Assert(primDir == 1 || primDir == -1);
4611
4612
8517
  int negPrim = -primDir;
4613
4614
8517
  int secDir = (k == EQUAL || k == DISTINCT) ? negPrim: 0;
4615
8517
  int negSecDir = (k == EQUAL || k == DISTINCT) ? primDir: 0;
4616
4617
  // primDir*[lm*( lp )] k primDir*[ [rm*( rp )] + sep ]
4618
  // primDir*[lm*( lp ) - rm*( rp ) ] k primDir*sep
4619
  // primDir*[dm * dp] k primDir*sep
4620
4621
17034
  std::pair<Node, DeltaRational> bestPrimLeft, bestNegPrimRight, bestPrimDiff, tmp;
4622
17034
  std::pair<Node, DeltaRational> bestSecLeft, bestNegSecRight, bestSecDiff;
4623
8517
  bestPrimLeft.first = Node::null(); bestNegPrimRight.first = Node::null(); bestPrimDiff.first = Node::null();
4624
8517
  bestSecLeft.first = Node::null(); bestNegSecRight.first = Node::null(); bestSecDiff.first = Node::null();
4625
4626
4627
4628
8517
  ArithEntailmentCheckParameters::const_iterator alg, alg_end;
4629
23454
  for( alg = params.begin(), alg_end = params.end(); alg != alg_end; ++alg ){
4630
16682
    const inferbounds::InferBoundAlgorithm& ibalg = *alg;
4631
4632
16682
    Debug("arith::entailCheck") << "entailmentCheck trying " << (inferbounds::Algorithms) ibalg.getAlgorithm() << endl;
4633
16682
    switch(ibalg.getAlgorithm()){
4634
    case inferbounds::None:
4635
      break;
4636
16682
    case inferbounds::Lookup:
4637
    case inferbounds::RowSum:
4638
      {
4639
        typedef void (TheoryArithPrivate::*EntailmentCheckFunc)(std::pair<Node, DeltaRational>&, int, TNode) const;
4640
4641
        EntailmentCheckFunc ecfunc =
4642
16682
          (ibalg.getAlgorithm() == inferbounds::Lookup)
4643
          ? (&TheoryArithPrivate::entailmentCheckBoundLookup)
4644
16682
          : (&TheoryArithPrivate::entailmentCheckRowSum);
4645
4646
16682
        (*this.*ecfunc)(tmp, primDir * lm.sgn(), lp);
4647
16682
        setToMin(primDir * lm.sgn(), bestPrimLeft, tmp);
4648
4649
16682
        (*this.*ecfunc)(tmp, negPrim * rm.sgn(), rp);
4650
16682
        setToMin(negPrim * rm.sgn(), bestNegPrimRight, tmp);
4651
4652
16682
        (*this.*ecfunc)(tmp, secDir * lm.sgn(), lp);
4653
16682
        setToMin(secDir * lm.sgn(), bestSecLeft, tmp);
4654
4655
16682
        (*this.*ecfunc)(tmp, negSecDir * rm.sgn(), rp);
4656
16682
        setToMin(negSecDir * rm.sgn(), bestNegSecRight, tmp);
4657
4658
16682
        (*this.*ecfunc)(tmp, primDir * dm.sgn(), dp);
4659
16682
        setToMin(primDir * dm.sgn(), bestPrimDiff, tmp);
4660
4661
16682
        (*this.*ecfunc)(tmp, secDir * dm.sgn(), dp);
4662
16682
        setToMin(secDir * dm.sgn(), bestSecDiff, tmp);
4663
      }
4664
16682
      break;
4665
    default:
4666
      Unhandled();
4667
    }
4668
4669
    // turn bounds on prim * left and -prim * right into bounds on prim * diff
4670
16682
    if(!bestPrimLeft.first.isNull() && !bestNegPrimRight.first.isNull()){
4671
      //  primDir*lm* lp <= primDir*lm*L
4672
      // -primDir*rm* rp <= -primDir*rm*R
4673
      // primDir*lm* lp -primDir*rm* rp <=  primDir*lm*L - primDir*rm*R
4674
      // primDir [lm* lp -rm* rp] <= primDir[lm*L - *rm*R]
4675
      // primDir [dm * dp] <= primDir[lm*L - *rm*R]
4676
      // primDir [dm * dp] <= primDir * dm * ([lm*L - *rm*R]/dm)
4677
3197
      tmp.second = ((bestPrimLeft.second * lm) - (bestNegPrimRight.second * rm)) / dm;
4678
3197
      tmp.first = (bestPrimLeft.first).andNode(bestNegPrimRight.first);
4679
3197
      setToMin(primDir, bestPrimDiff, tmp);
4680
    }
4681
4682
    // turn bounds on sec * left and sec * right into bounds on sec * diff
4683
16682
    if(secDir != 0 && !bestSecLeft.first.isNull() && !bestNegSecRight.first.isNull()){
4684
      //  secDir*lm* lp <= secDir*lm*L
4685
      // -secDir*rm* rp <= -secDir*rm*R
4686
      // secDir*lm* lp -secDir*rm* rp <=  secDir*lm*L - secDir*rm*R
4687
      // secDir [lm* lp -rm* rp] <= secDir[lm*L - *rm*R]
4688
      // secDir [dm * dp] <= secDir[lm*L - *rm*R]
4689
      // secDir [dm * dp] <= secDir * dm * ([lm*L - *rm*R]/dm)
4690
      tmp.second = ((bestSecLeft.second * lm) - (bestNegSecRight.second * rm)) / dm;
4691
      tmp.first = (bestSecLeft.first).andNode(bestNegSecRight.first);
4692
      setToMin(secDir, bestSecDiff, tmp);
4693
    }
4694
4695
16682
    switch(k){
4696
16638
    case LEQ:
4697
16638
      if(!bestPrimDiff.first.isNull()){
4698
4649
        DeltaRational d = (bestPrimDiff.second * dm);
4699
3197
        if((primDir > 0 && d <= sep) || (primDir < 0 && d >= sep) ){
4700
3490
          Debug("arith::entailCheck") << "entailmentCheck found "
4701
1745
                                      << primDir << "*" << dm << "*(" << dp<<")"
4702
1745
                                      << " <= " << primDir << "*" << dm << "*" << bestPrimDiff.second
4703
1745
                                      << " <= " << primDir << "*" << sep << endl
4704
1745
                                      << " by " << bestPrimDiff.first << endl;
4705
1745
          Assert(bestPrimDiff.second * (Rational(primDir) * dm)
4706
                 <= (sep * Rational(primDir)));
4707
1745
          return make_pair(true, bestPrimDiff.first);
4708
        }
4709
      }
4710
14893
      break;
4711
22
    case EQUAL:
4712
22
      if(!bestPrimDiff.first.isNull() && !bestSecDiff.first.isNull()){
4713
        // Is primDir [dm * dp] == primDir * sep entailed?
4714
        // Iff [dm * dp] == sep entailed?
4715
        // Iff dp == sep / dm entailed?
4716
        // Iff dp <= sep / dm and dp >= sep / dm entailed?
4717
4718
        // primDir [dm * dp] <= primDir * dm * U
4719
        // secDir [dm * dp] <= secDir * dm * L
4720
4721
        // Suppose primDir * dm > 0
4722
        // then secDir * dm < 0
4723
        //   dp >= (secDir * L) / secDir * dm
4724
        //   dp >= (primDir * L) / primDir * dm
4725
        //
4726
        //   dp <= U / dm
4727
        //   dp >= L / dm
4728
        //   dp == sep / dm entailed iff U == L == sep
4729
        // Suppose primDir * dm < 0
4730
        // then secDir * dm > 0
4731
        //   dp >= U / dm
4732
        //   dp <= L / dm
4733
        //   dp == sep / dm entailed iff U == L == sep
4734
        if(bestPrimDiff.second == bestSecDiff.second){
4735
          if(bestPrimDiff.second == sep){
4736
            return make_pair(true, (bestPrimDiff.first).andNode(bestSecDiff.first));
4737
          }
4738
        }
4739
      }
4740
      // intentionally fall through to DISTINCT case!
4741
      // entailments of negations are eager exit cases for EQUAL
4742
      CVC5_FALLTHROUGH;
4743
    case DISTINCT:
4744
44
      if(!bestPrimDiff.first.isNull()){
4745
        // primDir [dm * dp] <= primDir * dm * U < primDir * sep
4746
        if((primDir > 0 && (bestPrimDiff.second * dm  < sep)) ||
4747
           (primDir < 0 && (bestPrimDiff.second * dm  > sep))){
4748
          // entailment of negation
4749
          if(k == DISTINCT){
4750
            return make_pair(true, bestPrimDiff.first);
4751
          }else{
4752
            Assert(k == EQUAL);
4753
            return make_pair(false, Node::null());
4754
          }
4755
        }
4756
      }
4757
44
      if(!bestSecDiff.first.isNull()){
4758
        // If primDir [dm * dp] > primDir * sep, then this is not entailed.
4759
        // If primDir [dm * dp] >= primDir * dm * L > primDir * sep
4760
        // -primDir * dm * L < -primDir * sep
4761
        // secDir * dm * L < secDir * sep
4762
        if((secDir > 0 && (bestSecDiff.second * dm < sep)) ||
4763
           (secDir < 0 && (bestSecDiff.second * dm > sep))){
4764
          if(k == DISTINCT){
4765
            return make_pair(true, bestSecDiff.first);
4766
          }else{
4767
            Assert(k == EQUAL);
4768
            return make_pair(false, Node::null());
4769
          }
4770
        }
4771
      }
4772
4773
44
      break;
4774
    default:
4775
      Unreachable();
4776
      break;
4777
    }
4778
  }
4779
6772
  return make_pair(false, Node::null());
4780
}
4781
4782
25551
bool TheoryArithPrivate::decomposeTerm(Node term, Rational& m, Node& p, Rational& c){
4783
51102
  Node t = Rewriter::rewrite(term);
4784
25551
  if(!Polynomial::isMember(t)){
4785
    return false;
4786
  }
4787
4788
  // TODO Speed up
4789
51102
  preprocessing::util::ContainsTermITEVisitor ctv;
4790
25551
  if(ctv.containsTermITE(t)){
4791
    return false;
4792
  }
4793
4794
51102
  Polynomial poly = Polynomial::parsePolynomial(t);
4795
25551
  if(poly.isConstant()){
4796
8495
    c = poly.getHead().getConstant().getValue();
4797
8495
    p = mkRationalNode(Rational(0));
4798
8495
    m = Rational(1);
4799
8495
    return true;
4800
17056
  }else if(poly.containsConstant()){
4801
4148
    c = poly.getHead().getConstant().getValue();
4802
4148
    poly = poly.getTail();
4803
  }else{
4804
12908
    c = Rational(0);
4805
  }
4806
17056
  Assert(!poly.isConstant());
4807
17056
  Assert(!poly.containsConstant());
4808
4809
17056
  const bool intVars = poly.allIntegralVariables();
4810
4811
17056
  if(intVars){
4812
17056
    m = Rational(1);
4813
17056
    if(!poly.isIntegral()){
4814
      Integer denom = poly.denominatorLCM();
4815
      m /= denom;
4816
      poly = poly * denom;
4817
    }
4818
34112
    Integer g = poly.gcd();
4819
17056
    m *= g;
4820
17056
    poly = poly * Rational(1,g);
4821
17056
    Assert(poly.isIntegral());
4822
17056
    Assert(poly.leadingCoefficientIsPositive());
4823
  }else{
4824
    Assert(!intVars);
4825
    m = poly.getHead().getConstant().getValue();
4826
    poly = poly * m.inverse();
4827
    Assert(poly.leadingCoefficientIsAbsOne());
4828
  }
4829
17056
  p = poly.getNode();
4830
17056
  return true;
4831
}
4832
4833
103289
void TheoryArithPrivate::setToMin(int sgn, std::pair<Node, DeltaRational>& min, const std::pair<Node, DeltaRational>& e){
4834
103289
  if(sgn != 0){
4835
53375
    if(min.first.isNull() && !e.first.isNull()){
4836
14881
      min = e;
4837
38494
    }else if(!min.first.isNull() && !e.first.isNull()){
4838
3197
      if(sgn > 0 && min.second > e.second){
4839
        min = e;
4840
3197
      }else if(sgn < 0 &&  min.second < e.second){
4841
        min = e;
4842
      }
4843
    }
4844
  }
4845
103289
}
4846
4847
// std::pair<bool, Node> TheoryArithPrivate::entailmentUpperCheck(const Rational& lm, Node lp, const Rational& rm, Node rp, const DeltaRational& sep, const ArithEntailmentCheckParameters& params, ArithEntailmentCheckSideEffects& out){
4848
4849
//   Rational negRM = -rm;
4850
//   Node diff = NodeManager::currentNM()->mkNode(MULT, mkRationalConstan(lm), lp) + (negRM * rp);
4851
4852
//   Rational diffm;
4853
//   Node diffp;
4854
//   decompose(diff, diffm, diffNode);
4855
4856
4857
//   std::pair<Node, DeltaRational> bestUbLeft, bestLbRight, bestUbDiff, tmp;
4858
//   bestUbLeft = bestLbRight = bestUbDiff = make_pair(Node::Null(), DeltaRational());
4859
4860
//   return make_pair(false, Node::null());
4861
// }
4862
4863
/**
4864
 * Decomposes a literal into the form:
4865
 *   dir*[lm*( lp )] k dir*[ [rm*( rp )] + sep ]
4866
 *   dir*[dm* dp]  k dir *sep
4867
 *   dir is either 1 or -1
4868
 */
4869
8517
bool TheoryArithPrivate::decomposeLiteral(Node lit, Kind& k, int& dir, Rational& lm,  Node& lp, Rational& rm, Node& rp, Rational& dm, Node& dp, DeltaRational& sep){
4870
8517
  bool negated = (lit.getKind() == kind::NOT);
4871
17034
  TNode atom = negated ? lit[0] : lit;
4872
4873
17034
  TNode left = atom[0];
4874
17034
  TNode right = atom[1];
4875
4876
  // left : lm*( lp ) + lc
4877
  // right: rm*( rp ) + rc
4878
17034
  Rational lc, rc;
4879
8517
  bool success = decomposeTerm(left, lm, lp, lc);
4880
8517
  if(!success){ return false; }
4881
8517
  success = decomposeTerm(right, rm, rp, rc);
4882
8517
  if(!success){ return false; }
4883
4884
17034
  Node diff = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::MINUS, left, right));
4885
17034
  Rational dc;
4886
8517
  success = decomposeTerm(diff, dm, dp, dc);
4887
8517
  Assert(success);
4888
4889
  // reduce the kind of the to not include literals
4890
  // GT, NOT LEQ
4891
  // GEQ, NOT LT
4892
  // LT, NOT GEQ
4893
  // LEQ, NOT LT
4894
8517
  Kind atomKind = atom.getKind();
4895
8517
  Kind normKind = negated ? negateKind(atomKind) : atomKind;
4896
4897
8517
  if(normKind == GEQ || normKind == GT){
4898
4148
    dir = -1;
4899
4148
    normKind = (normKind == GEQ) ? LEQ : LT;
4900
  }else{
4901
4369
    dir = 1;
4902
  }
4903
4904
17034
  Debug("arith::decomp") << "arith::decomp "
4905
8517
                         << lit << "(" << normKind << "*" << dir << ")"<< endl
4906
8517
                         << "  left:" << lc << " + " << lm << "*(" <<  lp << ") : " <<left << endl
4907
8517
                         << "  right:" << rc << " + " << rm << "*(" <<  rp << ") : " << right << endl
4908
8517
                         << "  diff: " << dc << " + " << dm << "*("<< dp <<"): " << diff << endl
4909
8517
                         << "  sep: " << sep << endl;
4910
4911
4912
  // k in LT, LEQ, EQUAL, DISEQUAL
4913
  // [dir*lm*( lp ) + dir*lc] k [dir*rm*( rp ) + dir*rc]
4914
17034
  Rational change = rc - lc;
4915
8517
  Assert(change == (-dc));
4916
  // [dir*lm*( lp )] k [dir*rm*( rp ) + dir*(rc - lc)]
4917
8517
  if(normKind == LT){
4918
4347
    sep = DeltaRational(change, Rational(-1));
4919
4347
    k = LEQ;
4920
  }else{
4921
4170
    sep = DeltaRational(change);
4922
4170
    k = normKind;
4923
  }
4924
  // k in LEQ, EQUAL, DISEQUAL
4925
  // dir*lm*( lp ) k [dir*rm*( rp )] + dir*(sep + d * delta)
4926
8517
  return true;
4927
}
4928
4929
/**
4930
 *  Precondition:
4931
 *   tp is a polynomial not containing an ite.
4932
 *   either tp is constant or contains no constants.
4933
 *  Post:
4934
 *    if tmp.first is not null, then
4935
 *      sgn * tp <= sgn * tmp.second
4936
 */
4937
51102
void TheoryArithPrivate::entailmentCheckBoundLookup(std::pair<Node, DeltaRational>& tmp, int sgn, TNode tp) const {
4938
51102
  tmp.first = Node::null();
4939
51102
  if(sgn == 0){ return; }
4940
4941
25617
  Assert(Polynomial::isMember(tp));
4942
25617
  if(tp.getKind() == CONST_RATIONAL){
4943
8495
    tmp.first = mkBoolNode(true);
4944
8495
    tmp.second = DeltaRational(tp.getConst<Rational>());
4945
17122
  }else if(d_partialModel.hasArithVar(tp)){
4946
12534
    Assert(tp.getKind() != CONST_RATIONAL);
4947
12534
    ArithVar v = d_partialModel.asArithVar(tp);
4948
12534
    Assert(v != ARITHVAR_SENTINEL);
4949
    ConstraintP c = (sgn > 0)
4950
18698
      ? d_partialModel.getUpperBoundConstraint(v)
4951
18698
      : d_partialModel.getLowerBoundConstraint(v);
4952
12534
    if(c != NullConstraint){
4953
712
      tmp.first = Constraint::externalExplainByAssertions({c});
4954
712
      tmp.second = c->getValue();
4955
    }
4956
  }
4957
}
4958
4959
48990
void TheoryArithPrivate::entailmentCheckRowSum(std::pair<Node, DeltaRational>& tmp, int sgn, TNode tp) const {
4960
48990
  tmp.first = Node::null();
4961
92306
  if(sgn == 0){ return; }
4962
24561
  if(tp.getKind() != PLUS){ return; }
4963
16298
  Assert(Polynomial::isMember(tp));
4964
4965
16298
  tmp.second = DeltaRational(0);
4966
21972
  NodeBuilder nb(kind::AND);
4967
4968
21972
  Polynomial p = Polynomial::parsePolynomial(tp);
4969
33294
  for(Polynomial::iterator i = p.begin(), iend = p.end(); i != iend; ++i) {
4970
44616
    Monomial m = *i;
4971
44616
    Node x = m.getVarList().getNode();
4972
27620
    if(d_partialModel.hasArithVar(x)){
4973
27576
      ArithVar v = d_partialModel.asArithVar(x);
4974
27576
      const Rational& coeff = m.getConstant().getValue();
4975
27576
      int dir = sgn * coeff.sgn();
4976
      ConstraintP c = (dir > 0)
4977
38898
        ? d_partialModel.getUpperBoundConstraint(v)
4978
38898
        : d_partialModel.getLowerBoundConstraint(v);
4979
27576
      if(c != NullConstraint){
4980
16996
        tmp.second += c->getValue() * coeff;
4981
16996
        c->externalExplainByAssertions(nb);
4982
      }else{
4983
        //failed
4984
10580
        return;
4985
      }
4986
    }else{
4987
      // failed
4988
44
      return;
4989
    }
4990
  }
4991
  // success
4992
5674
  tmp.first = nb;
4993
}
4994
4995
3794
ArithProofRuleChecker* TheoryArithPrivate::getProofChecker()
4996
{
4997
3794
  return &d_checker;
4998
}
4999
5000
}  // namespace arith
5001
}  // namespace theory
5002
29574
}  // namespace cvc5