Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
43 kB · 1133 lines
C++
at develop
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134/* -*- 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/astiterator.hh>#include <minizinc/output.hh>
namespace MiniZinc {
void outputVarDecls(EnvI& env, Item* ci, Expression* e);
bool cannotUseRHSForOutput(EnvI& env, Expression* e, std::unordered_set<FunctionI*>& seen_functions) { if (e == NULL) return true;
class V : public EVisitor { public: EnvI& env; std::unordered_set<FunctionI*>& seen_functions; bool success; V(EnvI& env0, std::unordered_set<FunctionI*>& seen_functions0) : env(env0), seen_functions(seen_functions0), success(true) {} /// Visit anonymous variable void vAnonVar(const AnonVar&) { success = false; } /// Visit array literal void vArrayLit(const ArrayLit&) {} /// Visit array access void vArrayAccess(const ArrayAccess&) {} /// Visit array comprehension void vComprehension(const Comprehension&) {} /// Visit if-then-else void vITE(const ITE&) {} /// Visit binary operator void vBinOp(const BinOp&) {} /// Visit unary operator void vUnOp(const UnOp&) {} /// Visit call void vCall(Call& c) { std::vector<Type> tv(c.n_args()); for (unsigned int i = c.n_args(); i--;) { tv[i] = c.arg(i)->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = env.output->matchFn(env, c.id(), tv, false); Type t; if (decl == NULL) { FunctionI* origdecl = env.model->matchFn(env, c.id(), tv, false); if (origdecl == NULL) { throw FlatteningError( env, c.loc(), "function " + c.id().str() + " is used in output, par version needed"); } bool seen = (seen_functions.find(origdecl) != seen_functions.end()); if (seen) { success = false; } else { seen_functions.insert(origdecl); if (origdecl->e() && cannotUseRHSForOutput(env, origdecl->e(), seen_functions)) { success = false; } else { if (!origdecl->from_stdlib()) { decl = copy(env, env.cmap, origdecl)->cast<FunctionI>(); CollectOccurrencesE ce(env.output_vo, decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); env.output->registerFn(env, decl); env.output->addItem(decl); outputVarDecls(env, origdecl, decl->e()); outputVarDecls(env, origdecl, decl->ti()); } else { decl = origdecl; } c.decl(decl); } } } if (success) { t = decl->rtype(env, tv, false); if (!t.ispar()) success = false; } } void vId(const Id& id) {} /// Visit let void vLet(const Let&) { success = false; } /// Visit variable declaration void vVarDecl(const VarDecl& vd) {} /// Visit type inst void vTypeInst(const TypeInst&) {} /// Visit TIId void vTIId(const TIId&) {} /// Determine whether to enter node bool enter(Expression* e) { return success; } } _v(env, seen_functions); topDown(_v, e);
return !_v.success;}
bool cannotUseRHSForOutput(EnvI& env, Expression* e) { std::unordered_set<FunctionI*> seen_functions; return cannotUseRHSForOutput(env, e, seen_functions);}
void removeIsOutput(VarDecl* vd) { if (vd == NULL) return; vd->ann().remove(constants().ann.output_var); vd->ann().removeCall(constants().ann.output_array);}
void copyOutput(EnvI& e) { struct CopyOutput : public EVisitor { EnvI& env; CopyOutput(EnvI& env0) : env(env0) {} void vId(Id& _id) { _id.decl(_id.decl()->flat()); } void vCall(Call& c) { std::vector<Type> tv(c.n_args()); for (unsigned int i = c.n_args(); i--;) { tv[i] = c.arg(i)->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = c.decl(); if (!decl->from_stdlib()) { env.flat_addItem(decl); } } };
if (OutputI* oi = e.model->outputItem()) { GCLock lock; OutputI* noi = copy(e, oi)->cast<OutputI>(); CopyOutput co(e); topDown(co, noi->e()); e.flat_addItem(noi); }}
void cleanupOutput(EnvI& env) { for (unsigned int i = 0; i < env.output->size(); i++) { if (VarDeclI* vdi = (*env.output)[i]->dyn_cast<VarDeclI>()) { vdi->e()->flat(NULL); } }}
void makePar(EnvI& env, Expression* e) { class OutputJSON : public EVisitor { public: EnvI& env; OutputJSON(EnvI& env0) : env(env0) {} void vCall(Call& c) { if (c.id() == "outputJSON") { bool outputObjective = (c.n_args() == 1 && eval_bool(env, c.arg(0))); c.id(ASTString("array1d")); Expression* json = copy(env, env.cmap, createJSONOutput(env, outputObjective, false)); std::vector<Expression*> new_args({json}); new_args[0]->type(Type::parstring(1)); c.args(new_args); } } } _outputJSON(env); topDown(_outputJSON, e); class Par : public EVisitor { public: /// Visit variable declaration void vVarDecl(VarDecl& vd) { vd.ti()->type(vd.type()); } /// Determine whether to enter node bool enter(Expression* e) { Type t = e->type(); t.ti(Type::TI_PAR); e->type(t); return true; } } _par; topDown(_par, e); class Decls : public EVisitor { protected: static std::string createEnumToStringName(Id* ident, std::string prefix) { std::string name = ident->str().str(); if (name[0] == '\'') { name = "'" + prefix + name.substr(1); } else { name = prefix + name; } return name; }
public: EnvI& env; Decls(EnvI& env0) : env(env0) {} void vCall(Call& c) { if (c.id() == "format" || c.id() == "show" || c.id() == "showDzn" || c.id() == "showJSON") { int enumId = c.arg(c.n_args() - 1)->type().enumId(); if (enumId != 0 && c.arg(c.n_args() - 1)->type().dim() != 0) { const std::vector<unsigned int>& enumIds = env.getArrayEnum(enumId); enumId = enumIds[enumIds.size() - 1]; } if (enumId > 0) { Id* ti_id = env.getEnum(enumId)->e()->id(); GCLock lock; std::vector<Expression*> args(3); args[0] = c.arg(c.n_args() - 1); if (args[0]->type().dim() > 1) { std::vector<Expression*> a1dargs(1); a1dargs[0] = args[0]; Call* array1d = new Call(Location().introduce(), ASTString("array1d"), a1dargs); Type array1dt = args[0]->type(); array1dt.dim(1); array1d->type(array1dt); args[0] = array1d; } args[1] = constants().boollit(c.id() == "showDzn"); args[2] = constants().boollit(c.id() == "showJSON"); std::string enumName = createEnumToStringName(ti_id, "_toString_"); c.id(ASTString(enumName)); c.args(args); } if (c.id() == "showDzn" || (c.id() == "showJSON" && enumId > 0)) { c.id(constants().ids.show); } } c.decl(env.model->matchFn(env, &c, false)); } } _decls(env); topDown(_decls, e);}
void checkRenameVar(EnvI& e, VarDecl* vd) { if (vd->id()->idn() != vd->flat()->id()->idn()) { TypeInst* vd_rename_ti = copy(e, e.cmap, vd->ti())->cast<TypeInst>(); VarDecl* vd_rename = new VarDecl(Location().introduce(), vd_rename_ti, vd->flat()->id()->idn(), NULL); vd_rename->flat(vd->flat()); makePar(e, vd_rename); vd->e(vd_rename->id()); e.output->addItem(new VarDeclI(Location().introduce(), vd_rename)); }}
class ClearAnnotations {public: /// Push all elements of \a v onto \a stack template <class E> static void pushVec(std::vector<Expression*>& stack, ASTExprVec<E> v) { for (unsigned int i = 0; i < v.size(); i++) stack.push_back(v[i]); }
static void run(Expression* root) { std::vector<Expression*> stack; stack.push_back(root); while (!stack.empty()) { Expression* e = stack.back(); stack.pop_back(); if (e == NULL) { continue; } e->ann().clear(); switch (e->eid()) { case Expression::E_INTLIT: case Expression::E_FLOATLIT: case Expression::E_BOOLLIT: case Expression::E_STRINGLIT: case Expression::E_ID: case Expression::E_ANON: case Expression::E_TIID: break; case Expression::E_SETLIT: pushVec(stack, e->template cast<SetLit>()->v()); break; case Expression::E_ARRAYLIT: for (unsigned int i = 0; i < e->cast<ArrayLit>()->size(); i++) { stack.push_back((*e->cast<ArrayLit>())[i]); } break; case Expression::E_ARRAYACCESS: pushVec(stack, e->template cast<ArrayAccess>()->idx()); stack.push_back(e->template cast<ArrayAccess>()->v()); break; case Expression::E_COMP: { Comprehension* comp = e->template cast<Comprehension>(); for (unsigned int i = comp->n_generators(); i--;) { stack.push_back(comp->where(i)); stack.push_back(comp->in(i)); for (unsigned int j = comp->n_decls(i); j--;) { stack.push_back(comp->decl(i, j)); } } stack.push_back(comp->e()); } break; case Expression::E_ITE: { ITE* ite = e->template cast<ITE>(); stack.push_back(ite->e_else()); for (int i = 0; i < ite->size(); i++) { stack.push_back(ite->e_if(i)); stack.push_back(ite->e_then(i)); } } break; case Expression::E_BINOP: stack.push_back(e->template cast<BinOp>()->rhs()); stack.push_back(e->template cast<BinOp>()->lhs()); break; case Expression::E_UNOP: stack.push_back(e->template cast<UnOp>()->e()); break; case Expression::E_CALL: for (unsigned int i = 0; i < e->template cast<Call>()->n_args(); i++) stack.push_back(e->template cast<Call>()->arg(i)); break; case Expression::E_VARDECL: stack.push_back(e->template cast<VarDecl>()->e()); stack.push_back(e->template cast<VarDecl>()->ti()); break; case Expression::E_LET: stack.push_back(e->template cast<Let>()->in()); pushVec(stack, e->template cast<Let>()->let()); break; case Expression::E_TI: stack.push_back(e->template cast<TypeInst>()->domain()); pushVec(stack, e->template cast<TypeInst>()->ranges()); break; } } }};
void outputVarDecls(EnvI& env, Item* ci, Expression* e) { class O : public EVisitor { public: EnvI& env; Item* ci; O(EnvI& env0, Item* ci0) : env(env0), ci(ci0) {} void vId(Id& id) { if (&id == constants().absent) return; if (!id.decl()->toplevel()) return; VarDecl* vd = id.decl(); VarDecl* reallyFlat = vd->flat(); while (reallyFlat != NULL && reallyFlat != reallyFlat->flat()) reallyFlat = reallyFlat->flat(); IdMap<int>::iterator idx = reallyFlat ? env.output_vo_flat.idx.find(reallyFlat->id()) : env.output_vo_flat.idx.end(); IdMap<int>::iterator idx2 = env.output_vo.idx.find(vd->id()); if (idx == env.output_vo_flat.idx.end() && idx2 == env.output_vo.idx.end()) { VarDeclI* nvi = new VarDeclI(Location().introduce(), copy(env, env.cmap, vd)->cast<VarDecl>()); Type t = nvi->e()->ti()->type(); if (t.ti() != Type::TI_PAR) { t.ti(Type::TI_PAR); } makePar(env, nvi->e()); nvi->e()->ti()->domain(NULL); nvi->e()->flat(vd->flat()); ClearAnnotations::run(nvi->e()); nvi->e()->introduced(false); if (reallyFlat) env.output_vo_flat.add_idx(reallyFlat, env.output->size()); env.output_vo.add_idx(nvi, env.output->size()); env.output_vo.add(nvi->e(), ci); env.output->addItem(nvi);
IdMap<KeepAlive>::iterator it; if ((it = env.reverseMappers.find(nvi->e()->id())) != env.reverseMappers.end()) { Call* rhs = copy(env, env.cmap, it->second())->cast<Call>(); { std::vector<Type> tv(rhs->n_args()); for (unsigned int i = rhs->n_args(); i--;) { tv[i] = rhs->arg(i)->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = env.output->matchFn(env, rhs->id(), tv, false); Type t; if (decl == NULL) { FunctionI* origdecl = env.model->matchFn(env, rhs->id(), tv, false); if (origdecl == NULL) { throw FlatteningError( env, rhs->loc(), "function " + rhs->id().str() + " is used in output, par version needed"); } if (!origdecl->from_stdlib()) { decl = copy(env, env.cmap, origdecl)->cast<FunctionI>(); CollectOccurrencesE ce(env.output_vo, decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); env.output->registerFn(env, decl); env.output->addItem(decl); } else { decl = origdecl; } } rhs->decl(decl); } outputVarDecls(env, nvi, it->second()); nvi->e()->e(rhs); } else if (reallyFlat && cannotUseRHSForOutput(env, reallyFlat->e())) { assert(nvi->e()->flat()); nvi->e()->e(NULL); if (nvi->e()->type().dim() == 0) { reallyFlat->addAnnotation(constants().ann.output_var); } else { std::vector<Expression*> args(reallyFlat->e()->type().dim()); for (unsigned int i = 0; i < args.size(); i++) { if (nvi->e()->ti()->ranges()[i]->domain() == NULL) { args[i] = new SetLit(Location().introduce(), eval_intset(env, reallyFlat->ti()->ranges()[i]->domain())); } else { args[i] = new SetLit(Location().introduce(), eval_intset(env, nvi->e()->ti()->ranges()[i]->domain())); } } ArrayLit* al = new ArrayLit(Location().introduce(), args); args.resize(1); args[0] = al; reallyFlat->addAnnotation( new Call(Location().introduce(), constants().ann.output_array, args)); } checkRenameVar(env, nvi->e()); } else { outputVarDecls(env, nvi, nvi->e()->ti()); outputVarDecls(env, nvi, nvi->e()->e()); } CollectOccurrencesE ce(env.output_vo, nvi); topDown(ce, nvi->e()); } } } _o(env, ci); topDown(_o, e);}
void processDeletions(EnvI& e, std::vector<VarDecl*>& deletedFlatVarDecls) { std::vector<VarDecl*> deletedVarDecls; for (unsigned int i = 0; i < e.output->size(); i++) { if (VarDeclI* vdi = (*e.output)[i]->dyn_cast<VarDeclI>()) { if (!vdi->removed() && e.output_vo.occurrences(vdi->e()) == 0 && !vdi->e()->ann().contains(constants().ann.mzn_check_var) && !(vdi->e()->id()->idn() == -1 && vdi->e()->id()->v() == "_mzn_solution_checker")) { CollectDecls cd(e.output_vo, deletedVarDecls, vdi); topDown(cd, vdi->e()->e()); removeIsOutput(vdi->e()->flat()); if (e.output_vo.find(vdi->e()) != -1) e.output_vo.remove(vdi->e()); vdi->remove(); } } } while (!deletedVarDecls.empty()) { VarDecl* cur = deletedVarDecls.back(); deletedVarDecls.pop_back(); if (e.output_vo.occurrences(cur) == 0) { IdMap<int>::iterator cur_idx = e.output_vo.idx.find(cur->id()); if (cur_idx != e.output_vo.idx.end()) { VarDeclI* vdi = (*e.output)[cur_idx->second]->cast<VarDeclI>(); if (!vdi->removed()) { CollectDecls cd(e.output_vo, deletedVarDecls, vdi); topDown(cd, cur->e()); removeIsOutput(vdi->e()->flat()); if (e.output_vo.find(vdi->e()) != -1) e.output_vo.remove(vdi->e()); vdi->remove(); } } } }
for (IdMap<VarOccurrences::Items>::iterator it = e.output_vo._m.begin(); it != e.output_vo._m.end(); ++it) { std::vector<Item*> toRemove; for (VarOccurrences::Items::iterator iit = it->second.begin(); iit != it->second.end(); ++iit) { if ((*iit)->removed()) { toRemove.push_back(*iit); } } for (unsigned int i = 0; i < toRemove.size(); i++) { it->second.erase(toRemove[i]); } }}
void createDznOutputItem(EnvI& e, bool outputObjective, bool includeOutputItem) { std::vector<Expression*> outputVars;
class DZNOVisitor : public ItemVisitor { protected: EnvI& e; bool outputObjective; bool includeOutputItem; std::vector<Expression*>& outputVars; bool had_add_to_output;
public: DZNOVisitor(EnvI& e0, bool outputObjective0, bool includeOutputItem0, std::vector<Expression*>& outputVars0) : e(e0), outputObjective(outputObjective0), outputVars(outputVars0), includeOutputItem(includeOutputItem0), had_add_to_output(false) {} void vVarDeclI(VarDeclI* vdi) { VarDecl* vd = vdi->e(); bool process_var = false; if (outputObjective && vd->id()->idn() == -1 && vd->id()->v() == "_objective") { process_var = true; } else { if (vd->ann().contains(constants().ann.add_to_output)) { if (!had_add_to_output) { outputVars.clear(); } had_add_to_output = true; process_var = true; } else { if (!had_add_to_output) { process_var = false; if (vd->type().isvar()) { if (vd->e()) { if (ArrayLit* al = vd->e()->dyn_cast<ArrayLit>()) { for (unsigned int i = 0; i < al->size(); i++) { if ((*al)[i]->isa<AnonVar>()) { process_var = true; break; } } } else if (vd->ann().contains(constants().ann.rhs_from_assignment)) { process_var = true; } } else { process_var = true; } } } } } if (process_var) { std::ostringstream s; s << vd->id()->str().str() << " = "; if (vd->type().dim() > 0) { ArrayLit* al = NULL; if (vd->flat() && vd->flat()->e()) { al = eval_array_lit(e, vd->flat()->e()); } else if (vd->e()) { al = eval_array_lit(e, vd->e()); } s << "array" << vd->type().dim() << "d("; for (int i = 0; i < vd->type().dim(); i++) { unsigned int enumId = (vd->type().enumId() != 0 ? e.getArrayEnum(vd->type().enumId())[i] : 0); if (enumId != 0) { s << e.getEnum(enumId)->e()->id()->str() << ", "; } else if (al != NULL) { s << al->min(i) << ".." << al->max(i) << ", "; } else { IntSetVal* idxset = eval_intset(e, vd->ti()->ranges()[i]->domain()); s << *idxset << ", "; } } } StringLit* sl = new StringLit(Location().introduce(), s.str()); outputVars.push_back(sl);
std::vector<Expression*> showArgs(1); showArgs[0] = vd->id(); Call* show = new Call(Location().introduce(), ASTString("showDzn"), showArgs); show->type(Type::parstring()); FunctionI* fi = e.model->matchFn(e, show, false); assert(fi); show->decl(fi); outputVars.push_back(show); std::string ends = vd->type().dim() > 0 ? ")" : ""; ends += ";\n"; StringLit* eol = new StringLit(Location().introduce(), ends); outputVars.push_back(eol); } } void vOutputI(OutputI* oi) { if (includeOutputItem) { outputVars.push_back(new StringLit(Location().introduce(), "_output = ")); Call* concat = new Call(Location().introduce(), ASTString("concat"), {oi->e()}); concat->type(Type::parstring()); FunctionI* fi = e.model->matchFn(e, concat, false); assert(fi); concat->decl(fi); Call* show = new Call(Location().introduce(), ASTString("showDzn"), {concat}); show->type(Type::parstring()); fi = e.model->matchFn(e, show, false); assert(fi); show->decl(fi); outputVars.push_back(show); outputVars.push_back(new StringLit(Location().introduce(), ";\n")); }
oi->remove(); } } dznov(e, outputObjective, includeOutputItem, outputVars);
iterItems(dznov, e.model);
OutputI* newOutputItem = new OutputI(Location().introduce(), new ArrayLit(Location().introduce(), outputVars)); e.model->addItem(newOutputItem);}
ArrayLit* createJSONOutput(EnvI& e, bool outputObjective, bool includeOutputItem) { std::vector<Expression*> outputVars; outputVars.push_back(new StringLit(Location().introduce(), "{\n"));
class JSONOVisitor : public ItemVisitor { protected: EnvI& e; bool outputObjective; bool includeOutputItem; std::vector<Expression*>& outputVars; bool had_add_to_output; bool first_var;
public: JSONOVisitor(EnvI& e0, bool outputObjective0, bool includeOutputItem0, std::vector<Expression*>& outputVars0) : e(e0), outputObjective(outputObjective0), outputVars(outputVars0), includeOutputItem(includeOutputItem0), had_add_to_output(false), first_var(true) {} void vVarDeclI(VarDeclI* vdi) { VarDecl* vd = vdi->e(); bool process_var = false; if (outputObjective && vd->id()->idn() == -1 && vd->id()->v() == "_objective") { process_var = true; } else { if (vd->ann().contains(constants().ann.add_to_output)) { if (!had_add_to_output) { outputVars.clear(); outputVars.push_back(new StringLit(Location().introduce(), "{\n")); first_var = true; } had_add_to_output = true; process_var = true; } else { if (!had_add_to_output) { process_var = vd->type().isvar() && (vd->e() == NULL || vd->ann().contains(constants().ann.rhs_from_assignment)); } } } if (process_var) { std::ostringstream s; if (first_var) { first_var = false; } else { s << ",\n"; } s << " \"" << vd->id()->str().str() << "\"" << " : "; StringLit* sl = new StringLit(Location().introduce(), s.str()); outputVars.push_back(sl);
std::vector<Expression*> showArgs(1); showArgs[0] = vd->id(); Call* show = new Call(Location().introduce(), "showJSON", showArgs); show->type(Type::parstring()); FunctionI* fi = e.model->matchFn(e, show, false); assert(fi); show->decl(fi); outputVars.push_back(show); } } void vOutputI(OutputI* oi) { if (includeOutputItem) { std::ostringstream s; if (first_var) { first_var = false; } else { s << ",\n"; } s << " \"_output\"" << " : "; StringLit* sl = new StringLit(Location().introduce(), s.str()); outputVars.push_back(sl); Call* concat = new Call(Location().introduce(), ASTString("concat"), {oi->e()}); concat->type(Type::parstring()); FunctionI* fi = e.model->matchFn(e, concat, false); assert(fi); concat->decl(fi); Call* show = new Call(Location().introduce(), ASTString("showJSON"), {concat}); show->type(Type::parstring()); fi = e.model->matchFn(e, show, false); assert(fi); show->decl(fi); outputVars.push_back(show); }
oi->remove(); } } jsonov(e, outputObjective, includeOutputItem, outputVars);
iterItems(jsonov, e.model);
outputVars.push_back(new StringLit(Location().introduce(), "\n}\n")); return new ArrayLit(Location().introduce(), outputVars);}void createJSONOutputItem(EnvI& e, bool outputObjective, bool includeOutputItem) { OutputI* newOutputItem = new OutputI(Location().introduce(), createJSONOutput(e, outputObjective, includeOutputItem)); e.model->addItem(newOutputItem);}
void createOutput(EnvI& e, std::vector<VarDecl*>& deletedFlatVarDecls, FlatteningOptions::OutputMode outputMode, bool outputObjective, bool includeOutputItem) { // Create new output model OutputI* outputItem = NULL; GCLock lock;
switch (outputMode) { case FlatteningOptions::OUTPUT_DZN: createDznOutputItem(e, outputObjective, includeOutputItem); break; case FlatteningOptions::OUTPUT_JSON: createJSONOutputItem(e, outputObjective, includeOutputItem); default: if (e.model->outputItem() == NULL) { createDznOutputItem(e, outputObjective, false); } break; }
// Copy output item from model into output model outputItem = copy(e, e.cmap, e.model->outputItem())->cast<OutputI>(); makePar(e, outputItem->e()); e.output->addItem(outputItem);
// Copy all function definitions that are required for output into the output model class CollectFunctions : public EVisitor { public: EnvI& env; CollectFunctions(EnvI& env0) : env(env0) {} bool enter(Expression* e) { if (e->type().isvar()) { Type t = e->type(); t.ti(Type::TI_PAR); e->type(t); } return true; } void vCall(Call& c) { std::vector<Type> tv(c.n_args()); for (unsigned int i = c.n_args(); i--;) { tv[i] = c.arg(i)->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = env.output->matchFn(env, c.id(), tv, false); FunctionI* origdecl = env.model->matchFn(env, c.id(), tv, false); bool canReuseDecl = (decl != nullptr); if (canReuseDecl && origdecl) { // Check if this is the exact same overloaded declaration as in the model for (unsigned int i = 0; i < decl->params().size(); i++) { if (decl->params()[i]->type() != origdecl->params()[i]->type()) { // no, the types don't match, so we have to copy the original decl canReuseDecl = false; break; } } } Type t; if (!canReuseDecl) { if (origdecl == NULL || !origdecl->rtype(env, tv, false).ispar()) { throw FlatteningError( env, c.loc(), "function " + c.id().str() + " is used in output, par version needed"); } if (!origdecl->from_stdlib()) { decl = copy(env, env.cmap, origdecl)->cast<FunctionI>(); env.output->registerFn(env, decl); env.output->addItem(decl); if (decl->e()) { makePar(env, decl->e()); topDown(*this, decl->e()); } CollectOccurrencesE ce(env.output_vo, decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); } else { decl = origdecl; } } c.decl(decl); } } _cf(e); topDown(_cf, outputItem->e());
// If we are checking solutions using a checker model, all parameters of the checker model // have to be made available in the output model class OV1 : public ItemVisitor { public: EnvI& env; CollectFunctions& _cf; OV1(EnvI& env0, CollectFunctions& cf) : env(env0), _cf(cf) {} void vVarDeclI(VarDeclI* vdi) { if (vdi->e()->ann().contains(constants().ann.mzn_check_var)) { VarDecl* output_vd = copy(env, env.cmap, vdi->e())->cast<VarDecl>(); topDown(_cf, output_vd); } } } _ov1(e, _cf); iterItems(_ov1, e.model);
// Copying the output item and the functions it depends on has created copies // of all dependent VarDecls. However the output model does not contain VarDeclIs for // these VarDecls yet. This iterator processes all variable declarations of the // original model, and if they were copied (i.e., if the output model depends on them), // the corresponding VarDeclI is created in the output model. class OV2 : public ItemVisitor { public: EnvI& env; OV2(EnvI& env0) : env(env0) {} void vVarDeclI(VarDeclI* vdi) { IdMap<int>::iterator idx = env.output_vo.idx.find(vdi->e()->id()); if (idx != env.output_vo.idx.end()) return; if (Expression* vd_e = env.cmap.find(vdi->e())) { // We found a copied VarDecl, now need to create a VarDeclI VarDecl* vd = vd_e->cast<VarDecl>(); VarDeclI* vdi_copy = copy(env, env.cmap, vdi)->cast<VarDeclI>();
Type t = vdi_copy->e()->ti()->type(); t.ti(Type::TI_PAR); vdi_copy->e()->ti()->domain(NULL); vdi_copy->e()->flat(vdi->e()->flat()); bool isCheckVar = vdi_copy->e()->ann().contains(constants().ann.mzn_check_var); Call* checkVarEnum = vdi_copy->e()->ann().getCall(constants().ann.mzn_check_enum_var); vdi_copy->e()->ann().clear(); if (isCheckVar) { vdi_copy->e()->ann().add(constants().ann.mzn_check_var); } if (checkVarEnum) { vdi_copy->e()->ann().add(checkVarEnum); } vdi_copy->e()->introduced(false); IdMap<KeepAlive>::iterator it; if (!vdi->e()->type().ispar()) { if (vd->flat() == NULL && vdi->e()->e() != NULL && vdi->e()->e()->type().ispar()) { // Don't have a flat version of this variable, but the original has a right hand // side that is par, so we can use that. Expression* flate = eval_par(env, vdi->e()->e()); outputVarDecls(env, vdi_copy, flate); vd->e(flate); } else { vd = follow_id_to_decl(vd->id())->cast<VarDecl>(); VarDecl* reallyFlat = vd->flat(); while (reallyFlat && reallyFlat != reallyFlat->flat()) reallyFlat = reallyFlat->flat(); if (reallyFlat == NULL) { // The variable doesn't have a flat version. This can only happen if // the original variable had type-inst var, but a right-hand-side that // was par, so follow_id_to_decl lead to a par variable. assert(vd->e() && vd->e()->type().ispar()); Expression* flate = eval_par(env, vd->e()); outputVarDecls(env, vdi_copy, flate); vd->e(flate); } else if (vd->flat()->e() && vd->flat()->e()->type().ispar()) { // We can use the right hand side of the flat version of this variable Expression* flate = copy(env, env.cmap, follow_id(reallyFlat->id())); outputVarDecls(env, vdi_copy, flate); vd->e(flate); } else if ((it = env.reverseMappers.find(vd->id())) != env.reverseMappers.end()) { // Found a reverse mapper, so we need to add the mapping function to the // output model to map the FlatZinc value back to the model variable. Call* rhs = copy(env, env.cmap, it->second())->cast<Call>(); { std::vector<Type> tv(rhs->n_args()); for (unsigned int i = rhs->n_args(); i--;) { tv[i] = rhs->arg(i)->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = env.output->matchFn(env, rhs->id(), tv, false); if (decl == NULL) { FunctionI* origdecl = env.model->matchFn(env, rhs->id(), tv, false); if (origdecl == NULL) { throw FlatteningError( env, rhs->loc(), "function " + rhs->id().str() + " is used in output, par version needed"); } if (!origdecl->from_stdlib()) { decl = copy(env, env.cmap, origdecl)->cast<FunctionI>(); CollectOccurrencesE ce(env.output_vo, decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); env.output->registerFn(env, decl); env.output->addItem(decl); } else { decl = origdecl; } } rhs->decl(decl); } outputVarDecls(env, vdi_copy, rhs); vd->e(rhs); } else if (cannotUseRHSForOutput(env, vd->e())) { // If the VarDecl does not have a usable right hand side, it needs to be // marked as output in the FlatZinc vd->e(NULL); assert(vd->flat()); if (vd->type().dim() == 0) { vd->flat()->addAnnotation(constants().ann.output_var); checkRenameVar(env, vd); } else { bool needOutputAnn = true; if (reallyFlat->e() && reallyFlat->e()->isa<ArrayLit>()) { ArrayLit* al = reallyFlat->e()->cast<ArrayLit>(); for (unsigned int i = 0; i < al->size(); i++) { if (Id* id = (*al)[i]->dyn_cast<Id>()) { if (env.reverseMappers.find(id) != env.reverseMappers.end()) { needOutputAnn = false; break; } } } if (!needOutputAnn) { outputVarDecls(env, vdi_copy, al); vd->e(copy(env, env.cmap, al)); } } if (needOutputAnn) { std::vector<Expression*> args(vdi->e()->type().dim()); for (unsigned int i = 0; i < args.size(); i++) { if (vdi->e()->ti()->ranges()[i]->domain() == NULL) { args[i] = new SetLit(Location().introduce(), eval_intset(env, vd->flat()->ti()->ranges()[i]->domain())); } else { args[i] = new SetLit(Location().introduce(), eval_intset(env, vd->ti()->ranges()[i]->domain())); } } ArrayLit* al = new ArrayLit(Location().introduce(), args); args.resize(1); args[0] = al; vd->flat()->addAnnotation( new Call(Location().introduce(), constants().ann.output_array, args)); checkRenameVar(env, vd); } } } if (reallyFlat && env.output_vo_flat.find(reallyFlat) == -1) env.output_vo_flat.add_idx(reallyFlat, env.output->size()); } } makePar(env, vdi_copy->e()); env.output_vo.add_idx(vdi_copy, env.output->size()); CollectOccurrencesE ce(env.output_vo, vdi_copy); topDown(ce, vdi_copy->e()); env.output->addItem(vdi_copy); } } } _ov2(e); iterItems(_ov2, e.model);
CollectOccurrencesE ce(e.output_vo, outputItem); topDown(ce, outputItem->e());
e.model->mergeStdLib(e, e.output); processDeletions(e, deletedFlatVarDecls);}
Expression* isFixedDomain(EnvI& env, VarDecl* vd) { if (vd->type() != Type::varbool() && vd->type() != Type::varint() && vd->type() != Type::varfloat()) return NULL; Expression* e = vd->ti()->domain(); if (e == constants().lit_true || e == constants().lit_false) return e; if (SetLit* sl = Expression::dyn_cast<SetLit>(e)) { if (sl->type().bt() == Type::BT_INT) { IntSetVal* isv = eval_intset(env, sl); return isv->min() == isv->max() ? IntLit::a(isv->min()) : NULL; } else if (sl->type().bt() == Type::BT_FLOAT) { FloatSetVal* fsv = eval_floatset(env, sl); return fsv->min() == fsv->max() ? FloatLit::a(fsv->min()) : NULL; } } return NULL;}
void finaliseOutput(EnvI& e, std::vector<VarDecl*>& deletedFlatVarDecls) { if (e.output->size() > 0) { // Adapt existing output model // (generated by repeated flattening) e.output_vo.clear(); for (unsigned int i = 0; i < e.output->size(); i++) { Item* item = (*e.output)[i]; if (item->removed()) continue; switch (item->iid()) { case Item::II_VD: { VarDecl* vd = item->cast<VarDeclI>()->e(); IdMap<KeepAlive>::iterator it; GCLock lock; VarDecl* reallyFlat = vd->flat(); while (reallyFlat && reallyFlat != reallyFlat->flat()) reallyFlat = reallyFlat->flat(); if (vd->e() == NULL) { if ((vd->flat()->e() && vd->flat()->e()->type().ispar()) || isFixedDomain(e, vd->flat())) { VarDecl* reallyFlat = vd->flat(); while (reallyFlat != reallyFlat->flat()) reallyFlat = reallyFlat->flat(); removeIsOutput(reallyFlat); Expression* flate; if (Expression* fd = isFixedDomain(e, vd->flat())) { flate = fd; } else { flate = copy(e, e.cmap, follow_id(reallyFlat->id())); } outputVarDecls(e, item, flate); vd->e(flate); } else if ((it = e.reverseMappers.find(vd->id())) != e.reverseMappers.end()) { Call* rhs = copy(e, e.cmap, it->second())->cast<Call>(); std::vector<Type> tv(rhs->n_args()); for (unsigned int i = rhs->n_args(); i--;) { tv[i] = rhs->arg(i)->type(); tv[i].ti(Type::TI_PAR); } FunctionI* decl = e.output->matchFn(e, rhs->id(), tv, false); if (decl == NULL) { FunctionI* origdecl = e.model->matchFn(e, rhs->id(), tv, false); if (origdecl == NULL) { throw FlatteningError( e, rhs->loc(), "function " + rhs->id().str() + " is used in output, par version needed"); } if (!origdecl->from_stdlib()) { decl = copy(e, e.cmap, origdecl)->cast<FunctionI>(); CollectOccurrencesE ce(e.output_vo, decl); topDown(ce, decl->e()); topDown(ce, decl->ti()); for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]); e.output->registerFn(e, decl); e.output->addItem(decl); } else { decl = origdecl; } } rhs->decl(decl); removeIsOutput(reallyFlat);
if (e.vo.occurrences(reallyFlat) == 0 && reallyFlat->e() == NULL) { deletedFlatVarDecls.push_back(reallyFlat); }
outputVarDecls(e, item, it->second()->cast<Call>()); vd->e(rhs); } else { // If the VarDecl does not have a usable right hand side, it needs to be // marked as output in the FlatZinc assert(vd->flat());
bool needOutputAnn = true; if (reallyFlat->e() && reallyFlat->e()->isa<ArrayLit>()) { ArrayLit* al = reallyFlat->e()->cast<ArrayLit>(); for (unsigned int i = 0; i < al->size(); i++) { if (Id* id = (*al)[i]->dyn_cast<Id>()) { if (e.reverseMappers.find(id) != e.reverseMappers.end()) { needOutputAnn = false; break; } } } if (!needOutputAnn) { removeIsOutput(vd); removeIsOutput(reallyFlat); if (e.vo.occurrences(reallyFlat) == 0) { deletedFlatVarDecls.push_back(reallyFlat); }
outputVarDecls(e, item, al); vd->e(copy(e, e.cmap, al)); } } if (needOutputAnn) { if (!isOutput(vd->flat())) { GCLock lock; if (vd->type().dim() == 0) { vd->flat()->addAnnotation(constants().ann.output_var); } else { std::vector<Expression*> args(vd->type().dim()); for (unsigned int i = 0; i < args.size(); i++) { if (vd->ti()->ranges()[i]->domain() == NULL) { args[i] = new SetLit(Location().introduce(), eval_intset(e, vd->flat()->ti()->ranges()[i]->domain())); } else { args[i] = new SetLit(Location().introduce(), eval_intset(e, vd->ti()->ranges()[i]->domain())); } } ArrayLit* al = new ArrayLit(Location().introduce(), args); args.resize(1); args[0] = al; vd->flat()->addAnnotation( new Call(Location().introduce(), constants().ann.output_array, args)); } checkRenameVar(e, vd); } } } vd->flat(NULL); // Remove enum type Type vdt = vd->type(); vdt.enumId(0); vd->type(vdt); vd->ti()->type(vdt); } e.output_vo.add_idx(item->cast<VarDeclI>(), i); CollectOccurrencesE ce(e.output_vo, item); topDown(ce, vd); } break; case Item::II_OUT: { CollectOccurrencesE ce(e.output_vo, item); topDown(ce, item->cast<OutputI>()->e()); } break; case Item::II_FUN: { CollectOccurrencesE ce(e.output_vo, item); topDown(ce, item->cast<FunctionI>()->e()); topDown(ce, item->cast<FunctionI>()->ti()); for (unsigned int i = item->cast<FunctionI>()->params().size(); i--;) topDown(ce, item->cast<FunctionI>()->params()[i]); } break; default: throw FlatteningError(e, item->loc(), "invalid item in output model"); } } } processDeletions(e, deletedFlatVarDecls);}} // namespace MiniZinc