GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/nl/cad/cdcac.cpp Lines: 238 338 70.4 %
Date: 2021-08-14 Branches: 407 1170 34.8 %

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