this repo has no description
at develop 42 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 16std::vector<Expression*> toExpVec(std::vector<KeepAlive>& v) { 17 std::vector<Expression*> r(v.size()); 18 for (unsigned int i = static_cast<unsigned int>(v.size()); i--;) r[i] = v[i](); 19 return r; 20} 21 22bool isTotal(FunctionI* fi) { return fi->ann().contains(constants().ann.promise_total); } 23 24Call* same_call(EnvI& env, Expression* e, const ASTString& id) { 25 assert(GC::locked()); 26 Expression* ce = follow_id(e); 27 Call* c = Expression::dyn_cast<Call>(ce); 28 if (c) { 29 if (c->id() == id) { 30 return ce->cast<Call>(); 31 } else if (c->id() == constants().ids.int2float) { 32 Expression* i2f = follow_id(c->arg(0)); 33 Call* i2fc = Expression::dyn_cast<Call>(i2f); 34 if (i2fc && i2fc->id() == id && id == constants().ids.lin_exp) { 35 ArrayLit* coeffs = eval_array_lit(env, i2fc->arg(0)); 36 std::vector<Expression*> ncoeff_v(coeffs->size()); 37 for (unsigned int i = 0; i < coeffs->size(); i++) { 38 ncoeff_v[i] = FloatLit::a(eval_int(env, (*coeffs)[i])); 39 } 40 ArrayLit* ncoeff = new ArrayLit(coeffs->loc().introduce(), ncoeff_v); 41 ncoeff->type(Type::parfloat(1)); 42 ArrayLit* vars = eval_array_lit(env, i2fc->arg(1)); 43 std::vector<Expression*> n_vars_v(vars->size()); 44 for (unsigned int i = 0; i < vars->size(); i++) { 45 Call* f2i = 46 new Call((*vars)[i]->loc().introduce(), constants().ids.int2float, {(*vars)[i]}); 47 f2i->decl(env.model->matchFn(env, f2i, false)); 48 assert(f2i->decl()); 49 f2i->type(Type::varfloat()); 50 EE ee = flat_exp(env, Ctx(), f2i, NULL, constants().var_true); 51 n_vars_v[i] = ee.r(); 52 } 53 ArrayLit* nvars = new ArrayLit(vars->loc().introduce(), n_vars_v); 54 nvars->type(Type::varfloat(1)); 55 FloatVal c = eval_int(env, i2fc->arg(2)); 56 Call* nlinexp = new Call(i2fc->loc().introduce(), constants().ids.lin_exp, 57 {ncoeff, nvars, FloatLit::a(c)}); 58 nlinexp->decl(env.model->matchFn(env, nlinexp, false)); 59 assert(nlinexp->decl()); 60 nlinexp->type(Type::varfloat()); 61 return nlinexp; 62 } 63 } 64 } 65 return NULL; 66} 67 68class CmpExp { 69public: 70 bool operator()(const KeepAlive& i, const KeepAlive& j) const { 71 if (Expression::equal(i(), j())) return false; 72 return i() < j(); 73 } 74}; 75 76bool remove_dups(std::vector<KeepAlive>& x, bool identity) { 77 for (unsigned int i = 0; i < x.size(); i++) { 78 x[i] = follow_id_to_value(x[i]()); 79 } 80 std::sort(x.begin(), x.end(), CmpExp()); 81 int ci = 0; 82 Expression* prev = NULL; 83 for (unsigned int i = 0; i < x.size(); i++) { 84 if (!Expression::equal(x[i](), prev)) { 85 prev = x[i](); 86 if (x[i]()->isa<BoolLit>()) { 87 if (x[i]()->cast<BoolLit>()->v() == identity) { 88 // skip 89 } else { 90 return true; 91 } 92 } else { 93 x[ci++] = x[i]; 94 } 95 } 96 } 97 x.resize(ci); 98 return false; 99} 100bool contains_dups(std::vector<KeepAlive>& x, std::vector<KeepAlive>& y) { 101 if (x.size() == 0 || y.size() == 0) return false; 102 unsigned int ix = 0; 103 unsigned int iy = 0; 104 for (;;) { 105 if (x[ix]() == y[iy]()) return true; 106 if (x[ix]() < y[iy]()) { 107 ix++; 108 } else { 109 iy++; 110 } 111 if (ix == x.size() || iy == y.size()) return false; 112 } 113} 114 115template <class Lit> 116void flatten_linexp_call(EnvI& env, Ctx ctx, Ctx nctx, ASTString& cid, Call* c, EE& ret, VarDecl* b, 117 VarDecl* r, std::vector<EE>& args_ee, std::vector<KeepAlive>& args) { 118 typedef typename LinearTraits<Lit>::Val Val; 119 Expression* al_arg = (cid == constants().ids.sum ? args_ee[0].r() : args_ee[1].r()); 120 EE flat_al = flat_exp(env, nctx, al_arg, NULL, NULL); 121 ArrayLit* al = follow_id(flat_al.r())->template cast<ArrayLit>(); 122 KeepAlive al_ka = al; 123 if (al->dims() > 1) { 124 Type alt = al->type(); 125 alt.dim(1); 126 GCLock lock; 127 al = new ArrayLit(al->loc(), *al); 128 al->type(alt); 129 al_ka = al; 130 } 131 Val d = (cid == constants().ids.sum ? Val(0) : LinearTraits<Lit>::eval(env, args_ee[2].r())); 132 133 std::vector<Val> c_coeff(al->size()); 134 if (cid == constants().ids.sum) { 135 for (unsigned int i = al->size(); i--;) c_coeff[i] = 1; 136 } else { 137 EE flat_coeff = flat_exp(env, nctx, args_ee[0].r(), NULL, NULL); 138 ArrayLit* coeff = follow_id(flat_coeff.r())->template cast<ArrayLit>(); 139 for (unsigned int i = coeff->size(); i--;) 140 c_coeff[i] = LinearTraits<Lit>::eval(env, (*coeff)[i]); 141 } 142 cid = constants().ids.lin_exp; 143 std::vector<Val> coeffv; 144 std::vector<KeepAlive> alv; 145 for (unsigned int i = 0; i < al->size(); i++) { 146 GCLock lock; 147 if (Call* sc = Expression::dyn_cast<Call>(same_call(env, (*al)[i], cid))) { 148 if (VarDecl* alvi_decl = follow_id_to_decl((*al)[i])->dyn_cast<VarDecl>()) { 149 if (alvi_decl->ti()->domain()) { 150 // Test if the variable has tighter declared bounds than what can be inferred 151 // from its RHS. If yes, keep the variable (don't aggregate), because the tighter 152 // bounds are actually a constraint 153 typename LinearTraits<Lit>::Domain sc_dom = 154 LinearTraits<Lit>::eval_domain(env, alvi_decl->ti()->domain()); 155 typename LinearTraits<Lit>::Bounds sc_bounds = LinearTraits<Lit>::compute_bounds(env, sc); 156 if (LinearTraits<Lit>::domain_tighter(sc_dom, sc_bounds)) { 157 coeffv.push_back(c_coeff[i]); 158 alv.push_back((*al)[i]); 159 continue; 160 } 161 } 162 } 163 164 Val cd = c_coeff[i]; 165 ArrayLit* sc_coeff = eval_array_lit(env, sc->arg(0)); 166 ArrayLit* sc_al = eval_array_lit(env, sc->arg(1)); 167 Val sc_d = LinearTraits<Lit>::eval(env, sc->arg(2)); 168 assert(sc_coeff->size() == sc_al->size()); 169 for (unsigned int j = 0; j < sc_coeff->size(); j++) { 170 coeffv.push_back(cd * LinearTraits<Lit>::eval(env, (*sc_coeff)[j])); 171 alv.push_back((*sc_al)[j]); 172 } 173 d += cd * sc_d; 174 } else { 175 coeffv.push_back(c_coeff[i]); 176 alv.push_back((*al)[i]); 177 } 178 } 179 simplify_lin<Lit>(coeffv, alv, d); 180 if (coeffv.size() == 0) { 181 GCLock lock; 182 ret.b = conj(env, b, Ctx(), args_ee); 183 ret.r = bind(env, ctx, r, LinearTraits<Lit>::newLit(d)); 184 return; 185 } else if (coeffv.size() == 1 && coeffv[0] == 1 && d == 0) { 186 ret.b = conj(env, b, Ctx(), args_ee); 187 ret.r = bind(env, ctx, r, alv[0]()); 188 return; 189 } 190 GCLock lock; 191 std::vector<Expression*> coeff_ev(coeffv.size()); 192 for (unsigned int i = static_cast<unsigned int>(coeff_ev.size()); i--;) 193 coeff_ev[i] = LinearTraits<Lit>::newLit(coeffv[i]); 194 ArrayLit* ncoeff = new ArrayLit(Location().introduce(), coeff_ev); 195 Type t = coeff_ev[0]->type(); 196 t.dim(1); 197 ncoeff->type(t); 198 args.push_back(ncoeff); 199 std::vector<Expression*> alv_e(alv.size()); 200 bool al_same_as_before = alv.size() == al->size(); 201 for (unsigned int i = static_cast<unsigned int>(alv.size()); i--;) { 202 alv_e[i] = alv[i](); 203 al_same_as_before = al_same_as_before && Expression::equal(alv_e[i], (*al)[i]); 204 } 205 if (al_same_as_before) { 206 Expression* rd = follow_id_to_decl(flat_al.r()); 207 if (rd->isa<VarDecl>()) rd = rd->cast<VarDecl>()->id(); 208 if (rd->type().dim() > 1) { 209 ArrayLit* al = eval_array_lit(env, rd); 210 std::vector<std::pair<int, int> > dims(1); 211 dims[0].first = 1; 212 dims[0].second = al->size(); 213 rd = new ArrayLit(al->loc(), *al, dims); 214 Type t = al->type(); 215 t.dim(1); 216 rd->type(t); 217 } 218 args.push_back(rd); 219 } else { 220 ArrayLit* nal = new ArrayLit(al->loc(), alv_e); 221 nal->type(al->type()); 222 args.push_back(nal); 223 } 224 Lit* il = LinearTraits<Lit>::newLit(d); 225 args.push_back(il); 226} 227 228/// Special form of disjunction for SCIP 229bool addBoundsDisj(EnvI& env, Expression* arg, Call* c_orig) { 230 auto pArrayLit = arg->dyn_cast<ArrayLit>(); 231 if (nullptr == pArrayLit) return false; 232 std::vector<Expression*> isUBI, bndI, varI, // integer bounds and vars 233 isUBF, bndF, varF; // float bounds and vars 234 for (int i = pArrayLit->size(); i--;) { 235 auto pId = pArrayLit->operator[](i)->dyn_cast<Id>(); 236 if (nullptr == pId) return false; 237 auto pDecl = follow_id_to_decl(pId)->dyn_cast<VarDecl>(); 238 /// Checking the rhs 239 auto pRhs = pDecl->e(); 240 if (nullptr == pRhs) return false; // not checking this boolean 241 auto pCall = pRhs->dyn_cast<Call>(); 242 if (nullptr == pCall) return false; 243 if (constants().ids.int_.le != pCall->id() && constants().ids.float_.le != pCall->id()) 244 return false; 245 /// See if one is a constant and one a variable 246 Expression *pConst = nullptr, *pVar = nullptr; 247 bool fFloat = false; 248 bool isUB = false; 249 for (int j = pCall->n_args(); j--;) { 250 if (auto pF = pCall->arg(j)->dyn_cast<FloatLit>()) { 251 pConst = pF; 252 fFloat = true; 253 isUB = (1 == j); 254 } else if (auto pF = pCall->arg(j)->dyn_cast<IntLit>()) { 255 pConst = pF; 256 fFloat = false; 257 isUB = (1 == j); 258 } else if (auto pId = pCall->arg(j)->dyn_cast<Id>()) { 259 if (nullptr != pVar) return false; // 2 variables, exit 260 pVar = pId; 261 } 262 } 263 /// All good, add them 264 if (fFloat) { 265 isUBF.push_back(constants().boollit(isUB)); 266 bndF.push_back(pConst); 267 varF.push_back(pVar); 268 } else { 269 isUBI.push_back(constants().boollit(isUB)); 270 bndI.push_back(pConst); 271 varI.push_back(pVar); 272 } 273 } 274 /// Create new call 275 GCLock lock; 276 auto loc = c_orig->loc().introduce(); 277 std::vector<Expression*> args = {new ArrayLit(loc, isUBI), new ArrayLit(loc, bndI), 278 new ArrayLit(loc, varI), new ArrayLit(loc, isUBF), 279 new ArrayLit(loc, bndF), new ArrayLit(loc, varF)}; 280 281 Call* c = 282 new Call(c_orig->loc().introduce(), env.model->getFnDecls().bounds_disj.second->id(), args); 283 c->type(Type::varbool()); 284 c->decl(env.model->getFnDecls().bounds_disj.second); 285 env.flat_addItem(new ConstraintI(c_orig->loc().introduce(), c)); 286 return true; 287} 288 289class IgnorePartial { 290public: 291 EnvI& env; 292 bool ignorePartial; 293 IgnorePartial(EnvI& env0, Call* c) : env(env0), ignorePartial(env.ignorePartial) { 294 if (c->id().endsWith("_reif") || c->id().endsWith("_imp")) { 295 env.ignorePartial = true; 296 } 297 } 298 ~IgnorePartial(void) { env.ignorePartial = ignorePartial; } 299}; 300 301EE flatten_call(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { 302 EE ret; 303 Call* c = e->cast<Call>(); 304 IgnorePartial ignorePartial(env, c); 305 if (c->id().endsWith("_reif")) { 306 env.n_reif_ct++; 307 } else if (c->id().endsWith("_imp")) { 308 env.n_imp_ct++; 309 } 310 FunctionI* decl = env.model->matchFn(env, c, false); 311 if (decl == NULL) { 312 throw InternalError("undeclared function or predicate " + c->id().str()); 313 } 314 315 if (decl->params().size() == 1) { 316 if (Call* call_body = Expression::dyn_cast<Call>(decl->e())) { 317 if (call_body->n_args() == 1 && 318 Expression::equal(call_body->arg(0), decl->params()[0]->id())) { 319 c->id(call_body->id()); 320 c->decl(call_body->decl()); 321 decl = c->decl(); 322 for (ExpressionSetIter esi = call_body->ann().begin(); esi != call_body->ann().end(); 323 ++esi) { 324 c->addAnnotation(*esi); 325 } 326 } 327 } 328 } 329 330 Ctx nctx = ctx; 331 nctx.neg = false; 332 ASTString cid = c->id(); 333 CallStackItem _csi(env, e); 334 335 if (cid == constants().ids.bool2int && c->type().dim() == 0) { 336 if (ctx.neg) { 337 ctx.neg = false; 338 nctx.neg = true; 339 nctx.b = -ctx.i; 340 } else { 341 nctx.b = ctx.i; 342 } 343 } else if (cid == constants().ids.forall) { 344 nctx.b = +nctx.b; 345 if (ctx.neg) { 346 ctx.neg = false; 347 nctx.neg = true; 348 cid = constants().ids.exists; 349 } 350 } else if (cid == constants().ids.exists) { 351 nctx.b = +nctx.b; 352 if (ctx.neg) { 353 ctx.neg = false; 354 nctx.neg = true; 355 cid = constants().ids.forall; 356 } 357 } else if (decl->e() == NULL && (cid == constants().ids.assert || cid == constants().ids.trace)) { 358 if (cid == constants().ids.assert && c->n_args() == 2) { 359 (void)decl->_builtins.b(env, c); 360 ret = flat_exp(env, ctx, constants().lit_true, r, b); 361 } else { 362 KeepAlive callres = decl->_builtins.e(env, c); 363 ret = flat_exp(env, ctx, callres(), r, b); 364 // This is all we need to do for assert, so break out of the E_CALL 365 } 366 return ret; 367 } else if (decl->e() && ctx.b == C_ROOT && decl->e()->isa<BoolLit>() && 368 eval_bool(env, decl->e())) { 369 bool allBool = true; 370 for (unsigned int i = 0; i < c->n_args(); i++) { 371 if (c->arg(i)->type().bt() != Type::BT_BOOL) { 372 allBool = false; 373 break; 374 } 375 } 376 if (allBool) { 377 ret.r = bind(env, ctx, r, constants().lit_true); 378 ret.b = bind(env, ctx, b, constants().lit_true); 379 return ret; 380 } 381 } 382 383 if (ctx.b == C_ROOT && decl->e() == NULL && cid == constants().ids.forall && 384 r == constants().var_true) { 385 ret.b = bind(env, ctx, b, constants().lit_true); 386 ArrayLit* al; 387 if (c->arg(0)->isa<ArrayLit>()) { 388 al = c->arg(0)->cast<ArrayLit>(); 389 } else { 390 EE flat_al = flat_exp(env, Ctx(), c->arg(0), constants().var_ignore, constants().var_true); 391 al = follow_id(flat_al.r())->cast<ArrayLit>(); 392 } 393 nctx.b = C_ROOT; 394 for (unsigned int i = 0; i < al->size(); i++) (void)flat_exp(env, nctx, (*al)[i], r, b); 395 ret.r = bind(env, ctx, r, constants().lit_true); 396 } else { 397 if (decl->e() && decl->params().size() == 1 && decl->e()->isa<Id>() && 398 decl->params()[0]->ti()->domain() == NULL && 399 decl->e()->cast<Id>()->decl() == decl->params()[0]) { 400 Expression* arg = c->arg(0); 401 for (ExpressionSetIter esi = decl->e()->ann().begin(); esi != decl->e()->ann().end(); ++esi) { 402 arg->addAnnotation(*esi); 403 } 404 for (ExpressionSetIter esi = c->ann().begin(); esi != c->ann().end(); ++esi) { 405 arg->addAnnotation(*esi); 406 } 407 ret = flat_exp(env, ctx, c->arg(0), r, b); 408 return ret; 409 } 410 411 std::vector<EE> args_ee(c->n_args()); 412 bool isPartial = false; 413 414 if (cid == constants().ids.lin_exp && c->type().isint()) { 415 // Linear expressions need special context handling: 416 // the context of a variable expression depends on the corresponding coefficient 417 418 // flatten the coefficient array 419 Expression* tmp = follow_id_to_decl(c->arg(0)); 420 ArrayLit* coeffs; 421 if (VarDecl* vd = tmp->dyn_cast<VarDecl>()) tmp = vd->id(); 422 { 423 CallArgItem cai(env); 424 args_ee[0] = flat_exp(env, nctx, tmp, NULL, NULL); 425 isPartial |= isfalse(env, args_ee[0].b()); 426 coeffs = eval_array_lit(env, args_ee[0].r()); 427 } 428 429 ArrayLit* vars = eval_array_lit(env, c->arg(1)); 430 if (vars->flat()) { 431 args_ee[1].r = vars; 432 args_ee[1].b = constants().var_true; 433 } else { 434 CallArgItem cai(env); 435 CallStackItem _csi(env, c->arg(1)); 436 std::vector<EE> elems_ee(vars->size()); 437 for (unsigned int i = vars->size(); i--;) { 438 Ctx argctx = nctx; 439 argctx.i = eval_int(env, (*coeffs)[i]) < 0 ? -nctx.i : +nctx.i; 440 elems_ee[i] = flat_exp(env, argctx, (*vars)[i], NULL, NULL); 441 } 442 std::vector<Expression*> elems(elems_ee.size()); 443 for (unsigned int i = static_cast<unsigned int>(elems.size()); i--;) 444 elems[i] = elems_ee[i].r(); 445 KeepAlive ka; 446 { 447 GCLock lock; 448 ArrayLit* alr = new ArrayLit(Location().introduce(), elems); 449 alr->type(vars->type()); 450 alr->flat(true); 451 ka = alr; 452 } 453 args_ee[1].r = ka(); 454 args_ee[1].b = conj(env, b, Ctx(), elems_ee); 455 } 456 457 { 458 Expression* constant = follow_id_to_decl(c->arg(2)); 459 if (VarDecl* vd = constant->dyn_cast<VarDecl>()) constant = vd->id(); 460 CallArgItem cai(env); 461 args_ee[2] = flat_exp(env, nctx, constant, NULL, NULL); 462 isPartial |= isfalse(env, args_ee[2].b()); 463 } 464 465 } else { 466 bool mixContext = 467 (cid != constants().ids.forall && cid != constants().ids.exists && 468 (cid != constants().ids.bool2int || c->type().dim() > 0) && cid != constants().ids.sum && 469 cid != "assert" && cid != constants().var_redef->id() && cid != "mzn_reverse_map_var"); 470 if (cid == "mzn_reverse_map_var") { 471 env.in_reverse_map_var = true; 472 } 473 if (cid == constants().ids.clause && c->arg(0)->isa<ArrayLit>() && 474 c->arg(1)->isa<ArrayLit>()) { 475 GCLock lock; 476 // try to make negative arguments positive 477 std::vector<Expression*> newPositives; 478 std::vector<Expression*> newNegatives; 479 ArrayLit* al_neg = c->arg(1)->cast<ArrayLit>(); 480 for (unsigned int i = 0; i < al_neg->size(); i++) { 481 BinOp* bo = (*al_neg)[i]->dyn_cast<BinOp>(); 482 Call* co = (*al_neg)[i]->dyn_cast<Call>(); 483 if (bo || 484 (co && (co->id() == constants().ids.forall || co->id() == constants().ids.exists || 485 co->id() == constants().ids.clause))) { 486 UnOp* notBoe0 = new UnOp(Location().introduce(), UOT_NOT, (*al_neg)[i]); 487 notBoe0->type(Type::varbool()); 488 newPositives.push_back(notBoe0); 489 } else { 490 newNegatives.push_back((*al_neg)[i]); 491 } 492 } 493 if (!newPositives.empty()) { 494 ArrayLit* al_pos = c->arg(0)->cast<ArrayLit>(); 495 for (unsigned int i = 0; i < al_pos->size(); i++) { 496 newPositives.push_back((*al_pos)[i]); 497 } 498 c->arg(0, new ArrayLit(Location().introduce(), newPositives)); 499 c->arg(1, new ArrayLit(Location().introduce(), newNegatives)); 500 c->arg(0)->type(Type::varbool(1)); 501 c->arg(1)->type(Type::varbool(1)); 502 } 503 } 504 for (unsigned int i = c->n_args(); i--;) { 505 Ctx argctx = nctx; 506 if (mixContext) { 507 if (cid == constants().ids.clause) { 508 argctx.b = (i == 0 ? +nctx.b : -nctx.b); 509 } else if (c->arg(i)->type().bt() == Type::BT_BOOL) { 510 argctx.b = C_MIX; 511 } else if (c->arg(i)->type().bt() == Type::BT_INT) { 512 argctx.i = C_MIX; 513 } 514 } 515 Expression* tmp = follow_id_to_decl(c->arg(i)); 516 if (VarDecl* vd = tmp->dyn_cast<VarDecl>()) tmp = vd->id(); 517 CallArgItem cai(env); 518 args_ee[i] = flat_exp(env, argctx, tmp, NULL, NULL); 519 isPartial |= isfalse(env, args_ee[i].b()); 520 } 521 } 522 if (isPartial && c->type().isbool() && !c->type().isopt()) { 523 ret.b = bind(env, Ctx(), b, constants().lit_true); 524 args_ee.resize(1); 525 args_ee[0] = EE(NULL, constants().lit_false); 526 ret.r = conj(env, r, ctx, args_ee); 527 return ret; 528 } 529 530 std::vector<KeepAlive> args; 531 if (decl->e() == NULL && (cid == constants().ids.exists || cid == constants().ids.clause)) { 532 std::vector<KeepAlive> pos_alv; 533 std::vector<KeepAlive> neg_alv; 534 535 std::vector<Expression*> pos_stack; 536 std::vector<Expression*> neg_stack; 537 538 ArrayLit* al_pos = follow_id(args_ee[0].r())->cast<ArrayLit>(); 539 for (unsigned int i = 0; i < al_pos->size(); i++) { 540 pos_stack.push_back((*al_pos)[i]); 541 } 542 if (cid == constants().ids.clause) { 543 ArrayLit* al_neg = follow_id(args_ee[1].r())->cast<ArrayLit>(); 544 for (unsigned int i = 0; i < al_neg->size(); i++) { 545 neg_stack.push_back((*al_neg)[i]); 546 } 547 } 548 549 while (!pos_stack.empty() || !neg_stack.empty()) { 550 while (!pos_stack.empty()) { 551 Expression* cur = pos_stack.back(); 552 pos_stack.pop_back(); 553 GCLock lock; 554 if (Call* sc = Expression::dyn_cast<Call>(same_call(env, cur, constants().ids.exists))) { 555 GCLock lock; 556 ArrayLit* sc_c = eval_array_lit(env, sc->arg(0)); 557 for (unsigned int j = 0; j < sc_c->size(); j++) { 558 pos_stack.push_back((*sc_c)[j]); 559 } 560 } else if (Call* sc = 561 Expression::dyn_cast<Call>(same_call(env, cur, constants().ids.clause))) { 562 GCLock lock; 563 ArrayLit* sc_c = eval_array_lit(env, sc->arg(0)); 564 for (unsigned int j = 0; j < sc_c->size(); j++) { 565 pos_stack.push_back((*sc_c)[j]); 566 } 567 sc_c = eval_array_lit(env, sc->arg(1)); 568 for (unsigned int j = 0; j < sc_c->size(); j++) { 569 neg_stack.push_back((*sc_c)[j]); 570 } 571 } else { 572 Call* eq_call = 573 Expression::dyn_cast<Call>(same_call(env, cur, constants().ids.bool_eq)); 574 if (eq_call && Expression::equal(eq_call->arg(1), constants().lit_false)) { 575 neg_stack.push_back(eq_call->arg(0)); 576 } else if (eq_call && Expression::equal(eq_call->arg(0), constants().lit_false)) { 577 neg_stack.push_back(eq_call->arg(1)); 578 } else if (eq_call && Expression::equal(eq_call->arg(1), constants().lit_true)) { 579 pos_stack.push_back(eq_call->arg(0)); 580 } else if (eq_call && Expression::equal(eq_call->arg(0), constants().lit_true)) { 581 pos_stack.push_back(eq_call->arg(1)); 582 } else if (Id* ident = cur->dyn_cast<Id>()) { 583 if (ident->decl()->ti()->domain() != constants().lit_false) { 584 pos_alv.push_back(ident); 585 } 586 } else { 587 pos_alv.push_back(cur); 588 } 589 } 590 } 591 592 while (!neg_stack.empty()) { 593 GCLock lock; 594 Expression* cur = neg_stack.back(); 595 neg_stack.pop_back(); 596 if (Call* sc = Expression::dyn_cast<Call>(same_call(env, cur, constants().ids.forall))) { 597 GCLock lock; 598 ArrayLit* sc_c = eval_array_lit(env, sc->arg(0)); 599 for (unsigned int j = 0; j < sc_c->size(); j++) { 600 neg_stack.push_back((*sc_c)[j]); 601 } 602 } else { 603 Call* eq_call = 604 Expression::dyn_cast<Call>(same_call(env, cur, constants().ids.bool_eq)); 605 if (eq_call && Expression::equal(eq_call->arg(1), constants().lit_false)) { 606 pos_stack.push_back(eq_call->arg(0)); 607 } else if (eq_call && Expression::equal(eq_call->arg(0), constants().lit_false)) { 608 pos_stack.push_back(eq_call->arg(1)); 609 } else if (eq_call && Expression::equal(eq_call->arg(1), constants().lit_true)) { 610 neg_stack.push_back(eq_call->arg(0)); 611 } else if (eq_call && Expression::equal(eq_call->arg(0), constants().lit_true)) { 612 neg_stack.push_back(eq_call->arg(1)); 613 } else if (Id* ident = cur->dyn_cast<Id>()) { 614 if (ident->decl()->ti()->domain() != constants().lit_true) { 615 neg_alv.push_back(ident); 616 } 617 } else { 618 neg_alv.push_back(cur); 619 } 620 } 621 } 622 } 623 624 bool subsumed = remove_dups(pos_alv, false); 625 subsumed = subsumed || remove_dups(neg_alv, true); 626 subsumed = subsumed || contains_dups(pos_alv, neg_alv); 627 if (subsumed) { 628 ret.b = bind(env, Ctx(), b, constants().lit_true); 629 ret.r = bind(env, ctx, r, constants().lit_true); 630 return ret; 631 } 632 if (neg_alv.empty()) { 633 if (pos_alv.size() == 0) { 634 ret.b = bind(env, Ctx(), b, constants().lit_true); 635 ret.r = bind(env, ctx, r, constants().lit_false); 636 return ret; 637 } else if (pos_alv.size() == 1) { 638 ret.b = bind(env, Ctx(), b, constants().lit_true); 639 ret.r = bind(env, ctx, r, pos_alv[0]()); 640 return ret; 641 } 642 GCLock lock; 643 ArrayLit* nal = new ArrayLit(Location().introduce(), toExpVec(pos_alv)); 644 nal->type(Type::varbool(1)); 645 args.push_back(nal); 646 cid = constants().ids.exists; 647 } else { 648 GCLock lock; 649 ArrayLit* pos_al = new ArrayLit(Location().introduce(), toExpVec(pos_alv)); 650 pos_al->type(Type::varbool(1)); 651 ArrayLit* neg_al = new ArrayLit(Location().introduce(), toExpVec(neg_alv)); 652 neg_al->type(Type::varbool(1)); 653 cid = constants().ids.clause; 654 args.push_back(pos_al); 655 args.push_back(neg_al); 656 } 657 if (C_ROOT == ctx.b && cid == constants().ids.exists) { 658 /// Check the special bounds disjunction for SCIP 659 /// Only in root context 660 if (!env.model->getFnDecls().bounds_disj.first) { 661 env.model->getFnDecls().bounds_disj.first = true; 662 std::vector<Type> bj_t = {Type::parbool(1), Type::parint(1), Type::varint(1), 663 Type::parbool(1), Type::parfloat(1), Type::varfloat(1)}; 664 GCLock lock; 665 env.model->getFnDecls().bounds_disj.second = 666 env.model->matchFn(env, ASTString("bounds_disj"), bj_t, false); 667 } 668 /// When the SCIP predicate is declared only 669 bool fBoundsDisj_Maybe = (nullptr != env.model->getFnDecls().bounds_disj.second); 670 if (fBoundsDisj_Maybe) { 671 if (addBoundsDisj(env, args[0](), c)) { 672 ret.b = bind(env, Ctx(), b, constants().lit_true); 673 ret.r = bind(env, ctx, r, constants().lit_true); 674 return ret; 675 } 676 } 677 } 678 679 } else if (decl->e() == NULL && cid == constants().ids.forall) { 680 ArrayLit* al = follow_id(args_ee[0].r())->cast<ArrayLit>(); 681 std::vector<KeepAlive> alv; 682 for (unsigned int i = 0; i < al->size(); i++) { 683 GCLock lock; 684 if (Call* sc = Expression::dyn_cast<Call>(same_call(env, (*al)[i], cid))) { 685 GCLock lock; 686 ArrayLit* sc_c = eval_array_lit(env, sc->arg(0)); 687 for (unsigned int j = 0; j < sc_c->size(); j++) { 688 alv.push_back((*sc_c)[j]); 689 } 690 } else { 691 alv.push_back((*al)[i]); 692 } 693 } 694 bool subsumed = remove_dups(alv, true); 695 if (subsumed) { 696 ret.b = bind(env, Ctx(), b, constants().lit_true); 697 ret.r = bind(env, ctx, r, constants().lit_false); 698 return ret; 699 } 700 if (alv.size() == 0) { 701 ret.b = bind(env, Ctx(), b, constants().lit_true); 702 ret.r = bind(env, ctx, r, constants().lit_true); 703 return ret; 704 } else if (alv.size() == 1) { 705 ret.b = bind(env, Ctx(), b, constants().lit_true); 706 ret.r = bind(env, ctx, r, alv[0]()); 707 return ret; 708 } 709 GCLock lock; 710 ArrayLit* nal = new ArrayLit(al->loc(), toExpVec(alv)); 711 nal->type(al->type()); 712 args.push_back(nal); 713 } else if (decl->e() == NULL && 714 (cid == constants().ids.lin_exp || cid == constants().ids.sum)) { 715 if (e->type().isint()) { 716 flatten_linexp_call<IntLit>(env, ctx, nctx, cid, c, ret, b, r, args_ee, args); 717 } else { 718 flatten_linexp_call<FloatLit>(env, ctx, nctx, cid, c, ret, b, r, args_ee, args); 719 } 720 if (args.size() == 0) return ret; 721 } else { 722 for (unsigned int i = 0; i < args_ee.size(); i++) args.push_back(args_ee[i].r()); 723 } 724 KeepAlive cr; 725 { 726 GCLock lock; 727 std::vector<Expression*> e_args = toExpVec(args); 728 Call* cr_c = new Call(c->loc().introduce(), cid, e_args); 729 decl = env.model->matchFn(env, cr_c, false); 730 if (decl == NULL) throw FlatteningError(env, cr_c->loc(), "cannot find matching declaration"); 731 cr_c->type(decl->rtype(env, e_args, false)); 732 assert(decl); 733 cr_c->decl(decl); 734 cr = cr_c; 735 } 736 EnvI::CSEMap::iterator cit = env.cse_map_find(cr()); 737 if (cit != env.cse_map_end()) { 738 ret.b = bind(env, Ctx(), b, env.ignorePartial ? constants().lit_true : cit->second.b()); 739 ret.r = bind(env, ctx, r, cit->second.r()); 740 } else { 741 for (unsigned int i = 0; i < decl->params().size(); i++) { 742 if (decl->params()[i]->type().dim() > 0) { 743 // Check array index sets 744 ArrayLit* al = follow_id(args[i]())->cast<ArrayLit>(); 745 VarDecl* pi = decl->params()[i]; 746 for (unsigned int j = 0; j < pi->ti()->ranges().size(); j++) { 747 TypeInst* range_ti = pi->ti()->ranges()[j]; 748 if (range_ti->domain() && !range_ti->domain()->isa<TIId>()) { 749 GCLock lock; 750 IntSetVal* isv = eval_intset(env, range_ti->domain()); 751 if (isv->min() != al->min(j) || isv->max() != al->max(j)) { 752 std::ostringstream oss; 753 oss << "array index set " << (j + 1) << " of argument " << (i + 1) 754 << " does not match declared index set"; 755 throw FlatteningError(env, e->loc(), oss.str()); 756 } 757 } 758 } 759 } 760 if (Expression* dom = decl->params()[i]->ti()->domain()) { 761 if (!dom->isa<TIId>()) { 762 // May have to constrain actual argument 763 if (args[i]()->type().bt() == Type::BT_INT) { 764 GCLock lock; 765 IntSetVal* isv = eval_intset(env, dom); 766 BinOpType bot; 767 bool needToConstrain; 768 if (args[i]()->type().st() == Type::ST_SET) { 769 bot = BOT_SUBSET; 770 needToConstrain = true; 771 } else { 772 bot = BOT_IN; 773 if (args[i]()->type().dim() > 0) { 774 needToConstrain = true; 775 } else { 776 IntBounds ib = compute_int_bounds(env, args[i]()); 777 needToConstrain = !ib.valid || isv->size() == 0 || ib.l < isv->min(0) || 778 ib.u > isv->max(isv->size() - 1); 779 } 780 } 781 if (needToConstrain) { 782 GCLock lock; 783 Expression* domconstraint; 784 if (args[i]()->type().dim() > 0) { 785 std::vector<Expression*> domargs(2); 786 domargs[0] = args[i](); 787 domargs[1] = dom; 788 Call* c = new Call(Location().introduce(), "var_dom", domargs); 789 c->type(Type::varbool()); 790 c->decl(env.model->matchFn(env, c, false)); 791 if (c->decl() == NULL) 792 throw InternalError("no matching declaration found for var_dom"); 793 domconstraint = c; 794 } else { 795 domconstraint = new BinOp(Location().introduce(), args[i](), bot, dom); 796 } 797 domconstraint->type(args[i]()->type().ispar() ? Type::parbool() : Type::varbool()); 798 if (ctx.b == C_ROOT) { 799 (void)flat_exp(env, Ctx(), domconstraint, constants().var_true, 800 constants().var_true); 801 } else { 802 EE ee = flat_exp(env, Ctx(), domconstraint, NULL, constants().var_true); 803 ee.b = ee.r; 804 args_ee.push_back(ee); 805 } 806 } 807 } else if (args[i]()->type().bt() == Type::BT_FLOAT) { 808 GCLock lock; 809 810 FloatSetVal* fsv = eval_floatset(env, dom); 811 bool needToConstrain; 812 if (args[i]()->type().dim() > 0) { 813 needToConstrain = true; 814 } else { 815 FloatBounds fb = compute_float_bounds(env, args[i]()); 816 needToConstrain = !fb.valid || fsv->size() == 0 || fb.l < fsv->min(0) || 817 fb.u > fsv->max(fsv->size() - 1); 818 } 819 820 if (needToConstrain) { 821 GCLock lock; 822 Expression* domconstraint; 823 if (args[i]()->type().dim() > 0) { 824 std::vector<Expression*> domargs(2); 825 domargs[0] = args[i](); 826 domargs[1] = dom; 827 Call* c = new Call(Location().introduce(), "var_dom", domargs); 828 c->type(Type::varbool()); 829 c->decl(env.model->matchFn(env, c, false)); 830 if (c->decl() == NULL) 831 throw InternalError("no matching declaration found for var_dom"); 832 domconstraint = c; 833 } else { 834 domconstraint = new BinOp(Location().introduce(), args[i](), BOT_IN, dom); 835 } 836 domconstraint->type(args[i]()->type().ispar() ? Type::parbool() : Type::varbool()); 837 if (ctx.b == C_ROOT) { 838 (void)flat_exp(env, Ctx(), domconstraint, constants().var_true, 839 constants().var_true); 840 } else { 841 EE ee = flat_exp(env, Ctx(), domconstraint, NULL, constants().var_true); 842 ee.b = ee.r; 843 args_ee.push_back(ee); 844 } 845 } 846 } else if (args[i]()->type().bt() == Type::BT_BOT) { 847 // Nothing to be done for empty arrays/sets 848 } else { 849 throw EvalError(env, decl->params()[i]->loc(), 850 "domain restrictions other than int and float not supported yet"); 851 } 852 } 853 } 854 } 855 if (cr()->type().isbool() && !cr()->type().ispar() && !cr()->type().isopt() && 856 (ctx.b != C_ROOT || r != constants().var_true)) { 857 std::vector<Type> argtypes(args.size()); 858 for (unsigned int i = 0; i < args.size(); i++) argtypes[i] = args[i]()->type(); 859 argtypes.push_back(Type::varbool()); 860 GCLock lock; 861 ASTString r_cid = env.reifyId(cid); 862 FunctionI* reif_decl = env.model->matchFn(env, r_cid, argtypes, false); 863 if (reif_decl && reif_decl->e()) { 864 addPathAnnotation(env, reif_decl->e()); 865 VarDecl* reif_b; 866 if (r == NULL || (r != NULL && r->e() != NULL)) { 867 reif_b = newVarDecl(env, Ctx(), new TypeInst(Location().introduce(), Type::varbool()), 868 NULL, NULL, NULL); 869 addCtxAnn(reif_b, ctx.b); 870 if (reif_b->ti()->domain()) { 871 if (reif_b->ti()->domain() == constants().lit_true) { 872 bind(env, ctx, r, constants().lit_true); 873 r = constants().var_true; 874 ctx.b = C_ROOT; 875 goto call_nonreif; 876 } else { 877 std::vector<Expression*> args_e(args.size() + 1); 878 for (unsigned int i = 0; i < args.size(); i++) args_e[i] = args[i](); 879 args_e[args.size()] = constants().lit_false; 880 Call* reif_call = new Call(Location().introduce(), r_cid, args_e); 881 reif_call->type(Type::varbool()); 882 reif_call->decl(reif_decl); 883 flat_exp(env, Ctx(), reif_call, constants().var_true, constants().var_true); 884 args_ee.push_back(EE(NULL, constants().lit_false)); 885 ret.r = conj(env, r, ctx, args_ee); 886 ret.b = bind(env, ctx, b, constants().lit_true); 887 return ret; 888 } 889 } 890 } else { 891 reif_b = r; 892 } 893 // Annotate cr() with getPath() 894 addPathAnnotation(env, cr()); 895 reif_b->e(cr()); 896 if (r != NULL && r->e() != NULL) { 897 Ctx reif_ctx; 898 reif_ctx.neg = ctx.neg; 899 bind(env, reif_ctx, r, reif_b->id()); 900 } 901 env.vo_add_exp(reif_b); 902 ret.b = bind(env, Ctx(), b, constants().lit_true); 903 args_ee.push_back(EE(NULL, reif_b->id())); 904 ret.r = conj(env, NULL, ctx, args_ee); 905 if (!ctx.neg && !cr()->type().isann()) { 906 env.cse_map_insert(cr(), ret); 907 } 908 return ret; 909 } 910 } 911 call_nonreif: 912 if ((cr()->type().ispar() && !cr()->type().isann()) || decl->e() == NULL) { 913 Call* cr_c = cr()->cast<Call>(); 914 /// All builtins are total 915 std::vector<Type> argt(cr_c->n_args()); 916 for (unsigned int i = static_cast<unsigned int>(argt.size()); i--;) 917 argt[i] = cr_c->arg(i)->type(); 918 Type callt = decl->rtype(env, argt, false); 919 if (callt.ispar() && callt.bt() != Type::BT_ANN) { 920 GCLock lock; 921 try { 922 ret.r = bind(env, ctx, r, eval_par(env, cr_c)); 923 ret.b = conj(env, b, Ctx(), args_ee); 924 } catch (ResultUndefinedError&) { 925 ret.r = createDummyValue(env, cr_c->type()); 926 ret.b = bind(env, Ctx(), b, constants().lit_false); 927 return ret; 928 } 929 // Do not insert into map, since par results will quickly become 930 // garbage anyway and then disappear from the map 931 } else if (decl->_builtins.e) { 932 KeepAlive callres; 933 { 934 GCLock lock; 935 callres = decl->_builtins.e(env, cr_c); 936 } 937 EE res = flat_exp(env, ctx, callres(), r, b); 938 args_ee.push_back(res); 939 ret.b = conj(env, b, Ctx(), args_ee); 940 addPathAnnotation(env, res.r()); 941 ret.r = bind(env, ctx, r, res.r()); 942 if (!ctx.neg && !cr_c->type().isann()) env.cse_map_insert(cr_c, ret); 943 } else { 944 ret.b = conj(env, b, Ctx(), args_ee); 945 addPathAnnotation(env, cr_c); 946 ret.r = bind(env, ctx, r, cr_c); 947 if (!ctx.neg && !cr_c->type().isann()) env.cse_map_insert(cr_c, ret); 948 } 949 } else { 950 std::vector<KeepAlive> previousParameters(decl->params().size()); 951 for (unsigned int i = decl->params().size(); i--;) { 952 VarDecl* vd = decl->params()[i]; 953 previousParameters[i] = vd->e(); 954 vd->flat(vd); 955 vd->e(args[i]()); 956 } 957 958 if (decl->e()->type().isbool() && !decl->e()->type().isopt()) { 959 ret.b = bind(env, Ctx(), b, constants().lit_true); 960 if (ctx.b == C_ROOT && r == constants().var_true) { 961 (void)flat_exp(env, Ctx(), decl->e(), r, constants().var_true); 962 } else { 963 Ctx nctx; 964 if (!isTotal(decl)) { 965 nctx = ctx; 966 nctx.neg = false; 967 } 968 EE ee = flat_exp(env, nctx, decl->e(), NULL, constants().var_true); 969 ee.b = ee.r; 970 args_ee.push_back(ee); 971 } 972 ret.r = conj(env, r, ctx, args_ee); 973 } else { 974 if (isTotal(decl)) { 975 EE ee = flat_exp(env, Ctx(), decl->e(), r, constants().var_true); 976 ret.r = bind(env, ctx, r, ee.r()); 977 } else { 978 ret = flat_exp(env, ctx, decl->e(), r, NULL); 979 args_ee.push_back(ret); 980 if (decl->e()->type().dim() > 0) { 981 ArrayLit* al = follow_id(ret.r())->cast<ArrayLit>(); 982 assert(al->dims() == decl->e()->type().dim()); 983 for (unsigned int i = 0; i < decl->ti()->ranges().size(); i++) { 984 if (decl->ti()->ranges()[i]->domain() && 985 !decl->ti()->ranges()[i]->domain()->isa<TIId>()) { 986 GCLock lock; 987 IntSetVal* isv = eval_intset(env, decl->ti()->ranges()[i]->domain()); 988 if (al->min(i) != isv->min() || al->max(i) != isv->max()) { 989 EE ee; 990 ee.b = constants().lit_false; 991 args_ee.push_back(ee); 992 } 993 } 994 } 995 } 996 if (decl->ti()->domain() && !decl->ti()->domain()->isa<TIId>()) { 997 BinOpType bot; 998 if (ret.r()->type().st() == Type::ST_SET) { 999 bot = BOT_SUBSET; 1000 } else { 1001 bot = BOT_IN; 1002 } 1003 1004 KeepAlive domconstraint; 1005 if (decl->e()->type().dim() > 0) { 1006 GCLock lock; 1007 std::vector<Expression*> domargs(2); 1008 domargs[0] = ret.r(); 1009 domargs[1] = decl->ti()->domain(); 1010 Call* c = new Call(Location().introduce(), "var_dom", domargs); 1011 c->type(Type::varbool()); 1012 c->decl(env.model->matchFn(env, c, false)); 1013 if (c->decl() == NULL) 1014 throw InternalError("no matching declaration found for var_dom"); 1015 domconstraint = c; 1016 } else { 1017 GCLock lock; 1018 domconstraint = 1019 new BinOp(Location().introduce(), ret.r(), bot, decl->ti()->domain()); 1020 } 1021 domconstraint()->type(ret.r()->type().ispar() ? Type::parbool() : Type::varbool()); 1022 if (ctx.b == C_ROOT) { 1023 (void)flat_exp(env, Ctx(), domconstraint(), constants().var_true, 1024 constants().var_true); 1025 } else { 1026 EE ee = flat_exp(env, Ctx(), domconstraint(), NULL, constants().var_true); 1027 ee.b = ee.r; 1028 args_ee.push_back(ee); 1029 } 1030 } 1031 } 1032 ret.b = conj(env, b, Ctx(), args_ee); 1033 } 1034 if (!ctx.neg && !cr()->type().isann()) env.cse_map_insert(cr(), ret); 1035 1036 // Restore previous mapping 1037 for (unsigned int i = decl->params().size(); i--;) { 1038 VarDecl* vd = decl->params()[i]; 1039 vd->e(previousParameters[i]()); 1040 vd->flat(vd->e() ? vd : NULL); 1041 } 1042 } 1043 } 1044 } 1045 if (cid == "mzn_reverse_map_var") { 1046 env.in_reverse_map_var = false; 1047 } 1048 return ret; 1049} 1050} // namespace MiniZinc