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.

757 lines
17 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_ITER_HH__
#define __MINIZINC_ITER_HH__
#include <minizinc/values.hh>
#include <cmath>
#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 Val>
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 <class Val>
inline void MinMax<Val>::finish(void) {
mi = 1;
ma = 0;
}
template <class Val>
inline MinMax<Val>::MinMax(void) {}
template <class Val>
inline MinMax<Val>::MinMax(Val min, Val max) : mi(min), ma(max) {}
template <class Val>
inline bool MinMax<Val>::operator()(void) const {
return mi <= ma;
}
template <class Val>
inline Val MinMax<Val>::min(void) const {
return mi;
}
template <class Val>
inline Val MinMax<Val>::max(void) const {
return ma;
}
template <class Val>
inline Val MinMax<Val>::width(void) const {
if (mi > ma) return 0;
if (mi.isFinite() && ma.isFinite()) return ma - mi + 1;
return Val::infinity();
}
template <class Val, class I>
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 <class Val, class I>
inline Bounded<Val, I>::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 <class Val, class I>
inline Bounded<Val, I> Bounded<Val, I>::miniter(I& i, Val min) {
return Bounded(i, min, true, 0, false);
}
template <class Val, class I>
inline Bounded<Val, I> Bounded<Val, I>::maxiter(I& i, Val max) {
return Bounded(i, 0, false, max, true);
}
template <class Val, class I>
inline Bounded<Val, I> Bounded<Val, I>::minmaxiter(I& i, Val min, Val max) {
return Bounded(i, min, true, max, true);
}
template <class Val, class I>
inline bool Bounded<Val, I>::operator()(void) const {
return i() && (!use_max || i.min() <= _max);
}
template <class Val, class I>
inline void Bounded<Val, I>::operator++(void) {
++i;
while (i() && use_min && i.max() < _min) ++i;
}
template <class Val, class I>
inline Val Bounded<Val, I>::min(void) const {
return use_min ? std::max(_min, i.min()) : i.min();
}
template <class Val, class I>
inline Val Bounded<Val, I>::max(void) const {
return use_max ? std::min(_max, i.max()) : i.max();
}
template <class Val, class I>
inline Val Bounded<Val, I>::width(void) const {
if (min() > max()) return 0;
if (min().isFinite() && max().isFinite()) return max() - min() + 1;
return Val::infinity();
}
template <class Val>
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 <class Val>
inline Const<Val>::Const(Val min0, Val max0) : _min(min0), _max(max0), done(min0 > max0) {}
template <class Val>
inline bool Const<Val>::operator()(void) const {
return !done;
}
template <class Val>
inline void Const<Val>::operator++(void) {
done = true;
}
template <class Val>
inline Val Const<Val>::min(void) const {
return _min;
}
template <class Val>
inline Val Const<Val>::max(void) const {
return _max;
}
template <class Val>
inline Val Const<Val>::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 Val, class I, class J>
class Union : public MinMax<Val> {
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 <class Val, class I, class J>
inline void Union<Val, I, J>::operator++(void) {
if (!i() && !j()) {
MinMax<Val>::finish();
return;
}
if (!i() || (j() && (!overlaps(j.max(), i.min())))) {
MinMax<Val>::mi = j.min();
MinMax<Val>::ma = j.max();
++j;
return;
}
if (!j() || (i() && (!overlaps(i.max(), j.min())))) {
MinMax<Val>::mi = i.min();
MinMax<Val>::ma = i.max();
++i;
return;
}
MinMax<Val>::mi = std::min(i.min(), j.min());
MinMax<Val>::ma = std::max(i.max(), j.max());
++i;
++j;
next:
if (i() && (overlaps(MinMax<Val>::ma, i.min()))) {
MinMax<Val>::ma = std::max(MinMax<Val>::ma, i.max());
++i;
goto next;
}
if (j() && (overlaps(MinMax<Val>::ma, j.min()))) {
MinMax<Val>::ma = std::max(MinMax<Val>::ma, j.max());
++j;
goto next;
}
}
template <class Val, class I, class J>
inline Union<Val, I, J>::Union(void) {}
template <class Val, class I, class J>
inline Union<Val, I, J>::Union(I& i0, J& j0) : i(i0), j(j0) {
operator++();
}
template <class Val, class I, class J>
inline void Union<Val, I, J>::init(I& i0, J& j0) {
i = i0;
j = j0;
operator++();
}
/**
* \brief Range iterator for computing intersection (binary)
*
* \ingroup FuncIterRanges
*/
template <class Val, class I, class J>
class Inter : public MinMax<Val> {
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 <class Val, class I, class J>
inline void Inter<Val, I, J>::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<Val>::ma = std::min(i.max(), j.max());
MinMax<Val>::mi = std::max(i.min(), j.min());
if (i.max() < j.max())
++i;
else
++j;
return;
done:
MinMax<Val>::finish();
}
template <class Val, class I, class J>
inline Inter<Val, I, J>::Inter(void) {}
template <class Val, class I, class J>
inline Inter<Val, I, J>::Inter(I& i0, J& j0) : i(i0), j(j0) {
operator++();
}
template <class Val, class I, class J>
inline void Inter<Val, I, J>::init(I& i0, J& j0) {
i = i0;
j = j0;
operator++();
}
/**
* \brief Range iterator for computing set difference
*
* \ingroup FuncIterRanges
*/
template <class Val, class I, class J>
class Diff : public MinMax<Val> {
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 <class Val, class I, class J>
inline void Diff<Val, I, J>::operator++(void) {
// Precondition: mi <= ma
// Task: find next mi greater than ma
while (true) {
if (!i()) break;
bool isInfinite = (!MinMax<Val>::ma.isFinite() && MinMax<Val>::ma > 0);
MinMax<Val>::mi = nextHigher(MinMax<Val>::ma);
MinMax<Val>::ma = i.max();
if (isInfinite || MinMax<Val>::mi > i.max()) {
++i;
if (!i()) break;
MinMax<Val>::mi = i.min();
MinMax<Val>::ma = i.max();
}
while (j() && (j.max() < MinMax<Val>::mi)) ++j;
if (j() && (j.min() <= MinMax<Val>::ma)) {
// Now the interval [mi ... ma] must be shrunken
// Is [mi ... ma] completely consumed?
if ((MinMax<Val>::mi >= j.min()) && (MinMax<Val>::ma <= j.max())) continue;
// Does [mi ... ma] overlap on the left?
if (j.min() <= MinMax<Val>::mi) {
MinMax<Val>::mi = nextHigher(j.max());
// Search for max!
++j;
if (j() && (j.min() <= MinMax<Val>::ma)) MinMax<Val>::ma = nextLower(j.min());
} else {
MinMax<Val>::ma = nextLower(j.min());
}
}
return;
}
MinMax<Val>::finish();
}
template <class Val, class I, class J>
inline Diff<Val, I, J>::Diff(void) {}
template <class Val, class I, class J>
inline Diff<Val, I, J>::Diff(I& i0, J& j0) : i(i0), j(j0) {
if (!i()) {
MinMax<Val>::finish();
} else {
MinMax<Val>::mi = nextLower(i.min());
MinMax<Val>::ma = MinMax<Val>::mi;
operator++();
}
}
template <class Val, class I, class J>
inline void Diff<Val, I, J>::init(I& i0, J& j0) {
i = i0;
j = j0;
if (!i()) {
MinMax<Val>::finish();
} else {
MinMax<Val>::mi = nextLower(i.min());
MinMax<Val>::ma = MinMax<Val>::mi;
operator++();
}
}
/**
* \brief Value iterator from range iterator
*
* \ingroup FuncIterValues
*/
template <class I>
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 <class I>
inline ToValues<I>::ToValues(void) {}
template <class I>
inline void ToValues<I>::start(void) {
if (i()) {
cur = i.min();
max = i.max();
} else {
cur = 1;
max = 0;
}
}
template <class I>
inline ToValues<I>::ToValues(I& i0) : i(i0) {
start();
}
template <class I>
inline void ToValues<I>::init(I& i0) {
i = i0;
start();
}
template <class I>
inline bool ToValues<I>::operator()(void) const {
return (cur <= max);
}
template <class I>
inline void ToValues<I>::operator++(void) {
++cur;
if (cur > max) {
++i;
if (i()) {
cur = i.min();
max = i.max();
}
}
}
template <class I>
inline IntVal ToValues<I>::val(void) const {
return cur;
}
/**
* \defgroup FuncIterRangesOp Operations on range iterators
*
* \ingroup FuncIterRanges
*/
//@{
/// Cardinality of the set represented by range iterator \a i
template <class I>
IntVal cardinality(I& i);
/// Check whether range iterators \a i and \a j are equal
template <class I, class J>
bool equal(I& i, J& j);
/// Check whether range iterator \a i is subset of range iterator \a j
template <class I, class J>
bool subset(I& i, J& j);
/// Check whether range iterators \a i and \a j are disjoint
template <class I, class J>
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 <class I, class J>
CompareStatus compare(I& i, J& j);
//@}
template <class I>
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 <class I, class J>
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 <class I, class J>
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 <class I, class J>
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 <class I, class J>
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 <class I, class J>
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 <class I, class J>
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