cvc5-cvc5-1.2.0.src.util.cardinality.cpp Maven / Gradle / Ivy
The newest version!
/******************************************************************************
* Top contributors (to current version):
* Morgan Deters, Tim King, Aina Niemetz
*
* This file is part of the cvc5 project.
*
* Copyright (c) 2009-2024 by the authors listed in the file AUTHORS
* in the top-level source directory and their institutional affiliations.
* All rights reserved. See the file COPYING in the top-level source
* directory for licensing information.
* ****************************************************************************
*
* Representation of cardinality.
*
* Implementation of a simple class to represent a cardinality.
*/
#include "util/cardinality.h"
#include
#include
#include "base/check.h"
#include "base/exception.h"
namespace cvc5::internal {
const Integer Cardinality::s_unknownCard(0);
const Integer Cardinality::s_intCard(-1);
const Integer Cardinality::s_realCard(-2);
const Integer Cardinality::s_largeFiniteCard(
Integer("18446744073709551617")); // 2^64 + 1
const Cardinality Cardinality::INTEGERS(CardinalityBeth(0));
const Cardinality Cardinality::REALS(CardinalityBeth(1));
const Cardinality Cardinality::UNKNOWN_CARD((CardinalityUnknown()));
CardinalityBeth::CardinalityBeth(const Integer& beth) : d_index(beth) {
Assert(beth >= 0) << "Beth index must be a nonnegative integer, not "
<< beth.toString().c_str();
}
Cardinality::Cardinality(long card) : d_card(card) {
Assert(card >= 0) << "Cardinality must be a nonnegative integer, not "
<< card;
d_card += 1;
}
Cardinality::Cardinality(const Integer& card) : d_card(card) {
Assert(card >= 0) << "Cardinality must be a nonnegative integer, not "
<< card.toString().c_str();
d_card += 1;
}
Integer Cardinality::getFiniteCardinality() const {
Assert(isFinite()) << "This cardinality is not finite.";
Assert(!isLargeFinite())
<< "This cardinality is finite, but too large to represent.";
return d_card - 1;
}
Integer Cardinality::getBethNumber() const {
Assert(!isFinite() && !isUnknown())
<< "This cardinality is not infinite (or is unknown).";
return -d_card - 1;
}
Cardinality& Cardinality::operator+=(const Cardinality& c) {
if (isUnknown()) {
return *this;
} else if (c.isUnknown()) {
d_card = s_unknownCard;
return *this;
}
if (c.isFinite() && isLargeFinite()) {
return *this;
} else if (isFinite() && c.isLargeFinite()) {
d_card = s_largeFiniteCard;
return *this;
}
if (isFinite() && c.isFinite()) {
d_card += c.d_card - 1;
return *this;
}
if (compare(c) == LESS) {
return *this = c;
} else {
return *this;
}
Unreachable();
}
/** Assigning multiplication of this cardinality with another. */
Cardinality& Cardinality::operator*=(const Cardinality& c) {
if (isUnknown()) {
return *this;
} else if (c.isUnknown()) {
d_card = s_unknownCard;
return *this;
}
if (c.isFinite() && isLargeFinite()) {
return *this;
} else if (isFinite() && c.isLargeFinite()) {
d_card = s_largeFiniteCard;
return *this;
}
if (compare(0) == EQUAL || c.compare(0) == EQUAL) {
return *this = 0;
} else if (!isFinite() || !c.isFinite()) {
if (compare(c) == LESS) {
return *this = c;
} else {
return *this;
}
} else {
d_card -= 1;
d_card *= c.d_card - 1;
d_card += 1;
return *this;
}
Unreachable();
}
/** Assigning exponentiation of this cardinality with another. */
Cardinality& Cardinality::operator^=(const Cardinality& c) {
if (isUnknown()) {
return *this;
} else if (c.isUnknown()) {
d_card = s_unknownCard;
return *this;
}
if (c.isFinite() && isLargeFinite()) {
return *this;
} else if (isFinite() && c.isLargeFinite()) {
d_card = s_largeFiniteCard;
return *this;
}
if (c.compare(0) == EQUAL) {
// (anything) ^ 0 == 1
d_card = 2; // remember, +1 for finite cardinalities
return *this;
} else if (compare(0) == EQUAL) {
// 0 ^ (>= 1) == 0
return *this;
} else if (compare(1) == EQUAL) {
// 1 ^ (>= 1) == 1
return *this;
} else if (c.compare(1) == EQUAL) {
// (anything) ^ 1 == (that thing)
return *this;
} else if (isFinite() && c.isFinite()) {
// finite ^ finite == finite
try {
// Note: can throw an assertion if c is too big for
// exponentiation
if (d_card - 1 >= 2 && c.d_card - 1 >= 64) {
// don't bother, it's too large anyways
d_card = s_largeFiniteCard;
} else {
d_card = (d_card - 1).pow(c.d_card.getUnsignedInt() - 1) + 1;
}
} catch (IllegalArgumentException&) {
d_card = s_largeFiniteCard;
}
return *this;
} else if (!isFinite() && c.isFinite()) {
// inf ^ finite == inf
return *this;
} else {
Assert(compare(2) != LESS && !c.isFinite())
<< "fall-through case not as expected:\n"
<< this << "\n"
<< c;
// (>= 2) ^ beth_k == beth_(k+1)
// unless the base is already > the exponent
if (compare(c) == GREATER) {
return *this;
}
d_card = c.d_card - 1;
return *this;
}
Unreachable();
}
Cardinality::CardinalityComparison Cardinality::compare(
const Cardinality& c) const {
if (isUnknown() || c.isUnknown()) {
return UNKNOWN;
} else if (isLargeFinite()) {
if (c.isLargeFinite()) {
return UNKNOWN;
} else if (c.isFinite()) {
return GREATER;
} else {
Assert(c.isInfinite());
return LESS;
}
} else if (c.isLargeFinite()) {
if (isLargeFinite()) {
return UNKNOWN;
} else if (isFinite()) {
return LESS;
} else {
Assert(isInfinite());
return GREATER;
}
} else if (isInfinite()) {
if (c.isFinite()) {
return GREATER;
} else {
return d_card < c.d_card ? GREATER : (d_card == c.d_card ? EQUAL : LESS);
}
} else if (c.isInfinite()) {
Assert(isFinite());
return LESS;
} else {
Assert(isFinite() && !isLargeFinite());
Assert(c.isFinite() && !c.isLargeFinite());
return d_card < c.d_card ? LESS : (d_card == c.d_card ? EQUAL : GREATER);
}
Unreachable();
}
bool Cardinality::knownLessThanOrEqual(const Cardinality& c) const {
CardinalityComparison cmp = this->compare(c);
return cmp == LESS || cmp == EQUAL;
}
std::string Cardinality::toString() const {
std::stringstream ss;
ss << *this;
return ss.str();
}
std::ostream& operator<<(std::ostream& out, CardinalityBeth b) {
out << "beth[" << b.getNumber() << ']';
return out;
}
std::ostream& operator<<(std::ostream& out, const Cardinality& c) {
if (c.isUnknown()) {
out << "Cardinality::UNKNOWN";
} else if (c.isFinite()) {
out << c.getFiniteCardinality();
} else {
out << CardinalityBeth(c.getBethNumber());
}
return out;
}
} // namespace cvc5::internal