this repo has no description
at develop 6.7 kB view raw
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2 3/* 4 * Main authors: 5 * Guido Tack <guido.tack@monash.edu> 6 */ 7 8/* This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 11 12#include <minizinc/flat_exp.hh> 13 14namespace MiniZinc { 15 16EE flatten_id(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b, bool doNotFollowChains) { 17 CallStackItem _csi(env, e); 18 EE ret; 19 Id* id = e->cast<Id>(); 20 if (id->decl() == NULL) { 21 if (id->type().isann()) { 22 ret.b = bind(env, Ctx(), b, constants().lit_true); 23 ret.r = bind(env, ctx, r, e); 24 return ret; 25 } else { 26 throw FlatteningError(env, e->loc(), "undefined identifier"); 27 } 28 } 29 if (!doNotFollowChains) { 30 id = follow_id_to_decl(id)->cast<VarDecl>()->id(); 31 } 32 if (ctx.neg && id->type().dim() > 0) { 33 if (id->type().dim() > 1) 34 throw InternalError("multi-dim arrays in negative positions not supported yet"); 35 KeepAlive ka; 36 { 37 GCLock lock; 38 std::vector<VarDecl*> gen_id(1); 39 gen_id[0] = new VarDecl(id->loc(), new TypeInst(id->loc(), Type::parint()), env.genId(), 40 IntLit::a(0)); 41 42 /// TODO: support arbitrary dimensions 43 std::vector<Expression*> idxsetargs(1); 44 idxsetargs[0] = id; 45 Call* idxset = new Call(id->loc().introduce(), "index_set", idxsetargs); 46 idxset->decl(env.model->matchFn(env, idxset, false)); 47 idxset->type(idxset->decl()->rtype(env, idxsetargs, false)); 48 Generator gen(gen_id, idxset, NULL); 49 std::vector<Expression*> idx(1); 50 Generators gens; 51 gens._g.push_back(gen); 52 UnOp* aanot = new UnOp(id->loc(), UOT_NOT, NULL); 53 Comprehension* cp = new Comprehension(id->loc(), aanot, gens, false); 54 Id* bodyidx = cp->decl(0, 0)->id(); 55 idx[0] = bodyidx; 56 ArrayAccess* aa = new ArrayAccess(id->loc(), id, idx); 57 aanot->e(aa); 58 Type tt = id->type(); 59 tt.dim(0); 60 aa->type(tt); 61 aanot->type(aa->type()); 62 cp->type(id->type()); 63 ctx.neg = false; 64 ka = cp; 65 } 66 ret = flat_exp(env, ctx, ka(), r, b); 67 } else { 68 GCLock lock; 69 VarDecl* vd = id->decl()->flat(); 70 Expression* rete = NULL; 71 if (vd == NULL) { 72 if (id->decl()->e() == NULL || id->decl()->e()->type().isann() || 73 id->decl()->e()->type().isvar() || id->decl()->e()->type().cv() || 74 id->decl()->e()->type().dim() > 0) { 75 // New top-level id, need to copy into env.m 76 vd = flat_exp(env, Ctx(), id->decl(), NULL, constants().var_true).r()->cast<Id>()->decl(); 77 } else { 78 vd = id->decl(); 79 } 80 } 81 ret.b = bind(env, Ctx(), b, constants().lit_true); 82 if (vd->e() != NULL) { 83 if (vd->e()->type().ispar() && vd->e()->type().dim() == 0) { 84 rete = eval_par(env, vd->e()); 85 } else if (vd->e()->isa<Id>()) { 86 rete = vd->e(); 87 } 88 } else if (vd->ti()->ranges().size() > 0) { 89 // create fresh variables and array literal 90 std::vector<std::pair<int, int> > dims; 91 IntVal asize = 1; 92 for (unsigned int i = 0; i < vd->ti()->ranges().size(); i++) { 93 TypeInst* ti = vd->ti()->ranges()[i]; 94 if (ti->domain() == NULL) throw FlatteningError(env, ti->loc(), "array dimensions unknown"); 95 IntSetVal* isv = eval_intset(env, ti->domain()); 96 if (isv->size() == 0) { 97 dims.push_back(std::pair<int, int>(1, 0)); 98 asize = 0; 99 } else { 100 if (isv->size() != 1) throw FlatteningError(env, ti->loc(), "invalid array index set"); 101 asize *= (isv->max(0) - isv->min(0) + 1); 102 dims.push_back(std::pair<int, int>(static_cast<int>(isv->min(0).toInt()), 103 static_cast<int>(isv->max(0).toInt()))); 104 } 105 } 106 Type tt = vd->ti()->type(); 107 tt.dim(0); 108 109 if (asize > Constants::max_array_size) { 110 std::ostringstream oss; 111 oss << "array size (" << asize << ") exceeds maximum allowed size (" 112 << Constants::max_array_size << ")"; 113 throw FlatteningError(env, vd->loc(), oss.str()); 114 } 115 116 std::vector<Expression*> elems(static_cast<int>(asize.toInt())); 117 for (int i = 0; i < static_cast<int>(asize.toInt()); i++) { 118 CallStackItem csi(env, IntLit::a(i)); 119 TypeInst* vti = new TypeInst(Location().introduce(), tt, vd->ti()->domain()); 120 VarDecl* nvd = newVarDecl(env, Ctx(), vti, NULL, vd, NULL); 121 elems[i] = nvd->id(); 122 } 123 // After introducing variables for each array element, the original domain can be 124 // set to "computed" (since it is a consequence of the individual variable domains) 125 vd->ti()->setComputedDomain(true); 126 127 ArrayLit* al = new ArrayLit(Location().introduce(), elems, dims); 128 al->type(vd->type()); 129 vd->e(al); 130 env.vo_add_exp(vd); 131 EE ee; 132 ee.r = vd; 133 env.cse_map_insert(vd->e(), ee); 134 } 135 if (rete == NULL) { 136 if (!vd->toplevel()) { 137 // create new VarDecl in toplevel, if decl doesnt exist yet 138 EnvI::CSEMap::iterator it = env.cse_map_find(vd->e()); 139 if (it == env.cse_map_end()) { 140 Expression* vde = follow_id(vd->e()); 141 ArrayLit* vdea = vde ? vde->dyn_cast<ArrayLit>() : NULL; 142 if (vdea && vdea->size() == 0) { 143 // Do not create names for empty arrays but return array literal directly 144 rete = vdea; 145 } else { 146 VarDecl* nvd = newVarDecl(env, ctx, eval_typeinst(env, vd), NULL, vd, NULL); 147 148 if (vd->e()) { 149 (void)flat_exp(env, Ctx(), vd->e(), nvd, constants().var_true); 150 } 151 vd = nvd; 152 EE ee(vd, NULL); 153 if (vd->e()) env.cse_map_insert(vd->e(), ee); 154 } 155 } else { 156 if (it->second.r()->isa<VarDecl>()) { 157 vd = it->second.r()->cast<VarDecl>(); 158 } else { 159 rete = it->second.r(); 160 } 161 } 162 } 163 if (rete == NULL) { 164 if (id->type().bt() == Type::BT_ANN && vd->e()) { 165 rete = vd->e(); 166 } else { 167 ArrayLit* vda = vd->dyn_cast<ArrayLit>(); 168 if (vda && vda->size() == 0) { 169 // Do not create names for empty arrays but return array literal directly 170 rete = vda; 171 } else { 172 rete = vd->id(); 173 } 174 } 175 } 176 } 177 ret.r = bind(env, ctx, r, rete); 178 } 179 return ret; 180} 181 182EE flatten_id(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { 183 return flatten_id(env, ctx, e, r, b, false); 184} 185 186} // namespace MiniZinc