Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
27 kB · 880 lines
C++
at develop
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881/* -*- 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 valueclass 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 IntSetValclass 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 valueclass 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 IntSetValclass 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