this repo has no description
at develop 51 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 16ASTString opToBuiltin(BinOp* op, BinOpType bot) { 17 std::string builtin; 18 if (op->rhs()->type().isint()) { 19 switch (bot) { 20 case BOT_PLUS: 21 return constants().ids.int_.plus; 22 case BOT_MINUS: 23 return constants().ids.int_.minus; 24 case BOT_MULT: 25 return constants().ids.int_.times; 26 case BOT_POW: 27 return constants().ids.pow; 28 case BOT_IDIV: 29 return constants().ids.int_.div; 30 case BOT_MOD: 31 return constants().ids.int_.mod; 32 case BOT_LE: 33 return constants().ids.int_.lt; 34 case BOT_LQ: 35 return constants().ids.int_.le; 36 case BOT_GR: 37 return constants().ids.int_.gt; 38 case BOT_GQ: 39 return constants().ids.int_.ge; 40 case BOT_EQ: 41 return constants().ids.int_.eq; 42 case BOT_NQ: 43 return constants().ids.int_.ne; 44 default: 45 throw InternalError("not yet implemented"); 46 } 47 } else if (op->rhs()->type().isbool()) { 48 if (bot == BOT_EQ || bot == BOT_EQUIV) return constants().ids.bool_eq; 49 builtin = "bool_"; 50 } else if (op->rhs()->type().is_set()) { 51 builtin = "set_"; 52 } else if (op->rhs()->type().isfloat()) { 53 switch (bot) { 54 case BOT_PLUS: 55 return constants().ids.float_.plus; 56 case BOT_MINUS: 57 return constants().ids.float_.minus; 58 case BOT_MULT: 59 return constants().ids.float_.times; 60 case BOT_POW: 61 return constants().ids.pow; 62 case BOT_DIV: 63 return constants().ids.float_.div; 64 case BOT_MOD: 65 return constants().ids.float_.mod; 66 case BOT_LE: 67 return constants().ids.float_.lt; 68 case BOT_LQ: 69 return constants().ids.float_.le; 70 case BOT_GR: 71 return constants().ids.float_.gt; 72 case BOT_GQ: 73 return constants().ids.float_.ge; 74 case BOT_EQ: 75 return constants().ids.float_.eq; 76 case BOT_NQ: 77 return constants().ids.float_.ne; 78 default: 79 throw InternalError("not yet implemented"); 80 } 81 } else if (op->rhs()->type().isopt() && (bot == BOT_EQUIV || bot == BOT_EQ)) { 82 /// TODO: extend to all option type operators 83 switch (op->lhs()->type().bt()) { 84 case Type::BT_BOOL: 85 return constants().ids.bool_eq; 86 case Type::BT_FLOAT: 87 return constants().ids.float_.eq; 88 case Type::BT_INT: 89 if (op->lhs()->type().st() == Type::ST_PLAIN) 90 return constants().ids.int_.eq; 91 else 92 return constants().ids.set_eq; 93 default: 94 throw InternalError("not yet implemented"); 95 } 96 97 } else { 98 throw InternalError(op->opToString().str() + " not yet implemented"); 99 } 100 switch (bot) { 101 case BOT_PLUS: 102 return builtin + "plus"; 103 case BOT_MINUS: 104 return builtin + "minus"; 105 case BOT_MULT: 106 return builtin + "times"; 107 case BOT_DIV: 108 return builtin + "div"; 109 case BOT_IDIV: 110 return builtin + "div"; 111 case BOT_MOD: 112 return builtin + "mod"; 113 case BOT_LE: 114 return builtin + "lt"; 115 case BOT_LQ: 116 return builtin + "le"; 117 case BOT_GR: 118 return builtin + "gt"; 119 case BOT_GQ: 120 return builtin + "ge"; 121 case BOT_EQ: 122 return builtin + "eq"; 123 case BOT_NQ: 124 return builtin + "ne"; 125 case BOT_IN: 126 return constants().ids.set_in; 127 case BOT_SUBSET: 128 return builtin + "subset"; 129 case BOT_SUPERSET: 130 return builtin + "superset"; 131 case BOT_UNION: 132 return builtin + "union"; 133 case BOT_DIFF: 134 return builtin + "diff"; 135 case BOT_SYMDIFF: 136 return builtin + "symdiff"; 137 case BOT_INTERSECT: 138 return builtin + "intersect"; 139 case BOT_PLUSPLUS: 140 case BOT_DOTDOT: 141 throw InternalError("not yet implemented"); 142 case BOT_EQUIV: 143 return builtin + "eq"; 144 case BOT_IMPL: 145 return builtin + "le"; 146 case BOT_RIMPL: 147 return builtin + "ge"; 148 case BOT_OR: 149 return builtin + "or"; 150 case BOT_AND: 151 return builtin + "and"; 152 case BOT_XOR: 153 return constants().ids.bool_xor; 154 default: 155 assert(false); 156 return ASTString(""); 157 } 158} 159 160bool isReverseMap(BinOp* e) { return e->ann().contains(constants().ann.is_reverse_map); } 161 162template <class Lit> 163void collectLinExps(EnvI& env, typename LinearTraits<Lit>::Val c, Expression* exp, 164 std::vector<typename LinearTraits<Lit>::Val>& coeffs, 165 std::vector<KeepAlive>& vars, typename LinearTraits<Lit>::Val& constval) { 166 typedef typename LinearTraits<Lit>::Val Val; 167 struct StackItem { 168 Expression* e; 169 Val c; 170 StackItem(Expression* e0, Val c0) : e(e0), c(c0) {} 171 }; 172 std::vector<StackItem> stack; 173 stack.push_back(StackItem(exp, c)); 174 while (!stack.empty()) { 175 Expression* e = stack.back().e; 176 Val c = stack.back().c; 177 stack.pop_back(); 178 if (e == NULL) continue; 179 if (e->type().ispar()) { 180 constval += c * LinearTraits<Lit>::eval(env, e); 181 } else if (Lit* l = e->dyn_cast<Lit>()) { 182 constval += c * l->v(); 183 } else if (BinOp* bo = e->dyn_cast<BinOp>()) { 184 switch (bo->op()) { 185 case BOT_PLUS: 186 stack.push_back(StackItem(bo->lhs(), c)); 187 stack.push_back(StackItem(bo->rhs(), c)); 188 break; 189 case BOT_MINUS: 190 stack.push_back(StackItem(bo->lhs(), c)); 191 stack.push_back(StackItem(bo->rhs(), -c)); 192 break; 193 case BOT_MULT: 194 if (bo->lhs()->type().ispar()) { 195 stack.push_back(StackItem(bo->rhs(), c * LinearTraits<Lit>::eval(env, bo->lhs()))); 196 } else if (bo->rhs()->type().ispar()) { 197 stack.push_back(StackItem(bo->lhs(), c * LinearTraits<Lit>::eval(env, bo->rhs()))); 198 } else { 199 coeffs.push_back(c); 200 vars.push_back(e); 201 } 202 break; 203 case BOT_DIV: 204 if (bo->rhs()->isa<FloatLit>() && bo->rhs()->cast<FloatLit>()->v() == 1.0) { 205 stack.push_back(StackItem(bo->lhs(), c)); 206 } else { 207 coeffs.push_back(c); 208 vars.push_back(e); 209 } 210 break; 211 case BOT_IDIV: 212 if (bo->rhs()->isa<IntLit>() && bo->rhs()->cast<IntLit>()->v() == 1) { 213 stack.push_back(StackItem(bo->lhs(), c)); 214 } else { 215 coeffs.push_back(c); 216 vars.push_back(e); 217 } 218 break; 219 default: 220 coeffs.push_back(c); 221 vars.push_back(e); 222 break; 223 } 224 // } else if (Call* call = e->dyn_cast<Call>()) { 225 // /// TODO! Handle sum, lin_exp (maybe not that important?) 226 } else { 227 coeffs.push_back(c); 228 vars.push_back(e); 229 } 230 } 231} 232 233template <class Lit> 234KeepAlive mklinexp(EnvI& env, typename LinearTraits<Lit>::Val c0, 235 typename LinearTraits<Lit>::Val c1, Expression* e0, Expression* e1) { 236 typedef typename LinearTraits<Lit>::Val Val; 237 GCLock lock; 238 239 std::vector<Val> coeffs; 240 std::vector<KeepAlive> vars; 241 Val constval = 0; 242 collectLinExps<Lit>(env, c0, e0, coeffs, vars, constval); 243 collectLinExps<Lit>(env, c1, e1, coeffs, vars, constval); 244 simplify_lin<Lit>(coeffs, vars, constval); 245 KeepAlive ka; 246 if (coeffs.size() == 0) { 247 ka = LinearTraits<Lit>::newLit(constval); 248 } else if (coeffs.size() == 1 && coeffs[0] == 1 && constval == 0) { 249 ka = vars[0]; 250 } else { 251 std::vector<Expression*> coeffs_e(coeffs.size()); 252 for (unsigned int i = static_cast<unsigned int>(coeffs.size()); i--;) { 253 if (!LinearTraits<Lit>::finite(coeffs[i])) { 254 throw FlatteningError( 255 env, e0->loc(), 256 "unbounded coefficient in linear expression." 257 " Make sure variables involved in non-linear/logical expressions have finite bounds" 258 " in their definition or via constraints"); 259 } 260 coeffs_e[i] = LinearTraits<Lit>::newLit(coeffs[i]); 261 } 262 std::vector<Expression*> vars_e(vars.size()); 263 for (unsigned int i = static_cast<unsigned int>(vars.size()); i--;) vars_e[i] = vars[i](); 264 265 std::vector<Expression*> args(3); 266 args[0] = new ArrayLit(e0->loc(), coeffs_e); 267 Type t = coeffs_e[0]->type(); 268 t.dim(1); 269 args[0]->type(t); 270 args[1] = new ArrayLit(e0->loc(), vars_e); 271 Type tt = vars_e[0]->type(); 272 tt.dim(1); 273 args[1]->type(tt); 274 args[2] = LinearTraits<Lit>::newLit(constval); 275 Call* c = new Call(e0->loc().introduce(), constants().ids.lin_exp, args); 276 addPathAnnotation(env, c); 277 tt = args[1]->type(); 278 tt.dim(0); 279 c->decl(env.model->matchFn(env, c, false)); 280 if (c->decl() == NULL) { 281 throw FlatteningError(env, c->loc(), "cannot find matching declaration"); 282 } 283 c->type(c->decl()->rtype(env, args, false)); 284 ka = c; 285 } 286 assert(ka()); 287 return ka; 288} 289 290Call* aggregateAndOrOps(EnvI& env, BinOp* bo, bool negateArgs, BinOpType bot) { 291 assert(bot == BOT_AND || bot == BOT_OR); 292 BinOpType negbot = (bot == BOT_AND ? BOT_OR : BOT_AND); 293 typedef std::pair<Expression*, bool> arg_literal; 294 std::vector<arg_literal> bo_args(2); 295 bo_args[0] = arg_literal(bo->lhs(), !negateArgs); 296 bo_args[1] = arg_literal(bo->rhs(), !negateArgs); 297 std::vector<Expression*> output_pos; 298 std::vector<Expression*> output_neg; 299 unsigned int processed = 0; 300 while (processed < bo_args.size()) { 301 BinOp* bo_arg = bo_args[processed].first->dyn_cast<BinOp>(); 302 UnOp* uo_arg = bo_args[processed].first->dyn_cast<UnOp>(); 303 bool positive = bo_args[processed].second; 304 if (bo_arg && positive && bo_arg->op() == bot) { 305 bo_args[processed].first = bo_arg->lhs(); 306 bo_args.push_back(arg_literal(bo_arg->rhs(), true)); 307 } else if (bo_arg && !positive && bo_arg->op() == negbot) { 308 bo_args[processed].first = bo_arg->lhs(); 309 bo_args.push_back(arg_literal(bo_arg->rhs(), false)); 310 } else if (uo_arg && !positive && uo_arg->op() == UOT_NOT) { 311 bo_args[processed].first = uo_arg->e(); 312 bo_args[processed].second = true; 313 } else if (bot == BOT_OR && uo_arg && positive && uo_arg->op() == UOT_NOT) { 314 output_neg.push_back(uo_arg->e()); 315 processed++; 316 } else { 317 if (positive) { 318 output_pos.push_back(bo_args[processed].first); 319 } else { 320 output_neg.push_back(bo_args[processed].first); 321 } 322 processed++; 323 } 324 } 325 Call* c; 326 std::vector<Expression*> c_args(1); 327 if (bot == BOT_AND) { 328 for (unsigned int i = 0; i < output_neg.size(); i++) { 329 UnOp* neg_arg = new UnOp(output_neg[i]->loc(), UOT_NOT, output_neg[i]); 330 neg_arg->type(output_neg[i]->type()); 331 output_pos.push_back(neg_arg); 332 } 333 ArrayLit* al = new ArrayLit(bo->loc().introduce(), output_pos); 334 Type al_t = bo->type(); 335 al_t.dim(1); 336 al->type(al_t); 337 env.annotateFromCallStack(al); 338 c_args[0] = al; 339 c = new Call(bo->loc().introduce(), 340 bot == BOT_AND ? constants().ids.forall : constants().ids.exists, c_args); 341 } else { 342 ArrayLit* al_pos = new ArrayLit(bo->loc().introduce(), output_pos); 343 Type al_t = bo->type(); 344 al_t.dim(1); 345 al_pos->type(al_t); 346 env.annotateFromCallStack(al_pos); 347 c_args[0] = al_pos; 348 if (output_neg.size() > 0) { 349 ArrayLit* al_neg = new ArrayLit(bo->loc().introduce(), output_neg); 350 al_neg->type(al_t); 351 env.annotateFromCallStack(al_neg); 352 c_args.push_back(al_neg); 353 } 354 c = new Call(bo->loc().introduce(), 355 output_neg.empty() ? constants().ids.exists : constants().ids.clause, c_args); 356 } 357 c->decl(env.model->matchFn(env, c, false)); 358 assert(c->decl()); 359 Type t = c->decl()->rtype(env, c_args, false); 360 t.cv(bo->type().cv()); 361 c->type(t); 362 return c; 363} 364 365/// Return a lin_exp or id if \a e is a lin_exp or id 366template <class Lit> 367Expression* get_linexp(Expression* e) { 368 for (;;) { 369 if (e && e->eid() == Expression::E_ID && e != constants().absent) { 370 if (e->cast<Id>()->decl()->e()) { 371 e = e->cast<Id>()->decl()->e(); 372 } else { 373 break; 374 } 375 } else { 376 break; 377 } 378 } 379 if (e && (e->isa<Id>() || e->isa<Lit>() || 380 (e->isa<Call>() && e->cast<Call>()->id() == constants().ids.lin_exp))) 381 return e; 382 return NULL; 383} 384 385template <class Lit> 386void flatten_linexp_binop(EnvI& env, Ctx ctx, VarDecl* r, VarDecl* b, EE& ret, Expression* le0, 387 Expression* le1, BinOpType& bot, bool doubleNeg, std::vector<EE>& ees, 388 std::vector<KeepAlive>& args, ASTString& callid) { 389 typedef typename LinearTraits<Lit>::Val Val; 390 std::vector<Val> coeffv; 391 std::vector<KeepAlive> alv; 392 Val d = 0; 393 Expression* le[2] = {le0, le1}; 394 395 Id* assignTo = NULL; 396 if (bot == BOT_EQ && ctx.b == C_ROOT) { 397 if (le0->isa<Id>()) { 398 assignTo = le0->cast<Id>(); 399 } else if (le1->isa<Id>()) { 400 assignTo = le1->cast<Id>(); 401 } 402 } 403 404 for (unsigned int i = 0; i < 2; i++) { 405 Val sign = (i == 0 ? 1 : -1); 406 if (Lit* l = le[i]->dyn_cast<Lit>()) { 407 try { 408 d += sign * l->v(); 409 } catch (ArithmeticError& e) { 410 throw EvalError(env, l->loc(), e.msg()); 411 } 412 } else if (le[i]->isa<Id>()) { 413 coeffv.push_back(sign); 414 alv.push_back(le[i]); 415 } else if (Call* sc = le[i]->dyn_cast<Call>()) { 416 GCLock lock; 417 ArrayLit* sc_coeff = eval_array_lit(env, sc->arg(0)); 418 ArrayLit* sc_al = eval_array_lit(env, sc->arg(1)); 419 try { 420 d += sign * LinearTraits<Lit>::eval(env, sc->arg(2)); 421 for (unsigned int j = 0; j < sc_coeff->size(); j++) { 422 coeffv.push_back(sign * LinearTraits<Lit>::eval(env, (*sc_coeff)[j])); 423 alv.push_back((*sc_al)[j]); 424 } 425 } catch (ArithmeticError& e) { 426 throw EvalError(env, sc->loc(), e.msg()); 427 } 428 429 } else { 430 throw EvalError(env, le[i]->loc(), 431 "Internal error, unexpected expression inside linear expression"); 432 } 433 } 434 simplify_lin<Lit>(coeffv, alv, d); 435 if (coeffv.size() == 0) { 436 bool result; 437 switch (bot) { 438 case BOT_LE: 439 result = (0 < -d); 440 break; 441 case BOT_LQ: 442 result = (0 <= -d); 443 break; 444 case BOT_GR: 445 result = (0 > -d); 446 break; 447 case BOT_GQ: 448 result = (0 >= -d); 449 break; 450 case BOT_EQ: 451 result = (0 == -d); 452 break; 453 case BOT_NQ: 454 result = (0 != -d); 455 break; 456 default: 457 assert(false); 458 break; 459 } 460 if (doubleNeg) result = !result; 461 ees[2].b = constants().boollit(result); 462 ret.r = conj(env, r, ctx, ees); 463 return; 464 } else if (coeffv.size() == 1 && std::abs(coeffv[0]) == 1) { 465 if (coeffv[0] == -1) { 466 switch (bot) { 467 case BOT_LE: 468 bot = BOT_GR; 469 break; 470 case BOT_LQ: 471 bot = BOT_GQ; 472 break; 473 case BOT_GR: 474 bot = BOT_LE; 475 break; 476 case BOT_GQ: 477 bot = BOT_LQ; 478 break; 479 default: 480 break; 481 } 482 } else { 483 d = -d; 484 } 485 typename LinearTraits<Lit>::Bounds ib = LinearTraits<Lit>::compute_bounds(env, alv[0]()); 486 if (ib.valid) { 487 bool failed = false; 488 bool subsumed = false; 489 switch (bot) { 490 case BOT_LE: 491 subsumed = ib.u < d; 492 failed = ib.l >= d; 493 break; 494 case BOT_LQ: 495 subsumed = ib.u <= d; 496 failed = ib.l > d; 497 break; 498 case BOT_GR: 499 subsumed = ib.l > d; 500 failed = ib.u <= d; 501 break; 502 case BOT_GQ: 503 subsumed = ib.l >= d; 504 failed = ib.u < d; 505 break; 506 case BOT_EQ: 507 subsumed = ib.l == d && ib.u == d; 508 failed = ib.u < d || ib.l > d; 509 break; 510 case BOT_NQ: 511 subsumed = ib.u < d || ib.l > d; 512 failed = ib.l == d && ib.u == d; 513 break; 514 default: 515 break; 516 } 517 if (doubleNeg) { 518 std::swap(subsumed, failed); 519 } 520 if (subsumed) { 521 ees[2].b = constants().lit_true; 522 ret.r = conj(env, r, ctx, ees); 523 return; 524 } else if (failed) { 525 ees[2].b = constants().lit_false; 526 ret.r = conj(env, r, ctx, ees); 527 return; 528 } 529 } 530 531 if (ctx.b == C_ROOT && alv[0]()->isa<Id>() && bot == BOT_EQ) { 532 GCLock lock; 533 VarDecl* vd = alv[0]()->cast<Id>()->decl(); 534 if (vd->ti()->domain()) { 535 typename LinearTraits<Lit>::Domain domain = 536 LinearTraits<Lit>::eval_domain(env, vd->ti()->domain()); 537 if (LinearTraits<Lit>::domain_contains(domain, d)) { 538 if (!LinearTraits<Lit>::domain_equals(domain, d)) { 539 // vd->ti()->setComputedDomain(false); 540 // vd->ti()->domain(LinearTraits<Lit>::new_domain(d)); 541 setComputedDomain(env, vd, LinearTraits<Lit>::new_domain(d), false); 542 } 543 ret.r = bind(env, ctx, r, constants().lit_true); 544 } else { 545 ret.r = bind(env, ctx, r, constants().lit_false); 546 } 547 } else { 548 // vd->ti()->setComputedDomain(false); 549 // vd->ti()->domain(LinearTraits<Lit>::new_domain(d)); 550 setComputedDomain(env, vd, LinearTraits<Lit>::new_domain(d), false); 551 ret.r = bind(env, ctx, r, constants().lit_true); 552 } 553 } else { 554 GCLock lock; 555 Expression* e0; 556 Expression* e1; 557 BinOpType old_bot = bot; 558 Val old_d = d; 559 switch (bot) { 560 case BOT_LE: 561 e0 = alv[0](); 562 if (e0->type().isint()) { 563 d--; 564 bot = BOT_LQ; 565 } 566 e1 = LinearTraits<Lit>::newLit(d); 567 break; 568 case BOT_GR: 569 e1 = alv[0](); 570 if (e1->type().isint()) { 571 d++; 572 bot = BOT_LQ; 573 } else { 574 bot = BOT_LE; 575 } 576 e0 = LinearTraits<Lit>::newLit(d); 577 break; 578 case BOT_GQ: 579 e0 = LinearTraits<Lit>::newLit(d); 580 e1 = alv[0](); 581 bot = BOT_LQ; 582 break; 583 default: 584 e0 = alv[0](); 585 e1 = LinearTraits<Lit>::newLit(d); 586 } 587 if (ctx.b == C_ROOT && alv[0]()->isa<Id>() && alv[0]()->cast<Id>()->decl()->ti()->domain()) { 588 VarDecl* vd = alv[0]()->cast<Id>()->decl(); 589 typename LinearTraits<Lit>::Domain domain = 590 LinearTraits<Lit>::eval_domain(env, vd->ti()->domain()); 591 typename LinearTraits<Lit>::Domain ndomain = 592 LinearTraits<Lit>::limit_domain(old_bot, domain, old_d); 593 if (domain && ndomain) { 594 if (LinearTraits<Lit>::domain_empty(ndomain)) { 595 ret.r = bind(env, ctx, r, constants().lit_false); 596 return; 597 } else if (!LinearTraits<Lit>::domain_equals(domain, ndomain)) { 598 ret.r = bind(env, ctx, r, constants().lit_true); 599 // vd->ti()->setComputedDomain(false); 600 // vd->ti()->domain(LinearTraits<Lit>::new_domain(ndomain)); 601 setComputedDomain(env, vd, LinearTraits<Lit>::new_domain(ndomain), false); 602 603 if (r == constants().var_true) { 604 BinOp* bo = new BinOp(Location().introduce(), e0, bot, e1); 605 bo->type(Type::varbool()); 606 std::vector<Expression*> boargs(2); 607 boargs[0] = e0; 608 boargs[1] = e1; 609 Call* c = new Call(Location(), opToBuiltin(bo, bot), boargs); 610 c->type(Type::varbool()); 611 c->decl(env.model->matchFn(env, c, false)); 612 EnvI::CSEMap::iterator it = env.cse_map_find(c); 613 if (it != env.cse_map_end()) { 614 if (Id* ident = it->second.r()->template dyn_cast<Id>()) { 615 bind(env, Ctx(), ident->decl(), constants().lit_true); 616 it->second.r = constants().lit_true; 617 } 618 if (Id* ident = it->second.b()->template dyn_cast<Id>()) { 619 bind(env, Ctx(), ident->decl(), constants().lit_true); 620 it->second.b = constants().lit_true; 621 } 622 } 623 } 624 } 625 return; 626 } 627 } 628 args.push_back(e0); 629 args.push_back(e1); 630 } 631 } else if (bot == BOT_EQ && coeffv.size() == 2 && coeffv[0] == -coeffv[1] && d == 0) { 632 Id* id0 = alv[0]()->cast<Id>(); 633 Id* id1 = alv[1]()->cast<Id>(); 634 if (ctx.b == C_ROOT && r == constants().var_true && 635 (id0->decl()->e() == NULL || id1->decl()->e() == NULL)) { 636 if (id0->decl()->e()) 637 (void)bind(env, ctx, id1->decl(), id0); 638 else 639 (void)bind(env, ctx, id0->decl(), id1); 640 } else { 641 callid = LinearTraits<Lit>::id_eq(); 642 args.push_back(alv[0]()); 643 args.push_back(alv[1]()); 644 } 645 } else { 646 GCLock lock; 647 if (assignTo != NULL) { 648 Val resultCoeff = 0; 649 typename LinearTraits<Lit>::Bounds bounds(d, d, true); 650 for (unsigned int i = static_cast<unsigned int>(coeffv.size()); i--;) { 651 if (alv[i]() == assignTo) { 652 resultCoeff = coeffv[i]; 653 continue; 654 } 655 typename LinearTraits<Lit>::Bounds b = LinearTraits<Lit>::compute_bounds(env, alv[i]()); 656 657 if (b.valid && LinearTraits<Lit>::finite(b)) { 658 if (coeffv[i] > 0) { 659 bounds.l += coeffv[i] * b.l; 660 bounds.u += coeffv[i] * b.u; 661 } else { 662 bounds.l += coeffv[i] * b.u; 663 bounds.u += coeffv[i] * b.l; 664 } 665 } else { 666 bounds.valid = false; 667 break; 668 } 669 } 670 if (bounds.valid && resultCoeff != 0) { 671 if (resultCoeff < 0) { 672 bounds.l = LinearTraits<Lit>::floor_div(bounds.l, -resultCoeff); 673 bounds.u = LinearTraits<Lit>::ceil_div(bounds.u, -resultCoeff); 674 } else { 675 Val bl = bounds.l; 676 bounds.l = LinearTraits<Lit>::ceil_div(bounds.u, -resultCoeff); 677 bounds.u = LinearTraits<Lit>::floor_div(bl, -resultCoeff); 678 } 679 VarDecl* vd = assignTo->decl(); 680 if (vd->ti()->domain()) { 681 typename LinearTraits<Lit>::Domain domain = 682 LinearTraits<Lit>::eval_domain(env, vd->ti()->domain()); 683 if (LinearTraits<Lit>::domain_intersects(domain, bounds.l, bounds.u)) { 684 typename LinearTraits<Lit>::Domain new_domain = 685 LinearTraits<Lit>::intersect_domain(domain, bounds.l, bounds.u); 686 if (!LinearTraits<Lit>::domain_equals(domain, new_domain)) { 687 // vd->ti()->setComputedDomain(false); 688 // vd->ti()->domain(LinearTraits<Lit>::new_domain(new_domain)); 689 setComputedDomain(env, vd, LinearTraits<Lit>::new_domain(new_domain), false); 690 } 691 } else { 692 ret.r = bind(env, ctx, r, constants().lit_false); 693 } 694 } else { 695 // vd->ti()->setComputedDomain(true); 696 // vd->ti()->domain(LinearTraits<Lit>::new_domain(bounds.l,bounds.u)); 697 setComputedDomain(env, vd, LinearTraits<Lit>::new_domain(bounds.l, bounds.u), true); 698 } 699 } 700 } 701 702 int coeff_sign; 703 LinearTraits<Lit>::constructLinBuiltin(bot, callid, coeff_sign, d); 704 std::vector<Expression*> coeff_ev(coeffv.size()); 705 for (unsigned int i = static_cast<unsigned int>(coeff_ev.size()); i--;) 706 coeff_ev[i] = LinearTraits<Lit>::newLit(coeff_sign * coeffv[i]); 707 ArrayLit* ncoeff = new ArrayLit(Location().introduce(), coeff_ev); 708 Type t = coeff_ev[0]->type(); 709 t.dim(1); 710 ncoeff->type(t); 711 args.push_back(ncoeff); 712 std::vector<Expression*> alv_e(alv.size()); 713 Type tt = alv[0]()->type(); 714 tt.dim(1); 715 for (unsigned int i = static_cast<unsigned int>(alv.size()); i--;) { 716 if (alv[i]()->type().isvar()) tt.ti(Type::TI_VAR); 717 alv_e[i] = alv[i](); 718 } 719 ArrayLit* nal = new ArrayLit(Location().introduce(), alv_e); 720 nal->type(tt); 721 args.push_back(nal); 722 Lit* il = LinearTraits<Lit>::newLit(-d); 723 args.push_back(il); 724 } 725} 726 727EE flatten_binop(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b) { 728 CallStackItem _csi(env, e); 729 EE ret; 730 BinOp* bo = e->cast<BinOp>(); 731 if (isReverseMap(bo)) { 732 CallArgItem cai(env); 733 Id* id = bo->lhs()->dyn_cast<Id>(); 734 if (id == NULL) 735 throw EvalError(env, bo->lhs()->loc(), "Reverse mappers are only defined for identifiers"); 736 if (bo->op() != BOT_EQ && bo->op() != BOT_EQUIV) 737 throw EvalError(env, bo->loc(), "Reverse mappers have to use `=` as the operator"); 738 Call* c = bo->rhs()->dyn_cast<Call>(); 739 if (c == NULL) 740 throw EvalError(env, bo->rhs()->loc(), "Reverse mappers require call on right hand side"); 741 742 std::vector<Expression*> args(c->n_args()); 743 for (unsigned int i = 0; i < c->n_args(); i++) { 744 Id* idi = c->arg(i)->dyn_cast<Id>(); 745 if (idi == NULL) 746 throw EvalError(env, c->arg(i)->loc(), 747 "Reverse mapper calls require identifiers as arguments"); 748 EE ee = flat_exp(env, Ctx(), idi, NULL, constants().var_true); 749 args[i] = ee.r(); 750 } 751 752 EE ee = flat_exp(env, Ctx(), id, NULL, constants().var_true); 753 754 GCLock lock; 755 Call* revMap = new Call(Location().introduce(), c->id(), args); 756 757 args.push_back(ee.r()); 758 Call* keepAlive = new Call(Location().introduce(), constants().var_redef->id(), args); 759 keepAlive->type(Type::varbool()); 760 keepAlive->decl(constants().var_redef); 761 ret = flat_exp(env, Ctx(), keepAlive, constants().var_true, constants().var_true); 762 763 if (ee.r()->isa<Id>()) { 764 env.reverseMappers.insert(ee.r()->cast<Id>(), revMap); 765 } 766 return ret; 767 } 768 if ((bo->op() == BOT_EQ || bo->op() == BOT_EQUIV) && 769 (bo->lhs() == constants().absent || bo->rhs() == constants().absent)) { 770 GCLock lock; 771 std::vector<Expression*> args(1); 772 args[0] = bo->lhs() == constants().absent ? bo->rhs() : bo->lhs(); 773 if (args[0] != constants().absent) { 774 Call* cr = new Call(bo->loc().introduce(), "absent", args); 775 cr->decl(env.model->matchFn(env, cr, false)); 776 cr->type(cr->decl()->rtype(env, args, false)); 777 ret = flat_exp(env, ctx, cr, r, b); 778 } else { 779 ret.b = bind(env, Ctx(), b, constants().lit_true); 780 ret.r = bind(env, ctx, r, constants().lit_true); 781 } 782 return ret; 783 } 784 Ctx ctx0 = ctx; 785 ctx0.neg = false; 786 Ctx ctx1 = ctx; 787 ctx1.neg = false; 788 BinOpType bot = bo->op(); 789 if (bo->lhs()->type().isbool()) { 790 switch (bot) { 791 case BOT_EQ: 792 bot = BOT_EQUIV; 793 break; 794 case BOT_NQ: 795 bot = BOT_XOR; 796 break; 797 case BOT_LQ: 798 bot = BOT_IMPL; 799 break; 800 case BOT_GQ: 801 bot = BOT_RIMPL; 802 break; 803 default: 804 break; 805 } 806 } 807 bool negArgs = false; 808 bool doubleNeg = false; 809 if (ctx.neg) { 810 switch (bot) { 811 case BOT_AND: 812 ctx.b = -ctx.b; 813 ctx.neg = false; 814 negArgs = true; 815 bot = BOT_OR; 816 break; 817 case BOT_OR: 818 ctx.b = -ctx.b; 819 ctx.neg = false; 820 negArgs = true; 821 bot = BOT_AND; 822 break; 823 default: 824 break; 825 } 826 } 827 Expression* boe0 = bo->lhs(); 828 Expression* boe1 = bo->rhs(); 829 bool isBuiltin = bo->decl() == NULL || bo->decl()->e() == NULL; 830 switch (bot) { 831 case BOT_PLUS: 832 if (isBuiltin) { 833 KeepAlive ka; 834 if (boe0->type().isint()) { 835 ka = mklinexp<IntLit>(env, 1, 1, boe0, boe1); 836 } else { 837 ka = mklinexp<FloatLit>(env, 1.0, 1.0, boe0, boe1); 838 } 839 ret = flat_exp(env, ctx, ka(), r, b); 840 break; 841 } 842 case BOT_MINUS: 843 if (isBuiltin) { 844 KeepAlive ka; 845 if (boe0->type().isint()) { 846 ka = mklinexp<IntLit>(env, 1, -1, boe0, boe1); 847 } else { 848 ka = mklinexp<FloatLit>(env, 1.0, -1.0, boe0, boe1); 849 } 850 ret = flat_exp(env, ctx, ka(), r, b); 851 break; 852 } 853 case BOT_MULT: 854 case BOT_IDIV: 855 case BOT_MOD: 856 case BOT_POW: 857 case BOT_DIV: 858 case BOT_UNION: 859 case BOT_DIFF: 860 case BOT_SYMDIFF: 861 case BOT_INTERSECT: 862 case BOT_DOTDOT: { 863 assert(!ctx0.neg); 864 assert(!ctx1.neg); 865 EE e0 = flat_exp(env, ctx0, boe0, NULL, b); 866 EE e1 = flat_exp(env, ctx1, boe1, NULL, b); 867 868 if (e0.r()->type().ispar() && e1.r()->type().ispar()) { 869 GCLock lock; 870 BinOp* parbo = new BinOp(bo->loc(), e0.r(), bo->op(), e1.r()); 871 Type tt = bo->type(); 872 tt.ti(Type::TI_PAR); 873 parbo->type(tt); 874 try { 875 Expression* res = eval_par(env, parbo); 876 assert(!res->type().isunknown()); 877 ret.r = bind(env, ctx, r, res); 878 std::vector<EE> ees(2); 879 ees[0].b = e0.b; 880 ees[1].b = e1.b; 881 ret.b = conj(env, b, Ctx(), ees); 882 } catch (ResultUndefinedError&) { 883 ret.r = createDummyValue(env, e->type()); 884 ret.b = bind(env, Ctx(), b, constants().lit_false); 885 } 886 break; 887 } 888 889 if (isBuiltin && bot == BOT_MULT) { 890 Expression* e0r = e0.r(); 891 Expression* e1r = e1.r(); 892 if (e0r->type().ispar()) std::swap(e0r, e1r); 893 if (e1r->type().ispar() && e1r->type().isint()) { 894 IntVal coeff = eval_int(env, e1r); 895 KeepAlive ka = mklinexp<IntLit>(env, coeff, 0, e0r, NULL); 896 ret = flat_exp(env, ctx, ka(), r, b); 897 break; 898 } else if (e1r->type().ispar() && e1r->type().isfloat()) { 899 FloatVal coeff = eval_float(env, e1r); 900 KeepAlive ka = mklinexp<FloatLit>(env, coeff, 0.0, e0r, NULL); 901 ret = flat_exp(env, ctx, ka(), r, b); 902 break; 903 } 904 } else if (isBuiltin && (bot == BOT_DIV || bot == BOT_IDIV)) { 905 Expression* e0r = e0.r(); 906 Expression* e1r = e1.r(); 907 if (e1r->type().ispar() && e1r->type().isint()) { 908 IntVal coeff = eval_int(env, e1r); 909 if (coeff == 1) { 910 ret = flat_exp(env, ctx, e0r, r, b); 911 break; 912 } 913 } else if (e1r->type().ispar() && e1r->type().isfloat()) { 914 FloatVal coeff = eval_float(env, e1r); 915 if (coeff == 1.0) { 916 ret = flat_exp(env, ctx, e0r, r, b); 917 break; 918 } else { 919 KeepAlive ka = mklinexp<FloatLit>(env, 1.0 / coeff, 0.0, e0r, NULL); 920 ret = flat_exp(env, ctx, ka(), r, b); 921 break; 922 } 923 } 924 } 925 926 GC::lock(); 927 std::vector<Expression*> args(2); 928 args[0] = e0.r(); 929 args[1] = e1.r(); 930 Call* cc; 931 if (bo->decl()) { 932 cc = new Call(bo->loc().introduce(), bo->opToString(), args); 933 } else { 934 cc = new Call(bo->loc().introduce(), opToBuiltin(bo, bot), args); 935 } 936 cc->type(bo->type()); 937 EnvI::CSEMap::iterator cit; 938 if ((cit = env.cse_map_find(cc)) != env.cse_map_end()) { 939 ret.b = bind(env, Ctx(), b, env.ignorePartial ? constants().lit_true : cit->second.b()); 940 ret.r = bind(env, ctx, r, cit->second.r()); 941 } else { 942 if (FunctionI* fi = env.model->matchFn(env, cc->id(), args, false)) { 943 assert(cc->type() == fi->rtype(env, args, false)); 944 cc->decl(fi); 945 cc->type(cc->decl()->rtype(env, args, false)); 946 KeepAlive ka(cc); 947 GC::unlock(); 948 EE ee = flat_exp(env, ctx, cc, r, NULL); 949 GC::lock(); 950 ret.r = ee.r; 951 std::vector<EE> ees(3); 952 ees[0].b = e0.b; 953 ees[1].b = e1.b; 954 ees[2].b = ee.b; 955 ret.b = conj(env, b, Ctx(), ees); 956 } else { 957 addPathAnnotation(env, cc); 958 ret.r = bind(env, ctx, r, cc); 959 std::vector<EE> ees(2); 960 ees[0].b = e0.b; 961 ees[1].b = e1.b; 962 ret.b = conj(env, b, Ctx(), ees); 963 if (!ctx.neg) env.cse_map_insert(cc, ret); 964 } 965 } 966 } 967 GC::unlock(); 968 break; 969 970 case BOT_AND: { 971 if (r == constants().var_true) { 972 Ctx nctx; 973 nctx.neg = negArgs; 974 nctx.b = negArgs ? C_NEG : C_ROOT; 975 std::vector<Expression*> todo; 976 todo.push_back(boe1); 977 todo.push_back(boe0); 978 while (!todo.empty()) { 979 Expression* e_todo = todo.back(); 980 todo.pop_back(); 981 BinOp* e_bo = e_todo->dyn_cast<BinOp>(); 982 if (e_bo && e_bo->op() == BOT_AND) { 983 todo.push_back(e_bo->rhs()); 984 todo.push_back(e_bo->lhs()); 985 } else { 986 (void)flat_exp(env, nctx, e_todo, constants().var_true, constants().var_true); 987 } 988 } 989 ret.r = bind(env, ctx, r, constants().lit_true); 990 break; 991 } else { 992 GC::lock(); 993 Call* c = aggregateAndOrOps(env, bo, negArgs, bot); 994 KeepAlive ka(c); 995 GC::unlock(); 996 ret = flat_exp(env, ctx, c, r, b); 997 if (Id* id = ret.r()->dyn_cast<Id>()) { 998 addCtxAnn(id->decl(), ctx.b); 999 } 1000 } 1001 break; 1002 } 1003 case BOT_OR: { 1004 GC::lock(); 1005 Call* c = aggregateAndOrOps(env, bo, negArgs, bot); 1006 KeepAlive ka(c); 1007 GC::unlock(); 1008 ret = flat_exp(env, ctx, c, r, b); 1009 if (Id* id = ret.r()->dyn_cast<Id>()) { 1010 addCtxAnn(id->decl(), ctx.b); 1011 } 1012 } break; 1013 case BOT_RIMPL: { 1014 std::swap(boe0, boe1); 1015 } 1016 // fall through 1017 case BOT_IMPL: { 1018 if (ctx.b == C_ROOT && r == constants().var_true && boe0->type().ispar()) { 1019 bool b; 1020 { 1021 GCLock lock; 1022 b = eval_bool(env, boe0); 1023 } 1024 if (b) { 1025 Ctx nctx = ctx; 1026 nctx.neg = negArgs; 1027 nctx.b = negArgs ? C_NEG : C_ROOT; 1028 ret = flat_exp(env, nctx, boe1, constants().var_true, constants().var_true); 1029 } else { 1030 Ctx nctx = ctx; 1031 nctx.neg = negArgs; 1032 nctx.b = negArgs ? C_NEG : C_ROOT; 1033 ret = 1034 flat_exp(env, nctx, constants().lit_true, constants().var_true, constants().var_true); 1035 } 1036 break; 1037 } 1038 if (ctx.b == C_ROOT && r == constants().var_true && boe1->type().ispar()) { 1039 bool b; 1040 { 1041 GCLock lock; 1042 b = eval_bool(env, boe1); 1043 } 1044 if (b) { 1045 Ctx nctx = ctx; 1046 nctx.neg = negArgs; 1047 nctx.b = negArgs ? C_NEG : C_ROOT; 1048 ret = 1049 flat_exp(env, nctx, constants().lit_true, constants().var_true, constants().var_true); 1050 break; 1051 } else { 1052 Ctx nctx = ctx; 1053 nctx.neg = !negArgs; 1054 nctx.b = !negArgs ? C_NEG : C_ROOT; 1055 ret = flat_exp(env, nctx, boe0, constants().var_true, constants().var_true); 1056 break; 1057 } 1058 } 1059 GC::lock(); 1060 std::vector<Expression*> args; 1061 ASTString id; 1062 if (ctx.neg) { 1063 std::vector<Expression*> bo_args(2); 1064 bo_args[0] = boe0; 1065 bo_args[1] = new UnOp(bo->loc(), UOT_NOT, boe1); 1066 bo_args[1]->type(boe1->type()); 1067 id = constants().ids.forall; 1068 args.push_back(new ArrayLit(bo->loc(), bo_args)); 1069 args[0]->type(Type::varbool(1)); 1070 } else { 1071 std::vector<Expression*> clause_pos(1); 1072 clause_pos[0] = boe1; 1073 std::vector<Expression*> clause_neg(1); 1074 clause_neg[0] = boe0; 1075 args.push_back(new ArrayLit(boe1->loc().introduce(), clause_pos)); 1076 Type t0 = boe1->type(); 1077 t0.dim(1); 1078 args[0]->type(t0); 1079 args.push_back(new ArrayLit(boe0->loc().introduce(), clause_neg)); 1080 Type t1 = boe0->type(); 1081 t1.dim(1); 1082 args[1]->type(t1); 1083 id = constants().ids.clause; 1084 } 1085 ctx.neg = false; 1086 Call* c = new Call(bo->loc().introduce(), id, args); 1087 c->decl(env.model->matchFn(env, c, false)); 1088 if (c->decl() == NULL) { 1089 throw FlatteningError(env, c->loc(), "cannot find matching declaration"); 1090 } 1091 c->type(c->decl()->rtype(env, args, false)); 1092 KeepAlive ka(c); 1093 GC::unlock(); 1094 ret = flat_exp(env, ctx, c, r, b); 1095 if (Id* id = ret.r()->dyn_cast<Id>()) { 1096 addCtxAnn(id->decl(), ctx.b); 1097 } 1098 } break; 1099 case BOT_EQUIV: 1100 if (ctx.neg) { 1101 ctx.neg = false; 1102 ctx.b = -ctx.b; 1103 bot = BOT_XOR; 1104 ctx0.b = ctx1.b = C_MIX; 1105 goto flatten_bool_op; 1106 } else { 1107 if (!boe1->type().isopt() && istrue(env, boe0)) { 1108 return flat_exp(env, ctx, boe1, r, b); 1109 } 1110 if (!boe0->type().isopt() && istrue(env, boe1)) { 1111 return flat_exp(env, ctx, boe0, r, b); 1112 } 1113 if (r && r == constants().var_true) { 1114 if (boe1->type().ispar() || boe1->isa<Id>()) std::swap(boe0, boe1); 1115 if (istrue(env, boe0)) { 1116 return flat_exp(env, ctx1, boe1, r, b); 1117 } else if (isfalse(env, boe0)) { 1118 ctx1.neg = true; 1119 ctx1.b = -ctx1.b; 1120 return flat_exp(env, ctx1, boe1, r, b); 1121 } else { 1122 ctx0.b = C_MIX; 1123 EE e0 = flat_exp(env, ctx0, boe0, NULL, NULL); 1124 if (istrue(env, e0.r())) { 1125 return flat_exp(env, ctx1, boe1, r, b); 1126 } else if (isfalse(env, e0.r())) { 1127 ctx1.neg = true; 1128 ctx1.b = -ctx1.b; 1129 return flat_exp(env, ctx1, boe1, r, b); 1130 } else { 1131 Id* id = e0.r()->cast<Id>(); 1132 ctx1.b = C_MIX; 1133 (void)flat_exp(env, ctx1, boe1, id->decl(), constants().var_true); 1134 addCtxAnn(id->decl(), ctx1.b); 1135 ret.b = bind(env, Ctx(), b, constants().lit_true); 1136 ret.r = bind(env, Ctx(), r, constants().lit_true); 1137 } 1138 } 1139 break; 1140 } else { 1141 ctx0.b = ctx1.b = C_MIX; 1142 goto flatten_bool_op; 1143 } 1144 } 1145 case BOT_XOR: 1146 if (ctx.neg) { 1147 ctx.neg = false; 1148 ctx.b = -ctx.b; 1149 bot = BOT_EQUIV; 1150 } 1151 ctx0.b = ctx1.b = C_MIX; 1152 goto flatten_bool_op; 1153 case BOT_LE: 1154 if (ctx.neg) { 1155 doubleNeg = true; 1156 bot = BOT_GQ; 1157 if (boe0->type().bt() == Type::BT_BOOL) { 1158 ctx0.b = +ctx0.b; 1159 ctx1.b = -ctx1.b; 1160 } else if (boe0->type().bt() == Type::BT_INT) { 1161 ctx0.i = +ctx0.b; 1162 ctx1.i = -ctx1.b; 1163 } 1164 } else { 1165 if (boe0->type().bt() == Type::BT_BOOL) { 1166 ctx0.b = -ctx0.b; 1167 ctx1.b = +ctx1.b; 1168 } else if (boe0->type().bt() == Type::BT_INT) { 1169 ctx0.i = -ctx0.b; 1170 ctx1.i = +ctx1.b; 1171 } 1172 } 1173 goto flatten_bool_op; 1174 case BOT_LQ: 1175 if (ctx.neg) { 1176 doubleNeg = true; 1177 bot = BOT_GR; 1178 if (boe0->type().bt() == Type::BT_BOOL) { 1179 ctx0.b = +ctx0.b; 1180 ctx1.b = -ctx1.b; 1181 } else if (boe0->type().bt() == Type::BT_INT) { 1182 ctx0.i = +ctx0.b; 1183 ctx1.i = -ctx1.b; 1184 } 1185 } else { 1186 if (boe0->type().bt() == Type::BT_BOOL) { 1187 ctx0.b = -ctx0.b; 1188 ctx1.b = +ctx1.b; 1189 } else if (boe0->type().bt() == Type::BT_INT) { 1190 ctx0.i = -ctx0.b; 1191 ctx1.i = +ctx1.b; 1192 } 1193 } 1194 goto flatten_bool_op; 1195 case BOT_GR: 1196 if (ctx.neg) { 1197 doubleNeg = true; 1198 bot = BOT_LQ; 1199 if (boe0->type().bt() == Type::BT_BOOL) { 1200 ctx0.b = -ctx0.b; 1201 ctx1.b = +ctx1.b; 1202 } else if (boe0->type().bt() == Type::BT_INT) { 1203 ctx0.i = -ctx0.b; 1204 ctx1.i = +ctx1.b; 1205 } 1206 } else { 1207 if (boe0->type().bt() == Type::BT_BOOL) { 1208 ctx0.b = +ctx0.b; 1209 ctx1.b = -ctx1.b; 1210 } else if (boe0->type().bt() == Type::BT_INT) { 1211 ctx0.i = +ctx0.b; 1212 ctx1.i = -ctx1.b; 1213 } 1214 } 1215 goto flatten_bool_op; 1216 case BOT_GQ: 1217 if (ctx.neg) { 1218 doubleNeg = true; 1219 bot = BOT_LE; 1220 if (boe0->type().bt() == Type::BT_BOOL) { 1221 ctx0.b = -ctx0.b; 1222 ctx1.b = +ctx1.b; 1223 } else if (boe0->type().bt() == Type::BT_INT) { 1224 ctx0.i = -ctx0.b; 1225 ctx1.i = +ctx1.b; 1226 } 1227 } else { 1228 if (boe0->type().bt() == Type::BT_BOOL) { 1229 ctx0.b = +ctx0.b; 1230 ctx1.b = -ctx1.b; 1231 } else if (boe0->type().bt() == Type::BT_INT) { 1232 ctx0.i = +ctx0.b; 1233 ctx1.i = -ctx1.b; 1234 } 1235 } 1236 goto flatten_bool_op; 1237 case BOT_EQ: 1238 if (ctx.neg) { 1239 doubleNeg = true; 1240 bot = BOT_NQ; 1241 } 1242 if (boe0->type().bt() == Type::BT_BOOL) { 1243 ctx0.b = ctx1.b = C_MIX; 1244 } else if (boe0->type().bt() == Type::BT_INT) { 1245 ctx0.i = ctx1.i = C_MIX; 1246 } 1247 goto flatten_bool_op; 1248 case BOT_NQ: 1249 if (ctx.neg) { 1250 doubleNeg = true; 1251 bot = BOT_EQ; 1252 } 1253 if (boe0->type().bt() == Type::BT_BOOL) { 1254 ctx0.b = ctx1.b = C_MIX; 1255 } else if (boe0->type().bt() == Type::BT_INT) { 1256 ctx0.i = ctx1.i = C_MIX; 1257 } 1258 goto flatten_bool_op; 1259 case BOT_IN: 1260 case BOT_SUBSET: 1261 case BOT_SUPERSET: 1262 ctx0.i = ctx1.i = C_MIX; 1263 flatten_bool_op : { 1264 bool inRootCtx = (ctx0.b == ctx1.b && ctx0.b == C_ROOT && b == constants().var_true); 1265 EE e0 = flat_exp(env, ctx0, boe0, NULL, inRootCtx ? b : NULL); 1266 EE e1 = flat_exp(env, ctx1, boe1, NULL, inRootCtx ? b : NULL); 1267 1268 ret.b = bind(env, Ctx(), b, constants().lit_true); 1269 1270 std::vector<EE> ees(3); 1271 ees[0].b = e0.b; 1272 ees[1].b = e1.b; 1273 1274 if (isfalse(env, e0.b()) || isfalse(env, e1.b())) { 1275 ees.resize(2); 1276 ret.r = conj(env, r, ctx, ees); 1277 break; 1278 } 1279 1280 if (e0.r()->type().ispar() && e1.r()->type().ispar()) { 1281 GCLock lock; 1282 BinOp* bo_par = new BinOp(e->loc(), e0.r(), bot, e1.r()); 1283 std::vector<Expression*> args({e0.r(), e1.r()}); 1284 bo_par->decl(env.model->matchFn(env, bo_par->opToString(), args, false)); 1285 if (bo_par->decl() == NULL) { 1286 throw FlatteningError(env, bo_par->loc(), "cannot find matching declaration"); 1287 } 1288 bo_par->type(Type::parbool()); 1289 bool bo_val = eval_bool(env, bo_par); 1290 if (doubleNeg) bo_val = !bo_val; 1291 ees[2].b = constants().boollit(bo_val); 1292 ret.r = conj(env, r, ctx, ees); 1293 break; 1294 } 1295 1296 if (e0.r()->type().bt() == Type::BT_INT && e1.r()->type().ispar() && e0.r()->isa<Id>() && 1297 (bot == BOT_IN || bot == BOT_SUBSET)) { 1298 VarDecl* vd = e0.r()->cast<Id>()->decl(); 1299 Id* ident = vd->id(); 1300 if (ctx.b == C_ROOT && r == constants().var_true) { 1301 if (vd->ti()->domain() == NULL) { 1302 vd->ti()->domain(e1.r()); 1303 } else { 1304 GCLock lock; 1305 IntSetVal* newdom = eval_intset(env, e1.r()); 1306 while (ident != NULL) { 1307 bool changeDom = false; 1308 if (ident->decl()->ti()->domain()) { 1309 IntSetVal* domain = eval_intset(env, ident->decl()->ti()->domain()); 1310 IntSetRanges dr(domain); 1311 IntSetRanges ibr(newdom); 1312 Ranges::Inter<IntVal, IntSetRanges, IntSetRanges> i(dr, ibr); 1313 IntSetVal* newibv = IntSetVal::ai(i); 1314 if (domain->card() != newibv->card()) { 1315 newdom = newibv; 1316 changeDom = true; 1317 } 1318 } else { 1319 changeDom = true; 1320 } 1321 if (ident->type().st() == Type::ST_PLAIN && newdom->size() == 0) { 1322 env.fail(); 1323 } else if (changeDom) { 1324 // ident->decl()->ti()->setComputedDomain(false); 1325 // ident->decl()->ti()->domain(new SetLit(Location().introduce(),newdom)); 1326 setComputedDomain(env, ident->decl(), new SetLit(Location().introduce(), newdom), 1327 false); 1328 if (ident->decl()->e() == NULL && newdom->min() == newdom->max()) { 1329 ident->decl()->e(IntLit::a(newdom->min())); 1330 } 1331 } 1332 ident = ident->decl()->e() ? ident->decl()->e()->dyn_cast<Id>() : NULL; 1333 } 1334 } 1335 ret.r = bind(env, ctx, r, constants().lit_true); 1336 break; 1337 } else if (vd->ti()->domain() != NULL) { 1338 // check if current domain is already subsumed or falsified by this constraint 1339 GCLock lock; 1340 IntSetVal* check_dom = eval_intset(env, e1.r()); 1341 IntSetVal* domain = eval_intset(env, ident->decl()->ti()->domain()); 1342 { 1343 IntSetRanges cdr(check_dom); 1344 IntSetRanges dr(domain); 1345 if (Ranges::subset(dr, cdr)) { 1346 // the constraint is subsumed 1347 ret.r = bind(env, ctx, r, constants().lit_true); 1348 break; 1349 } 1350 } 1351 if (vd->type().st() == Type::ST_PLAIN) { 1352 // only for var int (for var set of int, subset can never fail because of the domain) 1353 IntSetRanges cdr(check_dom); 1354 IntSetRanges dr(domain); 1355 if (Ranges::disjoint(cdr, dr)) { 1356 // the constraint is false 1357 ret.r = bind(env, ctx, r, constants().lit_false); 1358 break; 1359 } 1360 } 1361 } 1362 } 1363 1364 std::vector<KeepAlive> args; 1365 ASTString callid; 1366 1367 Expression* le0 = NULL; 1368 Expression* le1 = NULL; 1369 1370 if (boe0->type().isint() && !boe0->type().isopt() && bot != BOT_IN) { 1371 le0 = get_linexp<IntLit>(e0.r()); 1372 } else if (boe0->type().isfloat() && !boe0->type().isopt() && bot != BOT_IN) { 1373 le0 = get_linexp<FloatLit>(e0.r()); 1374 } 1375 if (le0) { 1376 if (boe0->type().isint() && boe1->type().isint() && !boe1->type().isopt()) { 1377 le1 = get_linexp<IntLit>(e1.r()); 1378 } else if (boe0->type().isfloat() && boe1->type().isfloat() && !boe1->type().isopt()) { 1379 le1 = get_linexp<FloatLit>(e1.r()); 1380 } 1381 } 1382 if (le1) { 1383 if (boe0->type().isint()) { 1384 flatten_linexp_binop<IntLit>(env, ctx, r, b, ret, le0, le1, bot, doubleNeg, ees, args, 1385 callid); 1386 } else { 1387 flatten_linexp_binop<FloatLit>(env, ctx, r, b, ret, le0, le1, bot, doubleNeg, ees, args, 1388 callid); 1389 } 1390 } else { 1391 if (bo->decl() == NULL) { 1392 switch (bot) { 1393 case BOT_GR: 1394 std::swap(e0, e1); 1395 bot = BOT_LE; 1396 break; 1397 case BOT_GQ: 1398 std::swap(e0, e1); 1399 bot = BOT_LQ; 1400 break; 1401 default: 1402 break; 1403 } 1404 } 1405 args.push_back(e0.r); 1406 args.push_back(e1.r); 1407 } 1408 1409 if (args.size() > 0) { 1410 GC::lock(); 1411 1412 if (callid == "") { 1413 if (bo->decl()) { 1414 callid = bo->decl()->id(); 1415 } else { 1416 callid = opToBuiltin(bo, bot); 1417 } 1418 } 1419 1420 std::vector<Expression*> args_e(args.size()); 1421 for (unsigned int i = static_cast<unsigned int>(args.size()); i--;) args_e[i] = args[i](); 1422 Call* cc = new Call(e->loc().introduce(), callid, args_e); 1423 cc->decl(env.model->matchFn(env, cc->id(), args_e, false)); 1424 if (cc->decl() == NULL) { 1425 throw FlatteningError(env, cc->loc(), "cannot find matching declaration"); 1426 } 1427 cc->type(cc->decl()->rtype(env, args_e, false)); 1428 1429 // add defines_var annotation if applicable 1430 Id* assignTo = NULL; 1431 if (bot == BOT_EQ && ctx.b == C_ROOT) { 1432 if (le0 && le0->isa<Id>()) { 1433 assignTo = le0->cast<Id>(); 1434 } else if (le1 && le1->isa<Id>()) { 1435 assignTo = le1->cast<Id>(); 1436 } 1437 if (assignTo) { 1438 makeDefinedVar(assignTo->decl()->flat(), cc); 1439 } 1440 } 1441 1442 EnvI::CSEMap::iterator cit = env.cse_map_find(cc); 1443 if (cit != env.cse_map_end()) { 1444 ees[2].b = cit->second.r(); 1445 if (doubleNeg) { 1446 Type t = ees[2].b()->type(); 1447 ees[2].b = new UnOp(Location().introduce(), UOT_NOT, ees[2].b()); 1448 ees[2].b()->type(t); 1449 } 1450 if (Id* id = ees[2].b()->dyn_cast<Id>()) { 1451 addCtxAnn(id->decl(), ctx.b); 1452 } 1453 ret.r = conj(env, r, ctx, ees); 1454 GC::unlock(); 1455 } else { 1456 bool singleExp = true; 1457 for (unsigned int i = 0; i < ees.size(); i++) { 1458 if (!istrue(env, ees[i].b())) { 1459 singleExp = false; 1460 break; 1461 } 1462 } 1463 KeepAlive ka(cc); 1464 GC::unlock(); 1465 if (singleExp) { 1466 if (doubleNeg) { 1467 ctx.b = -ctx.b; 1468 ctx.neg = !ctx.neg; 1469 } 1470 ret.r = flat_exp(env, ctx, cc, r, NULL).r; 1471 } else { 1472 ees[2].b = flat_exp(env, Ctx(), cc, NULL, NULL).r; 1473 if (doubleNeg) { 1474 GCLock lock; 1475 Type t = ees[2].b()->type(); 1476 ees[2].b = new UnOp(Location().introduce(), UOT_NOT, ees[2].b()); 1477 ees[2].b()->type(t); 1478 } 1479 if (Id* id = ees[2].b()->dyn_cast<Id>()) { 1480 addCtxAnn(id->decl(), ctx.b); 1481 } 1482 ret.r = conj(env, r, ctx, ees); 1483 } 1484 } 1485 } else { 1486 ret.r = conj(env, r, ctx, ees); 1487 } 1488 } break; 1489 1490 case BOT_PLUSPLUS: { 1491 std::vector<EE> ee(2); 1492 EE eev = flat_exp(env, ctx, boe0, NULL, NULL); 1493 ee[0] = eev; 1494 ArrayLit* al; 1495 if (eev.r()->isa<ArrayLit>()) { 1496 al = eev.r()->cast<ArrayLit>(); 1497 } else { 1498 Id* id = eev.r()->cast<Id>(); 1499 if (id->decl() == NULL) { 1500 throw InternalError("undefined identifier"); 1501 } 1502 if (id->decl()->e() == NULL) { 1503 throw InternalError("array without initialiser not supported"); 1504 } 1505 al = follow_id(id)->cast<ArrayLit>(); 1506 } 1507 ArrayLit* al0 = al; 1508 eev = flat_exp(env, ctx, boe1, NULL, NULL); 1509 ee[1] = eev; 1510 if (eev.r()->isa<ArrayLit>()) { 1511 al = eev.r()->cast<ArrayLit>(); 1512 } else { 1513 Id* id = eev.r()->cast<Id>(); 1514 if (id->decl() == NULL) { 1515 throw InternalError("undefined identifier"); 1516 } 1517 if (id->decl()->e() == NULL) { 1518 throw InternalError("array without initialiser not supported"); 1519 } 1520 al = follow_id(id)->cast<ArrayLit>(); 1521 } 1522 ArrayLit* al1 = al; 1523 std::vector<Expression*> v(al0->size() + al1->size()); 1524 for (unsigned int i = al0->size(); i--;) v[i] = (*al0)[i]; 1525 for (unsigned int i = al1->size(); i--;) v[al0->size() + i] = (*al1)[i]; 1526 GCLock lock; 1527 ArrayLit* alret = new ArrayLit(e->loc(), v); 1528 alret->type(e->type()); 1529 ret.b = conj(env, b, Ctx(), ee); 1530 ret.r = bind(env, ctx, r, alret); 1531 } break; 1532 } 1533 return ret; 1534} 1535 1536} // namespace MiniZinc