GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/util/cardinality.cpp Lines: 114 144 79.2 %
Date: 2021-05-22 Branches: 223 462 48.3 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Morgan Deters, Tim King, Mathias Preiner
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
 * Representation of cardinality.
14
 *
15
 * Implementation of a simple class to represent a cardinality.
16
 */
17
18
#include "util/cardinality.h"
19
20
#include <ostream>
21
#include <sstream>
22
23
#include "base/check.h"
24
#include "base/exception.h"
25
26
namespace cvc5 {
27
28
9398
const Integer Cardinality::s_unknownCard(0);
29
9398
const Integer Cardinality::s_intCard(-1);
30
9398
const Integer Cardinality::s_realCard(-2);
31
9398
const Integer Cardinality::s_largeFiniteCard(
32
    Integer("18446744073709551617"));  // 2^64 + 1
33
34
9398
const Cardinality Cardinality::INTEGERS(CardinalityBeth(0));
35
9398
const Cardinality Cardinality::REALS(CardinalityBeth(1));
36
9398
const Cardinality Cardinality::UNKNOWN_CARD((CardinalityUnknown()));
37
38
18797
CardinalityBeth::CardinalityBeth(const Integer& beth) : d_index(beth) {
39
18797
  PrettyCheckArgument(beth >= 0, beth,
40
                      "Beth index must be a nonnegative integer, not %s.",
41
                      beth.toString().c_str());
42
18797
}
43
44
38513
Cardinality::Cardinality(long card) : d_card(card) {
45
38509
  PrettyCheckArgument(card >= 0, card,
46
                      "Cardinality must be a nonnegative integer, not %ld.",
47
                      card);
48
38505
  d_card += 1;
49
38505
}
50
51
2411
Cardinality::Cardinality(const Integer& card) : d_card(card) {
52
2409
  PrettyCheckArgument(card >= 0, card,
53
                      "Cardinality must be a nonnegative integer, not %s.",
54
                      card.toString().c_str());
55
2407
  d_card += 1;
56
2407
}
57
58
1149
Integer Cardinality::getFiniteCardinality() const {
59
1149
  PrettyCheckArgument(isFinite(), *this, "This cardinality is not finite.");
60
1145
  PrettyCheckArgument(
61
      !isLargeFinite(), *this,
62
      "This cardinality is finite, but too large to represent.");
63
1143
  return d_card - 1;
64
}
65
66
29
Integer Cardinality::getBethNumber() const {
67
29
  PrettyCheckArgument(!isFinite() && !isUnknown(), *this,
68
                      "This cardinality is not infinite (or is unknown).");
69
15
  return -d_card - 1;
70
}
71
72
13947
Cardinality& Cardinality::operator+=(const Cardinality& c) {
73
13947
  if (isUnknown()) {
74
    return *this;
75
13947
  } else if (c.isUnknown()) {
76
    d_card = s_unknownCard;
77
    return *this;
78
  }
79
80
13947
  if (c.isFinite() && isLargeFinite()) {
81
    return *this;
82
13947
  } else if (isFinite() && c.isLargeFinite()) {
83
    d_card = s_largeFiniteCard;
84
    return *this;
85
  }
86
87
13947
  if (isFinite() && c.isFinite()) {
88
13459
    d_card += c.d_card - 1;
89
13459
    return *this;
90
  }
91
488
  if (compare(c) == LESS) {
92
243
    return *this = c;
93
  } else {
94
245
    return *this;
95
  }
96
97
  Unreachable();
98
}
99
100
/** Assigning multiplication of this cardinality with another. */
101
5414
Cardinality& Cardinality::operator*=(const Cardinality& c) {
102
5414
  if (isUnknown()) {
103
    return *this;
104
5414
  } else if (c.isUnknown()) {
105
    d_card = s_unknownCard;
106
    return *this;
107
  }
108
109
5414
  if (c.isFinite() && isLargeFinite()) {
110
    return *this;
111
5414
  } else if (isFinite() && c.isLargeFinite()) {
112
    d_card = s_largeFiniteCard;
113
    return *this;
114
  }
115
116
5414
  if (compare(0) == EQUAL || c.compare(0) == EQUAL) {
117
6
    return *this = 0;
118
5408
  } else if (!isFinite() || !c.isFinite()) {
119
696
    if (compare(c) == LESS) {
120
397
      return *this = c;
121
    } else {
122
299
      return *this;
123
    }
124
  } else {
125
4712
    d_card -= 1;
126
4712
    d_card *= c.d_card - 1;
127
4712
    d_card += 1;
128
4712
    return *this;
129
  }
130
131
  Unreachable();
132
}
133
134
/** Assigning exponentiation of this cardinality with another. */
135
688
Cardinality& Cardinality::operator^=(const Cardinality& c) {
136
688
  if (isUnknown()) {
137
    return *this;
138
688
  } else if (c.isUnknown()) {
139
    d_card = s_unknownCard;
140
    return *this;
141
  }
142
143
688
  if (c.isFinite() && isLargeFinite()) {
144
    return *this;
145
688
  } else if (isFinite() && c.isLargeFinite()) {
146
    d_card = s_largeFiniteCard;
147
    return *this;
148
  }
149
150
688
  if (c.compare(0) == EQUAL) {
151
    // (anything) ^ 0 == 1
152
12
    d_card = 2;  // remember, +1 for finite cardinalities
153
12
    return *this;
154
676
  } else if (compare(0) == EQUAL) {
155
    // 0 ^ (>= 1) == 0
156
8
    return *this;
157
668
  } else if (compare(1) == EQUAL) {
158
    // 1 ^ (>= 1) == 1
159
16
    return *this;
160
652
  } else if (c.compare(1) == EQUAL) {
161
    // (anything) ^ 1 == (that thing)
162
6
    return *this;
163
646
  } else if (isFinite() && c.isFinite()) {
164
    // finite ^ finite == finite
165
    try {
166
      // Note: can throw an assertion if c is too big for
167
      // exponentiation
168
294
      if (d_card - 1 >= 2 && c.d_card - 1 >= 64) {
169
        // don't bother, it's too large anyways
170
10
        d_card = s_largeFiniteCard;
171
      } else {
172
284
        d_card = (d_card - 1).pow(c.d_card.getUnsignedLong() - 1) + 1;
173
      }
174
    } catch (IllegalArgumentException&) {
175
      d_card = s_largeFiniteCard;
176
    }
177
294
    return *this;
178
352
  } else if (!isFinite() && c.isFinite()) {
179
    // inf ^ finite == inf
180
28
    return *this;
181
  } else {
182
324
    Assert(compare(2) != LESS && !c.isFinite())
183
        << "fall-through case not as expected:\n"
184
        << this << "\n"
185
        << c;
186
    // (>= 2) ^ beth_k == beth_(k+1)
187
    // unless the base is already > the exponent
188
324
    if (compare(c) == GREATER) {
189
16
      return *this;
190
    }
191
308
    d_card = c.d_card - 1;
192
308
    return *this;
193
  }
194
195
  Unreachable();
196
}
197
198
18065
Cardinality::CardinalityComparison Cardinality::compare(
199
    const Cardinality& c) const {
200
18065
  if (isUnknown() || c.isUnknown()) {
201
    return UNKNOWN;
202
18065
  } else if (isLargeFinite()) {
203
112
    if (c.isLargeFinite()) {
204
10
      return UNKNOWN;
205
102
    } else if (c.isFinite()) {
206
74
      return GREATER;
207
    } else {
208
28
      Assert(c.isInfinite());
209
28
      return LESS;
210
    }
211
17953
  } else if (c.isLargeFinite()) {
212
12
    if (isLargeFinite()) {
213
      return UNKNOWN;
214
12
    } else if (isFinite()) {
215
4
      return LESS;
216
    } else {
217
8
      Assert(isInfinite());
218
8
      return GREATER;
219
    }
220
17941
  } else if (isInfinite()) {
221
3486
    if (c.isFinite()) {
222
2725
      return GREATER;
223
    } else {
224
761
      return d_card < c.d_card ? GREATER : (d_card == c.d_card ? EQUAL : LESS);
225
    }
226
14455
  } else if (c.isInfinite()) {
227
728
    Assert(isFinite());
228
728
    return LESS;
229
  } else {
230
13727
    Assert(isFinite() && !isLargeFinite());
231
13727
    Assert(c.isFinite() && !c.isLargeFinite());
232
13727
    return d_card < c.d_card ? LESS : (d_card == c.d_card ? EQUAL : GREATER);
233
  }
234
235
  Unreachable();
236
}
237
238
15
bool Cardinality::knownLessThanOrEqual(const Cardinality& c) const {
239
15
  CardinalityComparison cmp = this->compare(c);
240
15
  return cmp == LESS || cmp == EQUAL;
241
}
242
243
std::string Cardinality::toString() const {
244
  std::stringstream ss;
245
  ss << *this;
246
  return ss.str();
247
}
248
249
1
std::ostream& operator<<(std::ostream& out, CardinalityBeth b) {
250
1
  out << "beth[" << b.getNumber() << ']';
251
252
1
  return out;
253
}
254
255
1
std::ostream& operator<<(std::ostream& out, const Cardinality& c) {
256
1
  if (c.isUnknown()) {
257
    out << "Cardinality::UNKNOWN";
258
1
  } else if (c.isFinite()) {
259
    out << c.getFiniteCardinality();
260
  } else {
261
1
    out << CardinalityBeth(c.getBethNumber());
262
  }
263
264
1
  return out;
265
}
266
267
28194
}  // namespace cvc5