GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/theory_arith_private.cpp Lines: 1695 2921 58.0 %
Date: 2021-09-29 Branches: 3362 12528 26.8 %

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