this repo has no description
at develop 9.3 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_comp(EnvI& env, const Ctx& ctx, Expression* e, VarDecl* r, VarDecl* b) { 17 CallStackItem _csi(env, e); 18 EE ret; 19 auto* c = e->cast<Comprehension>(); 20 KeepAlive c_ka(c); 21 22 bool isvarset = false; 23 if (c->set()) { 24 for (int i = 0; i < c->numberOfGenerators(); i++) { 25 Expression* g_in = c->in(i); 26 if (g_in != nullptr) { 27 const Type& ty_in = g_in->type(); 28 if (ty_in == Type::varsetint()) { 29 isvarset = true; 30 break; 31 } 32 if (c->where(i) != nullptr) { 33 if (c->where(i)->type() == Type::varbool()) { 34 isvarset = true; 35 break; 36 } 37 } 38 } 39 } 40 } 41 42 if (c->type().isOpt() || isvarset) { 43 std::vector<Expression*> in(c->numberOfGenerators()); 44 std::vector<Expression*> orig_where(c->numberOfGenerators()); 45 std::vector<Expression*> where; 46 GCLock lock; 47 for (int i = 0; i < c->numberOfGenerators(); i++) { 48 if (c->in(i) == nullptr) { 49 in[i] = nullptr; 50 orig_where[i] = c->where(i); 51 } else { 52 if (c->in(i)->type().isvar() && c->in(i)->type().dim() == 0) { 53 std::vector<Expression*> args(1); 54 args[0] = c->in(i); 55 Call* ub = new Call(Location().introduce(), "ub", args); 56 ub->type(Type::parsetint()); 57 ub->decl(env.model->matchFn(env, ub, false)); 58 in[i] = ub; 59 for (int j = 0; j < c->numberOfDecls(i); j++) { 60 auto* bo = new BinOp(Location().introduce(), c->decl(i, j)->id(), BOT_IN, c->in(i)); 61 bo->type(Type::varbool()); 62 where.push_back(bo); 63 } 64 } else { 65 in[i] = c->in(i); 66 } 67 if ((c->where(i) != nullptr) && c->where(i)->type().isvar()) { 68 // This is a generalised where clause. Split into par and var part. 69 // The par parts can remain in where clause. The var parts are translated 70 // into optionality constraints. 71 if (c->where(i)->isa<BinOp>() && c->where(i)->cast<BinOp>()->op() == BOT_AND) { 72 std::vector<Expression*> parWhere; 73 std::vector<BinOp*> todo; 74 todo.push_back(c->where(i)->cast<BinOp>()); 75 while (!todo.empty()) { 76 BinOp* bo = todo.back(); 77 todo.pop_back(); 78 if (bo->rhs()->type().isPar()) { 79 parWhere.push_back(bo->rhs()); 80 } else if (bo->rhs()->isa<BinOp>() && bo->rhs()->cast<BinOp>()->op() == BOT_AND) { 81 todo.push_back(bo->rhs()->cast<BinOp>()); 82 } else { 83 where.push_back(bo->rhs()); 84 } 85 if (bo->lhs()->type().isPar()) { 86 parWhere.push_back(bo->lhs()); 87 } else if (bo->lhs()->isa<BinOp>() && bo->lhs()->cast<BinOp>()->op() == BOT_AND) { 88 todo.push_back(bo->lhs()->cast<BinOp>()); 89 } else { 90 where.push_back(bo->lhs()); 91 } 92 } 93 switch (parWhere.size()) { 94 case 0: 95 orig_where[i] = nullptr; 96 break; 97 case 1: 98 orig_where[i] = parWhere[0]; 99 break; 100 case 2: 101 orig_where[i] = new BinOp(c->where(i)->loc(), parWhere[0], BOT_AND, parWhere[1]); 102 orig_where[i]->type(Type::parbool()); 103 break; 104 default: { 105 auto* parWhereAl = new ArrayLit(c->where(i)->loc(), parWhere); 106 parWhereAl->type(Type::parbool(1)); 107 Call* forall = new Call(c->where(i)->loc(), constants().ids.forall, {parWhereAl}); 108 forall->type(Type::parbool()); 109 forall->decl(env.model->matchFn(env, forall, false)); 110 orig_where[i] = forall; 111 break; 112 } 113 } 114 } else { 115 orig_where[i] = nullptr; 116 where.push_back(c->where(i)); 117 } 118 } else { 119 orig_where[i] = c->where(i); 120 } 121 } 122 } 123 if (!where.empty()) { 124 Generators gs; 125 for (int i = 0; i < c->numberOfGenerators(); i++) { 126 std::vector<VarDecl*> vds(c->numberOfDecls(i)); 127 for (int j = 0; j < c->numberOfDecls(i); j++) { 128 vds[j] = c->decl(i, j); 129 } 130 gs.g.emplace_back(vds, in[i], orig_where[i]); 131 } 132 Expression* cond; 133 if (where.size() > 1) { 134 auto* al = new ArrayLit(Location().introduce(), where); 135 al->type(Type::varbool(1)); 136 std::vector<Expression*> args(1); 137 args[0] = al; 138 Call* forall = new Call(Location().introduce(), constants().ids.forall, args); 139 forall->type(Type::varbool()); 140 forall->decl(env.model->matchFn(env, forall, false)); 141 cond = forall; 142 } else { 143 cond = where[0]; 144 } 145 146 Expression* new_e; 147 148 Call* surround = env.surroundingCall(); 149 150 Type ntype = c->type(); 151 if ((surround != nullptr) && surround->id() == constants().ids.forall) { 152 new_e = new BinOp(Location().introduce(), cond, BOT_IMPL, c->e()); 153 new_e->type(Type::varbool()); 154 ntype.ot(Type::OT_PRESENT); 155 } else if ((surround != nullptr) && surround->id() == constants().ids.exists) { 156 new_e = new BinOp(Location().introduce(), cond, BOT_AND, c->e()); 157 new_e->type(Type::varbool()); 158 ntype.ot(Type::OT_PRESENT); 159 } else if ((surround != nullptr) && surround->id() == constants().ids.sum) { 160 ITE* if_b_else_zero = new ITE(c->loc().introduce(), {cond, c->e()}, IntLit::a(0)); 161 Type tt; 162 tt = c->e()->type(); 163 tt.ti(Type::TI_VAR); 164 tt.ot(Type::OT_PRESENT); 165 if_b_else_zero->type(tt); 166 new_e = if_b_else_zero; 167 ntype.ot(Type::OT_PRESENT); 168 } else { 169 ITE* if_b_else_absent = new ITE(c->loc().introduce(), {cond, c->e()}, constants().absent); 170 Type tt; 171 tt = c->e()->type(); 172 tt.ti(Type::TI_VAR); 173 tt.ot(Type::OT_OPTIONAL); 174 if_b_else_absent->type(tt); 175 new_e = if_b_else_absent; 176 } 177 auto* nc = new Comprehension(c->loc(), new_e, gs, c->set()); 178 nc->type(ntype); 179 c = nc; 180 c_ka = c; 181 } 182 } 183 184 class EvalF : public EvalBase { 185 public: 186 Ctx ctx; 187 EvalF(const Ctx& ctx0) : ctx(ctx0) {} 188 typedef EE ArrayVal; 189 EE e(EnvI& env, Expression* e0) const { 190 VarDecl* b = ctx.b == C_ROOT ? constants().varTrue : nullptr; 191 VarDecl* r = (ctx.b == C_ROOT && e0->type().isbool() && !e0->type().isOpt()) 192 ? constants().varTrue 193 : nullptr; 194 return flat_exp(env, ctx, e0, r, b); 195 } 196 static Expression* flatten(EnvI& env, Expression* e0) { 197 return flat_exp(env, Ctx(), e0, nullptr, constants().varTrue).r(); 198 } 199 } _evalf(ctx); 200 std::vector<EE> elems_ee; 201 bool wasUndefined = false; 202 try { 203 elems_ee = eval_comp<EvalF>(env, _evalf, c); 204 } catch (ResultUndefinedError&) { 205 wasUndefined = true; 206 } 207 std::vector<Expression*> elems(elems_ee.size()); 208 Type elemType = Type::bot(); 209 bool allPar = true; 210 bool someOpt = false; 211 for (auto i = static_cast<unsigned int>(elems.size()); (i--) != 0U;) { 212 elems[i] = elems_ee[i].r(); 213 if (elemType == Type::bot()) { 214 elemType = elems[i]->type(); 215 } 216 if (!elems[i]->type().isPar()) { 217 allPar = false; 218 } 219 if (elems[i]->type().isOpt()) { 220 someOpt = true; 221 } 222 } 223 if (elemType.isbot()) { 224 elemType = c->type(); 225 elemType.ti(Type::TI_PAR); 226 } 227 if (!allPar) { 228 elemType.ti(Type::TI_VAR); 229 } 230 if (someOpt) { 231 elemType.ot(Type::OT_OPTIONAL); 232 } 233 if (c->set()) { 234 elemType.st(Type::ST_SET); 235 } else { 236 elemType.dim(c->type().dim()); 237 } 238 KeepAlive ka; 239 { 240 GCLock lock; 241 if (c->set()) { 242 if (c->type().isPar() && allPar) { 243 auto* sl = new SetLit(c->loc(), elems); 244 sl->type(elemType); 245 Expression* slr = eval_par(env, sl); 246 slr->type(elemType); 247 ka = slr; 248 } else { 249 auto* alr = new ArrayLit(Location().introduce(), elems); 250 elemType.st(Type::ST_PLAIN); 251 elemType.dim(1); 252 alr->type(elemType); 253 alr->flat(true); 254 Call* a2s = new Call(Location().introduce(), "array2set", {alr}); 255 a2s->decl(env.model->matchFn(env, a2s, false)); 256 a2s->type(a2s->decl()->rtype(env, {alr}, false)); 257 EE ee = flat_exp(env, Ctx(), a2s, nullptr, constants().varTrue); 258 ka = ee.r(); 259 } 260 } else { 261 auto* alr = new ArrayLit(Location().introduce(), elems); 262 alr->type(elemType); 263 alr->flat(true); 264 ka = alr; 265 } 266 } 267 assert(!ka()->type().isbot()); 268 if (wasUndefined) { 269 ret.b = bind(env, Ctx(), b, constants().literalFalse); 270 } else { 271 ret.b = conj(env, b, Ctx(), elems_ee); 272 } 273 ret.r = bind(env, Ctx(), r, ka()); 274 return ret; 275} 276 277} // namespace MiniZinc