GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/nl/cad/proof_generator.cpp Lines: 70 84 83.3 %
Date: 2021-05-22 Branches: 103 278 37.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Gereon Kremer
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
 * Implementation of CAD proof generator.
14
 */
15
16
#include "theory/arith/nl/cad/proof_generator.h"
17
18
#ifdef CVC5_POLY_IMP
19
20
#include "theory/lazy_tree_proof_generator.h"
21
#include "theory/arith/nl/poly_conversion.h"
22
23
namespace cvc5 {
24
namespace theory {
25
namespace arith {
26
namespace nl {
27
namespace cad {
28
29
namespace {
30
/**
31
 * Retrieves the root indices of the sign-invariant region of v.
32
 *
33
 * We assume that roots holds a sorted list of roots from one polynomial.
34
 * If v is equal to one of these roots, we return (id,id) where id is the index
35
 * of this root within roots. Otherwise, we return the id of the largest root
36
 * below v and the id of the smallest root above v. To make sure a smaller root
37
 * and a larger root always exist, we implicitly extend the roots by -infty and
38
 * infty.
39
 *
40
 * ATTENTION: if we return id, the corresponding root is:
41
 *   - id = 0: -infty
42
 *   - 0 < id <= roots.size(): roots[id-1]
43
 *   - id = roots.size() + 1: infty
44
 */
45
5
std::pair<std::size_t, std::size_t> getRootIDs(
46
    const std::vector<poly::Value>& roots, const poly::Value& v)
47
{
48
6
  for (std::size_t i = 0; i < roots.size(); ++i)
49
  {
50
5
    if (roots[i] == v)
51
    {
52
4
      return {i + 1, i + 1};
53
    }
54
1
    if (roots[i] > v)
55
    {
56
      return {i, i + 1};
57
    }
58
  }
59
1
  return {roots.size(), roots.size() + 1};
60
}
61
62
/**
63
 * Constructs an IndexedRootExpression:
64
 *   var ~rel~ root_k(poly)
65
 * where root_k(poly) is "the k'th root of the polynomial".
66
 *
67
 * @param var The variable that is bounded
68
 * @param rel The relation for this constraint
69
 * @param zero A node representing Rational(0)
70
 * @param k The index of the root (starting with 1)
71
 * @param poly The polynomial whose root shall be considered
72
 * @param vm A variable mapper from cvc5 to libpoly variables
73
 */
74
5
Node mkIRP(const Node& var,
75
           Kind rel,
76
           const Node& zero,
77
           std::size_t k,
78
           const poly::Polynomial& poly,
79
           VariableMapper& vm)
80
{
81
5
  auto* nm = NodeManager::currentNM();
82
10
  auto op = nm->mkConst<IndexedRootPredicate>(IndexedRootPredicate(k));
83
  return nm->mkNode(Kind::INDEXED_ROOT_PREDICATE,
84
                    op,
85
10
                    nm->mkNode(rel, var, zero),
86
20
                    as_cvc_polynomial(poly, vm));
87
}
88
89
}  // namespace
90
91
543
CADProofGenerator::CADProofGenerator(context::Context* ctx,
92
543
                                     ProofNodeManager* pnm)
93
543
    : d_pnm(pnm), d_proofs(pnm, ctx), d_current(nullptr)
94
{
95
543
  d_false = NodeManager::currentNM()->mkConst<bool>(false);
96
543
  d_zero = NodeManager::currentNM()->mkConst<Rational>(0);
97
543
}
98
99
1
void CADProofGenerator::startNewProof()
100
{
101
1
  d_current = d_proofs.allocateProof();
102
1
}
103
2
void CADProofGenerator::startRecursive() { d_current->openChild(); }
104
2
void CADProofGenerator::endRecursive()
105
{
106
2
  d_current->setCurrent(PfRule::ARITH_NL_CAD_RECURSIVE, {}, {d_false}, d_false);
107
2
  d_current->closeChild();
108
2
}
109
5
void CADProofGenerator::startScope()
110
{
111
5
  d_current->openChild();
112
5
  d_current->getCurrent().d_rule = PfRule::SCOPE;
113
5
}
114
6
void CADProofGenerator::endScope(const std::vector<Node>& args)
115
{
116
6
  d_current->setCurrent(PfRule::SCOPE, {}, args, d_false);
117
6
  d_current->closeChild();
118
6
}
119
120
1
ProofGenerator* CADProofGenerator::getProofGenerator() const
121
{
122
1
  return d_current;
123
}
124
125
4
void CADProofGenerator::addDirect(Node var,
126
                                  VariableMapper& vm,
127
                                  const poly::Polynomial& poly,
128
                                  const poly::Assignment& a,
129
                                  poly::SignCondition& sc,
130
                                  const poly::Interval& interval,
131
                                  Node constraint)
132
{
133
8
  if (is_minus_infinity(get_lower(interval))
134
4
      && is_plus_infinity(get_upper(interval)))
135
  {
136
    // "Full conflict", constraint excludes (-inf,inf)
137
    d_current->openChild();
138
    d_current->setCurrent(
139
        PfRule::ARITH_NL_CAD_DIRECT, {constraint}, {d_false}, d_false);
140
    d_current->closeChild();
141
    return;
142
  }
143
8
  std::vector<Node> res;
144
8
  auto roots = poly::isolate_real_roots(poly, a);
145
4
  if (get_lower(interval) == get_upper(interval))
146
  {
147
    // Excludes a single point only
148
    auto ids = getRootIDs(roots, get_lower(interval));
149
    Assert(ids.first == ids.second);
150
    res.emplace_back(mkIRP(var, Kind::EQUAL, d_zero, ids.first, poly, vm));
151
  }
152
  else
153
  {
154
    // Excludes an open interval
155
4
    if (!is_minus_infinity(get_lower(interval)))
156
    {
157
      // Interval has lower bound that is not -inf
158
2
      auto ids = getRootIDs(roots, get_lower(interval));
159
2
      Assert(ids.first == ids.second);
160
2
      Kind rel = poly::get_lower_open(interval) ? Kind::GT : Kind::GEQ;
161
2
      res.emplace_back(mkIRP(var, rel, d_zero, ids.first, poly, vm));
162
    }
163
4
    if (!is_plus_infinity(get_upper(interval)))
164
    {
165
      // Interval has upper bound that is not inf
166
2
      auto ids = getRootIDs(roots, get_upper(interval));
167
2
      Assert(ids.first == ids.second);
168
2
      Kind rel = poly::get_upper_open(interval) ? Kind::LT : Kind::LEQ;
169
2
      res.emplace_back(mkIRP(var, rel, d_zero, ids.first, poly, vm));
170
    }
171
  }
172
  // Add to proof manager
173
4
  startScope();
174
4
  d_current->openChild();
175
12
  d_current->setCurrent(
176
8
      PfRule::ARITH_NL_CAD_DIRECT, {constraint}, {d_false}, d_false);
177
4
  d_current->closeChild();
178
4
  endScope(res);
179
}
180
181
1
std::vector<Node> CADProofGenerator::constructCell(Node var,
182
                                                   const CACInterval& i,
183
                                                   const poly::Assignment& a,
184
                                                   const poly::Value& s,
185
                                                   VariableMapper& vm)
186
{
187
2
  if (is_minus_infinity(get_lower(i.d_interval))
188
1
      && is_plus_infinity(get_upper(i.d_interval)))
189
  {
190
    // "Full conflict", constraint excludes (-inf,inf)
191
    return {};
192
  }
193
194
2
  std::vector<Node> res;
195
196
  // Just use bounds for all polynomials
197
2
  for (const auto& poly : i.d_mainPolys)
198
  {
199
2
    auto roots = poly::isolate_real_roots(poly, a);
200
1
    auto ids = getRootIDs(roots, s);
201
1
    if (ids.first == ids.second)
202
    {
203
      // Excludes a single point only
204
      res.emplace_back(mkIRP(var, Kind::EQUAL, d_zero, ids.first, poly, vm));
205
    }
206
    else
207
    {
208
      // Excludes an open interval
209
1
      if (ids.first > 0)
210
      {
211
        // Interval has lower bound that is not -inf
212
1
        res.emplace_back(mkIRP(var, Kind::GT, d_zero, ids.first, poly, vm));
213
      }
214
1
      if (ids.second <= roots.size())
215
      {
216
        // Interval has upper bound that is not inf
217
        res.emplace_back(mkIRP(var, Kind::LT, d_zero, ids.first, poly, vm));
218
      }
219
    }
220
  }
221
222
1
  return res;
223
}
224
225
std::ostream& operator<<(std::ostream& os, const CADProofGenerator& proof)
226
{
227
  return os << *proof.d_current;
228
}
229
230
}  // namespace cad
231
}  // namespace nl
232
}  // namespace arith
233
}  // namespace theory
234
28191
}  // namespace cvc5
235
236
#endif