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