GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/nl/cad/cdcac.cpp Lines: 241 341 70.7 %
Date: 2021-09-07 Branches: 410 1176 34.9 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Gereon Kremer, Aina Niemetz
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
 * Implements the CDCAC approach as described in
14
 * https://arxiv.org/pdf/2003.05633.pdf.
15
 */
16
17
#include "theory/arith/nl/cad/cdcac.h"
18
19
#ifdef CVC5_POLY_IMP
20
21
#include "options/arith_options.h"
22
#include "theory/arith/nl/cad/lazard_evaluation.h"
23
#include "theory/arith/nl/cad/projections.h"
24
#include "theory/arith/nl/cad/variable_ordering.h"
25
#include "theory/arith/nl/nl_model.h"
26
#include "theory/quantifiers/extended_rewrite.h"
27
28
namespace std {
29
/** Generic streaming operator for std::vector. */
30
template <typename T>
31
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v)
32
{
33
  cvc5::container_to_stream(os, v);
34
  return os;
35
}
36
}  // namespace std
37
38
namespace cvc5 {
39
namespace theory {
40
namespace arith {
41
namespace nl {
42
namespace cad {
43
44
5220
CDCAC::CDCAC(Env& env, const std::vector<poly::Variable>& ordering)
45
5220
    : d_env(env), d_variableOrdering(ordering)
46
{
47
5220
  if (d_env.isTheoryProofProducing())
48
  {
49
1186
    d_proof.reset(
50
593
        new CADProofGenerator(d_env.getContext(), d_env.getProofNodeManager()));
51
  }
52
5220
}
53
54
60
void CDCAC::reset()
55
{
56
60
  d_constraints.reset();
57
60
  d_assignment.clear();
58
60
}
59
60
68
void CDCAC::computeVariableOrdering()
61
{
62
  // Actually compute the variable ordering
63
136
  d_variableOrdering = d_varOrder(d_constraints.getConstraints(),
64
68
                                  VariableOrderingStrategy::BROWN);
65
136
  Trace("cdcac") << "Variable ordering is now " << d_variableOrdering
66
68
                 << std::endl;
67
68
  // Write variable ordering back to libpoly.
69
68
  lp_variable_order_t* vo = poly::Context::get_context().get_variable_order();
70
68
  lp_variable_order_clear(vo);
71
223
  for (const auto& v : d_variableOrdering)
72
  {
73
155
    lp_variable_order_push(vo, v.get_internal());
74
  }
75
68
}
76
77
56
void CDCAC::retrieveInitialAssignment(NlModel& model, const Node& ran_variable)
78
{
79
56
  if (!d_env.getOptions().arith.nlCadUseInitial) return;
80
  d_initialAssignment.clear();
81
  Trace("cdcac") << "Retrieving initial assignment:" << std::endl;
82
  for (const auto& var : d_variableOrdering)
83
  {
84
    Node v = getConstraints().varMapper()(var);
85
    Node val = model.computeConcreteModelValue(v);
86
    poly::Value value = node_to_value(val, ran_variable);
87
    Trace("cdcac") << "\t" << var << " = " << value << std::endl;
88
    d_initialAssignment.emplace_back(value);
89
  }
90
}
91
1127
Constraints& CDCAC::getConstraints() { return d_constraints; }
92
const Constraints& CDCAC::getConstraints() const { return d_constraints; }
93
94
73
const poly::Assignment& CDCAC::getModel() const { return d_assignment; }
95
96
16
const std::vector<poly::Variable>& CDCAC::getVariableOrdering() const
97
{
98
16
  return d_variableOrdering;
99
}
100
101
223
std::vector<CACInterval> CDCAC::getUnsatIntervals(std::size_t cur_variable)
102
{
103
223
  std::vector<CACInterval> res;
104
446
  LazardEvaluation le;
105
446
  if (d_env.getOptions().arith.nlCadLifting
106
223
      == options::NlCadLiftingMode::LAZARD)
107
  {
108
    for (size_t vid = 0; vid < cur_variable; ++vid)
109
    {
110
      const auto& val = d_assignment.get(d_variableOrdering[vid]);
111
      le.add(d_variableOrdering[vid], val);
112
    }
113
    le.addFreeVariable(d_variableOrdering[cur_variable]);
114
  }
115
2747
  for (const auto& c : d_constraints.getConstraints())
116
  {
117
2524
    const poly::Polynomial& p = std::get<0>(c);
118
2524
    poly::SignCondition sc = std::get<1>(c);
119
2524
    const Node& n = std::get<2>(c);
120
121
2524
    if (main_variable(p) != d_variableOrdering[cur_variable])
122
    {
123
      // Constraint is in another variable, ignore it.
124
1368
      continue;
125
    }
126
127
2312
    Trace("cdcac") << "Infeasible intervals for " << p << " " << sc
128
1156
                   << " 0 over " << d_assignment << std::endl;
129
2312
    std::vector<poly::Interval> intervals;
130
2312
    if (d_env.getOptions().arith.nlCadLifting
131
1156
        == options::NlCadLiftingMode::LAZARD)
132
    {
133
      intervals = le.infeasibleRegions(p, sc);
134
      if (Trace.isOn("cdcac"))
135
      {
136
        auto reference = poly::infeasible_regions(p, d_assignment, sc);
137
        Trace("cdcac") << "Lazard: " << intervals << std::endl;
138
        Trace("cdcac") << "Regular: " << reference << std::endl;
139
      }
140
    }
141
    else
142
    {
143
1156
      intervals = poly::infeasible_regions(p, d_assignment, sc);
144
    }
145
2694
    for (const auto& i : intervals)
146
    {
147
1538
      Trace("cdcac") << "-> " << i << std::endl;
148
3076
      PolyVector l, u, m, d;
149
1538
      m.add(p);
150
1538
      m.pushDownPolys(d, d_variableOrdering[cur_variable]);
151
1538
      if (!is_minus_infinity(get_lower(i))) l = m;
152
1538
      if (!is_plus_infinity(get_upper(i))) u = m;
153
1538
      res.emplace_back(CACInterval{i, l, u, m, d, {n}});
154
1538
      if (isProofEnabled())
155
      {
156
12
        d_proof->addDirect(
157
8
            d_constraints.varMapper()(d_variableOrdering[cur_variable]),
158
            d_constraints.varMapper(),
159
            p,
160
            d_assignment,
161
            sc,
162
            i,
163
            n);
164
      }
165
    }
166
  }
167
223
  pruneRedundantIntervals(res);
168
446
  return res;
169
}
170
171
321
bool CDCAC::sampleOutsideWithInitial(const std::vector<CACInterval>& infeasible,
172
                                     poly::Value& sample,
173
                                     std::size_t cur_variable)
174
{
175
642
  if (d_env.getOptions().arith.nlCadUseInitial
176
321
      && cur_variable < d_initialAssignment.size())
177
  {
178
    const poly::Value& suggested = d_initialAssignment[cur_variable];
179
    for (const auto& i : infeasible)
180
    {
181
      if (poly::contains(i.d_interval, suggested))
182
      {
183
        d_initialAssignment.clear();
184
        return sampleOutside(infeasible, sample);
185
      }
186
    }
187
    Trace("cdcac") << "Using suggested initial value" << std::endl;
188
    sample = suggested;
189
    return true;
190
  }
191
321
  return sampleOutside(infeasible, sample);
192
}
193
194
namespace {
195
196
/**
197
 * This method follows the projection operator as detailed in algorithm 6 of
198
 * 10.1016/j.jlamp.2020.100633, which mostly follows the projection operator due
199
 * to McCallum. It uses all coefficients until one is either constant or does
200
 * not vanish over the current assignment.
201
 */
202
184
PolyVector requiredCoefficientsOriginal(const poly::Polynomial& p,
203
                                        const poly::Assignment& assignment)
204
{
205
184
  PolyVector res;
206
184
  for (long deg = degree(p); deg >= 0; --deg)
207
  {
208
184
    auto coeff = coefficient(p, deg);
209
184
    Assert(poly::is_constant(coeff)
210
           == lp_polynomial_is_constant(coeff.get_internal()));
211
184
    if (poly::is_constant(coeff)) break;
212
26
    res.add(coeff);
213
26
    if (evaluate_constraint(coeff, assignment, poly::SignCondition::NE))
214
    {
215
26
      break;
216
    }
217
  }
218
184
  return res;
219
}
220
221
/**
222
 * This method follows the original projection operator due to Lazard from
223
 * section 3 of 10.1007/978-1-4612-2628-4_29. It uses the leading and trailing
224
 * coefficient, and makes some limited efforts to avoid them in certain cases:
225
 * We avoid the leading coefficient if it is constant. We avoid the trailing
226
 * coefficient if the leading coefficient does not vanish over the current
227
 * assignment and the trailing coefficient is not constant.
228
 */
229
PolyVector requiredCoefficientsLazard(const poly::Polynomial& p,
230
                                      const poly::Assignment& assignment)
231
{
232
  PolyVector res;
233
  auto lc = poly::leading_coefficient(p);
234
  if (poly::is_constant(lc)) return res;
235
  res.add(lc);
236
  if (evaluate_constraint(lc, assignment, poly::SignCondition::NE)) return res;
237
  auto tc = poly::coefficient(p, 0);
238
  if (poly::is_constant(tc)) return res;
239
  res.add(tc);
240
  return res;
241
}
242
243
/**
244
 * This method follows the enhancements from 10.1007/978-3-030-60026-6_8 for the
245
 * projection operator due to Lazard, more specifically Section 3.3 and
246
 * Definition 4. In essence, we can skip the trailing coefficient if we can show
247
 * that p is not nullified by any n-1 dimensional point. The statement in the
248
 * paper is slightly more general, but there is no simple way to have such a
249
 * procedure T here. We simply try to show that T(f) = {} by using the extended
250
 * rewriter to simplify (and (= f_i 0)) (f_i being the coefficients of f) to
251
 * false.
252
 */
253
PolyVector requiredCoefficientsLazardModified(
254
    const poly::Polynomial& p,
255
    const poly::Assignment& assignment,
256
    VariableMapper& vm)
257
{
258
  PolyVector res;
259
  auto lc = poly::leading_coefficient(p);
260
  // if leading coefficient is constant
261
  if (poly::is_constant(lc)) return res;
262
  // add leading coefficient
263
  res.add(lc);
264
  auto tc = poly::coefficient(p, 0);
265
  // if trailing coefficient is constant
266
  if (poly::is_constant(tc)) return res;
267
  // if leading coefficient does not vanish over the current assignment
268
  if (evaluate_constraint(lc, assignment, poly::SignCondition::NE)) return res;
269
270
  // construct phi := (and (= p_i 0)) with p_i the coefficients of p
271
  std::vector<Node> conditions;
272
  auto zero = NodeManager::currentNM()->mkConst(Rational(0));
273
  for (const auto& coeff : poly::coefficients(p))
274
  {
275
    conditions.emplace_back(NodeManager::currentNM()->mkNode(
276
        Kind::EQUAL, nl::as_cvc_polynomial(coeff, vm), zero));
277
  }
278
  // if phi is false (i.e. p can not vanish)
279
  quantifiers::ExtendedRewriter rew;
280
  Node rewritten =
281
      rew.extendedRewrite(NodeManager::currentNM()->mkAnd(conditions));
282
  if (rewritten.isConst())
283
  {
284
    Assert(rewritten.getKind() == Kind::CONST_BOOLEAN);
285
    Assert(!rewritten.getConst<bool>());
286
    return res;
287
  }
288
  // otherwise add trailing coefficient as well
289
  res.add(tc);
290
  return res;
291
}
292
293
}  // namespace
294
295
184
PolyVector CDCAC::requiredCoefficients(const poly::Polynomial& p)
296
{
297
184
  if (Trace.isOn("cdcac"))
298
  {
299
    Trace("cdcac") << "Poly: " << p << " over " << d_assignment << std::endl;
300
    Trace("cdcac") << "Lazard:   "
301
                   << requiredCoefficientsLazard(p, d_assignment) << std::endl;
302
    Trace("cdcac") << "LMod: "
303
                   << requiredCoefficientsLazardModified(
304
                          p, d_assignment, d_constraints.varMapper())
305
                   << std::endl;
306
    Trace("cdcac") << "Original: "
307
                   << requiredCoefficientsOriginal(p, d_assignment)
308
                   << std::endl;
309
  }
310
184
  switch (d_env.getOptions().arith.nlCadProjection)
311
  {
312
184
    case options::NlCadProjectionMode::MCCALLUM:
313
184
      return requiredCoefficientsOriginal(p, d_assignment);
314
    case options::NlCadProjectionMode::LAZARD:
315
      return requiredCoefficientsLazard(p, d_assignment);
316
    case options::NlCadProjectionMode::LAZARDMOD:
317
      return requiredCoefficientsLazardModified(
318
          p, d_assignment, d_constraints.varMapper());
319
    default:
320
      Assert(false);
321
      return requiredCoefficientsOriginal(p, d_assignment);
322
  }
323
}
324
325
98
PolyVector CDCAC::constructCharacterization(std::vector<CACInterval>& intervals)
326
{
327
98
  Assert(!intervals.empty()) << "A covering can not be empty";
328
98
  Trace("cdcac") << "Constructing characterization now" << std::endl;
329
98
  PolyVector res;
330
331
180
  for (std::size_t i = 0, n = intervals.size(); i < n - 1; ++i)
332
  {
333
82
    cad::makeFinestSquareFreeBasis(intervals[i], intervals[i + 1]);
334
  }
335
336
278
  for (const auto& i : intervals)
337
  {
338
180
    Trace("cdcac") << "Considering " << i.d_interval << std::endl;
339
360
    Trace("cdcac") << "-> " << i.d_lowerPolys << " / " << i.d_upperPolys
340
180
                   << " and " << i.d_mainPolys << " / " << i.d_downPolys
341
180
                   << std::endl;
342
180
    Trace("cdcac") << "-> " << i.d_origins << std::endl;
343
218
    for (const auto& p : i.d_downPolys)
344
    {
345
      // Add all polynomial from lower levels.
346
38
      res.add(p);
347
    }
348
364
    for (const auto& p : i.d_mainPolys)
349
    {
350
368
      Trace("cdcac") << "Discriminant of " << p << " -> " << discriminant(p)
351
184
                     << std::endl;
352
      // Add all discriminants
353
184
      res.add(discriminant(p));
354
355
210
      for (const auto& q : requiredCoefficients(p))
356
      {
357
        // Add all required coefficients
358
26
        Trace("cdcac") << "Coeff of " << p << " -> " << q << std::endl;
359
26
        res.add(q);
360
      }
361
268
      for (const auto& q : i.d_lowerPolys)
362
      {
363
84
        if (p == q) continue;
364
        // Check whether p(s \times a) = 0 for some a <= l
365
2
        if (!hasRootBelow(q, get_lower(i.d_interval))) continue;
366
4
        Trace("cdcac") << "Resultant of " << p << " and " << q << " -> "
367
2
                       << resultant(p, q) << std::endl;
368
2
        res.add(resultant(p, q));
369
      }
370
268
      for (const auto& q : i.d_upperPolys)
371
      {
372
84
        if (p == q) continue;
373
        // Check whether p(s \times a) = 0 for some a >= u
374
2
        if (!hasRootAbove(q, get_upper(i.d_interval))) continue;
375
4
        Trace("cdcac") << "Resultant of " << p << " and " << q << " -> "
376
2
                       << resultant(p, q) << std::endl;
377
2
        res.add(resultant(p, q));
378
      }
379
    }
380
  }
381
382
180
  for (std::size_t i = 0, n = intervals.size(); i < n - 1; ++i)
383
  {
384
    // Add resultants of consecutive intervals.
385
164
    for (const auto& p : intervals[i].d_upperPolys)
386
    {
387
164
      for (const auto& q : intervals[i + 1].d_lowerPolys)
388
      {
389
164
        Trace("cdcac") << "Resultant of " << p << " and " << q << " -> "
390
82
                       << resultant(p, q) << std::endl;
391
82
        res.add(resultant(p, q));
392
      }
393
    }
394
  }
395
396
98
  res.reduce();
397
98
  res.makeFinestSquareFreeBasis();
398
399
98
  return res;
400
}
401
402
98
CACInterval CDCAC::intervalFromCharacterization(
403
    const PolyVector& characterization,
404
    std::size_t cur_variable,
405
    const poly::Value& sample)
406
{
407
196
  PolyVector l;
408
196
  PolyVector u;
409
196
  PolyVector m;
410
196
  PolyVector d;
411
412
244
  for (const auto& p : characterization)
413
  {
414
    // Add polynomials to main
415
146
    m.add(p);
416
  }
417
  // Push lower-dimensional polys to down
418
98
  m.pushDownPolys(d, d_variableOrdering[cur_variable]);
419
420
  // Collect -oo, all roots, oo
421
196
  std::vector<poly::Value> roots;
422
98
  roots.emplace_back(poly::Value::minus_infty());
423
222
  for (const auto& p : m)
424
  {
425
248
    auto tmp = isolate_real_roots(p, d_assignment);
426
124
    roots.insert(roots.end(), tmp.begin(), tmp.end());
427
  }
428
98
  roots.emplace_back(poly::Value::plus_infty());
429
98
  std::sort(roots.begin(), roots.end());
430
431
  // Now find the interval bounds
432
196
  poly::Value lower;
433
196
  poly::Value upper;
434
260
  for (std::size_t i = 0, n = roots.size(); i < n; ++i)
435
  {
436
260
    if (sample < roots[i])
437
    {
438
84
      lower = roots[i - 1];
439
84
      upper = roots[i];
440
84
      break;
441
    }
442
176
    if (roots[i] == sample)
443
    {
444
14
      lower = sample;
445
14
      upper = sample;
446
14
      break;
447
    }
448
  }
449
98
  Assert(!is_none(lower) && !is_none(upper));
450
451
98
  if (!is_minus_infinity(lower))
452
  {
453
    // Identify polynomials that have a root at the lower bound
454
60
    d_assignment.set(d_variableOrdering[cur_variable], lower);
455
142
    for (const auto& p : m)
456
    {
457
82
      if (evaluate_constraint(p, d_assignment, poly::SignCondition::EQ))
458
      {
459
60
        l.add(p, true);
460
      }
461
    }
462
60
    d_assignment.unset(d_variableOrdering[cur_variable]);
463
  }
464
98
  if (!is_plus_infinity(upper))
465
  {
466
    // Identify polynomials that have a root at the upper bound
467
62
    d_assignment.set(d_variableOrdering[cur_variable], upper);
468
140
    for (const auto& p : m)
469
    {
470
78
      if (evaluate_constraint(p, d_assignment, poly::SignCondition::EQ))
471
      {
472
62
        u.add(p, true);
473
      }
474
    }
475
62
    d_assignment.unset(d_variableOrdering[cur_variable]);
476
  }
477
478
98
  if (lower == upper)
479
  {
480
    // construct a point interval
481
    return CACInterval{
482
14
        poly::Interval(lower, false, upper, false), l, u, m, d, {}};
483
  }
484
  else
485
  {
486
    // construct an open interval
487
84
    Assert(lower < upper);
488
    return CACInterval{
489
84
        poly::Interval(lower, true, upper, true), l, u, m, d, {}};
490
  }
491
}
492
493
223
std::vector<CACInterval> CDCAC::getUnsatCover(std::size_t curVariable,
494
                                              bool returnFirstInterval)
495
{
496
223
  if (isProofEnabled())
497
  {
498
2
    d_proof->startRecursive();
499
  }
500
446
  Trace("cdcac") << "Looking for unsat cover for "
501
223
                 << d_variableOrdering[curVariable] << std::endl;
502
446
  std::vector<CACInterval> intervals = getUnsatIntervals(curVariable);
503
504
223
  if (Trace.isOn("cdcac"))
505
  {
506
    Trace("cdcac") << "Unsat intervals for " << d_variableOrdering[curVariable]
507
                   << ":" << std::endl;
508
    for (const auto& i : intervals)
509
    {
510
      Trace("cdcac") << "-> " << i.d_interval << " from " << i.d_origins
511
                     << std::endl;
512
    }
513
  }
514
446
  poly::Value sample;
515
516
419
  while (sampleOutsideWithInitial(intervals, sample, curVariable))
517
  {
518
197
    if (!checkIntegrality(curVariable, sample))
519
    {
520
      // the variable is integral, but the sample is not.
521
      Trace("cdcac") << "Used " << sample << " for integer variable "
522
                     << d_variableOrdering[curVariable] << std::endl;
523
      auto newInterval = buildIntegralityInterval(curVariable, sample);
524
      Trace("cdcac") << "Adding integrality interval " << newInterval.d_interval
525
                     << std::endl;
526
      intervals.emplace_back(newInterval);
527
      pruneRedundantIntervals(intervals);
528
      continue;
529
    }
530
197
    d_assignment.set(d_variableOrdering[curVariable], sample);
531
197
    Trace("cdcac") << "Sample: " << d_assignment << std::endl;
532
197
    if (curVariable == d_variableOrdering.size() - 1)
533
    {
534
      // We have a full assignment. SAT!
535
42
      Trace("cdcac") << "Found full assignment: " << d_assignment << std::endl;
536
141
      return {};
537
    }
538
155
    if (isProofEnabled())
539
    {
540
1
      d_proof->startScope();
541
    }
542
    // Recurse to next variable
543
253
    auto cov = getUnsatCover(curVariable + 1);
544
155
    if (cov.empty())
545
    {
546
      // Found SAT!
547
57
      Trace("cdcac") << "SAT!" << std::endl;
548
57
      return {};
549
    }
550
98
    Trace("cdcac") << "Refuting Sample: " << d_assignment << std::endl;
551
196
    auto characterization = constructCharacterization(cov);
552
98
    Trace("cdcac") << "Characterization: " << characterization << std::endl;
553
554
98
    d_assignment.unset(d_variableOrdering[curVariable]);
555
556
    auto newInterval =
557
196
        intervalFromCharacterization(characterization, curVariable, sample);
558
98
    newInterval.d_origins = collectConstraints(cov);
559
98
    intervals.emplace_back(newInterval);
560
98
    if (isProofEnabled())
561
    {
562
      auto cell = d_proof->constructCell(
563
2
          d_constraints.varMapper()(d_variableOrdering[curVariable]),
564
          newInterval,
565
          d_assignment,
566
          sample,
567
3
          d_constraints.varMapper());
568
1
      d_proof->endScope(cell);
569
    }
570
571
98
    if (returnFirstInterval)
572
    {
573
      return intervals;
574
    }
575
576
98
    Trace("cdcac") << "Added " << intervals.back().d_interval << std::endl;
577
196
    Trace("cdcac") << "\tlower:   " << intervals.back().d_lowerPolys
578
98
                   << std::endl;
579
196
    Trace("cdcac") << "\tupper:   " << intervals.back().d_upperPolys
580
98
                   << std::endl;
581
196
    Trace("cdcac") << "\tmain:    " << intervals.back().d_mainPolys
582
98
                   << std::endl;
583
196
    Trace("cdcac") << "\tdown:    " << intervals.back().d_downPolys
584
98
                   << std::endl;
585
98
    Trace("cdcac") << "\torigins: " << intervals.back().d_origins << std::endl;
586
587
    // Remove redundant intervals
588
98
    pruneRedundantIntervals(intervals);
589
  }
590
591
124
  if (Trace.isOn("cdcac"))
592
  {
593
    Trace("cdcac") << "Returning intervals for "
594
                   << d_variableOrdering[curVariable] << ":" << std::endl;
595
    for (const auto& i : intervals)
596
    {
597
      Trace("cdcac") << "-> " << i.d_interval << std::endl;
598
    }
599
  }
600
124
  if (isProofEnabled())
601
  {
602
2
    d_proof->endRecursive();
603
  }
604
124
  return intervals;
605
}
606
607
56
void CDCAC::startNewProof()
608
{
609
56
  if (isProofEnabled())
610
  {
611
1
    d_proof->startNewProof();
612
  }
613
56
}
614
615
24
ProofGenerator* CDCAC::closeProof(const std::vector<Node>& assertions)
616
{
617
24
  if (isProofEnabled())
618
  {
619
1
    d_proof->endScope(assertions);
620
1
    return d_proof->getProofGenerator();
621
  }
622
23
  return nullptr;
623
}
624
625
197
bool CDCAC::checkIntegrality(std::size_t cur_variable, const poly::Value& value)
626
{
627
394
  Node var = d_constraints.varMapper()(d_variableOrdering[cur_variable]);
628
197
  if (var.getType() != NodeManager::currentNM()->integerType())
629
  {
630
    // variable is not integral
631
183
    return true;
632
  }
633
14
  return poly::represents_integer(value);
634
}
635
636
CACInterval CDCAC::buildIntegralityInterval(std::size_t cur_variable,
637
                                            const poly::Value& value)
638
{
639
  poly::Variable var = d_variableOrdering[cur_variable];
640
  poly::Integer below = poly::floor(value);
641
  poly::Integer above = poly::ceil(value);
642
  // construct var \in (below, above)
643
  return CACInterval{poly::Interval(below, above),
644
                     {var - below},
645
                     {var - above},
646
                     {var - below, var - above},
647
                     {},
648
                     {}};
649
}
650
651
2
bool CDCAC::hasRootAbove(const poly::Polynomial& p,
652
                         const poly::Value& val) const
653
{
654
4
  auto roots = poly::isolate_real_roots(p, d_assignment);
655
4
  return std::any_of(roots.begin(), roots.end(), [&val](const poly::Value& r) {
656
    return r >= val;
657
6
  });
658
}
659
660
2
bool CDCAC::hasRootBelow(const poly::Polynomial& p,
661
                         const poly::Value& val) const
662
{
663
4
  auto roots = poly::isolate_real_roots(p, d_assignment);
664
4
  return std::any_of(roots.begin(), roots.end(), [&val](const poly::Value& r) {
665
    return r <= val;
666
6
  });
667
}
668
669
321
void CDCAC::pruneRedundantIntervals(std::vector<CACInterval>& intervals)
670
{
671
321
  if (isProofEnabled())
672
  {
673
6
    std::vector<CACInterval> allIntervals = intervals;
674
3
    cleanIntervals(intervals);
675
27
    d_proof->pruneChildren([&allIntervals, &intervals](std::size_t i) {
676
24
      return std::find(intervals.begin(), intervals.end(), allIntervals[i])
677
12
             != intervals.end();
678
12
    });
679
  }
680
  else
681
  {
682
318
    cleanIntervals(intervals);
683
  }
684
321
}
685
686
}  // namespace cad
687
}  // namespace nl
688
}  // namespace arith
689
}  // namespace theory
690
29502
}  // namespace cvc5
691
692
#endif