Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
9.7 kB · 294 lines
C++
at develop
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295/* -*- 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/. */
#include <minizinc/flat_exp.hh>
namespace MiniZinc {
EE flatten_arrayaccess(EnvI& env, const Ctx& ctx, Expression* e, VarDecl* r, VarDecl* b) { CallStackItem _csi(env, e); EE ret; auto* aa = e->cast<ArrayAccess>(); KeepAlive aa_ka = aa;
Ctx nctx = ctx; nctx.b = +nctx.b; nctx.neg = false; EE eev = flat_exp(env, nctx, aa->v(), nullptr, nullptr); std::vector<EE> ees;
start_flatten_arrayaccess: for (unsigned int i = 0; i < aa->idx().size(); i++) { Expression* tmp = follow_id_to_decl(aa->idx()[i]); if (auto* vd = tmp->dynamicCast<VarDecl>()) { tmp = vd->id(); } if (tmp->type().isPar()) { ArrayLit* al; if (eev.r()->isa<ArrayLit>()) { al = eev.r()->cast<ArrayLit>(); } else { Id* id = eev.r()->cast<Id>(); if (id->decl() == nullptr) { throw InternalError("undefined identifier"); } if (id->decl()->e() == nullptr) { throw InternalError("array without initialiser not supported"); } Expression* id_e = follow_id(id); if (id_e->isa<ArrayLit>()) { al = id_e->cast<ArrayLit>(); } else { throw InternalError("builtin function returning array not supported"); } }
std::vector<KeepAlive> elems; std::vector<IntVal> idx(aa->idx().size()); std::vector<std::pair<int, int> > dims; std::vector<Expression*> newaccess; std::vector<int> nonpar; std::vector<int> stack; for (unsigned int j = 0; j < aa->idx().size(); j++) { Expression* tmp = follow_id_to_decl(aa->idx()[j]); if (auto* vd = tmp->dynamicCast<VarDecl>()) { tmp = vd->id(); } if (tmp->type().isPar()) { GCLock lock; idx[j] = eval_int(env, tmp).toInt(); } else { idx[j] = al->min(j); stack.push_back(static_cast<int>(nonpar.size())); nonpar.push_back(j); dims.emplace_back(al->min(j), al->max(j)); newaccess.push_back(aa->idx()[j]); } } if (stack.empty()) { bool success; KeepAlive ka; { GCLock lock; ka = eval_arrayaccess(env, al, idx, success); if (!success && env.inMaybePartial == 0) { ResultUndefinedError warning(env, al->loc(), "array access out of bounds"); } } ees.emplace_back(nullptr, constants().boollit(success)); ees.emplace_back(nullptr, eev.b()); if (aa->type().isbool() && !aa->type().isOpt()) { ret.b = bind(env, Ctx(), b, constants().literalTrue); ees.emplace_back(nullptr, ka()); ret.r = conj(env, r, ctx, ees); } else { ret.b = conj(env, b, ctx, ees); ret.r = bind(env, ctx, r, ka()); } return ret; } while (!stack.empty()) { int cur = stack.back(); if (cur == nonpar.size() - 1) { stack.pop_back(); for (int i = al->min(nonpar[cur]); i <= al->max(nonpar[cur]); i++) { idx[nonpar[cur]] = i; bool success; GCLock lock; Expression* al_idx = eval_arrayaccess(env, al, idx, success); if (!success) { if (env.inMaybePartial == 0) { ResultUndefinedError warning(env, al->loc(), "array access out of bounds"); } ees.emplace_back(nullptr, constants().literalFalse); ees.emplace_back(nullptr, eev.b()); if (aa->type().isbool() && !aa->type().isOpt()) { ret.b = bind(env, Ctx(), b, constants().literalTrue); ret.r = conj(env, r, ctx, ees); } else { ret.b = conj(env, b, ctx, ees); ret.r = bind(env, ctx, r, al_idx); } return ret; } elems.emplace_back(al_idx); } } else { if (idx[nonpar[cur]].toInt() == al->max(nonpar[cur])) { idx[nonpar[cur]] = al->min(nonpar[cur]); stack.pop_back(); } else { idx[nonpar[cur]]++; for (unsigned int j = cur + 1; j < nonpar.size(); j++) { stack.push_back(j); } } } } std::vector<Expression*> elems_e(elems.size()); for (unsigned int i = 0; i < elems.size(); i++) { elems_e[i] = elems[i](); } { GCLock lock; Expression* newal = new ArrayLit(al->loc(), elems_e, dims); Type t = al->type(); t.dim(static_cast<int>(dims.size())); newal->type(t); eev.r = newal; auto* n_aa = new ArrayAccess(aa->loc(), newal, newaccess); n_aa->type(aa->type()); aa = n_aa; aa_ka = aa; } } }
if (aa->idx().size() == 1 && aa->idx()[0]->isa<ArrayAccess>()) { auto* aa_inner = aa->idx()[0]->cast<ArrayAccess>(); ArrayLit* al; if (eev.r()->isa<ArrayLit>()) { al = eev.r()->cast<ArrayLit>(); } else { Id* id = eev.r()->cast<Id>(); if (id->decl() == nullptr) { throw InternalError("undefined identifier"); } if (id->decl()->e() == nullptr) { throw InternalError("array without initialiser not supported"); } al = follow_id(id)->cast<ArrayLit>(); } if (aa_inner->v()->type().isPar()) { KeepAlive ka_al_inner = flat_cv_exp(env, ctx, aa_inner->v()); auto* al_inner = ka_al_inner()->cast<ArrayLit>(); std::vector<Expression*> composed_e(al_inner->size()); for (unsigned int i = 0; i < al_inner->size(); i++) { GCLock lock; IntVal inner_idx = eval_int(env, (*al_inner)[i]); if (inner_idx < al->min(0) || inner_idx > al->max(0)) { goto flatten_arrayaccess; } composed_e[i] = (*al)[static_cast<int>(inner_idx.toInt()) - al->min(0)]; } std::vector<std::pair<int, int> > dims(al_inner->dims()); for (int i = 0; i < al_inner->dims(); i++) { dims[i] = std::make_pair(al_inner->min(i), al_inner->max(i)); } { GCLock lock; Expression* newal = new ArrayLit(al->loc(), composed_e, dims); Type t = al->type(); t.dim(static_cast<int>(dims.size())); newal->type(t); eev.r = newal; auto* n_aa = new ArrayAccess(aa->loc(), newal, aa_inner->idx()); n_aa->type(aa->type()); aa = n_aa; aa_ka = aa; goto start_flatten_arrayaccess; } } }flatten_arrayaccess: Ctx dimctx = ctx; dimctx.neg = false; for (unsigned int i = 0; i < aa->idx().size(); i++) { Expression* tmp = follow_id_to_decl(aa->idx()[i]); if (auto* vd = tmp->dynamicCast<VarDecl>()) { tmp = vd->id(); } ees.push_back(flat_exp(env, dimctx, tmp, nullptr, nullptr)); } ees.emplace_back(nullptr, eev.b());
bool parAccess = true; for (unsigned int i = 0; i < aa->idx().size(); i++) { if (!ees[i].r()->type().isPar()) { parAccess = false; break; } }
if (parAccess) { ArrayLit* al; if (eev.r()->isa<ArrayLit>()) { al = eev.r()->cast<ArrayLit>(); } else { Id* id = eev.r()->cast<Id>(); if (id->decl() == nullptr) { throw InternalError("undefined identifier"); } if (id->decl()->e() == nullptr) { throw InternalError("array without initialiser not supported"); } al = follow_id(id)->cast<ArrayLit>(); } KeepAlive ka; bool success; { GCLock lock; std::vector<IntVal> dims(aa->idx().size()); for (unsigned int i = aa->idx().size(); (i--) != 0U;) { dims[i] = eval_int(env, ees[i].r()); } ka = eval_arrayaccess(env, al, dims, success); } if (!success && env.inMaybePartial == 0) { ResultUndefinedError warning(env, al->loc(), "array access out of bounds"); } ees.emplace_back(nullptr, constants().boollit(success)); if (aa->type().isbool() && !aa->type().isOpt()) { ret.b = bind(env, Ctx(), b, constants().literalTrue); ees.emplace_back(nullptr, ka()); ret.r = conj(env, r, ctx, ees); } else { ret.b = conj(env, b, ctx, ees); ret.r = bind(env, ctx, r, ka()); } } else { std::vector<Expression*> args(aa->idx().size() + 1); for (unsigned int i = aa->idx().size(); (i--) != 0U;) { args[i] = ees[i].r(); } args[aa->idx().size()] = eev.r(); KeepAlive ka; { GCLock lock; Call* cc = new Call(e->loc().introduce(), constants().ids.element, args); cc->type(aa->type()); FunctionI* fi = env.model->matchFn(env, cc->id(), args, false); if (fi == nullptr) { throw FlatteningError(env, cc->loc(), "cannot find matching declaration"); } assert(fi); assert(env.isSubtype(fi->rtype(env, args, false), cc->type(), false)); cc->decl(fi); ka = cc; } Ctx elemctx = ctx; elemctx.neg = false; EE ee = flat_exp(env, elemctx, ka(), nullptr, nullptr); ees.push_back(ee); if (aa->type().isbool() && !aa->type().isOpt()) { ee.b = ee.r; ees.push_back(ee); ret.r = conj(env, r, ctx, ees); ret.b = bind(env, ctx, b, constants().boollit(!ctx.neg)); } else { ret.r = bind(env, ctx, r, ee.r()); ret.b = conj(env, b, ctx, ees); } } return ret;}
} // namespace MiniZinc