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