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 fad1b07018 Squashed 'software/minizinc/' content from commit 4f10c8205
git-subtree-dir: software/minizinc
git-subtree-split: 4f10c82056ffcb1041d7ffef29d77a7eef92cf76
2021-06-16 14:06:46 +10:00

824 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/. */
#pragma once
#include <minizinc/values.hh>
#include <cmath>
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#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();
public:
/// \name Constructors and initialization
//@{
/// Default constructor
MinMax();
/// 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()() const;
//@}
/// \name Range access
//@{
/// Return smallest value of range
Val min() const;
/// Return largest value of range
Val max() const;
/// Return width of range (distance between minimum and maximum)
Val width() const;
//@}
};
template <class Val>
inline void MinMax<Val>::finish() {
_mi = 1;
_ma = 0;
}
template <class Val>
inline MinMax<Val>::MinMax() {}
template <class Val>
inline MinMax<Val>::MinMax(Val min, Val max) : _mi(min), _ma(max) {}
template <class Val>
inline bool MinMax<Val>::operator()() const {
return _mi <= _ma;
}
template <class Val>
inline Val MinMax<Val>::min() const {
return _mi;
}
template <class Val>
inline Val MinMax<Val>::max() const {
return _ma;
}
template <class Val>
inline Val MinMax<Val>::width() 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 _useMin;
Val _max;
bool _useMax;
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()() const;
/// Move iterator to next range (if possible)
void operator++();
//@}
/// \name Range access
//@{
/// Return smallest value of range
Val min() const;
/// Return largest value of range
Val max() const;
/// Return width of range (distance between minimum and maximum)
Val width() const;
//@}
};
template <class Val, class I>
inline Bounded<Val, I>::Bounded(I& i, Val min0, bool umin0, Val max0, bool umax0)
: _i(i), _min(min0), _useMin(umin0), _max(max0), _useMax(umax0) {
while (_i() && _useMin && _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()() const {
return _i() && (!_useMax || _i.min() <= _max);
}
template <class Val, class I>
inline void Bounded<Val, I>::operator++() {
++_i;
while (_i() && _useMin && _i.max() < _min) {
++_i;
}
}
template <class Val, class I>
inline Val Bounded<Val, I>::min() const {
return _useMin ? std::max(_min, _i.min()) : _i.min();
}
template <class Val, class I>
inline Val Bounded<Val, I>::max() const {
return _useMax ? std::min(_max, _i.max()) : _i.max();
}
template <class Val, class I>
inline Val Bounded<Val, I>::width() 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()() const;
/// Move iterator to next range (if possible)
void operator++();
//@}
/// \name Range access
//@{
/// Return smallest value of range
Val min() const;
/// Return largest value of range
Val max() const;
/// Return width of range (distance between minimum and maximum)
Val width() 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()() const {
return !_done;
}
template <class Val>
inline void Const<Val>::operator++() {
_done = true;
}
template <class Val>
inline Val Const<Val>::min() const {
return _min;
}
template <class Val>
inline Val Const<Val>::max() const {
return _max;
}
template <class Val>
inline Val Const<Val>::width() 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();
/// 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++();
//@}
};
/// 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 next_higher(const IntVal& x) { return x.plus(1); }
inline IntVal next_lower(const IntVal& x) { return x.minus(1); }
inline FloatVal next_higher(const FloatVal& x) {
if (x.isFinite()) {
return std::nextafter(x.toDouble(), INFINITY);
}
return x;
}
inline FloatVal next_lower(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++() {
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() {}
template <class Val, class I, class J>
inline Union<Val, I, J>::Union(I& i, J& j) : _i(i), _j(j) {
operator++();
}
template <class Val, class I, class J>
inline void Union<Val, I, J>::init(I& i, J& j) {
_i = i;
_j = j;
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();
/// 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++();
//@}
};
/*
* Binary intersection
*
*/
template <class Val, class I, class J>
inline void Inter<Val, I, J>::operator++() {
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() {}
template <class Val, class I, class J>
inline Inter<Val, I, J>::Inter(I& i, J& j) : _i(i), _j(j) {
operator++();
}
template <class Val, class I, class J>
inline void Inter<Val, I, J>::init(I& i, J& j) {
_i = i;
_j = j;
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();
/// 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++();
//@}
};
template <class Val, class I, class J>
inline void Diff<Val, I, J>::operator++() {
// 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 = next_higher(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 = next_higher(_j.max());
// Search for max!
++_j;
if (_j() && (_j.min() <= MinMax<Val>::_ma)) {
MinMax<Val>::_ma = next_lower(_j.min());
}
} else {
MinMax<Val>::_ma = next_lower(_j.min());
}
}
return;
}
MinMax<Val>::finish();
}
template <class Val, class I, class J>
inline Diff<Val, I, J>::Diff() {}
template <class Val, class I, class J>
inline Diff<Val, I, J>::Diff(I& i, J& j) : _i(i), _j(j) {
if (!_i()) {
MinMax<Val>::finish();
} else {
MinMax<Val>::_mi = next_lower(_i.min());
MinMax<Val>::_ma = MinMax<Val>::_mi;
operator++();
}
}
template <class Val, class I, class J>
inline void Diff<Val, I, J>::init(I& i, J& j) {
_i = i;
_j = j;
if (!_i()) {
MinMax<Val>::finish();
} else {
MinMax<Val>::_mi = next_lower(_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();
public:
/// \name Constructors and initialization
//@{
/// Default constructor
ToValues();
/// 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()() const;
/// Move iterator to next value (if possible)
void operator++();
//@}
/// \name Value access
//@{
/// Return current value
IntVal val() const;
//@}
};
template <class I>
inline ToValues<I>::ToValues() {}
template <class I>
inline void ToValues<I>::start() {
if (_i()) {
_cur = _i.min();
_max = _i.max();
} else {
_cur = 1;
_max = 0;
}
}
template <class I>
inline ToValues<I>::ToValues(I& i) : _i(i) {
start();
}
template <class I>
inline void ToValues<I>::init(I& i) {
_i = i;
start();
}
template <class I>
inline bool ToValues<I>::operator()() const {
return (_cur <= _max);
}
template <class I>
inline void ToValues<I>::operator++() {
++_cur;
if (_cur > _max) {
++_i;
if (_i()) {
_cur = _i.min();
_max = _i.max();
}
}
}
template <class I>
inline IntVal ToValues<I>::val() 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()) {
++j;
return j();
}
++i;
++j;
}
return static_cast<bool>(j());
}
template <class I, class J>
inline bool less_eq(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()) {
++j;
return j();
}
++i;
++j;
}
return true;
}
} // namespace Ranges
} // namespace MiniZinc