1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.
Jip J. Dekker f2a1c4e389 Squashed 'software/mza/' content from commit f970a59b17
git-subtree-dir: software/mza
git-subtree-split: f970a59b177c13ca3dd8aaef8cc6681d83b7e813
2021-07-11 16:34:30 +10:00

881 lines
26 KiB
C++

/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Main authors:
* Guido Tack <guido.tack@monash.edu>
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __MINIZINC_VALUES_HH__
#define __MINIZINC_VALUES_HH__
#include <minizinc/exception.hh>
#include <minizinc/gc.hh>
#include <algorithm>
#include <cmath>
#include <functional>
#include <limits>
#include <string>
#include <vector>
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
namespace MiniZinc {
class IntVal;
}
namespace std {
MiniZinc::IntVal abs(const MiniZinc::IntVal& x);
}
namespace MiniZinc {
class FloatVal;
class IntVal {
friend IntVal operator+(const IntVal& x, const IntVal& y);
friend IntVal operator-(const IntVal& x, const IntVal& y);
friend IntVal operator*(const IntVal& x, const IntVal& y);
friend IntVal operator/(const IntVal& x, const IntVal& y);
friend IntVal operator%(const IntVal& x, const IntVal& y);
friend IntVal std::abs(const MiniZinc::IntVal& x);
friend bool operator==(const IntVal& x, const IntVal& y);
friend class FloatVal;
private:
long long int _v;
bool _infinity;
IntVal(long long int v, bool infinity) : _v(v), _infinity(infinity) {}
static long long int safePlus(long long int x, long long int y) {
if (x < 0) {
if (y < std::numeric_limits<long long int>::min() - x)
throw ArithmeticError("integer overflow");
} else {
if (y > std::numeric_limits<long long int>::max() - x)
throw ArithmeticError("integer overflow");
}
return x + y;
}
static long long int safeMinus(long long int x, long long int y) {
if (x < 0) {
if (y > x - std::numeric_limits<long long int>::min())
throw ArithmeticError("integer overflow");
} else {
if (y < x - std::numeric_limits<long long int>::max())
throw ArithmeticError("integer overflow");
}
return x - y;
}
static long long int safeMult(long long int x, long long int y) {
if (y == 0) return 0;
long long unsigned int x_abs = (x < 0 ? 0 - x : x);
long long unsigned int y_abs = (y < 0 ? 0 - y : y);
if (x_abs > std::numeric_limits<long long int>::max() / y_abs)
throw ArithmeticError("integer overflow");
return x * y;
}
static long long int safeDiv(long long int x, long long int y) {
if (y == 0) throw ArithmeticError("integer division by zero");
if (x == 0) return 0;
if (x == std::numeric_limits<long long int>::min() && y == -1)
throw ArithmeticError("integer overflow");
return x / y;
}
static long long int safeMod(long long int x, long long int y) {
if (y == 0) throw ArithmeticError("integer division by zero");
if (y == -1) return 0;
return x % y;
}
public:
IntVal(void) : _v(0), _infinity(false) {}
IntVal(long long int v) : _v(v), _infinity(false) {}
IntVal(const FloatVal& v);
long long int toInt(void) const {
if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
return _v;
}
long long int toIntUnsafe(void) const;
bool isFinite(void) const { return !_infinity; }
bool isPlusInfinity(void) const { return _infinity && _v == 1; }
bool isMinusInfinity(void) const { return _infinity && _v == -1; }
IntVal& operator+=(const IntVal& x) {
if (!(isFinite() && x.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
_v = safePlus(_v, x._v);
return *this;
}
IntVal& operator-=(const IntVal& x) {
if (!(isFinite() && x.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
_v = safeMinus(_v, x._v);
return *this;
}
IntVal& operator*=(const IntVal& x) {
if (!(isFinite() && x.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
_v = safeMult(_v, x._v);
return *this;
}
IntVal& operator/=(const IntVal& x) {
if (!(isFinite() && x.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
_v = safeDiv(_v, x._v);
return *this;
}
IntVal operator-() const {
IntVal r = *this;
r._v = safeMinus(0, _v);
return r;
}
IntVal& operator++() {
if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
_v = safePlus(_v, 1);
return *this;
}
IntVal operator++(int) {
if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
IntVal ret = *this;
_v = safePlus(_v, 1);
return ret;
}
IntVal& operator--() {
if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
_v = safeMinus(_v, 1);
return *this;
}
IntVal operator--(int) {
if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
IntVal ret = *this;
_v = safeMinus(_v, 1);
return ret;
}
IntVal pow(const IntVal& exponent) {
if (!exponent.isFinite() || !isFinite())
throw ArithmeticError("arithmetic operation on infinite value");
if (exponent == 0) return 1;
if (exponent == 1) return *this;
IntVal result = 1;
for (int i = 0; i < exponent.toInt(); i++) {
result *= *this;
}
return result;
}
static const IntVal minint(void);
static const IntVal maxint(void);
static const IntVal infinity(void);
/// Infinity-safe addition
IntVal plus(int x) const {
if (isFinite())
return safePlus(_v, x);
else
return *this;
}
/// Infinity-safe subtraction
IntVal minus(int x) const {
if (isFinite())
return safeMinus(_v, x);
else
return *this;
}
size_t hash(void) const {
std::hash<long long int> longhash;
return longhash(_v);
}
};
inline long long int IntVal::toIntUnsafe(void) const { return _v; }
inline bool operator==(const IntVal& x, const IntVal& y) {
return x._infinity == y._infinity && x._v == y._v;
}
inline bool operator<=(const IntVal& x, const IntVal& y) {
return y.isPlusInfinity() || x.isMinusInfinity() ||
(x.isFinite() && y.isFinite() && x.toInt() <= y.toInt());
}
inline bool operator<(const IntVal& x, const IntVal& y) {
return (y.isPlusInfinity() && !x.isPlusInfinity()) ||
(x.isMinusInfinity() && !y.isMinusInfinity()) ||
(x.isFinite() && y.isFinite() && x.toInt() < y.toInt());
}
inline bool operator>=(const IntVal& x, const IntVal& y) { return y <= x; }
inline bool operator>(const IntVal& x, const IntVal& y) { return y < x; }
inline bool operator!=(const IntVal& x, const IntVal& y) { return !(x == y); }
inline IntVal operator+(const IntVal& x, const IntVal& y) {
if (!(x.isFinite() && y.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
return IntVal::safePlus(x._v, y._v);
}
inline IntVal operator-(const IntVal& x, const IntVal& y) {
if (!(x.isFinite() && y.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
return IntVal::safeMinus(x._v, y._v);
}
inline IntVal operator*(const IntVal& x, const IntVal& y) {
if (!x.isFinite()) {
if (y.isFinite() && (y._v == 1 || y._v == -1))
return IntVal(IntVal::safeMult(x._v, y._v), !x.isFinite());
} else if (!y.isFinite()) {
if (x.isFinite() && (y._v == 1 || y._v == -1))
return IntVal(IntVal::safeMult(x._v, y._v), true);
} else {
return IntVal::safeMult(x._v, y._v);
}
throw ArithmeticError("arithmetic operation on infinite value");
}
inline IntVal operator/(const IntVal& x, const IntVal& y) {
if (y.isFinite() && (y._v == 1 || y._v == -1))
return IntVal(IntVal::safeMult(x._v, y._v), !x.isFinite());
if (!(x.isFinite() && y.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
return IntVal::safeDiv(x._v, y._v);
}
inline IntVal operator%(const IntVal& x, const IntVal& y) {
if (!(x.isFinite() && y.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
return IntVal::safeMod(x._v, y._v);
}
template <class Char, class Traits>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,
const IntVal& s) {
if (s.isMinusInfinity())
return os << "-infinity";
else if (s.isPlusInfinity())
return os << "infinity";
else
return os << s.toInt();
}
} // namespace MiniZinc
namespace std {
inline MiniZinc::IntVal abs(const MiniZinc::IntVal& x) {
if (!x.isFinite()) return MiniZinc::IntVal::infinity();
return x < 0 ? MiniZinc::IntVal::safeMinus(0, x._v) : x;
}
inline MiniZinc::IntVal min(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) {
return x <= y ? x : y;
}
inline MiniZinc::IntVal max(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) {
return x >= y ? x : y;
}
template <>
struct equal_to<MiniZinc::IntVal> {
public:
bool operator()(const MiniZinc::IntVal& s0, const MiniZinc::IntVal& s1) const { return s0 == s1; }
};
inline MiniZinc::FloatVal abs(const MiniZinc::FloatVal&);
} // namespace std
namespace std {
template <>
struct hash<MiniZinc::IntVal> {
public:
size_t operator()(const MiniZinc::IntVal& s) const { return s.hash(); }
};
} // namespace std
namespace MiniZinc {
class FloatVal {
friend FloatVal operator+(const FloatVal& x, const FloatVal& y);
friend FloatVal operator-(const FloatVal& x, const FloatVal& y);
friend FloatVal operator*(const FloatVal& x, const FloatVal& y);
friend FloatVal operator/(const FloatVal& x, const FloatVal& y);
friend FloatVal std::abs(const MiniZinc::FloatVal& x);
friend bool operator==(const FloatVal& x, const FloatVal& y);
friend class IntVal;
private:
double _v;
bool _infinity;
void checkOverflow(void) {
if (!std::isfinite(_v)) throw ArithmeticError("overflow in floating point operation");
}
FloatVal(double v, bool infinity) : _v(v), _infinity(infinity) { checkOverflow(); }
public:
FloatVal(void) : _v(0.0), _infinity(false) {}
FloatVal(double v) : _v(v), _infinity(false) { checkOverflow(); }
FloatVal(const IntVal& v) : _v(static_cast<double>(v._v)), _infinity(!v.isFinite()) {}
double toDouble(void) const {
if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
return _v;
}
bool isFinite(void) const { return !_infinity; }
bool isPlusInfinity(void) const { return _infinity && _v == 1.0; }
bool isMinusInfinity(void) const { return _infinity && _v == -1.0; }
FloatVal& operator+=(const FloatVal& x) {
if (!(isFinite() && x.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
_v += x._v;
checkOverflow();
return *this;
}
FloatVal& operator-=(const FloatVal& x) {
if (!(isFinite() && x.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
_v -= x._v;
checkOverflow();
return *this;
}
FloatVal& operator*=(const FloatVal& x) {
if (!(isFinite() && x.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
_v *= x._v;
checkOverflow();
return *this;
}
FloatVal& operator/=(const FloatVal& x) {
if (!(isFinite() && x.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
_v = _v / x._v;
checkOverflow();
return *this;
}
FloatVal operator-() const {
FloatVal r = *this;
r._v = -r._v;
return r;
}
FloatVal& operator++() {
if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
_v = _v + 1;
checkOverflow();
return *this;
}
FloatVal operator++(int) {
if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
FloatVal ret = *this;
_v = _v + 1;
checkOverflow();
return ret;
}
FloatVal& operator--() {
if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
_v = _v - 1;
checkOverflow();
return *this;
}
FloatVal operator--(int) {
if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
FloatVal ret = *this;
_v = _v - 1;
checkOverflow();
return ret;
}
static const FloatVal infinity(void);
/// Infinity-safe addition
FloatVal plus(int x) {
if (isFinite())
return (*this) + x;
else
return *this;
}
/// Infinity-safe subtraction
FloatVal minus(int x) {
if (isFinite())
return (*this) - x;
else
return *this;
}
size_t hash(void) const {
std::hash<double> doublehash;
return doublehash(_v);
}
};
inline bool operator==(const FloatVal& x, const FloatVal& y) {
return x._infinity == y._infinity && x._v == y._v;
}
inline bool operator<=(const FloatVal& x, const FloatVal& y) {
return y.isPlusInfinity() || x.isMinusInfinity() ||
(x.isFinite() && y.isFinite() && x.toDouble() <= y.toDouble());
}
inline bool operator<(const FloatVal& x, const FloatVal& y) {
return (y.isPlusInfinity() && !x.isPlusInfinity()) ||
(x.isMinusInfinity() && !y.isMinusInfinity()) ||
(x.isFinite() && y.isFinite() && x.toDouble() < y.toDouble());
}
inline bool operator>=(const FloatVal& x, const FloatVal& y) { return y <= x; }
inline bool operator>(const FloatVal& x, const FloatVal& y) { return y < x; }
inline bool operator!=(const FloatVal& x, const FloatVal& y) { return !(x == y); }
inline FloatVal operator+(const FloatVal& x, const FloatVal& y) {
if (!(x.isFinite() && y.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
return x.toDouble() + y.toDouble();
}
inline FloatVal operator-(const FloatVal& x, const FloatVal& y) {
if (!(x.isFinite() && y.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
return x.toDouble() - y.toDouble();
}
inline FloatVal operator*(const FloatVal& x, const FloatVal& y) {
if (!(x.isFinite() && y.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
return x.toDouble() * y.toDouble();
}
inline FloatVal operator/(const FloatVal& x, const FloatVal& y) {
if (!(x.isFinite() && y.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
return x.toDouble() / y.toDouble();
}
template <class Char, class Traits>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,
const FloatVal& s) {
if (s.isMinusInfinity())
return os << "-infinity";
else if (s.isPlusInfinity())
return os << "infinity";
else
return os << s.toDouble();
}
inline IntVal::IntVal(const FloatVal& v)
: _v(static_cast<long long int>(v._v)), _infinity(!v.isFinite()) {}
} // namespace MiniZinc
namespace std {
inline MiniZinc::FloatVal abs(const MiniZinc::FloatVal& x) {
if (!x.isFinite()) return MiniZinc::FloatVal::infinity();
return x.toDouble() < 0 ? MiniZinc::FloatVal(-x.toDouble()) : x;
}
inline MiniZinc::FloatVal min(const MiniZinc::FloatVal& x, const MiniZinc::FloatVal& y) {
return x <= y ? x : y;
}
inline MiniZinc::FloatVal max(const MiniZinc::FloatVal& x, const MiniZinc::FloatVal& y) {
return x >= y ? x : y;
}
inline MiniZinc::FloatVal floor(const MiniZinc::FloatVal& x) {
if (!x.isFinite()) return x;
return floor(x.toDouble());
}
inline MiniZinc::FloatVal ceil(const MiniZinc::FloatVal& x) {
if (!x.isFinite()) return x;
return ceil(x.toDouble());
}
template <>
struct equal_to<MiniZinc::FloatVal> {
public:
bool operator()(const MiniZinc::FloatVal& s0, const MiniZinc::FloatVal& s1) const {
return s0 == s1;
}
};
} // namespace std
namespace std {
template <>
struct hash<MiniZinc::FloatVal> {
public:
size_t operator()(const MiniZinc::FloatVal& s) const { return s.hash(); }
};
} // namespace std
namespace MiniZinc {
typedef unsigned long long int UIntVal;
/// An integer set value
class IntSetVal : public ASTChunk {
public:
/// Contiguous range
struct Range {
/// Range minimum
IntVal min;
/// Range maximum
IntVal max;
/// Construct range from \a m to \a n
Range(IntVal m, IntVal n) : min(m), max(n) {}
/// Default constructor
Range(void) {}
};
private:
/// Return range at position \a i
Range& get(int i) { return reinterpret_cast<Range*>(_data)[i]; }
/// Return range at position \a i
const Range& get(int i) const { return reinterpret_cast<const Range*>(_data)[i]; }
/// Construct empty set
IntSetVal(void) : ASTChunk(0) {}
/// Construct set of single range
IntSetVal(IntVal m, IntVal n);
/// Construct set from \a s
IntSetVal(const std::vector<Range>& s) : ASTChunk(sizeof(Range) * s.size()) {
for (unsigned int i = static_cast<unsigned int>(s.size()); i--;) get(i) = s[i];
}
/// Disabled
IntSetVal(const IntSetVal& r);
/// Disabled
IntSetVal& operator=(const IntSetVal& r);
public:
/// Return number of ranges
int size(void) const { return static_cast<int>(_size / sizeof(Range)); }
/// Return minimum, or infinity if set is empty
IntVal min(void) const { return size() == 0 ? IntVal::infinity() : get(0).min; }
/// Return maximum, or minus infinity if set is empty
IntVal max(void) const { return size() == 0 ? -IntVal::infinity() : get(size() - 1).max; }
/// Return minimum of range \a i
IntVal min(int i) const {
assert(i < size());
return get(i).min;
}
/// Return maximum of range \a i
IntVal max(int i) const {
assert(i < size());
return get(i).max;
}
/// Return width of range \a i
IntVal width(int i) const {
assert(i < size());
if (min(i).isFinite() && max(i).isFinite())
return max(i) - min(i) + 1;
else
return IntVal::infinity();
}
/// Return cardinality
IntVal card(void) const {
IntVal c = 0;
for (unsigned int i = size(); i--;) {
if (width(i).isFinite())
c += width(i);
else
return IntVal::infinity();
}
return c;
}
/// Allocate empty set from context
static IntSetVal* a(void) {
IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(0));
new (r) IntSetVal();
return r;
}
/// Allocate set \f$\{m,n\}\f$ from context
static IntSetVal* a(IntVal m, IntVal n) {
if (m > n) {
return a();
} else {
IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(sizeof(Range)));
new (r) IntSetVal(m, n);
return r;
}
}
/// Allocate set using iterator \a i
template <class I>
static IntSetVal* ai(I& i) {
std::vector<Range> s;
for (; i(); ++i) s.push_back(Range(i.min(), i.max()));
IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(sizeof(Range) * s.size()));
new (r) IntSetVal(s);
return r;
}
/// Allocate set from vector \a s0 (may contain duplicates)
static IntSetVal* a(const std::vector<IntVal>& s0) {
if (s0.size() == 0) return a();
std::vector<IntVal> s = s0;
std::sort(s.begin(), s.end());
std::vector<Range> ranges;
IntVal min = s[0];
IntVal max = min;
for (unsigned int i = 1; i < s.size(); i++) {
if (s[i] > max + 1) {
ranges.push_back(Range(min, max));
min = s[i];
max = min;
} else {
max = s[i];
}
}
ranges.push_back(Range(min, max));
IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(sizeof(Range) * ranges.size()));
new (r) IntSetVal(ranges);
return r;
}
static IntSetVal* a(const std::vector<Range>& ranges) {
IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(sizeof(Range) * ranges.size()));
new (r) IntSetVal(ranges);
return r;
}
/// Check if set contains \a v
bool contains(const IntVal& v) {
for (int i = 0; i < size(); i++) {
if (v < min(i)) return false;
if (v <= max(i)) return true;
}
return false;
}
/// Check if it is equal to \a s
bool equal(const IntSetVal* s) {
if (size() != s->size()) return false;
for (int i = 0; i < size(); i++)
if (min(i) != s->min(i) || max(i) != s->max(i)) return false;
return true;
}
/// Mark for garbage collection
void mark(void) { _gc_mark = 1; }
};
/// Iterator over an IntSetVal
class IntSetRanges {
/// The set value
const IntSetVal* rs;
/// The current range
int n;
public:
/// Constructor
IntSetRanges(const IntSetVal* r) : rs(r), n(0) {}
/// Check if iterator is still valid
bool operator()(void) const { return n < rs->size(); }
/// Move to next range
void operator++(void) { ++n; }
/// Return minimum of current range
IntVal min(void) const { return rs->min(n); }
/// Return maximum of current range
IntVal max(void) const { return rs->max(n); }
/// Return width of current range
IntVal width(void) const { return rs->width(n); }
};
template <class Char, class Traits>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,
const IntSetVal& s) {
if (s.size() == 0) {
os << "1..0";
} else if (s.size() == 1) {
// Print the range
IntSetRanges isr(&s);
os << isr.min() << ".." << isr.max();
} else {
// Print each element of the set
bool first = true;
os << "{";
for (IntSetRanges isr(&s); isr(); ++isr) {
if (!first) os << ", ";
first = false;
for (IntVal v = isr.min(); v < isr.max(); ++v) {
os << v;
}
}
os << "}";
}
return os;
}
/// An integer set value
class FloatSetVal : public ASTChunk {
public:
/// Contiguous range
struct Range {
/// Range minimum
FloatVal min;
/// Range maximum
FloatVal max;
/// Construct range from \a m to \a n
Range(FloatVal m, FloatVal n) : min(m), max(n) {}
/// Default constructor
Range(void) {}
};
private:
/// Return range at position \a i
Range& get(int i) { return reinterpret_cast<Range*>(_data)[i]; }
/// Return range at position \a i
const Range& get(int i) const { return reinterpret_cast<const Range*>(_data)[i]; }
/// Construct empty set
FloatSetVal(void) : ASTChunk(0) {}
/// Construct set of single range
FloatSetVal(FloatVal m, FloatVal n);
/// Construct set from \a s
FloatSetVal(const std::vector<Range>& s) : ASTChunk(sizeof(Range) * s.size()) {
for (unsigned int i = static_cast<unsigned int>(s.size()); i--;) get(i) = s[i];
}
/// Disabled
FloatSetVal(const FloatSetVal& r);
/// Disabled
FloatSetVal& operator=(const FloatSetVal& r);
public:
/// Return number of ranges
int size(void) const { return static_cast<int>(_size / sizeof(Range)); }
/// Return minimum, or infinity if set is empty
FloatVal min(void) const { return size() == 0 ? FloatVal::infinity() : get(0).min; }
/// Return maximum, or minus infinity if set is empty
FloatVal max(void) const { return size() == 0 ? -FloatVal::infinity() : get(size() - 1).max; }
/// Return minimum of range \a i
FloatVal min(int i) const {
assert(i < size());
return get(i).min;
}
/// Return maximum of range \a i
FloatVal max(int i) const {
assert(i < size());
return get(i).max;
}
/// Return width of range \a i
FloatVal width(int i) const {
assert(i < size());
if (min(i).isFinite() && max(i).isFinite() && min(i) == max(i))
return 1;
else
return IntVal::infinity();
}
/// Return cardinality
FloatVal card(void) const {
FloatVal c = 0;
for (unsigned int i = size(); i--;) {
if (width(i).isFinite())
c += width(i);
else
return FloatVal::infinity();
}
return c;
}
/// Allocate empty set from context
static FloatSetVal* a(void) {
FloatSetVal* r = static_cast<FloatSetVal*>(ASTChunk::alloc(0));
new (r) FloatSetVal();
return r;
}
/// Allocate set \f$\{m,n\}\f$ from context
static FloatSetVal* a(FloatVal m, FloatVal n) {
if (m > n) {
return a();
} else {
FloatSetVal* r = static_cast<FloatSetVal*>(ASTChunk::alloc(sizeof(Range)));
new (r) FloatSetVal(m, n);
return r;
}
}
/// Allocate set using iterator \a i
template <class I>
static FloatSetVal* ai(I& i) {
std::vector<Range> s;
for (; i(); ++i) s.push_back(Range(i.min(), i.max()));
FloatSetVal* r = static_cast<FloatSetVal*>(ASTChunk::alloc(sizeof(Range) * s.size()));
new (r) FloatSetVal(s);
return r;
}
/// Allocate set from vector \a s0 (may contain duplicates)
static FloatSetVal* a(const std::vector<FloatVal>& s0) {
if (s0.size() == 0) return a();
std::vector<FloatVal> s = s0;
std::sort(s.begin(), s.end());
std::vector<Range> ranges;
FloatVal min = s[0];
FloatVal max = min;
for (unsigned int i = 1; i < s.size(); i++) {
if (s[i] > max) {
ranges.push_back(Range(min, max));
min = s[i];
max = min;
} else {
max = s[i];
}
}
ranges.push_back(Range(min, max));
FloatSetVal* r = static_cast<FloatSetVal*>(ASTChunk::alloc(sizeof(Range) * ranges.size()));
new (r) FloatSetVal(ranges);
return r;
}
static FloatSetVal* a(const std::vector<Range>& ranges) {
FloatSetVal* r = static_cast<FloatSetVal*>(ASTChunk::alloc(sizeof(Range) * ranges.size()));
new (r) FloatSetVal(ranges);
return r;
}
/// Check if set contains \a v
bool contains(const FloatVal& v) {
for (int i = 0; i < size(); i++) {
if (v < min(i)) return false;
if (v <= max(i)) return true;
}
return false;
}
/// Check if it is equal to \a s
bool equal(const FloatSetVal* s) {
if (size() != s->size()) return false;
for (int i = 0; i < size(); i++)
if (min(i) != s->min(i) || max(i) != s->max(i)) return false;
return true;
}
/// Mark for garbage collection
void mark(void) { _gc_mark = 1; }
};
/// Iterator over an IntSetVal
class FloatSetRanges {
/// The set value
const FloatSetVal* rs;
/// The current range
int n;
public:
/// Constructor
FloatSetRanges(const FloatSetVal* r) : rs(r), n(0) {}
/// Check if iterator is still valid
bool operator()(void) const { return n < rs->size(); }
/// Move to next range
void operator++(void) { ++n; }
/// Return minimum of current range
FloatVal min(void) const { return rs->min(n); }
/// Return maximum of current range
FloatVal max(void) const { return rs->max(n); }
/// Return width of current range
FloatVal width(void) const { return rs->width(n); }
};
template <class Char, class Traits>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,
const FloatSetVal& s) {
for (FloatSetRanges isr(&s); isr(); ++isr) os << isr.min() << ".." << isr.max() << " ";
return os;
}
} // namespace MiniZinc
#endif