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

901 lines
27 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/. */
#ifndef __MINIZINC_BYTECODE_PRIMITIVES_HH__
#define __MINIZINC_BYTECODE_PRIMITIVES_HH__
#include <minizinc/interpreter/bytecode.hh>
#include <minizinc/interpreter/constraint.hh>
#include <minizinc/interpreter/values.hh>
#include <random>
namespace MiniZinc {
class PrimitiveMap {
public:
enum Id {
// Partial Linear Primitives
INT_PLUS,
INT_MINUS,
INT_SUM,
INT_TIMES,
// Linear Primitives
INT_LIN_EQ,
INT_LIN_EQ_REIF,
INT_LIN_LE,
INT_LIN_LE_REIF,
MK_INTVAR,
BOOLNOT,
OP_NOT,
CLAUSE,
CLAUSE_REIF,
FORALL,
EXISTS,
UNIFORM,
SOL,
SORT,
SORT_BY,
INT_MAX_,
INFINITY_,
INFINITE_DOMAIN,
BOOLEAN_DOMAIN,
SLICE_XD,
ARRAY_XD,
INDEX_SET,
PARTIAL_LINEAR = INT_TIMES,
MAX_LIN = INT_LIN_LE_REIF,
MAX_ID = INDEX_SET,
};
class Primitive {
protected:
std::string _name;
int _n_args;
Id _ident;
Primitive(const std::string& name, const Id& ident0, int n_args0)
: _name(name), _n_args(n_args0), _ident(ident0) {}
public:
PropStatus ps_combine(const PropStatus& ps0, const PropStatus& ps1) {
if (ps0 == PS_FAILED || ps1 == PS_FAILED) return PS_FAILED;
if (ps0 == PS_ENTAILED || ps1 == PS_ENTAILED) return PS_ENTAILED;
return PS_OK;
}
const Id& ident(void) const { return _ident; }
int n_args(void) const { return _n_args; }
const std::string& name(void) const { return _name; }
virtual PropStatus subscribe(Interpreter& i, Constraint* c) const {
assert(false);
throw Error("internal error");
};
virtual void unsubscribe(Interpreter& i, Constraint* c) const {
assert(false);
throw Error("internal error");
};
virtual PropStatus propagate(Interpreter& i, Constraint* c) const {
assert(false);
throw Error("internal error");
};
virtual void execute(Interpreter& i, const std::vector<Val>& args) {
assert(false);
throw Error("internal error");
};
};
protected:
std::vector<Primitive*> _p;
std::unordered_map<std::string, Primitive*> _s;
std::vector<std::string> _n;
public:
PrimitiveMap(void);
Primitive* operator[](const std::string& s) { return _s[s]; }
Primitive* operator[](int i) {
assert(i >= 0 && i <= MAX_ID);
assert(_p.size() == MAX_ID + 1);
return _p[i];
}
std::vector<Primitive*>::iterator begin(void) { return _p.begin(); }
std::vector<Primitive*>::iterator end(void) { return _p.end(); }
int size(void) const { return _n.size(); }
};
PrimitiveMap& primitiveMap(void);
namespace BytecodePrimitives {
class IntPlus : public PrimitiveMap::Primitive {
public:
IntPlus(void) : PrimitiveMap::Primitive("int_plus", PrimitiveMap::INT_PLUS, 3) {}
virtual PropStatus subscribe(Interpreter& interpreter, Constraint* c) const {
Val lb = Val::follow_alias(c->arg(0), &interpreter).lb() +
Val::follow_alias(c->arg(1), &interpreter).lb();
Val ub = Val::follow_alias(c->arg(0), &interpreter).ub() +
Val::follow_alias(c->arg(1), &interpreter).ub();
std::vector<Val> ndom = {lb, ub};
// TODO: We officially don't know that it is not binding
c->arg(2).toVar()->domain(&interpreter, ndom, false);
return PS_OK;
}
};
class IntMinus : public PrimitiveMap::Primitive {
public:
IntMinus(void) : PrimitiveMap::Primitive("int_minus", PrimitiveMap::INT_MINUS, 3) {}
virtual PropStatus subscribe(Interpreter& interpreter, Constraint* c) const {
Val lb = Val::follow_alias(c->arg(0), &interpreter).lb() -
Val::follow_alias(c->arg(1), &interpreter).ub();
Val ub = Val::follow_alias(c->arg(0), &interpreter).ub() -
Val::follow_alias(c->arg(1), &interpreter).lb();
std::vector<Val> ndom = {lb, ub};
// TODO: We officially don't know that it is not binding
c->arg(2).toVar()->domain(&interpreter, ndom, false);
return PS_OK;
}
};
class IntSum : public PrimitiveMap::Primitive {
public:
IntSum(void) : PrimitiveMap::Primitive("int_sum", PrimitiveMap::INT_SUM, 2) {}
virtual PropStatus subscribe(Interpreter& interpreter, Constraint* c) const {
Val lb = 0;
Val ub = 0;
Val arr = c->arg(0).toVec()->raw_data();
for (int i = 0; i < arr.size(); ++i) {
lb += Val::follow_alias(arr[i], &interpreter).lb();
ub += Val::follow_alias(arr[i], &interpreter).ub();
}
std::vector<Val> ndom = {lb, ub};
// TODO: We officially don't know that it is not binding
c->arg(1).toVar()->domain(&interpreter, ndom, false);
return PS_OK;
}
};
class IntTimes : public PrimitiveMap::Primitive {
public:
IntTimes(void) : PrimitiveMap::Primitive("int_times", PrimitiveMap::INT_TIMES, 3) {}
virtual PropStatus subscribe(Interpreter& i, Constraint* c) const {
assert(c->mode() == BytecodeProc::ROOT);
bool propImmediately = true;
for (int j = 0; j < _n_args; ++j) {
Val arg = Val::follow_alias(c->arg(j), &i);
if (arg.isVar()) {
arg.toVar()->subscribe(c, Variable::SES_ANY);
if (j <= 1 && !arg.toVar()->isBounded()) {
propImmediately = false;
}
}
}
if (propImmediately) {
return propagate(i, c);
} else {
return PS_OK;
}
}
virtual void unsubscribe(Interpreter& i, Constraint* c) const {
for (int j = 0; j < _n_args; ++j) {
Val arg = Val::follow_alias(c->arg(j));
if (arg.isVar()) {
arg.toVar()->unsubscribe(c);
}
}
}
virtual PropStatus propagate(Interpreter& i, Constraint* c) const {
Val a = Val::follow_alias(c->arg(0), &i);
Val b = Val::follow_alias(c->arg(1), &i);
Val res = Val::follow_alias(c->arg(2), &i);
if (b.isInt() && a.isVar()) {
std::swap(a, b);
}
Val lb, ub;
if ((a.isVar() && !a.toVar()->isBounded()) || (b.isVar() && !b.toVar()->isBounded())) {
return PS_OK;
}
if (a.isInt() && a == 1) {
if (res.isVar()) {
if (b.isVar()) {
bool success = res.toVar()->intersectDom(&i, Val(b.toVar()->domain()));
if (!success) {
return PS_FAILED;
}
res.toVar()->alias(&i, b);
return PS_ENTAILED;
} else {
return res.toVar()->setVal(&i, b.toInt()) ? PS_ENTAILED : PS_FAILED;
}
} else {
if (b.isVar()) {
return b.toVar()->setVal(&i, res.toInt()) ? PS_ENTAILED : PS_FAILED;
} else {
return res.toInt() == b.toInt() ? PS_ENTAILED : PS_FAILED;
}
}
}
if (a.lb() > 0 && b.lb() > 0) {
lb = a.lb() * b.lb();
ub = a.ub() * b.ub();
} else {
std::vector<Val> mults = {a.lb() * b.lb(), a.lb() * b.ub(), a.ub() * b.lb(), a.ub() * b.ub()};
lb = *std::min_element(mults.begin(), mults.end());
ub = *std::max_element(mults.begin(), mults.end());
}
if (lb == ub) {
if (res.isVar()) {
return res.toVar()->setVal(&i, lb) ? PS_ENTAILED : PS_FAILED;
} else {
return res.toInt() == lb ? PS_ENTAILED : PS_FAILED;
}
} else {
if (res.isVar()) {
return res.toVar()->intersectDom(&i, {lb, ub}) ? PS_OK : PS_FAILED;
} else {
return (res.toInt() >= lb && res.toInt() <= ub) ? PS_OK : PS_FAILED;
}
}
// TODO: Backwards Propagation
}
};
class IntLinEq : public PrimitiveMap::Primitive {
public:
IntLinEq(void) : PrimitiveMap::Primitive("int_lin_eq", PrimitiveMap::INT_LIN_EQ, 3) {}
virtual PropStatus subscribe(Interpreter& i, Constraint* c) const {
// Check me: linear equation should be in its simplified form.
bool propImmediately = false;
int vars = 0;
Val arr = c->arg(1).toVec()->raw_data();
for (unsigned int j = 0; j < arr.size(); j++) {
Val v = arr[j];
assert(v.isVar());
v.toVar()->subscribe(c, Variable::SES_VAL);
}
if (arr.size() <= 2 /* || propImmediately */) {
return propagate(i, c);
} else {
return PS_OK;
}
}
virtual void unsubscribe(Interpreter& i, Constraint* c) const {
Val arr = c->arg(1).toVec()->raw_data();
for (int j = 0; j < arr.size(); ++j) {
Val arg = Val::follow_alias(arr[j], &i);
if (arg.isVar()) {
arg.toVar()->unsubscribe(c);
}
}
}
virtual PropStatus propagate(Interpreter& i, Constraint* c) const {
Val var = c->arg(1).toVec()->raw_data();
Val weight = c->arg(0).toVec()->raw_data();
if (var.size() == 1) {
Val v = Val::follow_alias(var[0], &i);
if (v.isVar()) {
if (c->arg(2) % weight[0] == 0) {
return v.toVar()->setVal(&i, c->arg(2) / weight[0]) ? PS_ENTAILED : PS_FAILED;
} else {
return PS_FAILED;
}
} else {
// aliased to val
return weight[0] * v == c->arg(2) ? PS_ENTAILED : PS_FAILED;
}
}
if (var.size() == 2) {
Val lhs = Val::follow_alias(var[0], &i);
Val rhs = Val::follow_alias(var[1], &i);
Val lhs_c = weight[0];
Val rhs_c = weight[1];
if (!lhs.isVar()) {
std::swap(lhs, rhs);
std::swap(lhs_c, rhs_c);
}
if (lhs.isVar()) {
if (rhs.isVar()) {
if (c->arg(2) == 0 && (lhs_c + rhs_c) == 0) {
if (lhs.toVar()->timestamp() < rhs.toVar()->timestamp()) {
std::swap(lhs, rhs);
}
bool success = rhs.toVar()->intersectDom(&i, Val(lhs.toVar()->domain()));
if (!success) {
return PS_FAILED;
}
lhs.toVar()->alias(&i, rhs);
return PS_ENTAILED;
}
} else {
if (c->arg(2) % lhs_c == 0) {
return lhs.toVar()->setVal(&i, (c->arg(2) - rhs_c * rhs) / lhs_c) ? PS_ENTAILED
: PS_FAILED;
} else {
return PS_FAILED;
}
}
} else {
return lhs * lhs_c + rhs * rhs_c == c->arg(2) ? PS_ENTAILED : PS_FAILED;
}
}
// More propagation?
return PS_OK;
}
};
class IntLinEqReif : public PrimitiveMap::Primitive {
public:
IntLinEqReif(void)
: PrimitiveMap::Primitive("int_lin_eq_reif", PrimitiveMap::INT_LIN_EQ_REIF, 4) {}
virtual PropStatus subscribe(Interpreter& i, Constraint* c) const {
// Check me: linear equation should be in its simplified form.
bool propImmediately = false;
int vars = 0;
Val arr = c->arg(1).toVec()->raw_data();
for (unsigned int j = 0; j < arr.size(); j++) {
Val v = arr[j];
assert(v.isVar());
v.toVar()->subscribe(c, Variable::SES_VAL);
}
if (c->arg(3).isVar()) {
c->arg(3).toVar()->subscribe(c, Variable::SES_VAL);
}
if (arr.size() <= 1 /* || propImmediately */) {
return propagate(i, c);
} else {
return PS_OK;
}
}
virtual void unsubscribe(Interpreter& i, Constraint* c) const {
Val arr = c->arg(1).toVec()->raw_data();
for (int j = 0; j < arr.size(); ++j) {
Val arg = Val::follow_alias(arr[j], &i);
if (arg.isVar()) {
arg.toVar()->unsubscribe(c);
}
}
Val r = Val::follow_alias(c->arg(3), &i);
if (r.isVar()) {
r.toVar()->subscribe(c, Variable::SES_VAL);
}
}
virtual PropStatus propagate(Interpreter& i, Constraint* c) const {
Val var = c->arg(1).toVec()->raw_data();
Val weight = c->arg(0).toVec()->raw_data();
Val r = Val::follow_alias(c->arg(3), &i);
if (r.isInt()) {
// TODO: Rewrite to int_lin_eq
return PS_OK;
}
if (var.size() == 1) {
Val v = Val::follow_alias(var[0], &i);
Val mult = Val::follow_alias(weight[0], &i);
if (v.isVar()) {
if (c->arg(2) % mult == 0) {
Val res = c->arg(2) / mult;
Vec* dom = v.toVar()->domain();
bool indom = true;
for (int j = 0; j < dom->size(); j += 2) {
if ((*dom)[j] <= res && res <= (*dom)[j + 1]) {
return PS_OK;
}
}
return r.toVar()->setVal(&i, false) ? PS_ENTAILED : PS_FAILED;
} else {
return PS_FAILED;
}
} else {
// aliased to val
return r.toVar()->setVal(&i, mult * v == c->arg(2)) ? PS_ENTAILED : PS_FAILED;
}
}
// More propagation?
return PS_OK;
}
};
class IntLinLe : public PrimitiveMap::Primitive {
public:
IntLinLe(void) : PrimitiveMap::Primitive("int_lin_le", PrimitiveMap::INT_LIN_LE, 3) {}
virtual PropStatus subscribe(Interpreter& i, Constraint* c) const {
// Check me: linear equation should be in its simplified form.
Val arr = c->arg(1).toVec()->raw_data();
for (unsigned int j = 0; j < arr.size(); j++) {
Val v = arr[j];
assert(v.isVar()); // cannot be alias because of simplify_linexp
v.toVar()->subscribe(c, Variable::SES_VAL);
}
if (arr.size() <= 2 /* || propImmediately */) {
return propagate(i, c);
} else {
return PS_OK;
}
}
virtual void unsubscribe(Interpreter& i, Constraint* c) const {
Val arr = c->arg(1).toVec()->raw_data();
for (int j = 0; j < arr.size(); ++j) {
Val arg = Val::follow_alias(arr[j], &i);
if (arg.isVar()) {
arg.toVar()->unsubscribe(c);
}
}
}
virtual PropStatus propagate(Interpreter& i, Constraint* c) const {
Val var = c->arg(1).toVec()->raw_data();
Val weight = c->arg(0).toVec()->raw_data();
if (var.size() == 1) {
Val v = Val::follow_alias(var[0], &i);
if (v.isVar()) {
Val newBound = c->arg(2) / weight[0];
if (weight[0] > 0) {
return v.toVar()->setMax(&i, newBound) ? PS_ENTAILED : PS_FAILED;
} else {
return v.toVar()->setMin(&i, newBound) ? PS_ENTAILED : PS_FAILED;
}
} else {
// aliased to val
return weight[0] * v <= c->arg(2) ? PS_ENTAILED : PS_FAILED;
}
}
// More propagation?
return PS_OK;
}
};
class IntLinLeReif : public PrimitiveMap::Primitive {
public:
IntLinLeReif(void)
: PrimitiveMap::Primitive("int_lin_le_reif", PrimitiveMap::INT_LIN_LE_REIF, 4) {}
virtual PropStatus subscribe(Interpreter& i, Constraint* c) const {
// Check me: linear equation should be in its simplified form.
Val arr = c->arg(1).toVec()->raw_data();
for (unsigned int j = 0; j < arr.size(); j++) {
Val v = arr[j];
assert(v.isVar()); // cannot be alias because of simplify_linexp
v.toVar()->subscribe(c, Variable::SES_VAL);
}
if (c->arg(3).isVar()) {
c->arg(3).toVar()->subscribe(c, Variable::SES_VAL);
}
if (arr.size() <= 1 /* || propImmediately */) {
return propagate(i, c);
} else {
return PS_OK;
}
}
virtual void unsubscribe(Interpreter& i, Constraint* c) const {
Val arr = c->arg(1).toVec()->raw_data();
for (int j = 0; j < arr.size(); ++j) {
Val arg = Val::follow_alias(arr[j], &i);
if (arg.isVar()) {
arg.toVar()->unsubscribe(c);
}
}
Val r = Val::follow_alias(c->arg(3), &i);
if (r.isVar()) {
r.toVar()->unsubscribe(c);
}
}
virtual PropStatus propagate(Interpreter& i, Constraint* c) const {
Val var = c->arg(1).toVec()->raw_data();
Val weight = c->arg(0).toVec()->raw_data();
Val r = Val::follow_alias(c->arg(3), &i);
if (r.isInt()) {
// TODO: Replace with int_lin_le
return PS_OK;
}
if (var.size() == 1) {
Val mult = weight[0];
Val v = Val::follow_alias(var[0], &i);
if (v.isVar()) {
if (mult * v.lb() <= c->arg(2) && mult * v.ub() <= c->arg(2)) {
return r.toVar()->setVal(&i, true) ? PS_ENTAILED : PS_FAILED;
} else if (mult * v.lb() > c->arg(2) && mult * v.ub() > c->arg(2)) {
return r.toVar()->setVal(&i, false) ? PS_ENTAILED : PS_FAILED;
}
} else {
// aliased to val
return r.toVar()->setVal(&i, mult * v <= c->arg(2)) ? PS_ENTAILED : PS_FAILED;
}
}
// More propagation?
return PS_OK;
}
};
class MkIntVar : public PrimitiveMap::Primitive {
public:
MkIntVar(void) : PrimitiveMap::Primitive("mk_intvar", PrimitiveMap::MK_INTVAR, 1) {}
};
class BoolNot : public PrimitiveMap::Primitive {
public:
BoolNot(void) : PrimitiveMap::Primitive("bool_not", PrimitiveMap::BOOLNOT, 2) {}
virtual PropStatus subscribe(Interpreter& i, Constraint* c) const {
bool propImmediately = false;
for (unsigned int j = 0; j < _n_args; j++) {
Val arg = c->arg(j);
if (arg.isVar()) {
arg.toVar()->subscribe(c, Variable::SES_VAL);
} else {
propImmediately = true;
}
}
if (propImmediately) {
return propagate(i, c);
} else {
return PS_OK;
}
}
virtual void unsubscribe(Interpreter& i, Constraint* c) const {
for (unsigned int j = 0; j < _n_args; j++) {
Val arg = Val::follow_alias(c->arg(j), &i);
if (arg.isVar()) {
arg.toVar()->unsubscribe(c);
}
}
}
virtual PropStatus propagate(Interpreter& i, Constraint* c) const {
Val lhs = Val::follow_alias(c->arg(0), &i);
Val rhs = Val::follow_alias(c->arg(1), &i);
if (!lhs.isInt()) {
std::swap(lhs, rhs);
}
if (!lhs.isInt()) {
return PS_OK;
}
if (rhs.isInt()) {
return lhs == rhs ? PS_ENTAILED : PS_FAILED;
}
return rhs.toVar()->setVal(&i, 1 - lhs) ? PS_ENTAILED : PS_FAILED;
}
};
// Reserve procedure code for op_not operation (to create CSE entries)
class OpNot : public PrimitiveMap::Primitive {
public:
OpNot(void) : PrimitiveMap::Primitive("f_op_not_vb", PrimitiveMap::OP_NOT, 1) {}
};
class Clause : public PrimitiveMap::Primitive {
public:
Clause(void) : PrimitiveMap::Primitive("bool_clause", PrimitiveMap::CLAUSE, 2) {}
virtual PropStatus subscribe(Interpreter& i, Constraint* c) const {
bool propImmediately = false;
Val pos = c->arg(0).toVec()->raw_data();
Val neg = c->arg(1).toVec()->raw_data();
for (unsigned int i = 0; i < pos.size(); i++) {
if (pos[i].isVar()) {
pos[i].toVar()->subscribe(c, Variable::SES_VAL);
} else {
propImmediately = true;
}
}
for (unsigned int i = 0; i < neg.size(); i++) {
if (neg[i].isVar()) {
neg[i].toVar()->subscribe(c, Variable::SES_VAL);
} else {
propImmediately = true;
}
}
if (propImmediately) {
return propagate(i, c);
} else {
return PS_OK;
}
}
virtual void unsubscribe(Interpreter& i, Constraint* c) const {
Val pos = c->arg(0).toVec()->raw_data();
Val neg = c->arg(1).toVec()->raw_data();
for (unsigned int i = 0; i < pos.size(); i++) {
Val arg = Val::follow_alias(pos[i]);
if (arg.isVar()) {
arg.toVar()->unsubscribe(c);
}
}
for (unsigned int i = 0; i < neg.size(); i++) {
Val arg = Val::follow_alias(neg[i]);
if (arg.isVar()) {
arg.toVar()->unsubscribe(c);
}
}
}
virtual PropStatus propagate(Interpreter& i, Constraint* c) const { return PS_OK; }
};
class ClauseReif : public PrimitiveMap::Primitive {
public:
ClauseReif(void) : PrimitiveMap::Primitive("bool_clause_reif", PrimitiveMap::CLAUSE_REIF, 3) {}
virtual PropStatus subscribe(Interpreter& i, Constraint* c) const {
bool propImmediately = false;
Val pos = c->arg(0).toVec()->raw_data();
Val neg = c->arg(1).toVec()->raw_data();
for (unsigned int i = 0; i < pos.size(); i++) {
if (pos[i].isVar()) {
pos[i].toVar()->subscribe(c, Variable::SES_VAL);
} else {
propImmediately = true;
}
}
for (unsigned int i = 0; i < neg.size(); i++) {
if (neg[i].isVar()) {
neg[i].toVar()->subscribe(c, Variable::SES_VAL);
} else {
propImmediately = true;
}
}
if (c->arg(2).isVar()) {
c->arg(2).toVar()->subscribe(c, Variable::SES_VAL);
}
if (propImmediately) {
return propagate(i, c);
} else {
return PS_OK;
}
}
virtual void unsubscribe(Interpreter& i, Constraint* c) const {
Val pos = c->arg(0).toVec()->raw_data();
Val neg = c->arg(1).toVec()->raw_data();
for (unsigned int i = 0; i < pos.size(); i++) {
Val arg = Val::follow_alias(pos[i]);
if (arg.isVar()) {
arg.toVar()->unsubscribe(c);
}
}
for (unsigned int i = 0; i < neg.size(); i++) {
Val arg = Val::follow_alias(neg[i]);
if (arg.isVar()) {
arg.toVar()->unsubscribe(c);
}
}
Val arg = Val::follow_alias(c->arg(2));
if (arg.isVar()) {
arg.toVar()->unsubscribe(c);
}
}
virtual PropStatus propagate(Interpreter& i, Constraint* c) const { return PS_OK; }
};
class Forall : public PrimitiveMap::Primitive {
public:
Forall(void) : PrimitiveMap::Primitive("array_bool_and", PrimitiveMap::FORALL, 2) {}
virtual PropStatus subscribe(Interpreter& i, Constraint* c) const {
bool propImmediately = false;
Val arr = c->arg(0).toVec()->raw_data();
for (unsigned int j = 0; j < arr.size(); j++) {
if (arr[j].isVar()) {
arr[j].toVar()->subscribe(c, Variable::SES_VAL);
} else {
propImmediately = true;
}
}
if (c->arg(1).isVar()) {
c->arg(1).toVar()->subscribe(c, Variable::SES_VAL);
} else {
propImmediately = true;
}
if (propImmediately) {
return propagate(i, c);
} else {
return PS_OK;
}
}
virtual void unsubscribe(Interpreter& i, Constraint* c) const {
Val arr = c->arg(0).toVec()->raw_data();
for (unsigned int i = 0; i < arr.size(); i++) {
Val arg = Val::follow_alias(arr[i]);
if (arg.isVar()) {
arg.toVar()->unsubscribe(c);
}
}
Val arg = Val::follow_alias(c->arg(1));
if (arg.isVar()) {
arg.toVar()->unsubscribe(c);
}
}
virtual PropStatus propagate(Interpreter& i, Constraint* c) const { return PS_OK; }
};
class Exists : public PrimitiveMap::Primitive {
public:
Exists(void) : PrimitiveMap::Primitive("array_bool_or", PrimitiveMap::EXISTS, 2) {}
virtual PropStatus subscribe(Interpreter& i, Constraint* c) const {
bool propImmediately = false;
Val arr = c->arg(0).toVec()->raw_data();
for (int j = 0; j < arr.size(); ++j) {
if (arr[j].isVar()) {
arr[j].toVar()->subscribe(c, Variable::SES_VAL);
} else {
propImmediately = true;
}
}
if (c->arg(1).isVar()) {
c->arg(1).toVar()->subscribe(c, Variable::SES_VAL);
} else {
propImmediately = true;
}
if (propImmediately) {
return propagate(i, c);
} else {
return PS_OK;
}
}
virtual void unsubscribe(Interpreter& i, Constraint* c) const {
Val arr = c->arg(0).toVec()->raw_data();
for (int j = 0; j < arr.size(); ++j) {
Val arg = Val::follow_alias(arr[j], &i);
if (arg.isVar()) {
arg.toVar()->unsubscribe(c);
}
}
}
virtual PropStatus propagate(Interpreter& i, Constraint* c) const { return PS_OK; }
};
class Uniform : public PrimitiveMap::Primitive {
public:
Uniform() : PrimitiveMap::Primitive("uniform", PrimitiveMap::UNIFORM, 2) {
std::random_device rnd;
generator = std::mt19937(0);
}
virtual void execute(Interpreter& i, const std::vector<Val>& args);
void setSeed(int seed) { generator = std::mt19937(seed); }
private:
std::mt19937 generator;
};
class Sol : public PrimitiveMap::Primitive {
public:
Sol() : PrimitiveMap::Primitive("sol", PrimitiveMap::SOL, 1) {}
virtual void execute(Interpreter& i, const std::vector<Val>& args);
};
class Sort : public PrimitiveMap::Primitive {
public:
Sort() : PrimitiveMap::Primitive("internal_sort", PrimitiveMap::SORT, 1) {}
virtual void execute(Interpreter& i, const std::vector<Val>& args);
};
class SortBy : public PrimitiveMap::Primitive {
public:
SortBy() : PrimitiveMap::Primitive("sort_by", PrimitiveMap::SORT_BY, 2) {}
virtual void execute(Interpreter& i, const std::vector<Val>& args);
};
class IntMax : public PrimitiveMap::Primitive {
public:
IntMax(void) : PrimitiveMap::Primitive("int_max", PrimitiveMap::INT_MAX_, 3) {}
virtual PropStatus subscribe(Interpreter& i, Constraint* c) const {
bool propImmediately = true;
for (int j = 0; j < _n_args; ++j) {
Val arg = Val::follow_alias(c->arg(j), &i);
if (arg.isVar()) {
arg.toVar()->subscribe(c, Variable::SES_ANY);
if (!arg.toVar()->isBounded()) {
propImmediately = false;
}
}
}
if (propImmediately) {
return propagate(i, c);
} else {
return PS_OK;
}
}
virtual void unsubscribe(Interpreter& i, Constraint* c) const {
for (int j = 0; j < _n_args; ++j) {
Val arg = Val::follow_alias(c->arg(j), &i);
if (arg.isVar()) {
arg.toVar()->unsubscribe(c);
}
}
}
virtual PropStatus propagate(Interpreter& i, Constraint* con) const {
Val a = Val::follow_alias(con->arg(0), &i);
Val b = Val::follow_alias(con->arg(1), &i);
Val c = Val::follow_alias(con->arg(2), &i);
if ((a.isVar() && !a.toVar()->isBounded()) || (b.isVar() && !b.toVar()->isBounded())) {
return PS_OK;
} else if (a.ub() <= b.lb() || a.ub() < c.lb() || a.lb() > c.ub()) {
if (c.isVar()) {
c.toVar()->alias(&i, b);
return PS_ENTAILED;
} else if (b.isVar()) {
return b.toVar()->setVal(&i, c) ? PS_ENTAILED : PS_FAILED;
} else {
return b == c ? PS_ENTAILED : PS_FAILED;
}
} else if (b.ub() <= a.lb() || b.ub() < c.lb() || b.lb() > c.ub()) {
if (c.isVar()) {
c.toVar()->alias(&i, a);
return PS_ENTAILED;
} else if (a.isVar()) {
return a.toVar()->setVal(&i, c) ? PS_ENTAILED : PS_FAILED;
} else {
return a == c ? PS_ENTAILED : PS_FAILED;
}
}
Val lb, ub;
lb = std::max(a.lb(), b.lb());
ub = std::max(a.ub(), b.ub());
// FIXME: c is not guaranteed to be a variable
if (lb == ub) {
return c.toVar()->setVal(&i, lb) ? PS_ENTAILED : PS_FAILED;
} else {
return c.toVar()->intersectDom(&i, {lb, ub}) ? PS_OK : PS_FAILED;
}
}
};
class Infinity : public PrimitiveMap::Primitive {
public:
Infinity() : PrimitiveMap::Primitive("infinity", PrimitiveMap::INFINITY_, 1) {}
virtual void execute(Interpreter& i, const std::vector<Val>& args);
};
class InfiniteDomain : public PrimitiveMap::Primitive {
public:
InfiniteDomain() : PrimitiveMap::Primitive("infinite_domain", PrimitiveMap::INFINITE_DOMAIN, 0) {}
virtual void execute(Interpreter& i, const std::vector<Val>& args);
};
class BooleanDomain : public PrimitiveMap::Primitive {
public:
BooleanDomain() : PrimitiveMap::Primitive("boolean_domain", PrimitiveMap::BOOLEAN_DOMAIN, 0) {}
virtual void execute(Interpreter& i, const std::vector<Val>& args);
};
class SliceXd : public PrimitiveMap::Primitive {
public:
SliceXd() : PrimitiveMap::Primitive("slice_Xd", PrimitiveMap::SLICE_XD, 3) {}
virtual void execute(Interpreter& i, const std::vector<Val>& args);
};
class ArrayXd : public PrimitiveMap::Primitive {
public:
ArrayXd() : PrimitiveMap::Primitive("array_Xd", PrimitiveMap::ARRAY_XD, 2) {}
virtual void execute(Interpreter& i, const std::vector<Val>& args);
};
class IndexSet : public PrimitiveMap::Primitive {
public:
IndexSet() : PrimitiveMap::Primitive("index_set", PrimitiveMap::INDEX_SET, 2) {}
virtual void execute(Interpreter& i, const std::vector<Val>& args);
};
} // namespace BytecodePrimitives
} // namespace MiniZinc
#endif