GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/arith/delta_rational.h Lines: 78 92 84.8 %
Date: 2021-09-07 Branches: 46 86 53.5 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Tim King, Aina Niemetz, Dejan Jovanovic
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
 * [[ Add one-line brief description here ]]
14
 *
15
 * [[ Add lengthier description here ]]
16
 * \todo document this file
17
 */
18
19
#include "cvc5_private.h"
20
21
#pragma once
22
23
#include <ostream>
24
25
#include "base/check.h"
26
#include "base/exception.h"
27
#include "util/integer.h"
28
#include "util/rational.h"
29
30
namespace cvc5 {
31
32
class DeltaRational;
33
34
class DeltaRationalException : public Exception {
35
 public:
36
  DeltaRationalException(const char* op,
37
                         const DeltaRational& a,
38
                         const DeltaRational& b);
39
  ~DeltaRationalException() override;
40
};
41
42
43
/**
44
 * A DeltaRational is a pair of rationals (c,k) that represent the number
45
 *   c + kd
46
 * where d is an implicit system wide symbolic infinitesimal.
47
 */
48
59153099
class DeltaRational {
49
private:
50
 cvc5::Rational c;
51
 cvc5::Rational k;
52
53
public:
54
4257655
  DeltaRational() : c(0,1), k(0,1) {}
55
7435747
  DeltaRational(const cvc5::Rational& base) : c(base), k(0, 1) {}
56
30370218
  DeltaRational(const cvc5::Rational& base, const cvc5::Rational& coeff)
57
30370218
      : c(base), k(coeff)
58
  {
59
30370218
  }
60
61
205225880
  const cvc5::Rational& getInfinitesimalPart() const { return k; }
62
63
206486017
  const cvc5::Rational& getNoninfinitesimalPart() const { return c; }
64
65
5639452
  int sgn() const {
66
5639452
    int s = getNoninfinitesimalPart().sgn();
67
5639452
    if(s == 0){
68
3633758
      return infinitesimalSgn();
69
    }else{
70
2005694
      return s;
71
    }
72
  }
73
74
6088147
  int infinitesimalSgn() const {
75
6088147
    return getInfinitesimalPart().sgn();
76
  }
77
78
195009605
  bool infinitesimalIsZero() const {
79
195009605
    return getInfinitesimalPart().isZero();
80
  }
81
82
  bool noninfinitesimalIsZero() const {
83
    return getNoninfinitesimalPart().isZero();
84
  }
85
86
  bool isZero() const {
87
    return noninfinitesimalIsZero() && infinitesimalIsZero();
88
  }
89
90
91
13425766
  int cmp(const DeltaRational& other) const{
92
13425766
    int cmp = c.cmp(other.c);
93
13425766
    if(cmp == 0){
94
6007285
      return k.cmp(other.k);
95
    }else{
96
7418481
      return cmp;
97
    }
98
  }
99
100
13694142
  DeltaRational operator+(const DeltaRational& other) const{
101
27388284
    cvc5::Rational tmpC = c + other.c;
102
27388284
    cvc5::Rational tmpK = k + other.k;
103
27388284
    return DeltaRational(tmpC, tmpK);
104
  }
105
106
14500709
  DeltaRational operator*(const Rational& a) const{
107
29001418
    cvc5::Rational tmpC = a * c;
108
29001418
    cvc5::Rational tmpK = a * k;
109
29001418
    return DeltaRational(tmpC, tmpK);
110
  }
111
112
113
  /**
114
   * Multiplies (this->c + this->k * delta) * (a.c + a.k * delta)
115
   * This can be done whenever this->k or a.k is 0.
116
   * Otherwise, the result is not a DeltaRational and a DeltaRationalException is thrown.
117
   */
118
1002086
  DeltaRational operator*(const DeltaRational& a) const
119
  /* throw(DeltaRationalException) */ {
120
1002086
    if(infinitesimalIsZero()){
121
1002086
      return a * (this->getNoninfinitesimalPart());
122
    }else if(a.infinitesimalIsZero()){
123
      return (*this) * a.getNoninfinitesimalPart();
124
    }else{
125
      throw DeltaRationalException("operator*", *this, a);
126
    }
127
  }
128
129
130
1475054
  DeltaRational operator-(const DeltaRational& a) const{
131
2950108
    cvc5::Rational negOne(cvc5::Integer(-1));
132
2950108
    return *(this) + (a * negOne);
133
  }
134
135
1068
  DeltaRational operator-() const{
136
1068
    return DeltaRational(-c, -k);
137
  }
138
139
626974
  DeltaRational operator/(const Rational& a) const{
140
1253948
    cvc5::Rational tmpC = c / a;
141
1253948
    cvc5::Rational tmpK = k / a;
142
1253948
    return DeltaRational(tmpC, tmpK);
143
  }
144
145
  DeltaRational operator/(const Integer& a) const{
146
    cvc5::Rational tmpC = c / a;
147
    cvc5::Rational tmpK = k / a;
148
    return DeltaRational(tmpC, tmpK);
149
  }
150
151
  /**
152
   * Divides (*this) / (a.c + a.k * delta)
153
   * This can be done when a.k is 0 and a.c is non-zero.
154
   * Otherwise, the result is not a DeltaRational and a DeltaRationalException is thrown.
155
   */
156
  DeltaRational operator/(const DeltaRational& a) const
157
  /* throw(DeltaRationalException) */ {
158
    if(a.infinitesimalIsZero()){
159
      return (*this) / a.getNoninfinitesimalPart();
160
    }else{
161
      throw DeltaRationalException("operator/", *this, a);
162
    }
163
  }
164
165
166
  DeltaRational abs() const {
167
    if(sgn() >= 0){
168
      return *this;
169
    }else{
170
      return (*this) * Rational(-1);
171
    }
172
  }
173
174
3450187
  bool operator==(const DeltaRational& other) const{
175
3450187
    return (k == other.k) && (c == other.c);
176
  }
177
178
286236
  bool operator!=(const DeltaRational& other) const{
179
286236
    return !(*this == other);
180
  }
181
182
183
65217320
  bool operator<=(const DeltaRational& other) const{
184
65217320
    int cmp = c.cmp(other.c);
185
65217320
    return (cmp < 0) || ((cmp==0)&&(k <= other.k));
186
  }
187
48605596
  bool operator<(const DeltaRational& other) const{
188
48605596
    return (other  > *this);
189
  }
190
4085289
  bool operator>=(const DeltaRational& other) const{
191
4085289
    return (other <= *this);
192
  }
193
51872681
  bool operator>(const DeltaRational& other) const{
194
51872681
    return !(*this <= other);
195
  }
196
197
  int compare(const DeltaRational& other) const{
198
    int cmpRes = c.cmp(other.c);
199
    return (cmpRes != 0) ? cmpRes : (k.cmp(other.k));
200
  }
201
202
22389861
  DeltaRational& operator=(const DeltaRational& other){
203
22389861
    c = other.c;
204
22389861
    k = other.k;
205
22389861
    return *(this);
206
  }
207
208
  DeltaRational& operator*=(const cvc5::Rational& a)
209
  {
210
    c *=  a;
211
    k *=  a;
212
213
    return *(this);
214
  }
215
216
2623188
  DeltaRational& operator+=(const DeltaRational& other){
217
2623188
    c += other.c;
218
2623188
    k += other.k;
219
220
2623188
    return *(this);
221
  }
222
223
  DeltaRational& operator/=(const Rational& a){
224
    Assert(!a.isZero());
225
    c /= a;
226
    k /= a;
227
    return *(this);
228
  }
229
230
193248873
  bool isIntegral() const {
231
193248873
    if(infinitesimalIsZero()){
232
193245234
      return getNoninfinitesimalPart().isIntegral();
233
    }else{
234
3639
      return false;
235
    }
236
  }
237
238
1232530
  Integer floor() const {
239
1232530
    if(getNoninfinitesimalPart().isIntegral()){
240
1232530
      if(getInfinitesimalPart().sgn() >= 0){
241
38655
        return getNoninfinitesimalPart().getNumerator();
242
      }else{
243
1193875
        return getNoninfinitesimalPart().getNumerator() - Integer(1);
244
      }
245
    }else{
246
      return getNoninfinitesimalPart().floor();
247
    }
248
  }
249
250
77151
  Integer ceiling() const {
251
77151
    if(getNoninfinitesimalPart().isIntegral()){
252
77151
      if(getInfinitesimalPart().sgn() <= 0){
253
        return getNoninfinitesimalPart().getNumerator();
254
      }else{
255
77151
        return getNoninfinitesimalPart().getNumerator() + Integer(1);
256
      }
257
    }else{
258
      return getNoninfinitesimalPart().ceiling();
259
    }
260
  }
261
262
  /** Only well defined if both this and y are integral. */
263
  Integer euclidianDivideQuotient(const DeltaRational& y) const
264
      /* throw(DeltaRationalException) */;
265
266
  /** Only well defined if both this and y are integral. */
267
  Integer euclidianDivideRemainder(const DeltaRational& y) const
268
      /* throw(DeltaRationalException) */;
269
270
  std::string toString() const;
271
272
963178
  Rational substituteDelta(const Rational& d) const{
273
963178
    return getNoninfinitesimalPart() + (d * getInfinitesimalPart());
274
  }
275
276
  /**
277
   * Computes a sufficient upperbound to separate two DeltaRationals.
278
   * This value is stored in res.
279
   * For any rational d such that
280
   *   0 < d < res
281
   * then
282
   *   a < b if and only if substituteDelta(a, d) < substituteDelta(b,d).
283
   * (Similar relationships hold for for a == b and a > b.)
284
   * Precondition: res > 0
285
   */
286
  static void seperatingDelta(Rational& res, const DeltaRational& a, const DeltaRational& b);
287
288
  uint32_t complexity() const {
289
    return c.complexity() + k.complexity();
290
  }
291
292
  double approx(double deltaSub) const {
293
    double maj = getNoninfinitesimalPart().getDouble();
294
    double min = deltaSub * (getInfinitesimalPart().getDouble());
295
    return maj + min;
296
  }
297
298
299
};
300
301
std::ostream& operator<<(std::ostream& os, const DeltaRational& n);
302
303
}  // namespace cvc5