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

305 lines
9.4 KiB
C++

/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Main authors:
* Jip J. Dekker <jip.dekker@monash.edu>
* 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/interpreter/_val_decl.hh>
#include <minizinc/interpreter/rco.hh>
#include <minizinc/interpreter/variable.hh>
#include <minizinc/interpreter/vector.hh>
namespace MiniZinc {
typedef std::vector<Val>::const_iterator arg_iter;
void simplify_linexp(std::vector<Val>& coeffs, std::vector<Val>& vars, Val& d);
std::tuple<std::vector<Val>, std::vector<Val>, Val> simplify_linexp(Val v);
inline Val::Val(const long long int i) {
static const unsigned int pointerBits = sizeof(void*) * 8;
static const long long int maxUnboxedVal =
(static_cast<long long int>(1) << (pointerBits - 3)) - static_cast<long long int>(1);
assert(i >= -maxUnboxedVal && i <= maxUnboxedVal);
ptrdiff_t ubi_p;
ubi_p = (static_cast<ptrdiff_t>(i < 0 ? -i : i) << 3);
if (i < 0) {
ubi_p = ubi_p | static_cast<ptrdiff_t>(4);
}
_v = reinterpret_cast<void*>(ubi_p);
}
inline Val::Val(const RefCountedObject* d) {
assert(d != nullptr);
_v = reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(d) | static_cast<ptrdiff_t>(1));
}
inline Val::~Val(void) {}
inline Val::Val(const Val& v) : _v(v._v) {}
inline Val& Val::operator=(const Val& v) {
_v = v._v;
return *this;
}
inline Val& Val::operator=(Val&& v) {
_v = v._v;
v._v = nullptr;
return *this;
}
inline Val::Val(Val&& v) : _v(v._v) { v._v = nullptr; }
inline void Val::assign(Interpreter* interpreter, const Val& v) {
if (_v != v._v) {
if (v.isRCO()) {
v.toRCO()->addRef(interpreter);
}
rmRef(interpreter);
_v = v._v;
}
}
inline void Val::assign(Interpreter* interpreter, Val&& v) {
if (_v != v._v) {
rmRef(interpreter);
_v = v._v;
v._v = nullptr;
}
}
inline const Val& Val::operator[](int i) const {
assert(isVec());
return (*toVec())[i];
}
/// Access value as vector, return size
inline size_t Val::size(void) const {
assert(isVec());
return toVec()->size();
}
inline bool operator==(const Val& lhs, const Val& rhs) {
if ((reinterpret_cast<ptrdiff_t>(lhs._v) & static_cast<ptrdiff_t>(3)) !=
(reinterpret_cast<ptrdiff_t>(rhs._v) & static_cast<ptrdiff_t>(3))) {
return false;
} else if (lhs.isVec() && rhs.isVec()) {
return (*lhs.toVec()) == (*rhs.toVec());
} else if (lhs.isInt() && rhs.isInt()) {
return lhs.toInt() == rhs.toInt();
} else {
return reinterpret_cast<ptrdiff_t>(lhs._v) == reinterpret_cast<ptrdiff_t>(rhs._v);
}
}
inline bool operator<=(const Val& x, const Val& y) {
return y.isPlusInfinity() || x.isMinusInfinity() ||
(x.isFinite() && y.isFinite() && x.toInt() <= y.toInt());
}
inline bool operator<(const Val& x, const Val& y) {
return (y.isPlusInfinity() && !x.isPlusInfinity()) ||
(x.isMinusInfinity() && !y.isMinusInfinity()) ||
(x.isFinite() && y.isFinite() && x.toInt() < y.toInt());
}
inline bool operator>=(const Val& x, const Val& y) { return y <= x; }
inline bool operator>(const Val& x, const Val& y) { return y < x; }
inline bool operator!=(const Val& x, const Val& y) { return !(x == y); }
inline Val Val::operator-() const {
Val r = *this;
r._v = reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(r._v) ^ static_cast<ptrdiff_t>(4));
return r;
}
inline Val Val::infinity(void) {
Val v;
v._v = reinterpret_cast<void*>(static_cast<ptrdiff_t>(2));
return v;
}
inline Val Val::fromIntVal(const IntVal& iv) {
if (iv.isPlusInfinity()) return Val::infinity();
if (iv.isMinusInfinity()) return -Val::infinity();
return iv.toIntUnsafe();
}
inline bool Val::isFinite(void) const {
assert(isInt());
return ((reinterpret_cast<ptrdiff_t>(_v) & static_cast<ptrdiff_t>(2)) == 0);
}
inline bool Val::isPlusInfinity(void) const {
assert(isInt());
return ((reinterpret_cast<ptrdiff_t>(_v) & static_cast<ptrdiff_t>(6)) ==
static_cast<ptrdiff_t>(2));
}
inline bool Val::isMinusInfinity(void) const {
assert(isInt());
return ((reinterpret_cast<ptrdiff_t>(_v) & static_cast<ptrdiff_t>(6)) ==
static_cast<ptrdiff_t>(6));
}
inline Val& Val::operator+=(const Val& x) {
if (!(isFinite() && x.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
safeSetVal(safePlus(toInt(), x.toInt()));
return *this;
}
inline Val& Val::operator-=(const Val& x) {
if (!(isFinite() && x.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
safeSetVal(safeMinus(toInt(), x.toInt()));
return *this;
}
inline Val& Val::operator*=(const Val& x) {
if (!(isFinite() && x.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
safeSetVal(safeMult(toInt(), x.toInt()));
return *this;
}
inline Val& Val::operator/=(const Val& x) {
if (!(isFinite() && x.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
safeSetVal(safeDiv(toInt(), x.toInt()));
return *this;
}
inline Val& Val::operator++() {
if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
safeSetVal(safePlus(toInt(), 1));
return *this;
}
inline Val Val::operator++(int) {
if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
Val ret = *this;
safeSetVal(safePlus(toInt(), 1));
return ret;
}
inline Val& Val::operator--() {
if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
safeSetVal(safeMinus(toInt(), 1));
return *this;
}
inline Val Val::operator--(int) {
if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
Val ret = *this;
safeSetVal(safeMinus(toInt(), 1));
return ret;
}
inline Val Val::pow(const Val& exponent) {
if (!exponent.isFinite() || !isFinite())
throw ArithmeticError("arithmetic operation on infinite value");
if (exponent == 0) return 1;
if (exponent == 1) return *this;
Val result = 1;
for (int i = 0; i < exponent.toInt(); i++) {
result *= *this;
}
return result;
}
inline Val Val::plus(int x) const {
if (isFinite())
return safePlus(toInt(), x);
else
return *this;
}
inline Val Val::minus(int x) const {
if (isFinite())
return safeMinus(toInt(), x);
else
return *this;
}
/// Return whether an interval ending with \a x overlaps with an interval starting at \a y
inline bool overlaps(const Val& x, const Val& y) { return x.plus(1) >= y; }
inline Val nextHigher(const Val& x) { return x.plus(1); }
inline Val nextLower(const Val& x) { return x.minus(1); }
inline Val operator+(const Val& x, const Val& y) {
if (!(x.isFinite() && y.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
return Val::safePlus(x.toInt(), y.toInt());
}
inline Val operator-(const Val& x, const Val& y) {
if (!(x.isFinite() && y.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
return Val::safeMinus(x.toInt(), y.toInt());
}
inline Val operator*(const Val& x, const Val& y) {
if (!x.isFinite()) {
if (y.isFinite()) {
if (y == 1) return x;
if (y == -1) return -x;
}
} else if (!y.isFinite()) {
if (x == 1) return y;
if (x == -1) return -y;
} else {
return Val::safeMult(x.toInt(), y.toInt());
}
throw ArithmeticError("arithmetic operation on infinite value");
}
inline Val operator/(const Val& x, const Val& y) {
if (y.isFinite()) {
if (y == 1) return x;
if (y == -1) return -x;
}
if (!(x.isFinite() && y.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
return Val::safeDiv(x.toInt(), y.toInt());
}
inline Val operator%(const Val& x, const Val& y) {
if (!(x.isFinite() && y.isFinite()))
throw ArithmeticError("arithmetic operation on infinite value");
return Val::safeMod(x.toInt(), y.toInt());
}
inline Variable* Val::toVar(void) const {
assert(isVar());
return static_cast<Variable*>(toRCO());
}
inline Vec* Val::toVec(void) const {
assert(isVec());
return static_cast<Vec*>(toRCO());
}
/// Iterator over a Vec interpreted as a range set
class VecSetRanges {
/// The vector
const Vec* rs;
/// The current range
int n;
public:
/// Constructor
VecSetRanges(const Vec* r) : rs(r), n(0) {}
/// Check if iterator is still valid
bool operator()(void) const { return n + 1 < rs->size(); }
/// Move to next range
void operator++(void) { n += 2; }
/// Return minimum of current range
Val min(void) const { return (*rs)[n]; }
/// Return maximum of current range
Val max(void) const { return (*rs)[n + 1]; }
/// Return width of current range
Val width(void) const { return (*rs)[n + 1] - (*rs)[n] + 1; }
};
/// Iterator over a std::vector interpreted as a range set
class StdVecSetRanges {
/// The vector
const std::vector<Val>* rs;
/// The current range
int n;
public:
/// Constructor
StdVecSetRanges(const std::vector<Val>* r) : rs(r), n(0) {}
/// Check if iterator is still valid
bool operator()(void) const { return n + 1 < rs->size(); }
/// Move to next range
void operator++(void) { n += 2; }
/// Return minimum of current range
Val min(void) const { return (*rs)[n]; }
/// Return maximum of current range
Val max(void) const { return (*rs)[n + 1]; }
/// Return width of current range
Val width(void) const { return (*rs)[n + 1] - (*rs)[n] + 1; }
};
} // namespace MiniZinc