1 /********************* */
2 /*! \file cardinality.cpp
4 ** Top contributors (to current version):
5 ** Morgan Deters, Tim King
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 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.\endverbatim
12 ** \brief Representation of cardinality
14 ** Implementation of a simple class to represent a cardinality.
17 #include "util/cardinality.h"
19 #include "base/check.h"
23 const Integer
Cardinality::s_unknownCard(0);
24 const Integer
Cardinality::s_intCard(-1);
25 const Integer
Cardinality::s_realCard(-2);
26 const Integer
Cardinality::s_largeFiniteCard(
27 Integer("18446744073709551617")); // 2^64 + 1
29 const Cardinality
Cardinality::INTEGERS(CardinalityBeth(0));
30 const Cardinality
Cardinality::REALS(CardinalityBeth(1));
31 const Cardinality
Cardinality::UNKNOWN_CARD((CardinalityUnknown()));
33 CardinalityBeth::CardinalityBeth(const Integer
& beth
) : d_index(beth
) {
34 PrettyCheckArgument(beth
>= 0, beth
,
35 "Beth index must be a nonnegative integer, not %s.",
36 beth
.toString().c_str());
39 Cardinality::Cardinality(long card
) : d_card(card
) {
40 PrettyCheckArgument(card
>= 0, card
,
41 "Cardinality must be a nonnegative integer, not %ld.",
46 Cardinality::Cardinality(const Integer
& card
) : d_card(card
) {
47 PrettyCheckArgument(card
>= 0, card
,
48 "Cardinality must be a nonnegative integer, not %s.",
49 card
.toString().c_str());
53 Integer
Cardinality::getFiniteCardinality() const {
54 PrettyCheckArgument(isFinite(), *this, "This cardinality is not finite.");
56 !isLargeFinite(), *this,
57 "This cardinality is finite, but too large to represent.");
61 Integer
Cardinality::getBethNumber() const {
62 PrettyCheckArgument(!isFinite() && !isUnknown(), *this,
63 "This cardinality is not infinite (or is unknown).");
67 Cardinality
& Cardinality::operator+=(const Cardinality
& c
) {
70 } else if (c
.isUnknown()) {
71 d_card
= s_unknownCard
;
75 if (c
.isFinite() && isLargeFinite()) {
77 } else if (isFinite() && c
.isLargeFinite()) {
78 d_card
= s_largeFiniteCard
;
82 if (isFinite() && c
.isFinite()) {
83 d_card
+= c
.d_card
- 1;
86 if (compare(c
) == LESS
) {
95 /** Assigning multiplication of this cardinality with another. */
96 Cardinality
& Cardinality::operator*=(const Cardinality
& c
) {
99 } else if (c
.isUnknown()) {
100 d_card
= s_unknownCard
;
104 if (c
.isFinite() && isLargeFinite()) {
106 } else if (isFinite() && c
.isLargeFinite()) {
107 d_card
= s_largeFiniteCard
;
111 if (compare(0) == EQUAL
|| c
.compare(0) == EQUAL
) {
113 } else if (!isFinite() || !c
.isFinite()) {
114 if (compare(c
) == LESS
) {
121 d_card
*= c
.d_card
- 1;
129 /** Assigning exponentiation of this cardinality with another. */
130 Cardinality
& Cardinality::operator^=(const Cardinality
& c
) {
133 } else if (c
.isUnknown()) {
134 d_card
= s_unknownCard
;
138 if (c
.isFinite() && isLargeFinite()) {
140 } else if (isFinite() && c
.isLargeFinite()) {
141 d_card
= s_largeFiniteCard
;
145 if (c
.compare(0) == EQUAL
) {
146 // (anything) ^ 0 == 1
147 d_card
= 2; // remember, +1 for finite cardinalities
149 } else if (compare(0) == EQUAL
) {
152 } else if (compare(1) == EQUAL
) {
155 } else if (c
.compare(1) == EQUAL
) {
156 // (anything) ^ 1 == (that thing)
158 } else if (isFinite() && c
.isFinite()) {
159 // finite ^ finite == finite
161 // Note: can throw an assertion if c is too big for
163 if (d_card
- 1 >= 2 && c
.d_card
- 1 >= 64) {
164 // don't bother, it's too large anyways
165 d_card
= s_largeFiniteCard
;
167 d_card
= (d_card
- 1).pow(c
.d_card
.getUnsignedLong() - 1) + 1;
169 } catch (IllegalArgumentException
&) {
170 d_card
= s_largeFiniteCard
;
173 } else if (!isFinite() && c
.isFinite()) {
174 // inf ^ finite == inf
177 Assert(compare(2) != LESS
&& !c
.isFinite())
178 << "fall-through case not as expected:\n"
181 // (>= 2) ^ beth_k == beth_(k+1)
182 // unless the base is already > the exponent
183 if (compare(c
) == GREATER
) {
186 d_card
= c
.d_card
- 1;
193 Cardinality::CardinalityComparison
Cardinality::compare(
194 const Cardinality
& c
) const {
195 if (isUnknown() || c
.isUnknown()) {
197 } else if (isLargeFinite()) {
198 if (c
.isLargeFinite()) {
200 } else if (c
.isFinite()) {
203 Assert(c
.isInfinite());
206 } else if (c
.isLargeFinite()) {
207 if (isLargeFinite()) {
209 } else if (isFinite()) {
212 Assert(isInfinite());
215 } else if (isInfinite()) {
219 return d_card
< c
.d_card
? GREATER
: (d_card
== c
.d_card
? EQUAL
: LESS
);
221 } else if (c
.isInfinite()) {
225 Assert(isFinite() && !isLargeFinite());
226 Assert(c
.isFinite() && !c
.isLargeFinite());
227 return d_card
< c
.d_card
? LESS
: (d_card
== c
.d_card
? EQUAL
: GREATER
);
233 bool Cardinality::knownLessThanOrEqual(const Cardinality
& c
) const {
234 CardinalityComparison cmp
= this->compare(c
);
235 return cmp
== LESS
|| cmp
== EQUAL
;
238 std::string
Cardinality::toString() const {
239 std::stringstream ss
;
244 std::ostream
& operator<<(std::ostream
& out
, CardinalityBeth b
) {
245 out
<< "beth[" << b
.getNumber() << ']';
250 std::ostream
& operator<<(std::ostream
& out
, const Cardinality
& c
) {
252 out
<< "Cardinality::UNKNOWN";
253 } else if (c
.isFinite()) {
254 out
<< c
.getFiniteCardinality();
256 out
<< CardinalityBeth(c
.getBethNumber());
262 } /* CVC4 namespace */