GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/theory_arith_private.cpp Lines: 1762 2970 59.3 %
Date: 2021-09-10 Branches: 3441 12526 27.5 %

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