/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* * Main authors: * Guido Tack */ /* 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_ITER_HH__ #define __MINIZINC_ITER_HH__ #include #include #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #undef ERROR // MICROsoft. #undef min #undef max #endif namespace MiniZinc { namespace Ranges { /** * \brief Base for range iterators with explicit min and max * * The iterator provides members \a mi and \a ma for storing the * limits of the currently iterated range. The iterator * continues until \a mi becomes greater than \a ma. The member function * finish does exactly that. * * \ingroup FuncIterRanges */ template class MinMax { protected: /// Minimum of current range Val mi; /// Maximum of current range Val ma; /// %Set range such that iteration stops void finish(void); public: /// \name Constructors and initialization //@{ /// Default constructor MinMax(void); /// Initialize with range \a min to \a max MinMax(Val min, Val max); //@} /// \name Iteration control //@{ /// Test whether iterator is still at a range or done bool operator()(void) const; //@} /// \name Range access //@{ /// Return smallest value of range Val min(void) const; /// Return largest value of range Val max(void) const; /// Return width of range (distance between minimum and maximum) Val width(void) const; //@} }; template inline void MinMax::finish(void) { mi = 1; ma = 0; } template inline MinMax::MinMax(void) {} template inline MinMax::MinMax(Val min, Val max) : mi(min), ma(max) {} template inline bool MinMax::operator()(void) const { return mi <= ma; } template inline Val MinMax::min(void) const { return mi; } template inline Val MinMax::max(void) const { return ma; } template inline Val MinMax::width(void) const { if (mi > ma) return 0; if (mi.isFinite() && ma.isFinite()) return ma - mi + 1; return Val::infinity(); } template class Bounded { protected: I i; Val _min; bool use_min; Val _max; bool use_max; Bounded(I& i, Val min0, bool umin0, Val max0, bool umax0); public: static Bounded miniter(I& i, Val min); static Bounded maxiter(I& i, Val max); static Bounded minmaxiter(I& i, Val min, Val max); /// \name Iteration control //@{ /// Test whether iterator is still at a range or done bool operator()(void) const; /// Move iterator to next range (if possible) void operator++(void); //@} /// \name Range access //@{ /// Return smallest value of range Val min(void) const; /// Return largest value of range Val max(void) const; /// Return width of range (distance between minimum and maximum) Val width(void) const; //@} }; template inline Bounded::Bounded(I& i0, Val min0, bool umin0, Val max0, bool umax0) : i(i0), _min(min0), use_min(umin0), _max(max0), use_max(umax0) { while (i() && use_min && i.max() < _min) ++i; } template inline Bounded Bounded::miniter(I& i, Val min) { return Bounded(i, min, true, 0, false); } template inline Bounded Bounded::maxiter(I& i, Val max) { return Bounded(i, 0, false, max, true); } template inline Bounded Bounded::minmaxiter(I& i, Val min, Val max) { return Bounded(i, min, true, max, true); } template inline bool Bounded::operator()(void) const { return i() && (!use_max || i.min() <= _max); } template inline void Bounded::operator++(void) { ++i; while (i() && use_min && i.max() < _min) ++i; } template inline Val Bounded::min(void) const { return use_min ? std::max(_min, i.min()) : i.min(); } template inline Val Bounded::max(void) const { return use_max ? std::min(_max, i.max()) : i.max(); } template inline Val Bounded::width(void) const { if (min() > max()) return 0; if (min().isFinite() && max().isFinite()) return max() - min() + 1; return Val::infinity(); } template class Const { protected: Val _min; Val _max; bool done; public: Const(Val min0, Val max0); /// \name Iteration control //@{ /// Test whether iterator is still at a range or done bool operator()(void) const; /// Move iterator to next range (if possible) void operator++(void); //@} /// \name Range access //@{ /// Return smallest value of range Val min(void) const; /// Return largest value of range Val max(void) const; /// Return width of range (distance between minimum and maximum) Val width(void) const; //@} }; template inline Const::Const(Val min0, Val max0) : _min(min0), _max(max0), done(min0 > max0) {} template inline bool Const::operator()(void) const { return !done; } template inline void Const::operator++(void) { done = true; } template inline Val Const::min(void) const { return _min; } template inline Val Const::max(void) const { return _max; } template inline Val Const::width(void) const { if (min() > max()) return 0; if (min().isFinite() && max().isFinite()) return max() - min() + 1; return Val::infinity(); } /** * \brief Range iterator for computing union (binary) * * \ingroup FuncIterRanges */ template class Union : public MinMax { protected: /// First iterator I i; /// Second iterator J j; public: /// \name Constructors and initialization //@{ /// Default constructor Union(void); /// Initialize with iterator \a i and \a j Union(I& i, J& j); /// Initialize with iterator \a i and \a j void init(I& i, J& j); //@} /// \name Iteration control //@{ /// Move iterator to next range (if possible) void operator++(void); //@} }; /// Return whether an interval ending with \a x overlaps with an interval starting at \a y inline bool overlaps(const IntVal& x, const IntVal& y) { return x.plus(1) >= y; } /// Return whether an interval ending with \a x overlaps with an interval starting at \a y inline bool overlaps(const FloatVal& x, const FloatVal& y) { if (x.isPlusInfinity()) return true; if (y.isMinusInfinity()) return true; if (x.isFinite() && y.isFinite()) { return std::nextafter(x.toDouble(), INFINITY) >= y.toDouble(); } return x >= y; } inline IntVal nextHigher(const IntVal& x) { return x.plus(1); } inline IntVal nextLower(const IntVal& x) { return x.minus(1); } inline FloatVal nextHigher(const FloatVal& x) { if (x.isFinite()) return std::nextafter(x.toDouble(), INFINITY); return x; } inline FloatVal nextLower(const FloatVal& x) { if (x.isFinite()) return std::nextafter(x.toDouble(), -INFINITY); return x; } /* * Binary union * */ template inline void Union::operator++(void) { if (!i() && !j()) { MinMax::finish(); return; } if (!i() || (j() && (!overlaps(j.max(), i.min())))) { MinMax::mi = j.min(); MinMax::ma = j.max(); ++j; return; } if (!j() || (i() && (!overlaps(i.max(), j.min())))) { MinMax::mi = i.min(); MinMax::ma = i.max(); ++i; return; } MinMax::mi = std::min(i.min(), j.min()); MinMax::ma = std::max(i.max(), j.max()); ++i; ++j; next: if (i() && (overlaps(MinMax::ma, i.min()))) { MinMax::ma = std::max(MinMax::ma, i.max()); ++i; goto next; } if (j() && (overlaps(MinMax::ma, j.min()))) { MinMax::ma = std::max(MinMax::ma, j.max()); ++j; goto next; } } template inline Union::Union(void) {} template inline Union::Union(I& i0, J& j0) : i(i0), j(j0) { operator++(); } template inline void Union::init(I& i0, J& j0) { i = i0; j = j0; operator++(); } /** * \brief Range iterator for computing intersection (binary) * * \ingroup FuncIterRanges */ template class Inter : public MinMax { protected: /// First iterator I i; /// Second iterator J j; public: /// \name Constructors and initialization //@{ /// Default constructor Inter(void); /// Initialize with iterator \a i and \a j Inter(I& i, J& j); /// Initialize with iterator \a i and \a j void init(I& i, J& j); //@} /// \name Iteration control //@{ /// Move iterator to next range (if possible) void operator++(void); //@} }; /* * Binary intersection * */ template inline void Inter::operator++(void) { if (!i() || !j()) goto done; do { while (i() && (i.max() < j.min())) ++i; if (!i()) goto done; while (j() && (j.max() < i.min())) ++j; if (!j()) goto done; } while (i.max() < j.min()); // Now the intervals overlap: consume the smaller interval MinMax::ma = std::min(i.max(), j.max()); MinMax::mi = std::max(i.min(), j.min()); if (i.max() < j.max()) ++i; else ++j; return; done: MinMax::finish(); } template inline Inter::Inter(void) {} template inline Inter::Inter(I& i0, J& j0) : i(i0), j(j0) { operator++(); } template inline void Inter::init(I& i0, J& j0) { i = i0; j = j0; operator++(); } /** * \brief Range iterator for computing set difference * * \ingroup FuncIterRanges */ template class Diff : public MinMax { protected: /// Iterator from which to subtract I i; /// Iterator to be subtracted J j; public: /// \name Constructors and initialization //@{ /// Default constructor Diff(void); /// Initialize with iterator \a i and \a j Diff(I& i, J& j); /// Initialize with iterator \a i and \a j void init(I& i, J& j); //@} /// \name Iteration control //@{ /// Move iterator to next range (if possible) void operator++(void); //@} }; template inline void Diff::operator++(void) { // Precondition: mi <= ma // Task: find next mi greater than ma while (true) { if (!i()) break; bool isInfinite = (!MinMax::ma.isFinite() && MinMax::ma > 0); MinMax::mi = nextHigher(MinMax::ma); MinMax::ma = i.max(); if (isInfinite || MinMax::mi > i.max()) { ++i; if (!i()) break; MinMax::mi = i.min(); MinMax::ma = i.max(); } while (j() && (j.max() < MinMax::mi)) ++j; if (j() && (j.min() <= MinMax::ma)) { // Now the interval [mi ... ma] must be shrunken // Is [mi ... ma] completely consumed? if ((MinMax::mi >= j.min()) && (MinMax::ma <= j.max())) continue; // Does [mi ... ma] overlap on the left? if (j.min() <= MinMax::mi) { MinMax::mi = nextHigher(j.max()); // Search for max! ++j; if (j() && (j.min() <= MinMax::ma)) MinMax::ma = nextLower(j.min()); } else { MinMax::ma = nextLower(j.min()); } } return; } MinMax::finish(); } template inline Diff::Diff(void) {} template inline Diff::Diff(I& i0, J& j0) : i(i0), j(j0) { if (!i()) { MinMax::finish(); } else { MinMax::mi = nextLower(i.min()); MinMax::ma = MinMax::mi; operator++(); } } template inline void Diff::init(I& i0, J& j0) { i = i0; j = j0; if (!i()) { MinMax::finish(); } else { MinMax::mi = nextLower(i.min()); MinMax::ma = MinMax::mi; operator++(); } } /** * \brief Value iterator from range iterator * * \ingroup FuncIterValues */ template class ToValues { protected: /// Range iterator used I i; /// Current value IntVal cur; /// End of current range IntVal max; /// Initialize iterator void start(void); public: /// \name Constructors and initialization //@{ /// Default constructor ToValues(void); /// Initialize with values from range iterator \a i ToValues(I& i); /// Initialize with values from range iterator \a i void init(I& i); //@} /// \name Iteration control //@{ /// Test whether iterator is still at a value or done bool operator()(void) const; /// Move iterator to next value (if possible) void operator++(void); //@} /// \name Value access //@{ /// Return current value IntVal val(void) const; //@} }; template inline ToValues::ToValues(void) {} template inline void ToValues::start(void) { if (i()) { cur = i.min(); max = i.max(); } else { cur = 1; max = 0; } } template inline ToValues::ToValues(I& i0) : i(i0) { start(); } template inline void ToValues::init(I& i0) { i = i0; start(); } template inline bool ToValues::operator()(void) const { return (cur <= max); } template inline void ToValues::operator++(void) { ++cur; if (cur > max) { ++i; if (i()) { cur = i.min(); max = i.max(); } } } template inline IntVal ToValues::val(void) const { return cur; } /** * \defgroup FuncIterRangesOp Operations on range iterators * * \ingroup FuncIterRanges */ //@{ /// Cardinality of the set represented by range iterator \a i template IntVal cardinality(I& i); /// Check whether range iterators \a i and \a j are equal template bool equal(I& i, J& j); /// Check whether range iterator \a i is subset of range iterator \a j template bool subset(I& i, J& j); /// Check whether range iterators \a i and \a j are disjoint template bool disjoint(I& i, J& j); /// Comapre two iterators with each other enum CompareStatus { CS_SUBSET, ///< First is subset of second iterator CS_DISJOINT, ///< Intersection is empty CS_NONE ///< Neither of the above }; /// Check whether range iterator \a i is a subset of \a j, or whether they are disjoint template CompareStatus compare(I& i, J& j); //@} template inline IntVal cardinality(I& i) { IntVal s = 0; while (i()) { if (i.width().isFinite()) { s += i.width(); ++i; } else { return IntVal::infinity(); } } return s; } template inline bool equal(I& i, J& j) { // Are i and j equal? while (i() && j()) if ((i.min() == j.min()) && (i.max() == j.max())) { ++i; ++j; } else { return false; } return !i() && !j(); } template inline bool subset(I& i, J& j) { // Is i subset of j? while (i() && j()) if (j.max() < i.min()) { ++j; } else if ((i.min() >= j.min()) && (i.max() <= j.max())) { ++i; } else { return false; } return !i(); } template inline bool disjoint(I& i, J& j) { // Are i and j disjoint? while (i() && j()) if (j.max() < i.min()) { ++j; } else if (i.max() < j.min()) { ++i; } else { return false; } return true; } template inline CompareStatus compare(I& i, J& j) { bool subset = true; bool disjoint = true; while (i() && j()) { if (j.max() < i.min()) { ++j; } else if (i.max() < j.min()) { ++i; subset = false; } else if ((i.min() >= j.min()) && (i.max() <= j.max())) { ++i; disjoint = false; } else if (i.max() <= j.max()) { ++i; disjoint = false; subset = false; } else if (j.max() <= i.max()) { ++j; disjoint = false; subset = false; } } if (i()) subset = false; if (subset) return CS_SUBSET; return disjoint ? CS_DISJOINT : CS_NONE; } template inline bool less(I& i, J& j) { while (i()) { if (!j()) return false; if (i.min() < j.min()) return true; if (i.min() > j.min()) return false; if (i.max() < j.max()) return true; if (i.max() > j.max()) return false; ++i; ++j; } if (j()) return true; return false; } template inline bool lessEq(I& i, J& j) { while (i()) { if (!j()) return false; if (i.min() < j.min()) return true; if (i.min() > j.min()) return false; if (i.max() < j.max()) return true; if (i.max() > j.max()) return false; ++i; ++j; } return true; } } // namespace Ranges } // namespace MiniZinc #endif