GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/nl/cad/cdcac.cpp Lines: 241 340 70.9 %
Date: 2021-09-15 Branches: 411 1178 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/rewriter.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
5215
CDCAC::CDCAC(Env& env, const std::vector<poly::Variable>& ordering)
45
5215
    : EnvObj(env), d_variableOrdering(ordering)
46
{
47
5215
  if (d_env.isTheoryProofProducing())
48
  {
49
1186
    d_proof.reset(
50
593
        new CADProofGenerator(d_env.getContext(), d_env.getProofNodeManager()));
51
  }
52
5215
}
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
  Node rewritten = Rewriter::callExtendedRewrite(
280
      NodeManager::currentNM()->mkAnd(conditions));
281
  if (rewritten.isConst())
282
  {
283
    Assert(rewritten.getKind() == Kind::CONST_BOOLEAN);
284
    Assert(!rewritten.getConst<bool>());
285
    return res;
286
  }
287
  // otherwise add trailing coefficient as well
288
  res.add(tc);
289
  return res;
290
}
291
292
}  // namespace
293
294
184
PolyVector CDCAC::requiredCoefficients(const poly::Polynomial& p)
295
{
296
184
  if (Trace.isOn("cdcac"))
297
  {
298
    Trace("cdcac") << "Poly: " << p << " over " << d_assignment << std::endl;
299
    Trace("cdcac") << "Lazard:   "
300
                   << requiredCoefficientsLazard(p, d_assignment) << std::endl;
301
    Trace("cdcac") << "LMod: "
302
                   << requiredCoefficientsLazardModified(
303
                          p, d_assignment, d_constraints.varMapper())
304
                   << std::endl;
305
    Trace("cdcac") << "Original: "
306
                   << requiredCoefficientsOriginal(p, d_assignment)
307
                   << std::endl;
308
  }
309
184
  switch (d_env.getOptions().arith.nlCadProjection)
310
  {
311
184
    case options::NlCadProjectionMode::MCCALLUM:
312
184
      return requiredCoefficientsOriginal(p, d_assignment);
313
    case options::NlCadProjectionMode::LAZARD:
314
      return requiredCoefficientsLazard(p, d_assignment);
315
    case options::NlCadProjectionMode::LAZARDMOD:
316
      return requiredCoefficientsLazardModified(
317
          p, d_assignment, d_constraints.varMapper());
318
    default:
319
      Assert(false);
320
      return requiredCoefficientsOriginal(p, d_assignment);
321
  }
322
}
323
324
98
PolyVector CDCAC::constructCharacterization(std::vector<CACInterval>& intervals)
325
{
326
98
  Assert(!intervals.empty()) << "A covering can not be empty";
327
98
  Trace("cdcac") << "Constructing characterization now" << std::endl;
328
98
  PolyVector res;
329
330
180
  for (std::size_t i = 0, n = intervals.size(); i < n - 1; ++i)
331
  {
332
82
    cad::makeFinestSquareFreeBasis(intervals[i], intervals[i + 1]);
333
  }
334
335
278
  for (const auto& i : intervals)
336
  {
337
180
    Trace("cdcac") << "Considering " << i.d_interval << std::endl;
338
360
    Trace("cdcac") << "-> " << i.d_lowerPolys << " / " << i.d_upperPolys
339
180
                   << " and " << i.d_mainPolys << " / " << i.d_downPolys
340
180
                   << std::endl;
341
180
    Trace("cdcac") << "-> " << i.d_origins << std::endl;
342
218
    for (const auto& p : i.d_downPolys)
343
    {
344
      // Add all polynomial from lower levels.
345
38
      res.add(p);
346
    }
347
364
    for (const auto& p : i.d_mainPolys)
348
    {
349
368
      Trace("cdcac") << "Discriminant of " << p << " -> " << discriminant(p)
350
184
                     << std::endl;
351
      // Add all discriminants
352
184
      res.add(discriminant(p));
353
354
210
      for (const auto& q : requiredCoefficients(p))
355
      {
356
        // Add all required coefficients
357
26
        Trace("cdcac") << "Coeff of " << p << " -> " << q << std::endl;
358
26
        res.add(q);
359
      }
360
268
      for (const auto& q : i.d_lowerPolys)
361
      {
362
84
        if (p == q) continue;
363
        // Check whether p(s \times a) = 0 for some a <= l
364
2
        if (!hasRootBelow(q, get_lower(i.d_interval))) continue;
365
4
        Trace("cdcac") << "Resultant of " << p << " and " << q << " -> "
366
2
                       << resultant(p, q) << std::endl;
367
2
        res.add(resultant(p, q));
368
      }
369
268
      for (const auto& q : i.d_upperPolys)
370
      {
371
84
        if (p == q) continue;
372
        // Check whether p(s \times a) = 0 for some a >= u
373
2
        if (!hasRootAbove(q, get_upper(i.d_interval))) continue;
374
4
        Trace("cdcac") << "Resultant of " << p << " and " << q << " -> "
375
2
                       << resultant(p, q) << std::endl;
376
2
        res.add(resultant(p, q));
377
      }
378
    }
379
  }
380
381
180
  for (std::size_t i = 0, n = intervals.size(); i < n - 1; ++i)
382
  {
383
    // Add resultants of consecutive intervals.
384
164
    for (const auto& p : intervals[i].d_upperPolys)
385
    {
386
164
      for (const auto& q : intervals[i + 1].d_lowerPolys)
387
      {
388
164
        Trace("cdcac") << "Resultant of " << p << " and " << q << " -> "
389
82
                       << resultant(p, q) << std::endl;
390
82
        res.add(resultant(p, q));
391
      }
392
    }
393
  }
394
395
98
  res.reduce();
396
98
  res.makeFinestSquareFreeBasis();
397
398
98
  return res;
399
}
400
401
98
CACInterval CDCAC::intervalFromCharacterization(
402
    const PolyVector& characterization,
403
    std::size_t cur_variable,
404
    const poly::Value& sample)
405
{
406
196
  PolyVector l;
407
196
  PolyVector u;
408
196
  PolyVector m;
409
196
  PolyVector d;
410
411
244
  for (const auto& p : characterization)
412
  {
413
    // Add polynomials to main
414
146
    m.add(p);
415
  }
416
  // Push lower-dimensional polys to down
417
98
  m.pushDownPolys(d, d_variableOrdering[cur_variable]);
418
419
  // Collect -oo, all roots, oo
420
196
  std::vector<poly::Value> roots;
421
98
  roots.emplace_back(poly::Value::minus_infty());
422
222
  for (const auto& p : m)
423
  {
424
248
    auto tmp = isolate_real_roots(p, d_assignment);
425
124
    roots.insert(roots.end(), tmp.begin(), tmp.end());
426
  }
427
98
  roots.emplace_back(poly::Value::plus_infty());
428
98
  std::sort(roots.begin(), roots.end());
429
430
  // Now find the interval bounds
431
196
  poly::Value lower;
432
196
  poly::Value upper;
433
260
  for (std::size_t i = 0, n = roots.size(); i < n; ++i)
434
  {
435
260
    if (sample < roots[i])
436
    {
437
84
      lower = roots[i - 1];
438
84
      upper = roots[i];
439
84
      break;
440
    }
441
176
    if (roots[i] == sample)
442
    {
443
14
      lower = sample;
444
14
      upper = sample;
445
14
      break;
446
    }
447
  }
448
98
  Assert(!is_none(lower) && !is_none(upper));
449
450
98
  if (!is_minus_infinity(lower))
451
  {
452
    // Identify polynomials that have a root at the lower bound
453
60
    d_assignment.set(d_variableOrdering[cur_variable], lower);
454
142
    for (const auto& p : m)
455
    {
456
82
      if (evaluate_constraint(p, d_assignment, poly::SignCondition::EQ))
457
      {
458
60
        l.add(p, true);
459
      }
460
    }
461
60
    d_assignment.unset(d_variableOrdering[cur_variable]);
462
  }
463
98
  if (!is_plus_infinity(upper))
464
  {
465
    // Identify polynomials that have a root at the upper bound
466
62
    d_assignment.set(d_variableOrdering[cur_variable], upper);
467
140
    for (const auto& p : m)
468
    {
469
78
      if (evaluate_constraint(p, d_assignment, poly::SignCondition::EQ))
470
      {
471
62
        u.add(p, true);
472
      }
473
    }
474
62
    d_assignment.unset(d_variableOrdering[cur_variable]);
475
  }
476
477
98
  if (lower == upper)
478
  {
479
    // construct a point interval
480
    return CACInterval{
481
14
        poly::Interval(lower, false, upper, false), l, u, m, d, {}};
482
  }
483
  else
484
  {
485
    // construct an open interval
486
84
    Assert(lower < upper);
487
    return CACInterval{
488
84
        poly::Interval(lower, true, upper, true), l, u, m, d, {}};
489
  }
490
}
491
492
223
std::vector<CACInterval> CDCAC::getUnsatCover(std::size_t curVariable,
493
                                              bool returnFirstInterval)
494
{
495
223
  if (isProofEnabled())
496
  {
497
2
    d_proof->startRecursive();
498
  }
499
446
  Trace("cdcac") << "Looking for unsat cover for "
500
223
                 << d_variableOrdering[curVariable] << std::endl;
501
446
  std::vector<CACInterval> intervals = getUnsatIntervals(curVariable);
502
503
223
  if (Trace.isOn("cdcac"))
504
  {
505
    Trace("cdcac") << "Unsat intervals for " << d_variableOrdering[curVariable]
506
                   << ":" << std::endl;
507
    for (const auto& i : intervals)
508
    {
509
      Trace("cdcac") << "-> " << i.d_interval << " from " << i.d_origins
510
                     << std::endl;
511
    }
512
  }
513
446
  poly::Value sample;
514
515
419
  while (sampleOutsideWithInitial(intervals, sample, curVariable))
516
  {
517
197
    if (!checkIntegrality(curVariable, sample))
518
    {
519
      // the variable is integral, but the sample is not.
520
      Trace("cdcac") << "Used " << sample << " for integer variable "
521
                     << d_variableOrdering[curVariable] << std::endl;
522
      auto newInterval = buildIntegralityInterval(curVariable, sample);
523
      Trace("cdcac") << "Adding integrality interval " << newInterval.d_interval
524
                     << std::endl;
525
      intervals.emplace_back(newInterval);
526
      pruneRedundantIntervals(intervals);
527
      continue;
528
    }
529
197
    d_assignment.set(d_variableOrdering[curVariable], sample);
530
197
    Trace("cdcac") << "Sample: " << d_assignment << std::endl;
531
197
    if (curVariable == d_variableOrdering.size() - 1)
532
    {
533
      // We have a full assignment. SAT!
534
42
      Trace("cdcac") << "Found full assignment: " << d_assignment << std::endl;
535
141
      return {};
536
    }
537
155
    if (isProofEnabled())
538
    {
539
1
      d_proof->startScope();
540
    }
541
    // Recurse to next variable
542
253
    auto cov = getUnsatCover(curVariable + 1);
543
155
    if (cov.empty())
544
    {
545
      // Found SAT!
546
57
      Trace("cdcac") << "SAT!" << std::endl;
547
57
      return {};
548
    }
549
98
    Trace("cdcac") << "Refuting Sample: " << d_assignment << std::endl;
550
196
    auto characterization = constructCharacterization(cov);
551
98
    Trace("cdcac") << "Characterization: " << characterization << std::endl;
552
553
98
    d_assignment.unset(d_variableOrdering[curVariable]);
554
555
    auto newInterval =
556
196
        intervalFromCharacterization(characterization, curVariable, sample);
557
98
    newInterval.d_origins = collectConstraints(cov);
558
98
    intervals.emplace_back(newInterval);
559
98
    if (isProofEnabled())
560
    {
561
      auto cell = d_proof->constructCell(
562
2
          d_constraints.varMapper()(d_variableOrdering[curVariable]),
563
          newInterval,
564
          d_assignment,
565
          sample,
566
3
          d_constraints.varMapper());
567
1
      d_proof->endScope(cell);
568
    }
569
570
98
    if (returnFirstInterval)
571
    {
572
      return intervals;
573
    }
574
575
98
    Trace("cdcac") << "Added " << intervals.back().d_interval << std::endl;
576
196
    Trace("cdcac") << "\tlower:   " << intervals.back().d_lowerPolys
577
98
                   << std::endl;
578
196
    Trace("cdcac") << "\tupper:   " << intervals.back().d_upperPolys
579
98
                   << std::endl;
580
196
    Trace("cdcac") << "\tmain:    " << intervals.back().d_mainPolys
581
98
                   << std::endl;
582
196
    Trace("cdcac") << "\tdown:    " << intervals.back().d_downPolys
583
98
                   << std::endl;
584
98
    Trace("cdcac") << "\torigins: " << intervals.back().d_origins << std::endl;
585
586
    // Remove redundant intervals
587
98
    pruneRedundantIntervals(intervals);
588
  }
589
590
124
  if (Trace.isOn("cdcac"))
591
  {
592
    Trace("cdcac") << "Returning intervals for "
593
                   << d_variableOrdering[curVariable] << ":" << std::endl;
594
    for (const auto& i : intervals)
595
    {
596
      Trace("cdcac") << "-> " << i.d_interval << std::endl;
597
    }
598
  }
599
124
  if (isProofEnabled())
600
  {
601
2
    d_proof->endRecursive();
602
  }
603
124
  return intervals;
604
}
605
606
56
void CDCAC::startNewProof()
607
{
608
56
  if (isProofEnabled())
609
  {
610
1
    d_proof->startNewProof();
611
  }
612
56
}
613
614
24
ProofGenerator* CDCAC::closeProof(const std::vector<Node>& assertions)
615
{
616
24
  if (isProofEnabled())
617
  {
618
1
    d_proof->endScope(assertions);
619
1
    return d_proof->getProofGenerator();
620
  }
621
23
  return nullptr;
622
}
623
624
197
bool CDCAC::checkIntegrality(std::size_t cur_variable, const poly::Value& value)
625
{
626
394
  Node var = d_constraints.varMapper()(d_variableOrdering[cur_variable]);
627
197
  if (var.getType() != NodeManager::currentNM()->integerType())
628
  {
629
    // variable is not integral
630
183
    return true;
631
  }
632
14
  return poly::represents_integer(value);
633
}
634
635
CACInterval CDCAC::buildIntegralityInterval(std::size_t cur_variable,
636
                                            const poly::Value& value)
637
{
638
  poly::Variable var = d_variableOrdering[cur_variable];
639
  poly::Integer below = poly::floor(value);
640
  poly::Integer above = poly::ceil(value);
641
  // construct var \in (below, above)
642
  return CACInterval{poly::Interval(below, above),
643
                     {var - below},
644
                     {var - above},
645
                     {var - below, var - above},
646
                     {},
647
                     {}};
648
}
649
650
2
bool CDCAC::hasRootAbove(const poly::Polynomial& p,
651
                         const poly::Value& val) const
652
{
653
4
  auto roots = poly::isolate_real_roots(p, d_assignment);
654
4
  return std::any_of(roots.begin(), roots.end(), [&val](const poly::Value& r) {
655
    return r >= val;
656
6
  });
657
}
658
659
2
bool CDCAC::hasRootBelow(const poly::Polynomial& p,
660
                         const poly::Value& val) const
661
{
662
4
  auto roots = poly::isolate_real_roots(p, d_assignment);
663
4
  return std::any_of(roots.begin(), roots.end(), [&val](const poly::Value& r) {
664
    return r <= val;
665
6
  });
666
}
667
668
321
void CDCAC::pruneRedundantIntervals(std::vector<CACInterval>& intervals)
669
{
670
321
  if (isProofEnabled())
671
  {
672
6
    std::vector<CACInterval> allIntervals = intervals;
673
3
    cleanIntervals(intervals);
674
27
    d_proof->pruneChildren([&allIntervals, &intervals](std::size_t i) {
675
24
      return std::find(intervals.begin(), intervals.end(), allIntervals[i])
676
12
             != intervals.end();
677
12
    });
678
  }
679
  else
680
  {
681
318
    cleanIntervals(intervals);
682
  }
683
321
}
684
685
}  // namespace cad
686
}  // namespace nl
687
}  // namespace arith
688
}  // namespace theory
689
29577
}  // namespace cvc5
690
691
#endif