GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/dio_solver.cpp Lines: 422 484 87.2 %
Date: 2021-09-10 Branches: 832 2344 35.5 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Tim King, Mathias Preiner, Morgan Deters
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
 * Diophantine equation solver
14
 *
15
 * A Diophantine equation solver for the theory of arithmetic.
16
 */
17
#include "theory/arith/dio_solver.h"
18
19
#include <iostream>
20
21
#include "base/output.h"
22
#include "expr/skolem_manager.h"
23
#include "options/arith_options.h"
24
#include "smt/smt_statistics_registry.h"
25
#include "theory/arith/partial_model.h"
26
27
using namespace std;
28
29
namespace cvc5 {
30
namespace theory {
31
namespace arith {
32
33
8044
inline Node makeIntegerVariable(){
34
8044
  NodeManager* nm = NodeManager::currentNM();
35
8044
  SkolemManager* sm = nm->getSkolemManager();
36
  return sm->mkDummySkolem("intvar",
37
16088
                           nm->integerType(),
38
24132
                           "is an integer variable created by the dio solver");
39
}
40
41
9913
DioSolver::DioSolver(context::Context* ctxt)
42
    : d_lastUsedProofVariable(ctxt, 0),
43
      d_inputConstraints(ctxt),
44
      d_nextInputConstraintToEnqueue(ctxt, 0),
45
      d_trail(ctxt),
46
      d_subs(ctxt),
47
      d_currentF(),
48
      d_savedQueue(ctxt),
49
      d_savedQueueIndex(ctxt, 0),
50
      d_conflictIndex(ctxt),
51
      d_maxInputCoefficientLength(ctxt, 0),
52
      d_usedDecomposeIndex(ctxt, false),
53
      d_lastPureSubstitution(ctxt, 0),
54
      d_pureSubstitionIter(ctxt, 0),
55
9913
      d_decompositionLemmaQueue(ctxt) {}
56
57
9913
DioSolver::Statistics::Statistics()
58
9913
    : d_conflictCalls(smtStatisticsRegistry().registerInt(
59
19826
        "theory::arith::dio::conflictCalls")),
60
      d_cutCalls(
61
19826
          smtStatisticsRegistry().registerInt("theory::arith::dio::cutCalls")),
62
19826
      d_cuts(smtStatisticsRegistry().registerInt("theory::arith::dio::cuts")),
63
      d_conflicts(
64
19826
          smtStatisticsRegistry().registerInt("theory::arith::dio::conflicts")),
65
9913
      d_conflictTimer(smtStatisticsRegistry().registerTimer(
66
19826
          "theory::arith::dio::conflictTimer")),
67
      d_cutTimer(
68
59478
          smtStatisticsRegistry().registerTimer("theory::arith::dio::cutTimer"))
69
{
70
9913
}
71
72
73948
bool DioSolver::queueConditions(TrailIndex t){
73
  /* debugPrintTrail(t); */
74
73948
  Debug("queueConditions") << !inConflict() << std::endl;
75
73948
  Debug("queueConditions") << gcdIsOne(t) << std::endl;
76
73948
  Debug("queueConditions") << !debugAnySubstitionApplies(t) << std::endl;
77
73948
  Debug("queueConditions") << !triviallySat(t) << std::endl;
78
73948
  Debug("queueConditions") << !triviallyUnsat(t) << std::endl;
79
80
  return
81
147896
    !inConflict() &&
82
147896
    gcdIsOne(t) &&
83
147896
    !debugAnySubstitionApplies(t) &&
84
221844
    !triviallySat(t) &&
85
147896
    !triviallyUnsat(t);
86
}
87
88
35509
size_t DioSolver::allocateProofVariable() {
89
35509
  Assert(d_lastUsedProofVariable <= d_proofVariablePool.size());
90
35509
  if(d_lastUsedProofVariable == d_proofVariablePool.size()){
91
7708
    Assert(d_lastUsedProofVariable == d_proofVariablePool.size());
92
15416
    Node intVar = makeIntegerVariable();
93
7708
    d_proofVariablePool.push_back(Variable(intVar));
94
  }
95
35509
  size_t res = d_lastUsedProofVariable;
96
35509
  d_lastUsedProofVariable = d_lastUsedProofVariable + 1;
97
35509
  return res;
98
}
99
100
101
Node DioSolver::nextPureSubstitution(){
102
  Assert(hasMorePureSubstitutions());
103
  SubIndex curr = d_pureSubstitionIter;
104
  d_pureSubstitionIter = d_pureSubstitionIter + 1;
105
106
  Assert(d_subs[curr].d_fresh.isNull());
107
  Variable v = d_subs[curr].d_eliminated;
108
109
  SumPair sp = d_trail[d_subs[curr].d_constraint].d_eq;
110
  Polynomial p = sp.getPolynomial();
111
  Constant c = -sp.getConstant();
112
  Polynomial cancelV = p + Polynomial::mkPolynomial(v);
113
  Node eq = NodeManager::currentNM()->mkNode(kind::EQUAL, v.getNode(), cancelV.getNode());
114
  return eq;
115
}
116
117
118
37987
bool DioSolver::debugEqualityInInputEquations(Node eq){
119
  typedef context::CDList<InputConstraint>::const_iterator const_iterator;
120
37987
  const_iterator i=d_inputConstraints.begin(), end = d_inputConstraints.end();
121
2127449
  for(; i != end; ++i){
122
2089462
    Node reason_i = (*i).d_reason;
123
1044731
    if(eq == reason_i){
124
      return true;
125
    }
126
  }
127
37987
  return false;
128
}
129
130
131
37987
void DioSolver::pushInputConstraint(const Comparison& eq, Node reason){
132
37987
  Assert(!debugEqualityInInputEquations(reason));
133
37987
  Assert(eq.debugIsIntegral());
134
37987
  Assert(eq.getNode().getKind() == kind::EQUAL);
135
136
73496
  SumPair sp = eq.toSumPair();
137
37987
  if(sp.isNonlinear()){
138
2478
    return;
139
  }
140
141
142
143
35509
  uint32_t length = sp.maxLength();
144
35509
  if(length > d_maxInputCoefficientLength){
145
3030
    d_maxInputCoefficientLength = length;
146
  }
147
148
35509
  size_t varIndex = allocateProofVariable();
149
71018
  Variable proofVariable(d_proofVariablePool[varIndex]);
150
  //Variable proofVariable(makeIntegerVariable());
151
152
35509
  TrailIndex posInTrail = d_trail.size();
153
71018
  Debug("dio::pushInputConstraint") << "pushInputConstraint @ " << posInTrail
154
35509
                                    << " " << eq.getNode()
155
35509
                                    << " " << reason << endl;
156
35509
  d_trail.push_back(Constraint(sp,Polynomial::mkPolynomial(proofVariable)));
157
158
35509
  size_t posInConstraintList = d_inputConstraints.size();
159
35509
  d_inputConstraints.push_back(InputConstraint(reason, posInTrail));
160
161
35509
  d_varToInputConstraintMap[proofVariable.getNode()] = posInConstraintList;
162
}
163
164
165
23948
DioSolver::TrailIndex DioSolver::scaleEqAtIndex(DioSolver::TrailIndex i, const Integer& g){
166
23948
  Assert(g != 0);
167
47896
  Constant invg = Constant::mkConstant(Rational(Integer(1),g));
168
23948
  const SumPair& sp = d_trail[i].d_eq;
169
23948
  const Polynomial& proof = d_trail[i].d_proof;
170
171
47896
  SumPair newSP = sp * invg;
172
47896
  Polynomial newProof = proof * invg;
173
174
23948
  Assert(newSP.isIntegral());
175
23948
  Assert(newSP.gcd() == 1);
176
177
23948
  TrailIndex j = d_trail.size();
178
179
23948
  d_trail.push_back(Constraint(newSP, newProof));
180
181
23948
  Debug("arith::dio") << "scaleEqAtIndex(" << i <<","<<g<<")"<<endl;
182
47896
  Debug("arith::dio") << "derived "<< newSP.getNode()
183
23948
                      <<" with proof " << newProof.getNode() << endl;
184
47896
  return j;
185
}
186
187
155
Node DioSolver::proveIndex(TrailIndex i){
188
155
  Assert(inRange(i));
189
155
  const Polynomial& proof = d_trail[i].d_proof;
190
155
  Assert(!proof.isConstant());
191
192
310
  NodeBuilder nb(kind::AND);
193
978
  for(Polynomial::iterator iter = proof.begin(), end = proof.end(); iter!= end; ++iter){
194
1646
    Monomial m = (*iter);
195
823
    Assert(!m.isConstant());
196
1646
    VarList vl = m.getVarList();
197
823
    Assert(vl.singleton());
198
1646
    Variable v = vl.getHead();
199
200
1646
    Node input = proofVariableToReason(v);
201
823
    if(input.getKind() == kind::AND){
202
260
      for(Node::iterator input_iter = input.begin(), input_end = input.end(); input_iter != input_end; ++input_iter){
203
350
	Node inputChild = *input_iter;
204
175
	nb << inputChild;
205
      }
206
    }else{
207
738
      nb << input;
208
    }
209
  }
210
211
155
  Node result = (nb.getNumChildren() == 1) ? nb[0] : (Node)nb;
212
310
  Debug("arith::dio") << "Proof at " << i << " is "
213
155
                      << d_trail[i].d_eq.getNode() << endl
214
155
                      << d_trail[i].d_proof.getNode() << endl
215
155
                      << " which becomes " << result << endl;
216
310
  return result;
217
}
218
219
51506
bool DioSolver::anyCoefficientExceedsMaximum(TrailIndex j) const{
220
51506
  uint32_t length = d_trail[j].d_eq.maxLength();
221
51506
  uint32_t nmonos = d_trail[j].d_eq.getPolynomial().numMonomials();
222
223
  bool result =
224
80692
    nmonos >= 2 &&
225
80692
    length > d_maxInputCoefficientLength + MAX_GROWTH_RATE;
226
51506
  if(Debug.isOn("arith::dio::max") && result){
227
    Debug("arith::dio::max") << "about to drop:";
228
    debugPrintTrail(j);
229
  }
230
51506
  return result;
231
}
232
233
4682
void DioSolver::enqueueInputConstraints(){
234
4682
  Assert(d_currentF.empty());
235
4682
  while(d_savedQueueIndex < d_savedQueue.size()){
236
    d_currentF.push_back(d_savedQueue[d_savedQueueIndex]);
237
    d_savedQueueIndex = d_savedQueueIndex + 1;
238
  }
239
240
71056
  while(d_nextInputConstraintToEnqueue < d_inputConstraints.size()  && !inConflict()){
241
33187
    size_t curr = d_nextInputConstraintToEnqueue;
242
33187
    d_nextInputConstraintToEnqueue = d_nextInputConstraintToEnqueue + 1;
243
244
33187
    TrailIndex i = d_inputConstraints[curr].d_trailPos;
245
33187
    TrailIndex j = applyAllSubstitutionsToIndex(i);
246
247
33187
    if(!triviallySat(j)){
248
32832
      if(triviallyUnsat(j)){
249
        raiseConflict(j);
250
      }else{
251
32832
        TrailIndex k = reduceByGCD(j);
252
253
32832
        if(!inConflict()){
254
32095
          if(triviallyUnsat(k)){
255
            raiseConflict(k);
256
32095
          }else if(!(triviallySat(k) || anyCoefficientExceedsMaximum(k))){
257
32067
            pushToQueueBack(k);
258
          }
259
        }
260
      }
261
    }
262
  }
263
4682
}
264
265
266
/*TODO Currently linear in the size of the Queue
267
 *It is not clear if am O(log n) strategy would be better.
268
 *Right before this in the algorithm is a substitution which could potentially
269
 *effect the key values of everything in the queue.
270
 */
271
22334
void DioSolver::moveMinimumByAbsToQueueFront(){
272
22334
  Assert(!queueEmpty());
273
274
  //Select the minimum element.
275
22334
  size_t indexInQueue = 0;
276
44668
  Monomial minMonomial = d_trail[d_currentF[indexInQueue]].d_minimalMonomial;
277
278
22334
  size_t N = d_currentF.size();
279
665148
  for(size_t i=1; i < N; ++i){
280
1285628
    Monomial curr = d_trail[d_currentF[i]].d_minimalMonomial;
281
642814
    if(curr.absCmp(minMonomial) < 0){
282
74
      indexInQueue = i;
283
74
      minMonomial = curr;
284
    }
285
  }
286
287
22334
  TrailIndex tmp = d_currentF[indexInQueue];
288
22334
  d_currentF[indexInQueue] = d_currentF.front();
289
22334
  d_currentF.front() = tmp;
290
22334
}
291
292
49350
bool DioSolver::queueEmpty() const{
293
49350
  return d_currentF.empty();
294
}
295
296
380
Node DioSolver::columnGcdIsOne() const{
297
760
  std::unordered_map<Node, Integer> gcdMap;
298
299
380
  std::deque<TrailIndex>::const_iterator iter, end;
300
802
  for(iter = d_currentF.begin(), end = d_currentF.end(); iter != end; ++iter){
301
466
    TrailIndex curr = *iter;
302
888
    Polynomial p = d_trail[curr].d_eq.getPolynomial();
303
888
    Polynomial::iterator monoIter = p.begin(), monoEnd = p.end();
304
2580
    for(; monoIter != monoEnd; ++monoIter){
305
2158
      Monomial m = *monoIter;
306
2158
      VarList vl = m.getVarList();
307
2158
      Node vlNode = vl.getNode();
308
309
2158
      Constant c = m.getConstant();
310
2158
      Integer zc = c.getValue().getNumerator();
311
1101
      if(gcdMap.find(vlNode) == gcdMap.end()){
312
        // have not seen vl yet.
313
        // gcd is c
314
956
        Assert(c.isIntegral());
315
956
        Assert(!m.absCoefficientIsOne());
316
956
        gcdMap.insert(make_pair(vlNode, zc.abs()));
317
      }else{
318
145
        const Integer& currentGcd = gcdMap[vlNode];
319
246
        Integer newGcd = currentGcd.gcd(zc);
320
145
        if(newGcd == 1){
321
44
          return vlNode;
322
        }else{
323
101
          gcdMap[vlNode] = newGcd;
324
        }
325
      }
326
    }
327
  }
328
336
  return Node::null();
329
}
330
331
void DioSolver::saveQueue(){
332
  std::deque<TrailIndex>::const_iterator iter, end;
333
  for(iter = d_currentF.begin(), end = d_currentF.end(); iter != end; ++iter){
334
    d_savedQueue.push_back(*iter);
335
  }
336
}
337
338
380
DioSolver::TrailIndex DioSolver::impliedGcdOfOne(){
339
760
  Node canReduce = columnGcdIsOne();
340
380
  if(canReduce.isNull()){
341
336
    return 0;
342
  }else{
343
88
    VarList vl = VarList::parseVarList(canReduce);
344
345
    TrailIndex current;
346
88
    Integer currentCoeff, currentGcd;
347
348
    //step 1 find the first equation containing vl
349
    //Set current and currentCoefficient
350
44
    std::deque<TrailIndex>::const_iterator iter, end;
351
44
    for(iter = d_currentF.begin(), end = d_currentF.end(); true; ++iter){
352
44
      Assert(iter != end);
353
44
      current = *iter;
354
44
      Constant coeff = d_trail[current].d_eq.getPolynomial().getCoefficient(vl);
355
44
      if(!coeff.isZero()){
356
44
        currentCoeff = coeff.getValue().getNumerator();
357
44
        currentGcd = currentCoeff.abs();
358
359
44
        ++iter;
360
44
        break;
361
      }
362
    }
363
364
    //For the rest of the equations keep reducing until the coefficient is one
365
48
    for(; iter != end; ++iter){
366
46
      Debug("arith::dio") << "next round : " << currentCoeff << " " << currentGcd << endl;
367
46
      TrailIndex inQueue = *iter;
368
48
      Constant iqc = d_trail[inQueue].d_eq.getPolynomial().getCoefficient(vl);
369
46
      if(!iqc.isZero()){
370
48
        Integer inQueueCoeff = iqc.getValue().getNumerator();
371
372
        //mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, mpz_t a, mpz_t b);
373
48
        Integer g, s, t;
374
        // g = a*s + b*t
375
46
        Integer::extendedGcd(g, s, t, currentCoeff, inQueueCoeff);
376
377
46
        Debug("arith::dio") << "extendedReduction : " << endl;
378
46
        Debug("arith::dio") << g << " = " << s <<"*"<< currentCoeff << " + " << t <<"*"<< inQueueCoeff << endl;
379
380
46
        Assert(g <= currentGcd);
381
46
        if(g < currentGcd){
382
44
          if(s.sgn() == 0){
383
            Debug("arith::dio") << "extendedReduction drop" << endl;
384
            Assert(inQueueCoeff.divides(currentGcd));
385
            current = *iter;
386
            currentCoeff = inQueueCoeff;
387
            currentGcd = inQueueCoeff.abs();
388
          }else{
389
390
44
            Debug("arith::dio") << "extendedReduction combine" << endl;
391
44
            TrailIndex next = combineEqAtIndexes(current, s, inQueue, t);
392
393
44
            Assert(d_trail[next]
394
                       .d_eq.getPolynomial()
395
                       .getCoefficient(vl)
396
                       .getValue()
397
                       .getNumerator()
398
                   == g);
399
400
44
            current = next;
401
44
            currentCoeff = g;
402
44
            currentGcd = g;
403
44
            if(currentGcd == 1){
404
44
              return current;
405
            }
406
          }
407
        }
408
      }
409
    }
410
    //This is not reachble as it is assured that the gcd of the column is 1
411
    Unreachable();
412
  }
413
}
414
415
4682
bool DioSolver::processEquations(bool allowDecomposition){
416
4682
  Assert(!inConflict());
417
418
4682
  enqueueInputConstraints();
419
49350
  while(! queueEmpty() && !inConflict()){
420
22334
    moveMinimumByAbsToQueueFront();
421
422
22334
    TrailIndex minimum = d_currentF.front();
423
    TrailIndex reduceIndex;
424
425
22334
    Assert(inRange(minimum));
426
22334
    Assert(!inConflict());
427
428
22334
    Debug("arith::dio") << "processEquations " << minimum << " : " << d_trail[minimum].d_eq.getNode() << endl;
429
430
22334
    Assert(queueConditions(minimum));
431
432
22334
    bool canDirectlySolve = d_trail[minimum].d_minimalMonomial.absCoefficientIsOne();
433
434
22334
    std::pair<SubIndex, TrailIndex> p;
435
22334
    if(canDirectlySolve){
436
21954
      d_currentF.pop_front();
437
21954
      p = solveIndex(minimum);
438
21954
      reduceIndex = minimum;
439
    }else{
440
380
      TrailIndex implied = impliedGcdOfOne();
441
442
380
      if(implied != 0){
443
44
        p = solveIndex(implied);
444
44
        reduceIndex = implied;
445
336
      }else if(allowDecomposition){
446
336
        d_currentF.pop_front();
447
336
        p = decomposeIndex(minimum);
448
336
        reduceIndex = minimum;
449
      }else {
450
        // Cannot make progress without decomposeIndex
451
        saveQueue();
452
        break;
453
      }
454
    }
455
456
22334
    SubIndex subIndex = p.first;
457
22334
    TrailIndex next = p.second;
458
22334
    subAndReduceCurrentFByIndex(subIndex);
459
460
22334
    if(next != reduceIndex){
461
336
      if(triviallyUnsat(next)){
462
        raiseConflict(next);
463
336
      }else if(! triviallySat(next) ){
464
336
        pushToQueueBack(next);
465
      }
466
    }
467
  }
468
469
4682
  d_currentF.clear();
470
4682
  return inConflict();
471
}
472
473
2759
Node DioSolver::processEquationsForConflict(){
474
5518
  TimerStat::CodeTimer codeTimer(d_statistics.d_conflictTimer);
475
2759
  ++(d_statistics.d_conflictCalls);
476
477
2759
  Assert(!inConflict());
478
2759
  if(processEquations(true)){
479
155
    ++(d_statistics.d_conflicts);
480
155
    return proveIndex(getConflictIndex());
481
  }else{
482
2604
    return Node::null();
483
  }
484
}
485
486
1923
SumPair DioSolver::processEquationsForCut(){
487
3846
  TimerStat::CodeTimer codeTimer(d_statistics.d_cutTimer);
488
1923
  ++(d_statistics.d_cutCalls);
489
490
1923
  Assert(!inConflict());
491
1923
  if(processEquations(true)){
492
1463
    ++(d_statistics.d_cuts);
493
1463
    return purifyIndex(getConflictIndex());
494
  }else{
495
460
    return SumPair::mkZero();
496
  }
497
}
498
499
500
1463
SumPair DioSolver::purifyIndex(TrailIndex i){
501
  // TODO: "This uses the substitution trail to reverse the substitutions from the sum term. Using the proof term should be more efficient."
502
503
1463
  SumPair curr = d_trail[i].d_eq;
504
505
2926
  Constant negOne = Constant::mkConstant(-1);
506
507
20442
  for(uint32_t revIter = d_subs.size(); revIter > 0; --revIter){
508
18979
    uint32_t i2 = revIter - 1;
509
19149
    Node freshNode = d_subs[i2].d_fresh;
510
18979
    if(freshNode.isNull()){
511
18809
      continue;
512
    }else{
513
340
      Variable var(freshNode);
514
340
      Polynomial vsum = curr.getPolynomial();
515
516
340
      Constant a = vsum.getCoefficient(VarList(var));
517
170
      if(!a.isZero()){
518
150
        const SumPair& sj = d_trail[d_subs[i2].d_constraint].d_eq;
519
150
        Assert(sj.getPolynomial().getCoefficient(VarList(var)).isOne());
520
300
        SumPair newSi = (curr * negOne) + (sj * a);
521
150
        Assert(newSi.getPolynomial().getCoefficient(VarList(var)).isZero());
522
150
        curr = newSi;
523
      }
524
    }
525
  }
526
2926
  return curr;
527
}
528
529
34386
DioSolver::TrailIndex DioSolver::combineEqAtIndexes(DioSolver::TrailIndex i, const Integer& q, DioSolver::TrailIndex j, const Integer& r){
530
68772
  Constant cq = Constant::mkConstant(q);
531
68772
  Constant cr = Constant::mkConstant(r);
532
533
34386
  const SumPair& si = d_trail[i].d_eq;
534
34386
  const SumPair& sj = d_trail[j].d_eq;
535
536
34386
  Debug("arith::dio") << "combineEqAtIndexes(" << i <<","<<q<<","<<j<<","<<r<<")"<<endl;
537
68772
  Debug("arith::dio") << "d_facts[i] = " << si.getNode() << endl
538
34386
                      << "d_facts[j] = " << sj.getNode() << endl;
539
540
541
68772
  SumPair newSi = (si * cq) + (sj * cr);
542
543
544
34386
  const Polynomial& pi = d_trail[i].d_proof;
545
34386
  const Polynomial& pj = d_trail[j].d_proof;
546
68772
  Polynomial newPi = (pi * cq) + (pj * cr);
547
548
34386
  TrailIndex k = d_trail.size();
549
34386
  d_trail.push_back(Constraint(newSi, newPi));
550
551
552
68772
  Debug("arith::dio") << "derived "<< newSi.getNode()
553
34386
                      <<" with proof " << newPi.getNode() << endl;
554
555
68772
  return k;
556
557
}
558
559
void DioSolver::printQueue(){
560
  Debug("arith::dio") << "DioSolver::printQueue()" << endl;
561
  for(TrailIndex i = 0, last = d_trail.size(); i < last; ++i){
562
    Debug("arith::dio") << "d_trail[i].d_eq = " << d_trail[i].d_eq.getNode() << endl;
563
    Debug("arith::dio") << "d_trail[i].d_proof = " << d_trail[i].d_proof.getNode() << endl;
564
  }
565
566
  Debug("arith::dio") << "DioSolver::printSubs()" << endl;
567
  for(SubIndex si=0, sN=d_subs.size(); si < sN; ++si){
568
    Debug("arith::dio") << "d_subs[i] = {"
569
                        << "d_fresh="<< d_subs[si].d_fresh <<","
570
                        << "d_eliminated="<< d_subs[si].d_eliminated.getNode() <<","
571
                        << "d_constraint="<< d_subs[si].d_constraint <<"}" << endl;
572
    Debug("arith::dio") << "d_trail[d_subs[i].d_constraint].d_eq="
573
                        << d_trail[d_subs[si].d_constraint].d_eq.getNode() << endl;
574
  }
575
}
576
577
33187
DioSolver::TrailIndex DioSolver::applyAllSubstitutionsToIndex(DioSolver::TrailIndex trailIndex){
578
33187
  TrailIndex currentIndex = trailIndex;
579
205824
  for(SubIndex subIter = 0, siEnd = d_subs.size(); subIter < siEnd; ++subIter){
580
172637
    currentIndex = applySubstitution(subIter, currentIndex);
581
  }
582
33187
  return currentIndex;
583
}
584
585
3441048
bool DioSolver::debugSubstitutionApplies(DioSolver::SubIndex si, DioSolver::TrailIndex ti){
586
6882096
  Variable var = d_subs[si].d_eliminated;
587
588
3441048
  const SumPair& curr = d_trail[ti].d_eq;
589
6882096
  Polynomial vsum = curr.getPolynomial();
590
591
6882096
  Constant a = vsum.getCoefficient(VarList(var));
592
6882096
  return !a.isZero();
593
}
594
595
147896
bool DioSolver::debugAnySubstitionApplies(DioSolver::TrailIndex i){
596
3588944
  for(SubIndex subIter = 0, siEnd = d_subs.size(); subIter < siEnd; ++subIter){
597
3441048
    if(debugSubstitutionApplies(subIter, i)){
598
      return true;
599
    }
600
  }
601
147896
  return false;
602
}
603
604
21998
std::pair<DioSolver::SubIndex, DioSolver::TrailIndex> DioSolver::solveIndex(DioSolver::TrailIndex i){
605
21998
  const SumPair& si = d_trail[i].d_eq;
606
607
21998
  Debug("arith::dio") << "before solveIndex("<<i<<":"<<si.getNode()<< ")" << endl;
608
609
#ifdef CVC5_ASSERTIONS
610
43996
  const Polynomial& p = si.getPolynomial();
611
#endif
612
613
21998
  Assert(p.isIntegral());
614
615
21998
  Assert(p.selectAbsMinimum() == d_trail[i].d_minimalMonomial);
616
43996
  const Monomial av = d_trail[i].d_minimalMonomial;
617
618
43996
  VarList vl = av.getVarList();
619
21998
  Assert(vl.singleton());
620
43996
  Variable var = vl.getHead();
621
43996
  Constant a = av.getConstant();
622
43996
  Integer a_abs = a.getValue().getNumerator().abs();
623
624
21998
  Assert(a_abs == 1);
625
626
21998
  TrailIndex ci = !a.isNegative() ? scaleEqAtIndex(i, Integer(-1)) : i;
627
628
21998
  SubIndex subBy = d_subs.size();
629
21998
  d_subs.push_back(Substitution(Node::null(), var, ci));
630
631
21998
  Debug("arith::dio") << "after solveIndex " <<  d_trail[ci].d_eq.getNode() << " for " << av.getNode() << endl;
632
21998
  Assert(d_trail[ci].d_eq.getPolynomial().getCoefficient(vl)
633
         == Constant::mkConstant(-1));
634
635
43996
  return make_pair(subBy, i);
636
}
637
638
336
std::pair<DioSolver::SubIndex, DioSolver::TrailIndex> DioSolver::decomposeIndex(DioSolver::TrailIndex i){
639
336
  const SumPair& si = d_trail[i].d_eq;
640
641
336
  d_usedDecomposeIndex = true;
642
643
336
  Debug("arith::dio") << "before decomposeIndex("<<i<<":"<<si.getNode()<< ")" << endl;
644
645
#ifdef CVC5_ASSERTIONS
646
672
  const Polynomial& p = si.getPolynomial();
647
#endif
648
649
336
  Assert(p.isIntegral());
650
651
336
  Assert(p.selectAbsMinimum() == d_trail[i].d_minimalMonomial);
652
336
  const Monomial& av = d_trail[i].d_minimalMonomial;
653
654
672
  VarList vl = av.getVarList();
655
336
  Assert(vl.singleton());
656
672
  Variable var = vl.getHead();
657
672
  Constant a = av.getConstant();
658
672
  Integer a_abs = a.getValue().getNumerator().abs();
659
660
336
  Assert(a_abs > 1);
661
662
  //It is not sufficient to reduce the case where abs(a) == 1 to abs(a) > 1.
663
  //We need to handle both cases seperately to ensure termination.
664
672
  Node qr = SumPair::computeQR(si, a.getValue().getNumerator());
665
666
336
  Assert(qr.getKind() == kind::PLUS);
667
336
  Assert(qr.getNumChildren() == 2);
668
672
  SumPair q = SumPair::parseSumPair(qr[0]);
669
672
  SumPair r = SumPair::parseSumPair(qr[1]);
670
671
336
  Assert(q.getPolynomial().getCoefficient(vl) == Constant::mkConstant(1));
672
673
336
  Assert(!r.isZero());
674
672
  Node freshNode = makeIntegerVariable();
675
672
  Variable fresh(freshNode);
676
672
  SumPair fresh_one=SumPair::mkSumPair(fresh);
677
672
  SumPair fresh_a = fresh_one * a;
678
679
672
  SumPair newSI = SumPair(fresh_one) - q;
680
  // this normalizes the coefficient of var to -1
681
682
683
336
  TrailIndex ci = d_trail.size();
684
336
  d_trail.push_back(Constraint(newSI, Polynomial::mkZero()));
685
  // no longer reference av safely!
686
336
  addTrailElementAsLemma(ci);
687
688
672
  Debug("arith::dio") << "Decompose ci(" << ci <<":" <<  d_trail[ci].d_eq.getNode()
689
336
                      << ") for " << d_trail[i].d_minimalMonomial.getNode() << endl;
690
336
  Assert(d_trail[ci].d_eq.getPolynomial().getCoefficient(vl)
691
         == Constant::mkConstant(-1));
692
693
672
  SumPair newFact = r + fresh_a;
694
695
336
  TrailIndex nextIndex = d_trail.size();
696
336
  d_trail.push_back(Constraint(newFact, d_trail[i].d_proof));
697
698
336
  SubIndex subBy = d_subs.size();
699
336
  d_subs.push_back(Substitution(freshNode, var, ci));
700
701
336
  Debug("arith::dio") << "Decompose nextIndex " <<  d_trail[nextIndex].d_eq.getNode() << endl;
702
672
  return make_pair(subBy, nextIndex);
703
}
704
705
706
812881
DioSolver::TrailIndex DioSolver::applySubstitution(DioSolver::SubIndex si, DioSolver::TrailIndex ti){
707
1625762
  Variable var = d_subs[si].d_eliminated;
708
812881
  TrailIndex subIndex = d_subs[si].d_constraint;
709
710
812881
  const SumPair& curr = d_trail[ti].d_eq;
711
1625762
  Polynomial vsum = curr.getPolynomial();
712
713
1625762
  Constant a = vsum.getCoefficient(VarList(var));
714
812881
  Assert(a.isIntegral());
715
812881
  if(!a.isZero()){
716
68684
    Integer one(1);
717
34342
    TrailIndex afterSub = combineEqAtIndexes(ti, one, subIndex, a.getValue().getNumerator());
718
34342
    Assert(d_trail[afterSub]
719
               .d_eq.getPolynomial()
720
               .getCoefficient(VarList(var))
721
               .isZero());
722
34342
    return afterSub;
723
  }else{
724
778539
    return ti;
725
  }
726
}
727
728
729
53124
DioSolver::TrailIndex DioSolver::reduceByGCD(DioSolver::TrailIndex ti){
730
53124
  const SumPair& sp = d_trail[ti].d_eq;
731
106248
  Polynomial vsum = sp.getPolynomial();
732
106248
  Constant c = sp.getConstant();
733
734
53124
  Debug("arith::dio") << "reduceByGCD " << vsum.getNode() << endl;
735
53124
  Assert(!vsum.isConstant());
736
106248
  Integer g = vsum.gcd();
737
53124
  Assert(g >= 1);
738
53124
  Debug("arith::dio") << "gcd("<< vsum.getNode() <<")=" << g << " " << c.getValue() << endl;
739
53124
  if(g.divides(c.getValue().getNumerator())){
740
51506
    if(g > 1){
741
3624
      return scaleEqAtIndex(ti, g);
742
    }else{
743
47882
      return ti;
744
    }
745
  }else{
746
1618
    raiseConflict(ti);
747
1618
    return ti;
748
  }
749
}
750
751
235860
bool DioSolver::triviallySat(TrailIndex i){
752
235860
  const SumPair& eq = d_trail[i].d_eq;
753
235860
  if(eq.isConstant()){
754
2409
    return eq.getConstant().isZero();
755
  }else{
756
233451
    return false;
757
  }
758
}
759
760
235505
bool DioSolver::triviallyUnsat(DioSolver::TrailIndex i){
761
235505
  const SumPair& eq = d_trail[i].d_eq;
762
235505
  if(eq.isConstant()){
763
2054
    return !eq.getConstant().isZero();
764
  }else{
765
233451
    return false;
766
  }
767
}
768
769
770
147896
bool DioSolver::gcdIsOne(DioSolver::TrailIndex i){
771
147896
  const SumPair& eq = d_trail[i].d_eq;
772
147896
  return eq.gcd() == Integer(1);
773
}
774
775
void DioSolver::debugPrintTrail(DioSolver::TrailIndex i) const{
776
  const SumPair& eq = d_trail[i].d_eq;
777
  const Polynomial& proof = d_trail[i].d_proof;
778
779
  CVC5Message() << "d_trail[" << i << "].d_eq = " << eq.getNode() << endl;
780
  CVC5Message() << "d_trail[" << i << "].d_proof = " << proof.getNode() << endl;
781
}
782
783
22334
void DioSolver::subAndReduceCurrentFByIndex(DioSolver::SubIndex subIndex){
784
22334
  size_t N = d_currentF.size();
785
786
22334
  size_t readIter = 0, writeIter = 0;
787
1302822
  for(; readIter < N && !inConflict(); ++readIter){
788
640244
    TrailIndex curr = d_currentF[readIter];
789
640244
    TrailIndex nextTI = applySubstitution(subIndex, curr);
790
640244
    if(nextTI == curr){
791
617898
      d_currentF[writeIter] = curr;
792
617898
      ++writeIter;
793
    }else{
794
22346
      Assert(nextTI != curr);
795
796
22346
      if(triviallyUnsat(nextTI)){
797
        raiseConflict(nextTI);
798
22346
      }else if(!triviallySat(nextTI)){
799
20292
        TrailIndex nextNextTI = reduceByGCD(nextTI);
800
801
20292
        if(!(inConflict() || anyCoefficientExceedsMaximum(nextNextTI))){
802
19211
          Assert(queueConditions(nextNextTI));
803
19211
          d_currentF[writeIter] = nextNextTI;
804
19211
          ++writeIter;
805
        }
806
      }
807
    }
808
  }
809
22334
  if(!inConflict() && writeIter < N){
810
1421
    d_currentF.resize(writeIter);
811
  }
812
22334
}
813
814
336
void DioSolver::addTrailElementAsLemma(TrailIndex i) {
815
336
  if(options::exportDioDecompositions()){
816
    d_decompositionLemmaQueue.push(i);
817
  }
818
336
}
819
820
Node DioSolver::trailIndexToEquality(TrailIndex i) const {
821
  const SumPair& sp = d_trail[i].d_eq;
822
  Node zero = mkRationalNode(0);
823
  Node eq = (sp.getNode()).eqNode(zero);
824
  return eq;
825
}
826
827
}  // namespace arith
828
}  // namespace theory
829
29502
}  // namespace cvc5