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

308 lines
8.0 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/. */
#include <minizinc/interpreter.hh>
#include <minizinc/interpreter/primitives.hh>
namespace MiniZinc {
namespace BytecodePrimitives {
IntPlus int_plus;
IntMinus int_minus;
IntSum int_sum;
IntTimes int_times;
IntLinEq int_lin_eq;
IntLinEqReif int_lin_eq_reif;
IntLinLe int_lin_le;
IntLinLeReif int_lin_le_reif;
MkIntVar mk_intvar;
BoolNot boolnot;
OpNot opnot;
Clause clause;
ClauseReif clause_reif;
Forall forall;
Exists exists;
Uniform uniform;
Sol sol;
Sort sort;
SortBy sortby;
IntMax intmax;
Infinity infinity;
InfiniteDomain inf_dom;
BooleanDomain bool_dom;
SliceXd slice_xd;
ArrayXd array_xd;
IndexSet index_set;
PrimitiveMap::Primitive* AllPrimitives[] = {
&int_plus, &int_minus,
&int_sum, &int_times,
&int_lin_eq, &int_lin_eq_reif,
&int_lin_le, &int_lin_le_reif,
&mk_intvar, &boolnot,
&opnot, &clause,
&clause_reif, &forall,
&exists, &uniform,
&sol, &sort,
&sortby, &intmax,
&infinity, &inf_dom,
&bool_dom, &slice_xd,
&array_xd, &index_set,
};
} // namespace BytecodePrimitives
PrimitiveMap::PrimitiveMap(void) : _p(PrimitiveMap::MAX_ID + 1) {
for (PrimitiveMap::Primitive* p : BytecodePrimitives::AllPrimitives) {
_p[p->ident()] = p;
}
for (Primitive* p : _p) {
_s.insert(std::make_pair(p->name(), p));
}
_n.resize(_s.size());
for (auto& entry : _s) {
_n[entry.second->ident()] = entry.first;
}
}
PrimitiveMap& primitiveMap(void) {
static PrimitiveMap _pm;
return _pm;
}
namespace BytecodePrimitives {
void Uniform::execute(Interpreter& i, const std::vector<Val>& args) {
assert(args.size() == 2);
assert(args[0].isInt() && args[1].isInt());
std::uniform_int_distribution<> dis(args[0].toInt(), args[1].toInt());
Val rnd = dis(generator);
i.pushAgg(rnd, -1);
}
void Sol::execute(Interpreter& i, const std::vector<Val>& args) {
assert(args.size() == 1);
if (args[0].isVar()) {
auto it = i.solutions.find(args[0].timestamp());
assert(it != i.solutions.end());
i.pushAgg(Val(it->second), -1);
} else {
assert(args[0].isInt());
i.pushAgg(args[0], -1);
}
};
void Sort::execute(Interpreter& i, const std::vector<Val>& args) {
assert(args.size() == 1);
Val al = args[0].toVec()->raw_data();
std::vector<int> ai(al.size());
for (int j = 0; j < al.size(); j++) {
ai[j] = al[j].toInt();
}
std::stable_sort(ai.begin(), ai.end());
std::vector<Val> sorted(al.size());
for (int j = 0; j < al.size(); j++) {
sorted[j] = Val(ai[j]);
}
Vec* al_sorted = Vec::a(&i, i.newIdent(), sorted);
i.pushAgg(Val(al_sorted), -1);
};
void SortBy::execute(Interpreter& i, const std::vector<Val>& args) {
assert(args.size() == 2);
Val al = args[0].toVec()->raw_data();
Val order_e = args[1].toVec()->raw_data();
std::vector<Val> order(order_e.size());
std::vector<int> a(order_e.size());
for (int j = 0; j < order.size(); j++) {
a[j] = j;
order[j] = order_e[j];
}
struct Ord {
std::vector<Val>& order;
explicit Ord(std::vector<Val>& order0) : order(order0) {}
bool operator()(int i, int j) { return order[i] < order[j]; }
} _ord(order);
std::stable_sort(a.begin(), a.end(), _ord);
std::vector<Val> sorted(a.size());
for (int j = sorted.size(); j--;) {
sorted[j] = al[a[j]];
}
Vec* al_sorted = Vec::a(&i, i.newIdent(), sorted);
i.pushAgg(Val(al_sorted), -1);
};
void Infinity::execute(Interpreter& i, const std::vector<Val>& args) {
assert(args.size() == 1);
assert(args[0].isInt());
if (args[0] > 0) {
i.pushAgg(Val::infinity(), -1);
} else {
i.pushAgg(-Val::infinity(), -1);
}
}
void InfiniteDomain::execute(Interpreter& i, const std::vector<Val>& args) {
assert(args.size() == 0);
i.pushAgg(i.infinite_domain(), -1);
}
void BooleanDomain::execute(Interpreter& i, const std::vector<Val>& args) {
assert(args.size() == 0);
i.pushAgg(i.boolean_domain(), -1);
};
void SliceXd::execute(Interpreter& i, const std::vector<Val>& args) {
assert(args.size() == 3);
assert(args[0].isVec() && args[1].isVec() && args[2].isVec());
Val content = args[0].toVec()->raw_data();
Val selection = args[1].toVec()->raw_data();
Val new_idxs = args[2].toVec()->raw_data();
std::vector<Val> idxs(args[1].size());
std::vector<Val> slice;
// Initialise indexes to the index lower bound
if (args[0].toVec()->hasIndexSet()) {
Val index_set = args[0].toVec()->index_set();
assert(index_set.size() / 2 == selection.size());
for (int j = 0; j < idxs.size(); ++j) {
idxs[j] = index_set[j * 2];
}
} else {
assert(selection.size() == 1);
idxs[0] = 1;
}
// Walk through array and make slice selection
int level = idxs.size() - 1;
int it = 0;
while (level >= 0) {
bool in_slice = true;
for (int k = 0; k < idxs.size(); ++k) {
assert(selection[k].size() == 2);
in_slice = in_slice && selection[k][0] <= idxs[k] && idxs[k] <= selection[k][1];
}
assert(it < content.size());
if (in_slice) {
slice.push_back(content[it]);
}
it++;
while (level >= 0) {
if (args[0].toVec()->hasIndexSet()) {
Val index_set = args[0].toVec()->index_set();
if (idxs[level] < index_set[level * 2 + 1]) {
idxs[level]++;
level = idxs.size() - 1;
break;
} else {
idxs[level] = index_set[level * 2];
level--;
}
} else {
assert(level == 0);
if (idxs[0] < content.size()) {
idxs[0]++;
// No need to reset level, there is only one.
break;
} else {
// Done (no need to reset index values).
level--;
}
}
}
}
// Format new index sets
std::vector<Val> dom;
dom.reserve(new_idxs.size() * 2);
for (int j = 0; j < new_idxs.size(); ++j) {
assert(new_idxs[j].size() == 2);
dom.push_back(new_idxs[j][0]);
dom.push_back(new_idxs[j][1]);
}
Vec* values = Vec::a(&i, i.newIdent(), slice);
Vec* idx = Vec::a(&i, i.newIdent(), dom);
Vec* nv = Vec::a(&i, i.newIdent(), {Val(values), Val(idx)}, true);
i.pushAgg(Val(nv), -1);
}
void ArrayXd::execute(Interpreter& i, const std::vector<Val>& args) {
assert(args.size() == 2);
assert(args[0].isVec());
// Array Elements
Val arr = args[0].toVec()->raw_data();
if (args[1].isInt()) {
assert(args[1].toInt() == 0);
i.pushAgg(arr, -1);
return;
}
assert(args[1].isVec());
assert(args[1].size() % 2 == 0);
// Check if the index sets actually match up
int prod = 1;
for (int i = 0; i < args[1].size(); i += 2) {
prod *= (args[1][i + 1].toInt() - args[1][i].toInt() + 1);
}
if (arr.size() != prod) {
throw std::runtime_error("ArrayXd cardinality mismatch");
}
Val ret = arr;
if (args[1].size() != 0 && !(args[1].size() == 2 && args[1][0].toInt() == 1)) {
ret = Val(Vec::a(&i, i.newIdent(), {arr, args[1]}, true));
}
i.pushAgg(ret, -1);
}
void IndexSet::execute(Interpreter& i, const std::vector<Val>& args) {
assert(args.size() == 2);
assert(args[0].isVec() && args[1].isInt());
Val ret;
if (!args[0].toVec()->hasIndexSet()) {
assert(args[1].toInt() == 1 || args[1] == 0);
ret = Val(Vec::a(&i, i.newIdent(), {Val(1), Val(args[0].size())}));
} else if (args[1] == 0) {
ret = args[0].toVec()->index_set();
} else {
assert(args[0].size() == 2);
assert(args[0][1].isVec());
assert(args[0][1].size() / 2 >= args[1].toInt());
Val index_sets = args[0].toVec()->index_set();
ret = Val(
Vec::a(&i, i.newIdent(),
{index_sets[(args[1].toInt() - 1) * 2], index_sets[(args[1].toInt() - 1) * 2 + 1]}));
}
i.pushAgg(ret, -1);
}
} // namespace BytecodePrimitives
} // namespace MiniZinc