this repo has no description
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/astexception.hh>
13#include <minizinc/astiterator.hh>
14#include <minizinc/copy.hh>
15#include <minizinc/eval_par.hh>
16#include <minizinc/flat_exp.hh>
17#include <minizinc/flatten.hh>
18#include <minizinc/flatten_internal.hh>
19#include <minizinc/hash.hh>
20#include <minizinc/optimize.hh>
21#include <minizinc/output.hh>
22
23#include <unordered_map>
24#include <unordered_set>
25
26namespace MiniZinc {
27
28// Create domain constraints. Return true if successful.
29bool createExplicitDomainConstraints(EnvI& envi, VarDecl* vd, Expression* domain) {
30 std::vector<Call*> calls;
31 Location iloc = Location().introduce();
32
33 if (domain->type().isfloat() || domain->type().isfloatset()) {
34 FloatSetVal* fsv = eval_floatset(envi, domain);
35 if (fsv->size() == 1) { // Range based
36 if (fsv->min() == fsv->max()) {
37 calls.push_back(
38 new Call(iloc, constants().ids.float_.eq, {vd->id(), FloatLit::a(fsv->min())}));
39 } else {
40 FloatSetVal* cfsv;
41 if (vd->ti()->domain()) {
42 cfsv = eval_floatset(envi, vd->ti()->domain());
43 } else {
44 cfsv = FloatSetVal::a(-FloatVal::infinity(), FloatVal::infinity());
45 }
46 if (cfsv->min() < fsv->min()) {
47 calls.push_back(
48 new Call(iloc, constants().ids.float_.le, {FloatLit::a(fsv->min()), vd->id()}));
49 }
50 if (cfsv->max() > fsv->max()) {
51 calls.push_back(
52 new Call(iloc, constants().ids.float_.le, {vd->id(), FloatLit::a(fsv->max())}));
53 }
54 }
55 } else {
56 calls.push_back(new Call(iloc, constants().ids.set_in, {vd->id(), new SetLit(iloc, fsv)}));
57 }
58 } else if (domain->type().isint() || domain->type().isintset()) {
59 IntSetVal* isv = eval_intset(envi, domain);
60 if (isv->size() == 1) { // Range based
61 if (isv->min() == isv->max()) {
62 calls.push_back(new Call(iloc, constants().ids.int_.eq, {vd->id(), IntLit::a(isv->min())}));
63 } else {
64 IntSetVal* cisv;
65 if (vd->ti()->domain()) {
66 cisv = eval_intset(envi, vd->ti()->domain());
67 } else {
68 cisv = IntSetVal::a(-IntVal::infinity(), IntVal::infinity());
69 }
70 if (cisv->min() < isv->min()) {
71 calls.push_back(
72 new Call(iloc, constants().ids.int_.le, {IntLit::a(isv->min()), vd->id()}));
73 }
74 if (cisv->max() > isv->max()) {
75 calls.push_back(
76 new Call(iloc, constants().ids.int_.le, {vd->id(), IntLit::a(isv->max())}));
77 }
78 }
79 } else {
80 calls.push_back(new Call(iloc, constants().ids.set_in, {vd->id(), new SetLit(iloc, isv)}));
81 }
82 } else {
83 std::cerr << "Warning: domain change not handled by -g mode: " << *vd->id() << " = " << *domain
84 << std::endl;
85 return false;
86 }
87
88 int counter = 0;
89 for (Call* c : calls) {
90 CallStackItem csi(envi, IntLit::a(counter++));
91 c->ann().add(constants().ann.domain_change_constraint);
92 c->type(Type::varbool());
93 c->decl(envi.model->matchFn(envi, c, true));
94 flat_exp(envi, Ctx(), c, constants().var_true, constants().var_true);
95 }
96 return true;
97}
98
99void setComputedDomain(EnvI& envi, VarDecl* vd, Expression* domain, bool is_computed) {
100 if (!envi.fopts.record_domain_changes || vd->ann().contains(constants().ann.is_defined_var) ||
101 vd->introduced() || !createExplicitDomainConstraints(envi, vd, domain)) {
102 vd->ti()->domain(domain);
103 vd->ti()->setComputedDomain(is_computed);
104 }
105}
106
107/// Output operator for contexts
108template <class Char, class Traits>
109std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, Ctx& ctx) {
110 switch (ctx.b) {
111 case C_ROOT:
112 os << "R";
113 break;
114 case C_POS:
115 os << "+";
116 break;
117 case C_NEG:
118 os << "-";
119 break;
120 case C_MIX:
121 os << "M";
122 break;
123 default:
124 assert(false);
125 break;
126 }
127 switch (ctx.i) {
128 case C_ROOT:
129 os << "R";
130 break;
131 case C_POS:
132 os << "+";
133 break;
134 case C_NEG:
135 os << "-";
136 break;
137 case C_MIX:
138 os << "M";
139 break;
140 default:
141 assert(false);
142 break;
143 }
144 if (ctx.neg) os << "!";
145 return os;
146}
147
148BCtx operator+(const BCtx& c) {
149 switch (c) {
150 case C_ROOT:
151 return C_POS;
152 case C_POS:
153 return C_POS;
154 case C_NEG:
155 return C_NEG;
156 case C_MIX:
157 return C_MIX;
158 default:
159 assert(false);
160 return C_ROOT;
161 }
162}
163
164BCtx operator-(const BCtx& c) {
165 switch (c) {
166 case C_ROOT:
167 return C_NEG;
168 case C_POS:
169 return C_NEG;
170 case C_NEG:
171 return C_POS;
172 case C_MIX:
173 return C_MIX;
174 default:
175 assert(false);
176 return C_ROOT;
177 }
178}
179
180/// Check if \a c is non-positive
181bool nonpos(const BCtx& c) { return c == C_NEG || c == C_MIX; }
182/// Check if \a c is non-negative
183bool nonneg(const BCtx& c) { return c == C_ROOT || c == C_POS; }
184
185void dumpEEb(const std::vector<EE>& ee) {
186 for (unsigned int i = 0; i < ee.size(); i++) std::cerr << *ee[i].b() << "\n";
187}
188void dumpEEr(const std::vector<EE>& ee) {
189 for (unsigned int i = 0; i < ee.size(); i++) std::cerr << *ee[i].r() << "\n";
190}
191
192std::tuple<BCtx, bool> ann2Ctx(VarDecl* vd) {
193 if (vd->ann().contains(constants().ctx.root)) {
194 return std::make_tuple(C_ROOT, true);
195 } else if (vd->ann().contains(constants().ctx.mix)) {
196 return std::make_tuple(C_MIX, true);
197 } else if (vd->ann().contains(constants().ctx.pos)) {
198 return std::make_tuple(C_POS, true);
199 } else if (vd->ann().contains(constants().ctx.neg)) {
200 return std::make_tuple(C_NEG, true);
201 } else {
202 return std::make_tuple(C_MIX, false);
203 }
204}
205
206void addCtxAnn(VarDecl* vd, BCtx& c) {
207 if (vd) {
208 Id* ctx_id = NULL;
209 BCtx nc;
210 bool annotated;
211 std::tie(nc, annotated) = ann2Ctx(vd);
212 // If previously annotated
213 if (annotated) {
214 // Early exit
215 if (nc == c || nc == C_ROOT || (nc == C_MIX && c != C_ROOT)) {
216 return;
217 }
218 // Remove old annotation
219 switch (nc) {
220 case C_ROOT:
221 vd->ann().remove(constants().ctx.root);
222 break;
223 case C_MIX:
224 vd->ann().remove(constants().ctx.mix);
225 break;
226 case C_POS:
227 vd->ann().remove(constants().ctx.pos);
228 break;
229 case C_NEG:
230 vd->ann().remove(constants().ctx.neg);
231 break;
232 default:
233 assert(false);
234 break;
235 }
236 // Determine new context
237 if (c == C_ROOT) {
238 nc = C_ROOT;
239 } else {
240 nc = C_MIX;
241 }
242 } else {
243 nc = c;
244 }
245 switch (nc) {
246 case C_ROOT:
247 ctx_id = constants().ctx.root;
248 break;
249 case C_POS:
250 ctx_id = constants().ctx.pos;
251 break;
252 case C_NEG:
253 ctx_id = constants().ctx.neg;
254 break;
255 case C_MIX:
256 ctx_id = constants().ctx.mix;
257 break;
258 default:
259 assert(false);
260 break;
261 }
262 vd->addAnnotation(ctx_id);
263 }
264}
265
266void makeDefinedVar(VarDecl* vd, Call* c) {
267 if (!vd->ann().contains(constants().ann.is_defined_var)) {
268 std::vector<Expression*> args(1);
269 args[0] = vd->id();
270 Call* dv = new Call(Location().introduce(), constants().ann.defines_var, args);
271 dv->type(Type::ann());
272 vd->addAnnotation(constants().ann.is_defined_var);
273 c->addAnnotation(dv);
274 }
275}
276
277bool isDefinesVarAnn(Expression* e) {
278 return e->isa<Call>() && e->cast<Call>()->id() == constants().ann.defines_var;
279}
280
281/// Check if \a e is NULL or true
282bool istrue(EnvI& env, Expression* e) {
283 GCLock lock;
284 return e == NULL || (e->type().ispar() && e->type().isbool() && eval_bool(env, e));
285}
286/// Check if \a e is non-NULL and false
287bool isfalse(EnvI& env, Expression* e) {
288 GCLock lock;
289 return e != NULL && e->type().ispar() && e->type().isbool() && !eval_bool(env, e);
290}
291
292EE flat_exp(EnvI& env, Ctx ctx, Expression* e, VarDecl* r, VarDecl* b);
293KeepAlive bind(EnvI& env, Ctx ctx, VarDecl* vd, Expression* e);
294
295/// Use bounds from ovd for vd if they are better.
296/// Returns true if ovd's bounds are better.
297bool updateBounds(EnvI& envi, VarDecl* ovd, VarDecl* vd) {
298 bool tighter = false;
299 bool fixed = false;
300 if (ovd->ti()->domain() || ovd->e()) {
301 IntVal intval;
302 FloatVal doubleval;
303 bool boolval;
304
305 if (vd->type().isint()) {
306 IntBounds oldbounds = compute_int_bounds(envi, ovd->id());
307 IntBounds bounds(0, 0, false);
308 if (vd->ti()->domain() || vd->e()) bounds = compute_int_bounds(envi, vd->id());
309
310 if ((vd->ti()->domain() || vd->e()) && bounds.valid && bounds.l.isFinite() &&
311 bounds.u.isFinite()) {
312 if (oldbounds.valid && oldbounds.l.isFinite() && oldbounds.u.isFinite()) {
313 fixed = oldbounds.u == oldbounds.l || bounds.u == bounds.l;
314 if (fixed) {
315 tighter = true;
316 intval = oldbounds.u == oldbounds.l ? oldbounds.u : bounds.l;
317 ovd->ti()->domain(new SetLit(ovd->loc(), IntSetVal::a(intval, intval)));
318 } else {
319 IntSetVal* olddom = ovd->ti()->domain() ? eval_intset(envi, ovd->ti()->domain()) : NULL;
320 IntSetVal* newdom = vd->ti()->domain() ? eval_intset(envi, vd->ti()->domain()) : NULL;
321
322 if (olddom) {
323 if (!newdom) {
324 tighter = true;
325 } else {
326 IntSetRanges oisr(olddom);
327 IntSetRanges nisr(newdom);
328 IntSetRanges nisr_card(newdom);
329
330 Ranges::Inter<IntVal, IntSetRanges, IntSetRanges> inter(oisr, nisr);
331
332 if (Ranges::cardinality(inter) < Ranges::cardinality(nisr_card)) {
333 IntSetRanges oisr_inter(olddom);
334 IntSetRanges nisr_inter(newdom);
335 Ranges::Inter<IntVal, IntSetRanges, IntSetRanges> inter_card(oisr_inter,
336 nisr_inter);
337 tighter = true;
338 ovd->ti()->domain(new SetLit(ovd->loc(), IntSetVal::ai(inter_card)));
339 }
340 }
341 }
342 }
343 }
344 } else {
345 if (oldbounds.valid && oldbounds.l.isFinite() && oldbounds.u.isFinite()) {
346 tighter = true;
347 fixed = oldbounds.u == oldbounds.l;
348 if (fixed) {
349 intval = oldbounds.u;
350 ovd->ti()->domain(new SetLit(ovd->loc(), IntSetVal::a(intval, intval)));
351 }
352 }
353 }
354 } else if (vd->type().isfloat()) {
355 FloatBounds oldbounds = compute_float_bounds(envi, ovd->id());
356 FloatBounds bounds(0.0, 0.0, false);
357 if (vd->ti()->domain() || vd->e()) bounds = compute_float_bounds(envi, vd->id());
358 if ((vd->ti()->domain() || vd->e()) && bounds.valid) {
359 if (oldbounds.valid) {
360 fixed = oldbounds.u == oldbounds.l || bounds.u == bounds.l;
361 if (fixed) doubleval = oldbounds.u == oldbounds.l ? oldbounds.u : bounds.l;
362 tighter = fixed || (oldbounds.u - oldbounds.l < bounds.u - bounds.l);
363 }
364 } else {
365 if (oldbounds.valid) {
366 tighter = true;
367 fixed = oldbounds.u == oldbounds.l;
368 if (fixed) doubleval = oldbounds.u;
369 }
370 }
371 } else if (vd->type().isbool()) {
372 if (ovd->ti()->domain()) {
373 fixed = tighter = true;
374 boolval = eval_bool(envi, ovd->ti()->domain());
375 } else {
376 fixed = tighter = (ovd->e() && ovd->e()->isa<BoolLit>());
377 if (fixed) boolval = ovd->e()->cast<BoolLit>()->v();
378 }
379 }
380
381 if (tighter) {
382 vd->ti()->domain(ovd->ti()->domain());
383 if (vd->e() == NULL && fixed) {
384 if (vd->ti()->type().isvarint()) {
385 vd->type(Type::parint());
386 vd->ti(new TypeInst(vd->loc(), Type::parint()));
387 vd->e(IntLit::a(intval));
388 } else if (vd->ti()->type().isvarfloat()) {
389 vd->type(Type::parfloat());
390 vd->ti(new TypeInst(vd->loc(), Type::parfloat()));
391 vd->e(FloatLit::a(doubleval));
392 } else if (vd->ti()->type().isvarbool()) {
393 vd->type(Type::parbool());
394 vd->ti(new TypeInst(vd->loc(), Type::parbool()));
395 vd->ti()->domain(boolval ? constants().lit_true : constants().lit_false);
396 vd->e(new BoolLit(vd->loc(), boolval));
397 }
398 }
399 }
400 }
401
402 return tighter;
403}
404
405std::string getPath(EnvI& env) {
406 std::string path;
407 std::stringstream ss;
408 if (env.dumpPath(ss)) path = ss.str();
409
410 return path;
411}
412
413inline Location getLoc(EnvI& env, Expression* e1, Expression* e2) {
414 if (e1) {
415 return e1->loc().introduce();
416 } else if (e2) {
417 return e2->loc().introduce();
418 } else {
419 return Location().introduce();
420 }
421}
422inline Id* getId(EnvI& env, Id* origId) {
423 return origId ? origId : new Id(Location().introduce(), env.genId(), NULL);
424}
425
426StringLit* getLongestMznPathAnnotation(EnvI& env, const Expression* e) {
427 StringLit* sl = NULL;
428
429 if (const VarDecl* vd = e->dyn_cast<const VarDecl>()) {
430 EnvI::ReversePathMap& reversePathMap = env.getReversePathMap();
431 KeepAlive vd_decl_ka(vd->id()->decl());
432 EnvI::ReversePathMap::iterator it = reversePathMap.find(vd_decl_ka);
433 if (it != reversePathMap.end()) {
434 sl = new StringLit(Location(), it->second);
435 }
436 } else {
437 for (ExpressionSetIter it = e->ann().begin(); it != e->ann().end(); ++it) {
438 if (Call* ca = (*it)->dyn_cast<Call>()) {
439 if (ca->id() == constants().ann.mzn_path) {
440 StringLit* sl1 = ca->arg(0)->cast<StringLit>();
441 if (sl) {
442 if (sl1->v().size() > sl->v().size()) sl = sl1;
443 } else {
444 sl = sl1;
445 }
446 }
447 }
448 }
449 }
450 return sl;
451}
452
453void addPathAnnotation(EnvI& env, Expression* e) {
454 if (!(e->type().isann() || e->isa<Id>()) && e->type().dim() == 0) {
455 GCLock lock;
456 Annotation& ann = e->ann();
457 if (ann.containsCall(constants().ann.mzn_path)) return;
458
459 EnvI::ReversePathMap& reversePathMap = env.getReversePathMap();
460
461 std::vector<Expression*> path_args(1);
462 std::string p;
463 KeepAlive e_ka(e);
464 EnvI::ReversePathMap::iterator it = reversePathMap.find(e_ka);
465 if (it == reversePathMap.end()) {
466 p = getPath(env);
467 } else {
468 p = it->second;
469 }
470
471 if (p.size() != 0) {
472 path_args[0] = new StringLit(Location(), p);
473 Call* path_call = new Call(e->loc(), constants().ann.mzn_path, path_args);
474 path_call->type(Type::ann());
475 e->addAnnotation(path_call);
476 }
477 }
478}
479
480VarDecl* newVarDecl(EnvI& env, Ctx ctx, TypeInst* ti, Id* origId, VarDecl* origVd,
481 Expression* rhs) {
482 VarDecl* vd = nullptr;
483
484 // Is this vardecl already in the FlatZinc (for unification)
485 bool hasBeenAdded = false;
486
487 // Don't use paths for arrays or annotations
488 if (ti->type().dim() == 0 && !ti->type().isann()) {
489 std::string path = getPath(env);
490 if (!path.empty()) {
491 EnvI::ReversePathMap& reversePathMap = env.getReversePathMap();
492 EnvI::PathMap& pathMap = env.getPathMap();
493 EnvI::PathMap::iterator it = pathMap.find(path);
494
495 if (it != pathMap.end()) {
496 VarDecl* ovd = Expression::cast<VarDecl>((it->second.decl)());
497 unsigned int ovd_pass = it->second.pass_no;
498
499 if (ovd) {
500 // If ovd was introduced during the same pass, we can unify
501 if (env.current_pass_no == ovd_pass) {
502 vd = ovd;
503 if (origId) origId->decl(vd);
504 hasBeenAdded = true;
505 } else {
506 vd = new VarDecl(getLoc(env, origVd, rhs), ti, getId(env, origId));
507 hasBeenAdded = false;
508 updateBounds(env, ovd, vd);
509 }
510
511 // Check whether ovd was unified in a previous pass
512 if (ovd->id() != ovd->id()->decl()->id()) {
513 // We may not have seen the pointed to decl just yet
514 KeepAlive ovd_decl_ka(ovd->id()->decl());
515 EnvI::ReversePathMap::iterator path2It = reversePathMap.find(ovd_decl_ka);
516 if (path2It != reversePathMap.end()) {
517 std::string path2 = path2It->second;
518 EnvI::PathVar vd_tup{vd, env.current_pass_no};
519
520 pathMap[path] = vd_tup;
521 pathMap[path2] = vd_tup;
522 KeepAlive vd_ka(vd);
523 reversePathMap.insert(vd_ka, path);
524 }
525 }
526 }
527 } else {
528 // Create new VarDecl and add it to the maps
529 vd = new VarDecl(getLoc(env, origVd, rhs), ti, getId(env, origId));
530 hasBeenAdded = false;
531 EnvI::PathVar vd_tup{vd, env.current_pass_no};
532 pathMap[path] = vd_tup;
533 KeepAlive vd_ka(vd);
534 reversePathMap.insert(vd_ka, path);
535 }
536 }
537 }
538 if (vd == nullptr) {
539 vd = new VarDecl(getLoc(env, origVd, rhs), ti, getId(env, origId));
540 hasBeenAdded = false;
541 }
542
543 // If vd has an e() use bind to turn rhs into a constraint
544 if (vd->e()) {
545 if (rhs) {
546 bind(env, ctx, vd, rhs);
547 }
548 } else {
549 vd->e(rhs);
550 }
551 assert(!vd->type().isbot());
552 if (origVd && (origVd->id()->idn() != -1 || origVd->toplevel())) {
553 vd->introduced(origVd->introduced());
554 } else {
555 vd->introduced(true);
556 }
557
558 vd->flat(vd);
559
560 // Copy annotations from origVd
561 if (origVd) {
562 for (ExpressionSetIter it = origVd->ann().begin(); it != origVd->ann().end(); ++it) {
563 EE ee_ann = flat_exp(env, Ctx(), *it, NULL, constants().var_true);
564 vd->addAnnotation(ee_ann.r());
565 }
566 }
567
568 if (!hasBeenAdded) {
569 if (FunctionI* fi = env.model->matchRevMap(env, vd->type())) {
570 // We need to introduce a reverse mapper
571 Call* revmap = new Call(Location().introduce(), fi->id(), {vd->id()});
572 revmap->decl(fi);
573 revmap->type(Type::varbool());
574 env.flat_addItem(new ConstraintI(Location().introduce(), revmap));
575 }
576
577 VarDeclI* ni = new VarDeclI(Location().introduce(), vd);
578 env.flat_addItem(ni);
579 EE ee(vd, NULL);
580 env.cse_map_insert(vd->id(), ee);
581 }
582
583 return vd;
584}
585
586#define MZN_FILL_REIFY_MAP(T, ID) \
587 reifyMap.insert( \
588 std::pair<ASTString, ASTString>(constants().ids.T.ID, constants().ids.T##reif.ID));
589
590EnvI::EnvI(Model* model0, std::ostream& outstream0, std::ostream& errstream0)
591 : model(model0),
592 orig_model(NULL),
593 output(new Model),
594 outstream(outstream0),
595 errstream(errstream0),
596 current_pass_no(0),
597 final_pass_no(1),
598 maxPathDepth(0),
599 ignorePartial(false),
600 ignoreUnknownIds(false),
601 maxCallStack(0),
602 collect_vardecls(false),
603 in_redundant_constraint(0),
604 in_maybe_partial(0),
605 in_reverse_map_var(false),
606 n_reif_ct(0),
607 n_imp_ct(0),
608 n_imp_del(0),
609 n_lin_del(0),
610 pathUse(0),
611 _flat(new Model),
612 _failed(false),
613 ids(0) {
614 MZN_FILL_REIFY_MAP(int_, lin_eq);
615 MZN_FILL_REIFY_MAP(int_, lin_le);
616 MZN_FILL_REIFY_MAP(int_, lin_ne);
617 MZN_FILL_REIFY_MAP(int_, plus);
618 MZN_FILL_REIFY_MAP(int_, minus);
619 MZN_FILL_REIFY_MAP(int_, times);
620 MZN_FILL_REIFY_MAP(int_, div);
621 MZN_FILL_REIFY_MAP(int_, mod);
622 MZN_FILL_REIFY_MAP(int_, lt);
623 MZN_FILL_REIFY_MAP(int_, le);
624 MZN_FILL_REIFY_MAP(int_, gt);
625 MZN_FILL_REIFY_MAP(int_, ge);
626 MZN_FILL_REIFY_MAP(int_, eq);
627 MZN_FILL_REIFY_MAP(int_, ne);
628 MZN_FILL_REIFY_MAP(float_, lin_eq);
629 MZN_FILL_REIFY_MAP(float_, lin_le);
630 MZN_FILL_REIFY_MAP(float_, lin_lt);
631 MZN_FILL_REIFY_MAP(float_, lin_ne);
632 MZN_FILL_REIFY_MAP(float_, plus);
633 MZN_FILL_REIFY_MAP(float_, minus);
634 MZN_FILL_REIFY_MAP(float_, times);
635 MZN_FILL_REIFY_MAP(float_, div);
636 MZN_FILL_REIFY_MAP(float_, mod);
637 MZN_FILL_REIFY_MAP(float_, lt);
638 MZN_FILL_REIFY_MAP(float_, le);
639 MZN_FILL_REIFY_MAP(float_, gt);
640 MZN_FILL_REIFY_MAP(float_, ge);
641 MZN_FILL_REIFY_MAP(float_, eq);
642 MZN_FILL_REIFY_MAP(float_, ne);
643 reifyMap.insert(
644 std::pair<ASTString, ASTString>(constants().ids.forall, constants().ids.forall_reif));
645 reifyMap.insert(
646 std::pair<ASTString, ASTString>(constants().ids.bool_eq, constants().ids.bool_eq_reif));
647 reifyMap.insert(std::pair<ASTString, ASTString>(constants().ids.bool_clause,
648 constants().ids.bool_clause_reif));
649 reifyMap.insert(
650 std::pair<ASTString, ASTString>(constants().ids.clause, constants().ids.bool_clause_reif));
651}
652EnvI::~EnvI(void) {
653 delete _flat;
654 delete output;
655 delete model;
656 delete orig_model;
657}
658long long int EnvI::genId(void) { return ids++; }
659void EnvI::cse_map_insert(Expression* e, const EE& ee) {
660 KeepAlive ka(e);
661 cse_map.insert(ka, WW(ee.r(), ee.b()));
662}
663EnvI::CSEMap::iterator EnvI::cse_map_find(Expression* e) {
664 KeepAlive ka(e);
665 CSEMap::iterator it = cse_map.find(ka);
666 if (it != cse_map.end()) {
667 if (it->second.r()) {
668 if (it->second.r()->isa<Id>()) {
669 int idx = vo.find(it->second.r()->cast<Id>()->decl());
670 if (idx == -1 || (*_flat)[idx]->removed()) return cse_map.end();
671 }
672 } else {
673 return cse_map.end();
674 }
675 }
676 return it;
677}
678void EnvI::cse_map_remove(Expression* e) {
679 KeepAlive ka(e);
680 cse_map.remove(ka);
681}
682EnvI::CSEMap::iterator EnvI::cse_map_end(void) { return cse_map.end(); }
683void EnvI::dump(void) {
684 struct EED {
685 static std::string k(Expression* e) {
686 std::ostringstream oss;
687 oss << *e;
688 return oss.str();
689 }
690 static std::string d(const WW& ee) {
691 std::ostringstream oss;
692 oss << *ee.r() << " " << ee.b();
693 return oss.str();
694 }
695 };
696 cse_map.dump<EED>();
697}
698
699void EnvI::flat_addItem(Item* i) {
700 assert(_flat);
701 if (_failed) return;
702 _flat->addItem(i);
703
704 Expression* toAnnotate = NULL;
705 Expression* toAdd = NULL;
706 switch (i->iid()) {
707 case Item::II_VD: {
708 VarDeclI* vd = i->cast<VarDeclI>();
709 addPathAnnotation(*this, vd->e());
710 toAnnotate = vd->e()->e();
711 vo.add_idx(vd, _flat->size() - 1);
712 toAdd = vd->e();
713 break;
714 }
715 case Item::II_CON: {
716 ConstraintI* ci = i->cast<ConstraintI>();
717
718 if (ci->e()->isa<BoolLit>() && !ci->e()->cast<BoolLit>()->v()) {
719 fail();
720 } else {
721 toAnnotate = ci->e();
722 addPathAnnotation(*this, ci->e());
723 toAdd = ci->e();
724 }
725 break;
726 }
727 case Item::II_SOL: {
728 SolveI* si = i->cast<SolveI>();
729 CollectOccurrencesE ce(vo, si);
730 topDown(ce, si->e());
731 for (ExpressionSetIter it = si->ann().begin(); it != si->ann().end(); ++it) topDown(ce, *it);
732 break;
733 }
734 case Item::II_OUT: {
735 OutputI* si = i->cast<OutputI>();
736 toAdd = si->e();
737 break;
738 }
739 default:
740 break;
741 }
742 if (toAnnotate && toAnnotate->isa<Call>()) {
743 annotateFromCallStack(toAnnotate);
744 }
745 if (toAdd) {
746 CollectOccurrencesE ce(vo, i);
747 topDown(ce, toAdd);
748 }
749}
750
751void EnvI::annotateFromCallStack(Expression* e) {
752 int prev = idStack.size() > 0 ? idStack.back() : 0;
753 bool allCalls = true;
754 for (int i = static_cast<int>(callStack.size()) - 1; i >= prev; i--) {
755 Expression* ee = callStack[i]->untag();
756 allCalls = allCalls && (i == callStack.size() - 1 || ee->isa<Call>());
757 for (ExpressionSetIter it = ee->ann().begin(); it != ee->ann().end(); ++it) {
758 EE ee_ann = flat_exp(*this, Ctx(), *it, NULL, constants().var_true);
759 if (allCalls || !isDefinesVarAnn(ee_ann.r())) e->addAnnotation(ee_ann.r());
760 }
761 }
762}
763
764void EnvI::copyPathMapsAndState(EnvI& env) {
765 final_pass_no = env.final_pass_no;
766 maxPathDepth = env.maxPathDepth;
767 current_pass_no = env.current_pass_no;
768 filenameMap = env.filenameMap;
769 maxPathDepth = env.maxPathDepth;
770 pathMap = env.getPathMap();
771 reversePathMap = env.getReversePathMap();
772}
773
774void EnvI::flat_removeItem(MiniZinc::Item* i) { i->remove(); }
775void EnvI::flat_removeItem(int i) { flat_removeItem((*_flat)[i]); }
776
777void EnvI::fail(const std::string& msg) {
778 if (!_failed) {
779 addWarning(std::string("model inconsistency detected") +
780 (msg.empty() ? std::string() : (": " + msg)));
781 _failed = true;
782 for (unsigned int i = 0; i < _flat->size(); i++) {
783 (*_flat)[i]->remove();
784 }
785 ConstraintI* failedConstraint = new ConstraintI(Location().introduce(), constants().lit_false);
786 _flat->addItem(failedConstraint);
787 _flat->addItem(SolveI::sat(Location().introduce()));
788 for (unsigned int i = 0; i < output->size(); i++) {
789 (*output)[i]->remove();
790 }
791 output->addItem(
792 new OutputI(Location().introduce(), new ArrayLit(Location(), std::vector<Expression*>())));
793 throw ModelInconsistent(*this, Location().introduce());
794 }
795}
796
797bool EnvI::failed() const { return _failed; }
798
799unsigned int EnvI::registerEnum(VarDeclI* vdi) {
800 EnumMap::iterator it = enumMap.find(vdi);
801 unsigned int ret;
802 if (it == enumMap.end()) {
803 ret = static_cast<unsigned int>(enumVarDecls.size());
804 enumVarDecls.push_back(vdi);
805 enumMap.insert(std::make_pair(vdi, ret));
806 } else {
807 ret = it->second;
808 }
809 return ret + 1;
810}
811VarDeclI* EnvI::getEnum(unsigned int i) const {
812 assert(i > 0 && i <= enumVarDecls.size());
813 return enumVarDecls[i - 1];
814}
815unsigned int EnvI::registerArrayEnum(const std::vector<unsigned int>& arrayEnum) {
816 std::ostringstream oss;
817 for (unsigned int i = 0; i < arrayEnum.size(); i++) {
818 assert(arrayEnum[i] <= enumVarDecls.size());
819 oss << arrayEnum[i] << ".";
820 }
821 ArrayEnumMap::iterator it = arrayEnumMap.find(oss.str());
822 unsigned int ret;
823 if (it == arrayEnumMap.end()) {
824 ret = static_cast<unsigned int>(arrayEnumDecls.size());
825 arrayEnumDecls.push_back(arrayEnum);
826 arrayEnumMap.insert(std::make_pair(oss.str(), ret));
827 } else {
828 ret = it->second;
829 }
830 return ret + 1;
831}
832const std::vector<unsigned int>& EnvI::getArrayEnum(unsigned int i) const {
833 assert(i > 0 && i <= arrayEnumDecls.size());
834 return arrayEnumDecls[i - 1];
835}
836bool EnvI::isSubtype(const Type& t1, const Type& t2, bool strictEnums) {
837 if (!t1.isSubtypeOf(t2, strictEnums)) return false;
838 if (strictEnums && t1.dim() == 0 && t2.dim() != 0 && t2.enumId() != 0) {
839 // set assigned to an array
840 const std::vector<unsigned int>& t2enumIds = getArrayEnum(t2.enumId());
841 if (t2enumIds[t2enumIds.size() - 1] != 0 && t1.enumId() != t2enumIds[t2enumIds.size() - 1])
842 return false;
843 }
844 if (strictEnums && t1.dim() > 0 && t1.enumId() != t2.enumId()) {
845 if (t1.enumId() == 0) {
846 return t1.isbot();
847 }
848 if (t2.enumId() != 0) {
849 const std::vector<unsigned int>& t1enumIds = getArrayEnum(t1.enumId());
850 const std::vector<unsigned int>& t2enumIds = getArrayEnum(t2.enumId());
851 assert(t1enumIds.size() == t2enumIds.size());
852 for (unsigned int i = 0; i < t1enumIds.size() - 1; i++) {
853 if (t2enumIds[i] != 0 && t1enumIds[i] != t2enumIds[i]) return false;
854 }
855 if (!t1.isbot() && t2enumIds[t1enumIds.size() - 1] != 0 &&
856 t1enumIds[t1enumIds.size() - 1] != t2enumIds[t2enumIds.size() - 1])
857 return false;
858 }
859 }
860 return true;
861}
862
863void EnvI::collectVarDecls(bool b) { collect_vardecls = b; }
864void EnvI::vo_add_exp(VarDecl* vd) {
865 if (vd->e() && vd->e()->isa<Call>() && !vd->e()->type().isann()) {
866 int prev = idStack.size() > 0 ? idStack.back() : 0;
867 for (int i = static_cast<int>(callStack.size()) - 1; i >= prev; i--) {
868 Expression* ee = callStack[i]->untag();
869 for (ExpressionSetIter it = ee->ann().begin(); it != ee->ann().end(); ++it) {
870 Expression* ann = *it;
871 if (ann != constants().ann.add_to_output && ann != constants().ann.rhs_from_assignment) {
872 bool needAnnotation = true;
873 if (Call* ann_c = ann->dyn_cast<Call>()) {
874 if (ann_c->id() == constants().ann.defines_var) {
875 // only add defines_var annotation if vd is the defined variable
876 if (Id* defined_var = ann_c->arg(0)->dyn_cast<Id>()) {
877 if (defined_var->decl() != vd->id()->decl()) {
878 needAnnotation = false;
879 }
880 }
881 }
882 }
883 if (needAnnotation) {
884 EE ee_ann = flat_exp(*this, Ctx(), *it, NULL, constants().var_true);
885 vd->e()->addAnnotation(ee_ann.r());
886 }
887 }
888 }
889 }
890 }
891 int idx = vo.find(vd);
892 CollectOccurrencesE ce(vo, (*_flat)[idx]);
893 topDown(ce, vd->e());
894 if (collect_vardecls) modifiedVarDecls.push_back(idx);
895}
896Model* EnvI::flat(void) { return _flat; }
897void EnvI::swap() {
898 Model* tmp = model;
899 model = _flat;
900 _flat = tmp;
901}
902ASTString EnvI::reifyId(const ASTString& id) {
903 ASTStringMap<ASTString>::t::iterator it = reifyMap.find(id);
904 if (it == reifyMap.end()) {
905 return id.str() + "_reif";
906 } else {
907 return it->second;
908 }
909}
910#undef MZN_FILL_REIFY_MAP
911ASTString EnvI::halfReifyId(const ASTString& id) { return id.str() + "_imp"; }
912
913void EnvI::addWarning(const std::string& msg) {
914 if (warnings.size() > 20) return;
915 if (warnings.size() == 20) {
916 warnings.push_back("Further warnings have been suppressed.\n");
917 } else {
918 std::ostringstream oss;
919 createErrorStack();
920 dumpStack(oss, true);
921 warnings.push_back(msg + "\n" + oss.str());
922 }
923}
924
925void EnvI::createErrorStack(void) {
926 errorStack.clear();
927 for (unsigned int i = static_cast<unsigned int>(callStack.size()); i--;) {
928 Expression* e = callStack[i]->untag();
929 bool isCompIter = callStack[i]->isTagged();
930 KeepAlive ka(e);
931 errorStack.push_back(std::make_pair(ka, isCompIter));
932 }
933}
934
935Call* EnvI::surroundingCall(void) const {
936 if (callStack.size() >= 2) return callStack[callStack.size() - 2]->untag()->dyn_cast<Call>();
937 return NULL;
938}
939
940void EnvI::cleanupExceptOutput() {
941 cmap.clear();
942 cse_map.clear();
943 delete _flat;
944 delete model;
945 delete orig_model;
946 _flat = 0;
947 model = 0;
948}
949
950CallStackItem::CallStackItem(EnvI& env0, Expression* e) : env(env0) {
951 if (e->isa<VarDecl>()) env.idStack.push_back(static_cast<int>(env.callStack.size()));
952 if (e->isa<Call>() && e->cast<Call>()->id() == "redundant_constraint")
953 env.in_redundant_constraint++;
954 if (e->ann().contains(constants().ann.maybe_partial)) env.in_maybe_partial++;
955 env.callStack.push_back(e);
956 env.maxCallStack = std::max(env.maxCallStack, static_cast<unsigned int>(env.callStack.size()));
957}
958CallStackItem::CallStackItem(EnvI& env0, Id* ident, IntVal i) : env(env0) {
959 Expression* ee = ident->tag();
960 env.callStack.push_back(ee);
961 env.maxCallStack = std::max(env.maxCallStack, static_cast<unsigned int>(env.callStack.size()));
962}
963CallStackItem::~CallStackItem(void) {
964 Expression* e = env.callStack.back()->untag();
965 if (e->isa<VarDecl>()) env.idStack.pop_back();
966 if (e->isa<Call>() && e->cast<Call>()->id() == "redundant_constraint")
967 env.in_redundant_constraint--;
968 if (e->ann().contains(constants().ann.maybe_partial)) env.in_maybe_partial--;
969 env.callStack.pop_back();
970}
971
972FlatteningError::FlatteningError(EnvI& env, const Location& loc, const std::string& msg)
973 : LocationException(env, loc, msg) {}
974
975Env::Env(Model* m, std::ostream& outstream, std::ostream& errstream)
976 : e(new EnvI(m, outstream, errstream)) {}
977Env::~Env(void) { delete e; }
978
979Model* Env::model(void) { return e->model; }
980void Env::model(Model* m) { e->model = m; }
981Model* Env::flat(void) { return e->flat(); }
982void Env::swap() { e->swap(); }
983Model* Env::output(void) { return e->output; }
984
985std::ostream& Env::evalOutput(std::ostream& os) { return e->evalOutput(os); }
986EnvI& Env::envi(void) { return *e; }
987const EnvI& Env::envi(void) const { return *e; }
988std::ostream& Env::dumpErrorStack(std::ostream& os) { return e->dumpStack(os, true); }
989
990bool EnvI::dumpPath(std::ostream& os, bool force) {
991 force = force ? force : fopts.collect_mzn_paths;
992 if (callStack.size() > maxPathDepth) {
993 if (!force && current_pass_no >= final_pass_no - 1) {
994 return false;
995 }
996 maxPathDepth = static_cast<int>(callStack.size());
997 }
998
999 unsigned int lastError = static_cast<unsigned int>(callStack.size());
1000
1001 std::string major_sep = ";";
1002 std::string minor_sep = "|";
1003 for (unsigned int i = 0; i < lastError; i++) {
1004 Expression* e = callStack[i]->untag();
1005 bool isCompIter = callStack[i]->isTagged();
1006 Location loc = e->loc();
1007 int filenameId;
1008 std::unordered_map<std::string, int>::iterator findFilename =
1009 filenameMap.find(loc.filename().str());
1010 if (findFilename == filenameMap.end()) {
1011 if (!force && current_pass_no >= final_pass_no - 1) return false;
1012 filenameId = static_cast<int>(filenameMap.size());
1013 filenameMap.insert(
1014 std::make_pair(loc.filename().str(), static_cast<int>(filenameMap.size())));
1015 } else {
1016 filenameId = findFilename->second;
1017 }
1018
1019 // If this call is not a dummy StringLit with empty Location (so that deferred compilation
1020 // doesn't drop the paths)
1021 if (e->eid() != Expression::E_STRINGLIT || loc.first_line() || loc.first_column() ||
1022 loc.last_line() || loc.last_column()) {
1023 os << loc.filename().str() << minor_sep << loc.first_line() << minor_sep << loc.first_column()
1024 << minor_sep << loc.last_line() << minor_sep << loc.last_column() << minor_sep;
1025 switch (e->eid()) {
1026 case Expression::E_INTLIT:
1027 os << "il" << minor_sep << *e;
1028 break;
1029 case Expression::E_FLOATLIT:
1030 os << "fl" << minor_sep << *e;
1031 break;
1032 case Expression::E_SETLIT:
1033 os << "sl" << minor_sep << *e;
1034 break;
1035 case Expression::E_BOOLLIT:
1036 os << "bl" << minor_sep << *e;
1037 break;
1038 case Expression::E_STRINGLIT:
1039 os << "stl" << minor_sep << *e;
1040 break;
1041 case Expression::E_ID:
1042 if (isCompIter) {
1043 // if (e->cast<Id>()->decl()->e()->type().ispar())
1044 os << *e << "=" << *e->cast<Id>()->decl()->e();
1045 // else
1046 // os << *e << "=?";
1047 } else {
1048 os << "id" << minor_sep << *e;
1049 }
1050 break;
1051 case Expression::E_ANON:
1052 os << "anon";
1053 break;
1054 case Expression::E_ARRAYLIT:
1055 os << "al";
1056 break;
1057 case Expression::E_ARRAYACCESS:
1058 os << "aa";
1059 break;
1060 case Expression::E_COMP: {
1061 const Comprehension* cmp = e->cast<Comprehension>();
1062 if (cmp->set())
1063 os << "sc";
1064 else
1065 os << "ac";
1066 } break;
1067 case Expression::E_ITE:
1068 os << "ite";
1069 break;
1070 case Expression::E_BINOP:
1071 os << "bin" << minor_sep << e->cast<BinOp>()->opToString();
1072 break;
1073 case Expression::E_UNOP:
1074 os << "un" << minor_sep << e->cast<UnOp>()->opToString();
1075 break;
1076 case Expression::E_CALL:
1077 if (fopts.only_toplevel_paths) return false;
1078 os << "ca" << minor_sep << e->cast<Call>()->id();
1079 break;
1080 case Expression::E_VARDECL:
1081 os << "vd";
1082 break;
1083 case Expression::E_LET:
1084 os << "l";
1085 break;
1086 case Expression::E_TI:
1087 os << "ti";
1088 break;
1089 case Expression::E_TIID:
1090 os << "ty";
1091 break;
1092 default:
1093 assert(false);
1094 os << "unknown expression (internal error)";
1095 break;
1096 }
1097 os << major_sep;
1098 } else {
1099 os << e->cast<StringLit>()->v() << major_sep;
1100 }
1101 }
1102 return true;
1103}
1104
1105std::ostream& EnvI::dumpStack(std::ostream& os, bool errStack) {
1106 int lastError = 0;
1107
1108 std::vector<Expression*> errStackCopy;
1109 if (errStack) {
1110 errStackCopy.resize(errorStack.size());
1111 for (unsigned int i = 0; i < errorStack.size(); i++) {
1112 Expression* e = errorStack[i].first();
1113 if (errorStack[i].second) {
1114 e = e->tag();
1115 }
1116 errStackCopy[i] = e;
1117 }
1118 }
1119
1120 std::vector<Expression*>& stack = errStack ? errStackCopy : callStack;
1121
1122 for (; lastError < stack.size(); lastError++) {
1123 Expression* e = stack[lastError]->untag();
1124 bool isCompIter = stack[lastError]->isTagged();
1125 if (e->loc().is_introduced()) continue;
1126 if (!isCompIter && e->isa<Id>()) {
1127 break;
1128 }
1129 }
1130
1131 ASTString curloc_f;
1132 int curloc_l = -1;
1133
1134 for (int i = lastError - 1; i >= 0; i--) {
1135 Expression* e = stack[i]->untag();
1136 bool isCompIter = stack[i]->isTagged();
1137 ASTString newloc_f = e->loc().filename();
1138 if (e->loc().is_introduced()) continue;
1139 int newloc_l = e->loc().first_line();
1140 if (newloc_f != curloc_f || newloc_l != curloc_l) {
1141 os << " " << newloc_f << ":" << newloc_l << ":" << std::endl;
1142 curloc_f = newloc_f;
1143 curloc_l = newloc_l;
1144 }
1145 if (isCompIter)
1146 os << " with ";
1147 else
1148 os << " in ";
1149 switch (e->eid()) {
1150 case Expression::E_INTLIT:
1151 os << "integer literal" << std::endl;
1152 break;
1153 case Expression::E_FLOATLIT:
1154 os << "float literal" << std::endl;
1155 break;
1156 case Expression::E_SETLIT:
1157 os << "set literal" << std::endl;
1158 break;
1159 case Expression::E_BOOLLIT:
1160 os << "bool literal" << std::endl;
1161 break;
1162 case Expression::E_STRINGLIT:
1163 os << "string literal" << std::endl;
1164 break;
1165 case Expression::E_ID:
1166 if (isCompIter) {
1167 if (e->cast<Id>()->decl()->e()->type().ispar())
1168 os << *e << " = " << *e->cast<Id>()->decl()->e() << std::endl;
1169 else
1170 os << *e << " = <expression>" << std::endl;
1171 } else {
1172 os << "identifier" << *e << std::endl;
1173 }
1174 break;
1175 case Expression::E_ANON:
1176 os << "anonymous variable" << std::endl;
1177 break;
1178 case Expression::E_ARRAYLIT:
1179 os << "array literal" << std::endl;
1180 break;
1181 case Expression::E_ARRAYACCESS:
1182 os << "array access" << std::endl;
1183 break;
1184 case Expression::E_COMP: {
1185 const Comprehension* cmp = e->cast<Comprehension>();
1186 if (cmp->set())
1187 os << "set ";
1188 else
1189 os << "array ";
1190 os << "comprehension expression" << std::endl;
1191 } break;
1192 case Expression::E_ITE:
1193 os << "if-then-else expression" << std::endl;
1194 break;
1195 case Expression::E_BINOP:
1196 os << "binary " << e->cast<BinOp>()->opToString() << " operator expression" << std::endl;
1197 break;
1198 case Expression::E_UNOP:
1199 os << "unary " << e->cast<UnOp>()->opToString() << " operator expression" << std::endl;
1200 break;
1201 case Expression::E_CALL:
1202 os << "call '" << e->cast<Call>()->id() << "'" << std::endl;
1203 break;
1204 case Expression::E_VARDECL: {
1205 GCLock lock;
1206 os << "variable declaration for '" << e->cast<VarDecl>()->id()->str() << "'" << std::endl;
1207 } break;
1208 case Expression::E_LET:
1209 os << "let expression" << std::endl;
1210 break;
1211 case Expression::E_TI:
1212 os << "type-inst expression" << std::endl;
1213 break;
1214 case Expression::E_TIID:
1215 os << "type identifier" << std::endl;
1216 break;
1217 default:
1218 assert(false);
1219 os << "unknown expression (internal error)" << std::endl;
1220 break;
1221 }
1222 }
1223 return os;
1224}
1225
1226void populateOutput(Env& env) {
1227 EnvI& envi = env.envi();
1228 Model* _flat = envi.flat();
1229 Model* _output = envi.output;
1230 std::vector<Expression*> outputVars;
1231 for (VarDeclIterator it = _flat->begin_vardecls(); it != _flat->end_vardecls(); ++it) {
1232 VarDecl* vd = it->e();
1233 Annotation& ann = vd->ann();
1234 ArrayLit* dims = NULL;
1235 bool has_output_ann = false;
1236 if (!ann.isEmpty()) {
1237 for (ExpressionSetIter ait = ann.begin(); ait != ann.end(); ++ait) {
1238 if (Call* c = (*ait)->dyn_cast<Call>()) {
1239 if (c->id() == constants().ann.output_array) {
1240 dims = c->arg(0)->cast<ArrayLit>();
1241 has_output_ann = true;
1242 break;
1243 }
1244 } else if ((*ait)->isa<Id>() &&
1245 (*ait)->cast<Id>()->str() == constants().ann.output_var->str()) {
1246 has_output_ann = true;
1247 }
1248 }
1249 if (has_output_ann) {
1250 std::ostringstream s;
1251 s << vd->id()->str().str() << " = ";
1252
1253 VarDecl* vd_output = copy(env.envi(), vd)->cast<VarDecl>();
1254 Type vd_t = vd_output->type();
1255 vd_t.ti(Type::TI_PAR);
1256 vd_output->type(vd_t);
1257 vd_output->ti()->type(vd_t);
1258 _output->addItem(new VarDeclI(Location().introduce(), vd_output));
1259
1260 if (dims) {
1261 s << "array" << dims->size() << "d(";
1262 for (unsigned int i = 0; i < dims->size(); i++) {
1263 IntSetVal* idxset = eval_intset(envi, (*dims)[i]);
1264 s << *idxset << ",";
1265 }
1266 }
1267 StringLit* sl = new StringLit(Location().introduce(), s.str());
1268 outputVars.push_back(sl);
1269
1270 std::vector<Expression*> showArgs(1);
1271 showArgs[0] = vd_output->id();
1272 Call* show = new Call(Location().introduce(), constants().ids.show, showArgs);
1273 show->type(Type::parstring());
1274 FunctionI* fi = _flat->matchFn(envi, show, false);
1275 assert(fi);
1276 show->decl(fi);
1277 outputVars.push_back(show);
1278 std::string ends = dims ? ")" : "";
1279 ends += ";\n";
1280 StringLit* eol = new StringLit(Location().introduce(), ends);
1281 outputVars.push_back(eol);
1282 }
1283 }
1284 }
1285 OutputI* newOutputItem =
1286 new OutputI(Location().introduce(), new ArrayLit(Location().introduce(), outputVars));
1287 _output->addItem(newOutputItem);
1288 envi.flat()->mergeStdLib(envi, _output);
1289}
1290
1291std::ostream& EnvI::evalOutput(std::ostream& os) {
1292 GCLock lock;
1293
1294 ArrayLit* al = eval_array_lit(*this, output->outputItem()->e());
1295 bool fLastEOL = true;
1296 for (unsigned int i = 0; i < al->size(); i++) {
1297 std::string s = eval_string(*this, (*al)[i]);
1298 if (!s.empty()) {
1299 os << s;
1300 fLastEOL = ('\n' == s.back());
1301 }
1302 }
1303 if (!fLastEOL) os << '\n';
1304 return os;
1305}
1306
1307const std::vector<std::string>& Env::warnings(void) { return envi().warnings; }
1308
1309void Env::clearWarnings(void) { envi().warnings.clear(); }
1310
1311unsigned int Env::maxCallStack(void) const { return envi().maxCallStack; }
1312
1313void checkIndexSets(EnvI& env, VarDecl* vd, Expression* e) {
1314 ASTExprVec<TypeInst> tis = vd->ti()->ranges();
1315 std::vector<TypeInst*> newtis(tis.size());
1316 bool needNewTypeInst = false;
1317 GCLock lock;
1318 switch (e->eid()) {
1319 case Expression::E_ID: {
1320 Id* id = e->cast<Id>();
1321 ASTExprVec<TypeInst> e_tis = id->decl()->ti()->ranges();
1322 assert(tis.size() == e_tis.size());
1323 for (unsigned int i = 0; i < tis.size(); i++) {
1324 if (tis[i]->domain() == NULL) {
1325 newtis[i] = e_tis[i];
1326 needNewTypeInst = true;
1327 } else {
1328 if (!eval_intset(env, tis[i]->domain())->equal(eval_intset(env, e_tis[i]->domain())))
1329 throw EvalError(env, vd->loc(), "Index set mismatch");
1330 newtis[i] = tis[i];
1331 }
1332 }
1333 } break;
1334 case Expression::E_ARRAYLIT: {
1335 ArrayLit* al = e->cast<ArrayLit>();
1336 for (unsigned int i = 0; i < tis.size(); i++) {
1337 if (tis[i]->domain() == NULL) {
1338 newtis[i] = new TypeInst(
1339 Location().introduce(), Type(),
1340 new SetLit(Location().introduce(), IntSetVal::a(al->min(i), al->max(i))));
1341 needNewTypeInst = true;
1342 } else if (i == 0 || al->size() != 0) {
1343 IntSetVal* isv = eval_intset(env, tis[i]->domain());
1344 assert(isv->size() <= 1);
1345 if ((isv->size() == 0 && al->min(i) <= al->max(i)) ||
1346 (isv->size() != 0 && (isv->min(0) != al->min(i) || isv->max(0) != al->max(i))))
1347 throw EvalError(env, vd->loc(), "Index set mismatch");
1348 newtis[i] = tis[i];
1349 }
1350 }
1351 } break;
1352 default:
1353 throw InternalError("not supported yet");
1354 }
1355 if (needNewTypeInst) {
1356 TypeInst* tic = copy(env, vd->ti())->cast<TypeInst>();
1357 tic->setRanges(newtis);
1358 vd->ti(tic);
1359 }
1360}
1361
1362/// Turn \a c into domain constraints if possible.
1363/// Return whether \a c is still required in the model.
1364bool checkDomainConstraints(EnvI& env, Call* c) {
1365 if (env.fopts.record_domain_changes) return true;
1366 if (c->id() == constants().ids.int_.le) {
1367 Expression* e0 = c->arg(0);
1368 Expression* e1 = c->arg(1);
1369 if (e0->type().ispar() && e1->isa<Id>()) {
1370 // greater than
1371 Id* id = e1->cast<Id>();
1372 IntVal lb = eval_int(env, e0);
1373 if (id->decl()->ti()->domain()) {
1374 IntSetVal* domain = eval_intset(env, id->decl()->ti()->domain());
1375 if (domain->min() >= lb) return false;
1376 if (domain->max() < lb) {
1377 env.fail();
1378 return false;
1379 }
1380 IntSetRanges dr(domain);
1381 Ranges::Const<IntVal> cr(lb, IntVal::infinity());
1382 Ranges::Inter<IntVal, IntSetRanges, Ranges::Const<IntVal> > i(dr, cr);
1383 IntSetVal* newibv = IntSetVal::ai(i);
1384 id->decl()->ti()->domain(new SetLit(Location().introduce(), newibv));
1385 id->decl()->ti()->setComputedDomain(false);
1386 } else {
1387 id->decl()->ti()->domain(
1388 new SetLit(Location().introduce(), IntSetVal::a(lb, IntVal::infinity())));
1389 }
1390 return false;
1391 } else if (e1->type().ispar() && e0->isa<Id>()) {
1392 // less than
1393 Id* id = e0->cast<Id>();
1394 IntVal ub = eval_int(env, e1);
1395 if (id->decl()->ti()->domain()) {
1396 IntSetVal* domain = eval_intset(env, id->decl()->ti()->domain());
1397 if (domain->max() <= ub) return false;
1398 if (domain->min() > ub) {
1399 env.fail();
1400 return false;
1401 }
1402 IntSetRanges dr(domain);
1403 Ranges::Const<IntVal> cr(-IntVal::infinity(), ub);
1404 Ranges::Inter<IntVal, IntSetRanges, Ranges::Const<IntVal> > i(dr, cr);
1405 IntSetVal* newibv = IntSetVal::ai(i);
1406 id->decl()->ti()->domain(new SetLit(Location().introduce(), newibv));
1407 id->decl()->ti()->setComputedDomain(false);
1408 } else {
1409 id->decl()->ti()->domain(
1410 new SetLit(Location().introduce(), IntSetVal::a(-IntVal::infinity(), ub)));
1411 }
1412 }
1413 } else if (c->id() == constants().ids.int_.lin_le) {
1414 ArrayLit* al_c = follow_id(c->arg(0))->cast<ArrayLit>();
1415 if (al_c->size() == 1) {
1416 ArrayLit* al_x = follow_id(c->arg(1))->cast<ArrayLit>();
1417 IntVal coeff = eval_int(env, (*al_c)[0]);
1418 IntVal y = eval_int(env, c->arg(2));
1419 IntVal lb = -IntVal::infinity();
1420 IntVal ub = IntVal::infinity();
1421 IntVal r = y % coeff;
1422 if (coeff >= 0) {
1423 ub = y / coeff;
1424 if (r < 0) --ub;
1425 } else {
1426 lb = y / coeff;
1427 if (r < 0) ++lb;
1428 }
1429 if (Id* id = (*al_x)[0]->dyn_cast<Id>()) {
1430 if (id->decl()->ti()->domain()) {
1431 IntSetVal* domain = eval_intset(env, id->decl()->ti()->domain());
1432 if (domain->max() <= ub && domain->min() >= lb) return false;
1433 if (domain->min() > ub || domain->max() < lb) {
1434 env.fail();
1435 return false;
1436 }
1437 IntSetRanges dr(domain);
1438 Ranges::Const<IntVal> cr(lb, ub);
1439 Ranges::Inter<IntVal, IntSetRanges, Ranges::Const<IntVal> > i(dr, cr);
1440 IntSetVal* newibv = IntSetVal::ai(i);
1441 id->decl()->ti()->domain(new SetLit(Location().introduce(), newibv));
1442 id->decl()->ti()->setComputedDomain(false);
1443 } else {
1444 id->decl()->ti()->domain(new SetLit(Location().introduce(), IntSetVal::a(lb, ub)));
1445 }
1446 return false;
1447 }
1448 }
1449 }
1450 return true;
1451}
1452
1453KeepAlive bind(EnvI& env, Ctx ctx, VarDecl* vd, Expression* e) {
1454 assert(e == NULL || !e->isa<VarDecl>());
1455 if (vd == constants().var_ignore) return e;
1456 if (Id* ident = e->dyn_cast<Id>()) {
1457 if (ident->decl()) {
1458 VarDecl* e_vd = follow_id_to_decl(ident)->cast<VarDecl>();
1459 e = e_vd->id();
1460 if (!env.in_reverse_map_var && ctx.b != C_ROOT && e->type() == Type::varbool()) {
1461 addCtxAnn(e_vd, ctx.b);
1462 if (e_vd != ident->decl()) {
1463 addCtxAnn(ident->decl(), ctx.b);
1464 }
1465 }
1466 }
1467 }
1468 if (ctx.neg) {
1469 assert(e->type().bt() == Type::BT_BOOL);
1470 if (vd == constants().var_true) {
1471 if (!isfalse(env, e)) {
1472 if (Id* id = e->dyn_cast<Id>()) {
1473 while (id != NULL) {
1474 assert(id->decl() != NULL);
1475 if (id->decl()->ti()->domain() && istrue(env, id->decl()->ti()->domain())) {
1476 GCLock lock;
1477 env.flat_addItem(new ConstraintI(Location().introduce(), constants().lit_false));
1478 } else {
1479 id->decl()->ti()->domain(constants().lit_false);
1480 GCLock lock;
1481 std::vector<Expression*> args(2);
1482 args[0] = id;
1483 args[1] = constants().lit_false;
1484 Call* c = new Call(Location().introduce(), constants().ids.bool_eq, args);
1485 c->decl(env.model->matchFn(env, c, false));
1486 c->type(c->decl()->rtype(env, args, false));
1487 if (c->decl()->e()) {
1488 flat_exp(env, Ctx(), c, constants().var_true, constants().var_true);
1489 }
1490 }
1491 id = id->decl()->e() ? id->decl()->e()->dyn_cast<Id>() : NULL;
1492 }
1493 return constants().lit_true;
1494 } else {
1495 GC::lock();
1496 BinOp* bo = new BinOp(e->loc(), e, BOT_EQUIV, constants().lit_false);
1497 bo->type(e->type());
1498 KeepAlive ka(bo);
1499 GC::unlock();
1500 EE ee = flat_exp(env, Ctx(), bo, NULL, constants().var_true);
1501 return bind(env, Ctx(), vd, ee.r());
1502 }
1503 }
1504 return constants().lit_true;
1505 } else {
1506 GC::lock();
1507 BinOp* bo = new BinOp(e->loc(), e, BOT_EQUIV, constants().lit_false);
1508 bo->type(e->type());
1509 KeepAlive ka(bo);
1510 GC::unlock();
1511 EE ee = flat_exp(env, Ctx(), bo, NULL, constants().var_true);
1512 return bind(env, Ctx(), vd, ee.r());
1513 }
1514 } else {
1515 if (vd == constants().var_true) {
1516 if (!istrue(env, e)) {
1517 if (Id* id = e->dyn_cast<Id>()) {
1518 assert(id->decl() != NULL);
1519 while (id != NULL) {
1520 if (id->decl()->ti()->domain() && isfalse(env, id->decl()->ti()->domain())) {
1521 GCLock lock;
1522 env.flat_addItem(new ConstraintI(Location().introduce(), constants().lit_false));
1523 } else if (id->decl()->ti()->domain() == NULL) {
1524 id->decl()->ti()->domain(constants().lit_true);
1525 GCLock lock;
1526 std::vector<Expression*> args(2);
1527 args[0] = id;
1528 args[1] = constants().lit_true;
1529 Call* c = new Call(Location().introduce(), constants().ids.bool_eq, args);
1530 c->decl(env.model->matchFn(env, c, false));
1531 c->type(c->decl()->rtype(env, args, false));
1532 if (c->decl()->e()) {
1533 flat_exp(env, Ctx(), c, constants().var_true, constants().var_true);
1534 }
1535 }
1536 id = id->decl()->e() ? id->decl()->e()->dyn_cast<Id>() : NULL;
1537 }
1538 } else {
1539 GCLock lock;
1540 // extract domain information from added constraint if possible
1541 if (!e->isa<Call>() || checkDomainConstraints(env, e->cast<Call>())) {
1542 env.flat_addItem(new ConstraintI(Location().introduce(), e));
1543 }
1544 }
1545 }
1546 return constants().lit_true;
1547 } else if (vd == constants().var_false) {
1548 if (!isfalse(env, e)) {
1549 throw InternalError("not supported yet");
1550 }
1551 return constants().lit_true;
1552 } else if (vd == NULL) {
1553 if (e == NULL) return NULL;
1554 switch (e->eid()) {
1555 case Expression::E_INTLIT:
1556 case Expression::E_FLOATLIT:
1557 case Expression::E_BOOLLIT:
1558 case Expression::E_STRINGLIT:
1559 case Expression::E_ANON:
1560 case Expression::E_ID:
1561 case Expression::E_TIID:
1562 case Expression::E_SETLIT:
1563 case Expression::E_VARDECL:
1564 return e;
1565 case Expression::E_BINOP:
1566 case Expression::E_UNOP:
1567 return e; /// TODO: should not happen once operators are evaluated
1568 case Expression::E_ARRAYACCESS:
1569 case Expression::E_COMP:
1570 case Expression::E_ITE:
1571 case Expression::E_LET:
1572 case Expression::E_TI:
1573 throw InternalError("unevaluated expression");
1574 case Expression::E_ARRAYLIT: {
1575 GCLock lock;
1576 ArrayLit* al = e->cast<ArrayLit>();
1577 /// TODO: review if limit of 10 is a sensible choice
1578 if (al->type().bt() == Type::BT_ANN || al->size() <= 10) return e;
1579
1580 EnvI::CSEMap::iterator it = env.cse_map_find(al);
1581 if (it != env.cse_map_end()) {
1582 return it->second.r()->cast<VarDecl>()->id();
1583 }
1584
1585 std::vector<TypeInst*> ranges(al->dims());
1586 for (unsigned int i = 0; i < ranges.size(); i++) {
1587 ranges[i] = new TypeInst(
1588 e->loc(), Type(),
1589 new SetLit(Location().introduce(), IntSetVal::a(al->min(i), al->max(i))));
1590 }
1591 ASTExprVec<TypeInst> ranges_v(ranges);
1592 assert(!al->type().isbot());
1593 Expression* domain = NULL;
1594 if (al->size() > 0 && (*al)[0]->type().isint()) {
1595 IntVal min = IntVal::infinity();
1596 IntVal max = -IntVal::infinity();
1597 for (unsigned int i = 0; i < al->size(); i++) {
1598 IntBounds ib = compute_int_bounds(env, (*al)[i]);
1599 if (!ib.valid) {
1600 min = -IntVal::infinity();
1601 max = IntVal::infinity();
1602 break;
1603 }
1604 min = std::min(min, ib.l);
1605 max = std::max(max, ib.u);
1606 }
1607 if (min != -IntVal::infinity() && max != IntVal::infinity()) {
1608 domain = new SetLit(Location().introduce(), IntSetVal::a(min, max));
1609 }
1610 }
1611 TypeInst* ti = new TypeInst(e->loc(), al->type(), ranges_v, domain);
1612 if (domain) ti->setComputedDomain(true);
1613
1614 VarDecl* vd = newVarDecl(env, ctx, ti, NULL, NULL, al);
1615 EE ee(vd, NULL);
1616 env.cse_map_insert(al, ee);
1617 env.cse_map_insert(vd->e(), ee);
1618 return vd->id();
1619 }
1620 case Expression::E_CALL: {
1621 if (e->type().isann()) return e;
1622 GCLock lock;
1623 /// TODO: handle array types
1624 TypeInst* ti = new TypeInst(Location().introduce(), e->type());
1625 VarDecl* vd = newVarDecl(env, ctx, ti, NULL, NULL, e);
1626 if (vd->e()->type().bt() == Type::BT_INT && vd->e()->type().dim() == 0) {
1627 IntSetVal* ibv = NULL;
1628 if (vd->e()->type().is_set()) {
1629 ibv = compute_intset_bounds(env, vd->e());
1630 } else {
1631 IntBounds ib = compute_int_bounds(env, vd->e());
1632 if (ib.valid) {
1633 ibv = IntSetVal::a(ib.l, ib.u);
1634 }
1635 }
1636 if (ibv) {
1637 Id* id = vd->id();
1638 while (id != NULL) {
1639 if (id->decl()->ti()->domain()) {
1640 IntSetVal* domain = eval_intset(env, id->decl()->ti()->domain());
1641 IntSetRanges dr(domain);
1642 IntSetRanges ibr(ibv);
1643 Ranges::Inter<IntVal, IntSetRanges, IntSetRanges> i(dr, ibr);
1644 IntSetVal* newibv = IntSetVal::ai(i);
1645 if (ibv->card() == newibv->card()) {
1646 id->decl()->ti()->setComputedDomain(true);
1647 } else {
1648 ibv = newibv;
1649 }
1650 } else {
1651 id->decl()->ti()->setComputedDomain(true);
1652 }
1653 if (id->type().st() == Type::ST_PLAIN && ibv->size() == 0) {
1654 env.fail();
1655 } else {
1656 id->decl()->ti()->domain(new SetLit(Location().introduce(), ibv));
1657 }
1658 id = id->decl()->e() ? id->decl()->e()->dyn_cast<Id>() : NULL;
1659 }
1660 }
1661 } else if (vd->e()->type().isbool()) {
1662 addCtxAnn(vd, ctx.b);
1663 } else if (vd->e()->type().bt() == Type::BT_FLOAT && vd->e()->type().dim() == 0) {
1664 FloatBounds fb = compute_float_bounds(env, vd->e());
1665 FloatSetVal* ibv = LinearTraits<FloatLit>::intersect_domain(NULL, fb.l, fb.u);
1666 if (fb.valid) {
1667 Id* id = vd->id();
1668 while (id != NULL) {
1669 if (id->decl()->ti()->domain()) {
1670 FloatSetVal* domain = eval_floatset(env, id->decl()->ti()->domain());
1671 FloatSetVal* ndomain =
1672 LinearTraits<FloatLit>::intersect_domain(domain, fb.l, fb.u);
1673 if (ibv && ndomain == domain) {
1674 id->decl()->ti()->setComputedDomain(true);
1675 } else {
1676 ibv = ndomain;
1677 }
1678 } else {
1679 id->decl()->ti()->setComputedDomain(true);
1680 }
1681 if (LinearTraits<FloatLit>::domain_empty(ibv)) {
1682 env.fail();
1683 } else {
1684 id->decl()->ti()->domain(new SetLit(Location(), ibv));
1685 }
1686 id = id->decl()->e() ? id->decl()->e()->dyn_cast<Id>() : NULL;
1687 }
1688 }
1689 }
1690
1691 return vd->id();
1692 }
1693 default:
1694 assert(false);
1695 return NULL;
1696 }
1697 } else {
1698 if (vd->e() == NULL) {
1699 Expression* ret = e;
1700 if (e == NULL || (e->type().ispar() && e->type().isbool())) {
1701 GCLock lock;
1702 bool isTrue = (e == NULL || eval_bool(env, e));
1703
1704 // Check if redefinition of bool_eq exists, if yes call it
1705 std::vector<Expression*> args(2);
1706 args[0] = vd->id();
1707 args[1] = constants().boollit(isTrue);
1708 Call* c = new Call(Location().introduce(), constants().ids.bool_eq, args);
1709 c->decl(env.model->matchFn(env, c, false));
1710 c->type(c->decl()->rtype(env, args, false));
1711 bool didRewrite = false;
1712 if (c->decl()->e()) {
1713 flat_exp(env, Ctx(), c, constants().var_true, constants().var_true);
1714 didRewrite = true;
1715 }
1716
1717 vd->e(constants().boollit(isTrue));
1718 if (vd->ti()->domain()) {
1719 if (vd->ti()->domain() != vd->e()) {
1720 env.fail();
1721 return vd->id();
1722 }
1723 } else {
1724 vd->ti()->domain(vd->e());
1725 vd->ti()->setComputedDomain(true);
1726 }
1727 if (didRewrite) {
1728 return vd->id();
1729 }
1730 } else {
1731 if (e->type().dim() > 0) {
1732 // Check that index sets match
1733 env.errorStack.clear();
1734 checkIndexSets(env, vd, e);
1735 if (vd->ti()->domain() && e->isa<ArrayLit>()) {
1736 ArrayLit* al = e->cast<ArrayLit>();
1737 if (e->type().bt() == Type::BT_INT) {
1738 IntSetVal* isv = eval_intset(env, vd->ti()->domain());
1739 for (unsigned int i = 0; i < al->size(); i++) {
1740 if (Id* id = (*al)[i]->dyn_cast<Id>()) {
1741 VarDecl* vdi = id->decl();
1742 if (vdi->ti()->domain() == NULL) {
1743 vdi->ti()->domain(vd->ti()->domain());
1744 } else {
1745 IntSetVal* vdi_dom = eval_intset(env, vdi->ti()->domain());
1746 IntSetRanges isvr(isv);
1747 IntSetRanges vdi_domr(vdi_dom);
1748 Ranges::Inter<IntVal, IntSetRanges, IntSetRanges> inter(isvr, vdi_domr);
1749 IntSetVal* newdom = IntSetVal::ai(inter);
1750 if (newdom->size() == 0) {
1751 env.fail();
1752 } else {
1753 IntSetRanges vdi_domr2(vdi_dom);
1754 IntSetRanges newdomr(newdom);
1755 if (!Ranges::equal(vdi_domr2, newdomr)) {
1756 vdi->ti()->domain(new SetLit(Location().introduce(), newdom));
1757 vdi->ti()->setComputedDomain(false);
1758 }
1759 }
1760 }
1761 } else {
1762 // at this point, can only be a constant
1763 assert((*al)[i]->type().ispar());
1764 if (e->type().st() == Type::ST_PLAIN) {
1765 IntVal iv = eval_int(env, (*al)[i]);
1766 if (!isv->contains(iv)) {
1767 std::ostringstream oss;
1768 oss << "value " << iv << " outside declared array domain " << *isv;
1769 env.fail(oss.str());
1770 }
1771 } else {
1772 IntSetVal* aisv = eval_intset(env, (*al)[i]);
1773 IntSetRanges aisv_r(aisv);
1774 IntSetRanges isv_r(isv);
1775 if (!Ranges::subset(aisv_r, isv_r)) {
1776 std::ostringstream oss;
1777 oss << "value " << *aisv << " outside declared array domain " << *isv;
1778 env.fail(oss.str());
1779 }
1780 }
1781 }
1782 }
1783 vd->ti()->setComputedDomain(true);
1784 } else if (e->type().bt() == Type::BT_FLOAT) {
1785 FloatSetVal* fsv = eval_floatset(env, vd->ti()->domain());
1786 for (unsigned int i = 0; i < al->size(); i++) {
1787 if (Id* id = (*al)[i]->dyn_cast<Id>()) {
1788 VarDecl* vdi = id->decl();
1789 if (vdi->ti()->domain() == NULL) {
1790 vdi->ti()->domain(vd->ti()->domain());
1791 } else {
1792 FloatSetVal* vdi_dom = eval_floatset(env, vdi->ti()->domain());
1793 FloatSetRanges fsvr(fsv);
1794 FloatSetRanges vdi_domr(vdi_dom);
1795 Ranges::Inter<FloatVal, FloatSetRanges, FloatSetRanges> inter(fsvr, vdi_domr);
1796 FloatSetVal* newdom = FloatSetVal::ai(inter);
1797 if (newdom->size() == 0) {
1798 env.fail();
1799 } else {
1800 FloatSetRanges vdi_domr2(vdi_dom);
1801 FloatSetRanges newdomr(newdom);
1802 if (!Ranges::equal(vdi_domr2, newdomr)) {
1803 vdi->ti()->domain(new SetLit(Location().introduce(), newdom));
1804 vdi->ti()->setComputedDomain(false);
1805 }
1806 }
1807 }
1808 } else {
1809 // at this point, can only be a constant
1810 assert((*al)[i]->type().ispar());
1811 FloatVal fv = eval_float(env, (*al)[i]);
1812 if (!fsv->contains(fv)) {
1813 std::ostringstream oss;
1814 oss << "value " << fv << " outside declared array domain " << *fsv;
1815 env.fail(oss.str());
1816 }
1817 }
1818 }
1819 vd->ti()->setComputedDomain(true);
1820 }
1821 }
1822 } else if (Id* e_id = e->dyn_cast<Id>()) {
1823 if (e_id == vd->id()) {
1824 ret = vd->id();
1825 } else {
1826 ASTString cid;
1827 if (e->type().isint()) {
1828 if (e->type().isopt()) {
1829 cid = ASTString("int_opt_eq");
1830 } else {
1831 cid = constants().ids.int_.eq;
1832 }
1833 } else if (e->type().isbool()) {
1834 if (e->type().isopt()) {
1835 cid = ASTString("bool_opt_eq");
1836 } else {
1837 cid = constants().ids.bool_eq;
1838 }
1839 } else if (e->type().is_set()) {
1840 cid = constants().ids.set_eq;
1841 } else if (e->type().isfloat()) {
1842 cid = constants().ids.float_.eq;
1843 }
1844 if (cid != "") {
1845 GCLock lock;
1846 std::vector<Expression*> args(2);
1847 args[0] = vd->id();
1848 args[1] = e_id;
1849 Call* c = new Call(Location().introduce(), cid, args);
1850 c->decl(env.model->matchFn(env, c, false));
1851 c->type(c->decl()->rtype(env, args, false));
1852 if (c->type().isbool() && ctx.b != C_ROOT) {
1853 addCtxAnn(vd, ctx.b);
1854 addCtxAnn(e_id->decl(), ctx.b);
1855 }
1856 if (c->decl()->e()) {
1857 flat_exp(env, Ctx(), c, constants().var_true, constants().var_true);
1858 ret = vd->id();
1859 vd->e(e);
1860 env.vo_add_exp(vd);
1861 }
1862 }
1863 }
1864 }
1865
1866 if (ret != vd->id()) {
1867 vd->e(ret);
1868 addPathAnnotation(env, ret);
1869 env.vo_add_exp(vd);
1870 ret = vd->id();
1871 }
1872 Id* vde_id = Expression::dyn_cast<Id>(vd->e());
1873 if (vde_id && vde_id->decl()->ti()->domain() == NULL) {
1874 if (vd->ti()->domain()) {
1875 GCLock lock;
1876 Expression* vd_dom = eval_par(env, vd->ti()->domain());
1877 vde_id->decl()->ti()->domain(vd_dom);
1878 }
1879 } else if (vd->e() && vd->e()->type().bt() == Type::BT_INT &&
1880 vd->e()->type().dim() == 0) {
1881 GCLock lock;
1882 IntSetVal* ibv = NULL;
1883 if (vd->e()->type().is_set()) {
1884 ibv = compute_intset_bounds(env, vd->e());
1885 } else {
1886 IntBounds ib = compute_int_bounds(env, vd->e());
1887 if (ib.valid) {
1888 Call* call = vd->e()->dyn_cast<Call>();
1889 if (call && call->id() == constants().ids.lin_exp) {
1890 ArrayLit* al = eval_array_lit(env, call->arg(1));
1891 if (al->size() == 1) {
1892 IntBounds check_zeroone = compute_int_bounds(env, (*al)[0]);
1893 if (check_zeroone.l == 0 && check_zeroone.u == 1) {
1894 ArrayLit* coeffs = eval_array_lit(env, call->arg(0));
1895 std::vector<IntVal> newdom(2);
1896 newdom[0] = 0;
1897 newdom[1] = eval_int(env, (*coeffs)[0]) + eval_int(env, call->arg(2));
1898 ibv = IntSetVal::a(newdom);
1899 }
1900 }
1901 }
1902 if (ibv == NULL) {
1903 ibv = IntSetVal::a(ib.l, ib.u);
1904 }
1905 }
1906 }
1907 if (ibv) {
1908 if (vd->ti()->domain()) {
1909 IntSetVal* domain = eval_intset(env, vd->ti()->domain());
1910 IntSetRanges dr(domain);
1911 IntSetRanges ibr(ibv);
1912 Ranges::Inter<IntVal, IntSetRanges, IntSetRanges> i(dr, ibr);
1913 IntSetVal* newibv = IntSetVal::ai(i);
1914 if (ibv->card() == newibv->card()) {
1915 vd->ti()->setComputedDomain(true);
1916 } else {
1917 ibv = newibv;
1918 }
1919 } else {
1920 vd->ti()->setComputedDomain(true);
1921 }
1922 SetLit* ibv_l = new SetLit(Location().introduce(), ibv);
1923 vd->ti()->domain(ibv_l);
1924 if (Id* rhs_ident = vd->e()->dyn_cast<Id>()) {
1925 if (rhs_ident->decl()->ti()->domain()) {
1926 IntSetVal* rhs_domain = eval_intset(env, rhs_ident->decl()->ti()->domain());
1927 IntSetRanges dr(rhs_domain);
1928 IntSetRanges ibr(ibv);
1929 Ranges::Inter<IntVal, IntSetRanges, IntSetRanges> i(dr, ibr);
1930 IntSetVal* rhs_newibv = IntSetVal::ai(i);
1931 if (rhs_domain->card() != rhs_newibv->card()) {
1932 rhs_ident->decl()->ti()->domain(ibv_l);
1933 rhs_ident->decl()->ti()->setComputedDomain(false);
1934 if (rhs_ident->decl()->type().isopt()) {
1935 std::vector<Expression*> args(2);
1936 args[0] = rhs_ident;
1937 args[1] = ibv_l;
1938 Call* c = new Call(Location().introduce(), "var_dom", args);
1939 c->type(Type::varbool());
1940 c->decl(env.model->matchFn(env, c, false));
1941 (void)flat_exp(env, Ctx(), c, constants().var_true, constants().var_true);
1942 }
1943 }
1944 }
1945 }
1946 if (vd->type().isopt()) {
1947 std::vector<Expression*> args(2);
1948 args[0] = vd->id();
1949 args[1] = ibv_l;
1950 Call* c = new Call(Location().introduce(), "var_dom", args);
1951 c->type(Type::varbool());
1952 c->decl(env.model->matchFn(env, c, false));
1953 (void)flat_exp(env, Ctx(), c, constants().var_true, constants().var_true);
1954 }
1955 }
1956 } else if (vd->e() && vd->e()->type().bt() == Type::BT_FLOAT &&
1957 vd->e()->type().dim() == 0) {
1958 GCLock lock;
1959 FloatSetVal* fbv = NULL;
1960 FloatBounds fb = compute_float_bounds(env, vd->e());
1961 if (fb.valid) {
1962 fbv = FloatSetVal::a(fb.l, fb.u);
1963 }
1964 if (fbv) {
1965 if (vd->ti()->domain()) {
1966 FloatSetVal* domain = eval_floatset(env, vd->ti()->domain());
1967 FloatSetRanges dr(domain);
1968 FloatSetRanges fbr(fbv);
1969 Ranges::Inter<FloatVal, FloatSetRanges, FloatSetRanges> i(dr, fbr);
1970 FloatSetVal* newfbv = FloatSetVal::ai(i);
1971
1972 FloatSetRanges dr_eq(domain);
1973 FloatSetRanges newfbv_eq(newfbv);
1974 if (Ranges::equal(dr_eq, newfbv_eq)) {
1975 vd->ti()->setComputedDomain(true);
1976 } else {
1977 fbv = newfbv;
1978 }
1979 } else {
1980 vd->ti()->setComputedDomain(true);
1981 }
1982 SetLit* fbv_l = new SetLit(Location().introduce(), fbv);
1983 vd->ti()->domain(fbv_l);
1984 if (Id* rhs_ident = vd->e()->dyn_cast<Id>()) {
1985 if (rhs_ident->decl()->ti()->domain()) {
1986 FloatSetVal* rhs_domain = eval_floatset(env, rhs_ident->decl()->ti()->domain());
1987 FloatSetRanges dr(rhs_domain);
1988 FloatSetRanges ibr(fbv);
1989 Ranges::Inter<FloatVal, FloatSetRanges, FloatSetRanges> i(dr, ibr);
1990 FloatSetVal* rhs_newfbv = FloatSetVal::ai(i);
1991 if (rhs_domain->card() != rhs_newfbv->card()) {
1992 rhs_ident->decl()->ti()->domain(fbv_l);
1993 rhs_ident->decl()->ti()->setComputedDomain(false);
1994 if (rhs_ident->decl()->type().isopt()) {
1995 std::vector<Expression*> args(2);
1996 args[0] = rhs_ident;
1997 args[1] = fbv_l;
1998 Call* c = new Call(Location().introduce(), "var_dom", args);
1999 c->type(Type::varbool());
2000 c->decl(env.model->matchFn(env, c, false));
2001 (void)flat_exp(env, Ctx(), c, constants().var_true, constants().var_true);
2002 }
2003 }
2004 }
2005 }
2006
2007 if (vd->type().isopt()) {
2008 std::vector<Expression*> args(2);
2009 args[0] = vd->id();
2010 args[1] = fbv_l;
2011 Call* c = new Call(Location().introduce(), "var_dom", args);
2012 c->type(Type::varbool());
2013 c->decl(env.model->matchFn(env, c, false));
2014 (void)flat_exp(env, Ctx(), c, constants().var_true, constants().var_true);
2015 }
2016 }
2017 }
2018 }
2019 return ret;
2020 } else if (vd == e) {
2021 return vd->id();
2022 } else if (vd->e() != e) {
2023 e = follow_id_to_decl(e);
2024 if (vd == e) return vd->id();
2025 switch (e->eid()) {
2026 case Expression::E_BOOLLIT: {
2027 Id* id = vd->id();
2028 while (id != NULL) {
2029 if (id->decl()->ti()->domain() &&
2030 eval_bool(env, id->decl()->ti()->domain()) == e->cast<BoolLit>()->v()) {
2031 return constants().lit_true;
2032 } else if (id->decl()->ti()->domain() &&
2033 eval_bool(env, id->decl()->ti()->domain()) != e->cast<BoolLit>()->v()) {
2034 GCLock lock;
2035 env.flat_addItem(new ConstraintI(Location().introduce(), constants().lit_false));
2036 } else {
2037 id->decl()->ti()->domain(e);
2038 GCLock lock;
2039 std::vector<Expression*> args(2);
2040 args[0] = id;
2041 args[1] = e;
2042 Call* c = new Call(Location().introduce(), constants().ids.bool_eq, args);
2043 c->decl(env.model->matchFn(env, c, false));
2044 c->type(c->decl()->rtype(env, args, false));
2045 if (c->decl()->e()) {
2046 flat_exp(env, Ctx(), c, constants().var_true, constants().var_true);
2047 }
2048 }
2049 id = id->decl()->e() ? id->decl()->e()->dyn_cast<Id>() : NULL;
2050 }
2051 return constants().lit_true;
2052 }
2053 case Expression::E_VARDECL: {
2054 VarDecl* e_vd = e->cast<VarDecl>();
2055 if (vd->e() == e_vd->id() || e_vd->e() == vd->id()) return vd->id();
2056 if (e->type().dim() != 0) throw InternalError("not supported yet");
2057 GCLock lock;
2058 ASTString cid;
2059 if (e->type().isint()) {
2060 cid = constants().ids.int_.eq;
2061 } else if (e->type().isbool()) {
2062 cid = constants().ids.bool_eq;
2063 } else if (e->type().is_set()) {
2064 cid = constants().ids.set_eq;
2065 } else if (e->type().isfloat()) {
2066 cid = constants().ids.float_.eq;
2067 } else {
2068 throw InternalError("not yet implemented");
2069 }
2070 std::vector<Expression*> args(2);
2071 args[0] = vd->id();
2072 args[1] = e_vd->id();
2073 Call* c = new Call(vd->loc().introduce(), cid, args);
2074 c->decl(env.model->matchFn(env, c, false));
2075 c->type(c->decl()->rtype(env, args, false));
2076 flat_exp(env, Ctx(), c, constants().var_true, constants().var_true);
2077 return vd->id();
2078 }
2079 case Expression::E_CALL: {
2080 Call* c = e->cast<Call>();
2081 GCLock lock;
2082 Call* nc;
2083 std::vector<Expression*> args;
2084 if (c->id() == constants().ids.lin_exp) {
2085 ArrayLit* le_c = follow_id(c->arg(0))->cast<ArrayLit>();
2086 std::vector<Expression*> ncoeff(le_c->size());
2087 for (unsigned int i = static_cast<unsigned int>(ncoeff.size()); i--;)
2088 ncoeff[i] = (*le_c)[i];
2089 ncoeff.push_back(IntLit::a(-1));
2090 args.push_back(new ArrayLit(Location().introduce(), ncoeff));
2091 args[0]->type(le_c->type());
2092 ArrayLit* le_x = follow_id(c->arg(1))->cast<ArrayLit>();
2093 std::vector<Expression*> nx(le_x->size());
2094 for (unsigned int i = static_cast<unsigned int>(nx.size()); i--;) nx[i] = (*le_x)[i];
2095 nx.push_back(vd->id());
2096 args.push_back(new ArrayLit(Location().introduce(), nx));
2097 args[1]->type(le_x->type());
2098 args.push_back(c->arg(2));
2099 nc = new Call(c->loc().introduce(), constants().ids.lin_exp, args);
2100 nc->decl(env.model->matchFn(env, nc, false));
2101 if (nc->decl() == NULL) {
2102 throw InternalError("undeclared function or predicate " + nc->id().str());
2103 }
2104 nc->type(nc->decl()->rtype(env, args, false));
2105 BinOp* bop = new BinOp(nc->loc(), nc, BOT_EQ, IntLit::a(0));
2106 bop->type(Type::varbool());
2107 flat_exp(env, Ctx(), bop, constants().var_true, constants().var_true);
2108 return vd->id();
2109 } else {
2110 args.resize(c->n_args());
2111 for (unsigned int i = static_cast<unsigned int>(args.size()); i--;)
2112 args[i] = c->arg(i);
2113 args.push_back(vd->id());
2114 ASTString nid = c->id();
2115
2116 if (c->id() == constants().ids.exists) {
2117 nid = constants().ids.array_bool_or;
2118 } else if (c->id() == constants().ids.forall) {
2119 nid = constants().ids.array_bool_and;
2120 } else if (vd->type().isbool()) {
2121 if (env.fopts.enable_imp && vd->ann().contains(constants().ctx.pos)) {
2122 nid = env.halfReifyId(c->id());
2123 if (env.model->matchFn(env, nid, args, false) == NULL) {
2124 nid = env.reifyId(c->id());
2125 }
2126 } else {
2127 nid = env.reifyId(c->id());
2128 }
2129 }
2130 nc = new Call(c->loc().introduce(), nid, args);
2131 }
2132 nc->decl(env.model->matchFn(env, nc, false));
2133 if (nc->decl() == NULL) {
2134 throw InternalError("undeclared function or predicate " + nc->id().str());
2135 }
2136 nc->type(nc->decl()->rtype(env, args, false));
2137 makeDefinedVar(vd, nc);
2138 flat_exp(env, Ctx(), nc, constants().var_true, constants().var_true);
2139 return vd->id();
2140 } break;
2141 default:
2142 throw InternalError("not supported yet");
2143 }
2144 } else {
2145 return e;
2146 }
2147 }
2148 }
2149}
2150
2151KeepAlive conj(EnvI& env, VarDecl* b, Ctx ctx, const std::vector<EE>& e) {
2152 if (!ctx.neg) {
2153 std::vector<Expression*> nontrue;
2154 for (unsigned int i = 0; i < e.size(); i++) {
2155 if (istrue(env, e[i].b())) continue;
2156 if (isfalse(env, e[i].b())) {
2157 return bind(env, Ctx(), b, constants().lit_false);
2158 }
2159 nontrue.push_back(e[i].b());
2160 }
2161 if (nontrue.empty()) {
2162 return bind(env, Ctx(), b, constants().lit_true);
2163 } else if (nontrue.size() == 1) {
2164 return bind(env, ctx, b, nontrue[0]);
2165 } else {
2166 if (b == constants().var_true) {
2167 for (unsigned int i = 0; i < nontrue.size(); i++) bind(env, ctx, b, nontrue[i]);
2168 return constants().lit_true;
2169 } else {
2170 GC::lock();
2171 std::vector<Expression*> args;
2172 ArrayLit* al = new ArrayLit(Location().introduce(), nontrue);
2173 al->type(Type::varbool(1));
2174 args.push_back(al);
2175 Call* ret = new Call(nontrue[0]->loc().introduce(), constants().ids.forall, args);
2176 ret->decl(env.model->matchFn(env, ret, false));
2177 ret->type(ret->decl()->rtype(env, args, false));
2178 KeepAlive ka(ret);
2179 GC::unlock();
2180 return flat_exp(env, ctx, ret, b, constants().var_true).r;
2181 }
2182 }
2183 } else {
2184 Ctx nctx = ctx;
2185 nctx.neg = false;
2186 // negated
2187 std::vector<Expression*> nonfalse;
2188 for (unsigned int i = 0; i < e.size(); i++) {
2189 if (istrue(env, e[i].b())) continue;
2190 if (isfalse(env, e[i].b())) {
2191 return bind(env, Ctx(), b, constants().lit_true);
2192 }
2193 nonfalse.push_back(e[i].b());
2194 }
2195 if (nonfalse.empty()) {
2196 return bind(env, Ctx(), b, constants().lit_false);
2197 } else if (nonfalse.size() == 1) {
2198 GC::lock();
2199 UnOp* uo = new UnOp(nonfalse[0]->loc(), UOT_NOT, nonfalse[0]);
2200 uo->type(Type::varbool());
2201 KeepAlive ka(uo);
2202 GC::unlock();
2203 return flat_exp(env, nctx, uo, b, constants().var_true).r;
2204 } else {
2205 if (b == constants().var_false) {
2206 for (unsigned int i = 0; i < nonfalse.size(); i++) bind(env, nctx, b, nonfalse[i]);
2207 return constants().lit_false;
2208 } else {
2209 GC::lock();
2210 std::vector<Expression*> args;
2211 for (unsigned int i = 0; i < nonfalse.size(); i++) {
2212 UnOp* uo = new UnOp(nonfalse[i]->loc(), UOT_NOT, nonfalse[i]);
2213 uo->type(Type::varbool());
2214 nonfalse[i] = uo;
2215 }
2216 ArrayLit* al = new ArrayLit(Location().introduce(), nonfalse);
2217 al->type(Type::varbool(1));
2218 args.push_back(al);
2219 Call* ret = new Call(Location().introduce(), constants().ids.exists, args);
2220 ret->decl(env.model->matchFn(env, ret, false));
2221 ret->type(ret->decl()->rtype(env, args, false));
2222 assert(ret->decl());
2223 KeepAlive ka(ret);
2224 GC::unlock();
2225 return flat_exp(env, nctx, ret, b, constants().var_true).r;
2226 }
2227 }
2228 }
2229}
2230
2231TypeInst* eval_typeinst(EnvI& env, VarDecl* vd) {
2232 bool hasTiVars = vd->ti()->domain() && vd->ti()->domain()->isa<TIId>();
2233 for (unsigned int i = 0; i < vd->ti()->ranges().size(); i++) {
2234 hasTiVars = hasTiVars ||
2235 (vd->ti()->ranges()[i]->domain() && vd->ti()->ranges()[i]->domain()->isa<TIId>());
2236 }
2237 if (hasTiVars) {
2238 assert(vd->e());
2239 if (vd->e()->type().dim() == 0) return new TypeInst(Location().introduce(), vd->e()->type());
2240 ArrayLit* al = eval_array_lit(env, vd->e());
2241 std::vector<TypeInst*> dims(al->dims());
2242 for (unsigned int i = 0; i < dims.size(); i++) {
2243 dims[i] =
2244 new TypeInst(Location().introduce(), Type(),
2245 new SetLit(Location().introduce(), IntSetVal::a(al->min(i), al->max(i))));
2246 }
2247 return new TypeInst(Location().introduce(), vd->e()->type(), dims,
2248 eval_par(env, vd->ti()->domain()));
2249 } else {
2250 std::vector<TypeInst*> dims(vd->ti()->ranges().size());
2251 for (unsigned int i = 0; i < vd->ti()->ranges().size(); i++) {
2252 if (vd->ti()->ranges()[i]->domain()) {
2253 IntSetVal* isv = eval_intset(env, vd->ti()->ranges()[i]->domain());
2254 if (isv->size() > 1)
2255 throw EvalError(env, vd->ti()->ranges()[i]->domain()->loc(),
2256 "array index set must be contiguous range");
2257 SetLit* sl = new SetLit(vd->ti()->ranges()[i]->loc(), isv);
2258 sl->type(Type::parsetint());
2259 dims[i] = new TypeInst(vd->ti()->ranges()[i]->loc(), Type(), sl);
2260 } else {
2261 dims[i] = new TypeInst(vd->ti()->ranges()[i]->loc(), Type(), NULL);
2262 }
2263 }
2264 Type t = (vd->e() && !vd->e()->type().isbot()) ? vd->e()->type() : vd->ti()->type();
2265 return new TypeInst(vd->ti()->loc(), t, dims, eval_par(env, vd->ti()->domain()));
2266 }
2267}
2268
2269bool isBuiltin(FunctionI* decl) {
2270 return (decl->loc().filename() == "builtins.mzn" ||
2271 decl->loc().filename().endsWith("/builtins.mzn") ||
2272 decl->loc().filename() == "stdlib.mzn" ||
2273 decl->loc().filename().endsWith("/stdlib.mzn") ||
2274 decl->loc().filename() == "flatzinc_builtins.mzn" ||
2275 decl->loc().filename().endsWith("/flatzinc_builtins.mzn"));
2276}
2277
2278KeepAlive flat_cv_exp(EnvI& env, Ctx ctx, Expression* e) {
2279 GCLock lock;
2280 if (e->type().ispar() && !e->type().cv()) {
2281 return eval_par(env, e);
2282 }
2283 if (e->type().isvar()) {
2284 EE ee = flat_exp(env, ctx, e, NULL, NULL);
2285 if (isfalse(env, ee.b()))
2286 throw FlatteningError(env, e->loc(), "cannot flatten partial function in this position");
2287 return ee.r();
2288 }
2289 switch (e->eid()) {
2290 case Expression::E_INTLIT:
2291 case Expression::E_FLOATLIT:
2292 case Expression::E_BOOLLIT:
2293 case Expression::E_STRINGLIT:
2294 case Expression::E_TIID:
2295 case Expression::E_VARDECL:
2296 case Expression::E_TI:
2297 case Expression::E_ANON:
2298 assert(false);
2299 return NULL;
2300 case Expression::E_ID: {
2301 Id* id = e->cast<Id>();
2302 return flat_cv_exp(env, ctx, id->decl()->e());
2303 }
2304 case Expression::E_SETLIT: {
2305 SetLit* sl = e->cast<SetLit>();
2306 if (sl->isv() || sl->fsv()) return sl;
2307 std::vector<Expression*> es(sl->v().size());
2308 GCLock lock;
2309 for (unsigned int i = 0; i < sl->v().size(); i++) {
2310 es[i] = flat_cv_exp(env, ctx, sl->v()[i])();
2311 }
2312 SetLit* sl_ret = new SetLit(Location().introduce(), es);
2313 Type t = sl->type();
2314 t.cv(false);
2315 sl_ret->type(t);
2316 return eval_par(env, sl_ret);
2317 }
2318 case Expression::E_ARRAYLIT: {
2319 ArrayLit* al = e->cast<ArrayLit>();
2320 std::vector<Expression*> es(al->size());
2321 GCLock lock;
2322 for (unsigned int i = 0; i < al->size(); i++) {
2323 es[i] = flat_cv_exp(env, ctx, (*al)[i])();
2324 }
2325 std::vector<std::pair<int, int> > dims(al->dims());
2326 for (int i = 0; i < al->dims(); i++) {
2327 dims[i] = std::make_pair(al->min(i), al->max(i));
2328 }
2329 Expression* al_ret = eval_par(env, new ArrayLit(Location().introduce(), es, dims));
2330 Type t = al->type();
2331 t.cv(false);
2332 al_ret->type(t);
2333 return al_ret;
2334 }
2335 case Expression::E_ARRAYACCESS: {
2336 ArrayAccess* aa = e->cast<ArrayAccess>();
2337 GCLock lock;
2338 Expression* av = flat_cv_exp(env, ctx, aa->v())();
2339 std::vector<Expression*> idx(aa->idx().size());
2340 for (unsigned int i = 0; i < aa->idx().size(); i++) {
2341 idx[i] = flat_cv_exp(env, ctx, aa->idx()[i])();
2342 }
2343 ArrayAccess* aa_ret = new ArrayAccess(Location().introduce(), av, idx);
2344 Type t = aa->type();
2345 t.cv(false);
2346 aa_ret->type(t);
2347 return eval_par(env, aa_ret);
2348 }
2349 case Expression::E_COMP: {
2350 Comprehension* c = e->cast<Comprehension>();
2351 GCLock lock;
2352 class EvalFlatCvExp {
2353 public:
2354 Ctx ctx;
2355 EvalFlatCvExp(Ctx& ctx0) : ctx(ctx0) {}
2356 typedef Expression* ArrayVal;
2357 Expression* e(EnvI& env, Expression* e) { return flat_cv_exp(env, ctx, e)(); }
2358 static Expression* exp(Expression* e) { return e; }
2359 Expression* flatten(EnvI& env, Expression* e0) {
2360 return flat_exp(env, Ctx(), e0, NULL, constants().var_true).r();
2361 }
2362
2363 } eval(ctx);
2364 std::vector<Expression*> a = eval_comp<EvalFlatCvExp>(env, eval, c);
2365
2366 Type t = Type::bot();
2367 bool allPar = true;
2368 for (unsigned int i = 0; i < a.size(); i++) {
2369 if (t == Type::bot()) t = a[i]->type();
2370 if (!a[i]->type().ispar()) allPar = false;
2371 }
2372 if (!allPar) t.ti(Type::TI_VAR);
2373 if (c->set())
2374 t.st(Type::ST_SET);
2375 else
2376 t.dim(c->type().dim());
2377 t.cv(false);
2378 if (c->set()) {
2379 if (c->type().ispar() && allPar) {
2380 SetLit* sl = new SetLit(c->loc().introduce(), a);
2381 sl->type(t);
2382 Expression* slr = eval_par(env, sl);
2383 slr->type(t);
2384 return slr;
2385 } else {
2386 throw InternalError("var set comprehensions not supported yet");
2387 }
2388 } else {
2389 ArrayLit* alr = new ArrayLit(Location().introduce(), a);
2390 alr->type(t);
2391 alr->flat(true);
2392 return alr;
2393 }
2394 }
2395 case Expression::E_ITE: {
2396 ITE* ite = e->cast<ITE>();
2397 for (int i = 0; i < ite->size(); i++) {
2398 KeepAlive ka = flat_cv_exp(env, ctx, ite->e_if(i));
2399 if (eval_bool(env, ka())) return flat_cv_exp(env, ctx, ite->e_then(i));
2400 }
2401 return flat_cv_exp(env, ctx, ite->e_else());
2402 }
2403 case Expression::E_BINOP: {
2404 BinOp* bo = e->cast<BinOp>();
2405 if (bo->op() == BOT_AND) {
2406 GCLock lock;
2407 Expression* lhs = flat_cv_exp(env, ctx, bo->lhs())();
2408 if (!eval_bool(env, lhs)) {
2409 return constants().lit_false;
2410 }
2411 return eval_par(env, flat_cv_exp(env, ctx, bo->rhs())());
2412 } else if (bo->op() == BOT_OR) {
2413 GCLock lock;
2414 Expression* lhs = flat_cv_exp(env, ctx, bo->lhs())();
2415 if (eval_bool(env, lhs)) {
2416 return constants().lit_true;
2417 }
2418 return eval_par(env, flat_cv_exp(env, ctx, bo->rhs())());
2419 }
2420 GCLock lock;
2421 BinOp* nbo = new BinOp(bo->loc().introduce(), flat_cv_exp(env, ctx, bo->lhs())(), bo->op(),
2422 flat_cv_exp(env, ctx, bo->rhs())());
2423 nbo->type(bo->type());
2424 nbo->decl(bo->decl());
2425 return eval_par(env, nbo);
2426 }
2427 case Expression::E_UNOP: {
2428 UnOp* uo = e->cast<UnOp>();
2429 GCLock lock;
2430 UnOp* nuo = new UnOp(uo->loc(), uo->op(), flat_cv_exp(env, ctx, uo->e())());
2431 nuo->type(uo->type());
2432 return eval_par(env, nuo);
2433 }
2434 case Expression::E_CALL: {
2435 Call* c = e->cast<Call>();
2436 if (c->id() == "mzn_in_root_context") {
2437 return constants().boollit(ctx.b == C_ROOT);
2438 }
2439 if (ctx.b == C_ROOT && c->decl()->e() && c->decl()->e()->isa<BoolLit>()) {
2440 bool allBool = true;
2441 for (unsigned int i = 0; i < c->n_args(); i++) {
2442 if (c->arg(i)->type().bt() != Type::BT_BOOL) {
2443 allBool = false;
2444 break;
2445 }
2446 }
2447 if (allBool) {
2448 return c->decl()->e();
2449 }
2450 }
2451 std::vector<Expression*> args(c->n_args());
2452 GCLock lock;
2453 for (unsigned int i = 0; i < c->n_args(); i++) {
2454 args[i] = flat_cv_exp(env, ctx, c->arg(i))();
2455 }
2456 Call* nc = new Call(c->loc(), c->id(), args);
2457 nc->decl(c->decl());
2458 nc->type(c->type());
2459 return eval_par(env, nc);
2460 }
2461 case Expression::E_LET: {
2462 Let* l = e->cast<Let>();
2463 l->pushbindings();
2464 KeepAlive ret = flat_cv_exp(env, ctx, l->in());
2465 l->popbindings();
2466 return ret;
2467 }
2468 }
2469 throw InternalError("internal error");
2470}
2471
2472void flatten(Env& e, FlatteningOptions opt) {
2473 try {
2474 EnvI& env = e.envi();
2475 env.fopts = opt;
2476
2477 bool onlyRangeDomains = false;
2478 if (opt.onlyRangeDomains) {
2479 onlyRangeDomains = true; // compulsory
2480 } else {
2481 GCLock lock;
2482 Call* check_only_range =
2483 new Call(Location(), "mzn_check_only_range_domains", std::vector<Expression*>());
2484 check_only_range->type(Type::parbool());
2485 check_only_range->decl(env.model->matchFn(e.envi(), check_only_range, false));
2486 onlyRangeDomains = eval_bool(e.envi(), check_only_range);
2487 }
2488
2489 bool hadSolveItem = false;
2490 // Flatten main model
2491 class FV : public ItemVisitor {
2492 public:
2493 EnvI& env;
2494 bool& hadSolveItem;
2495 FV(EnvI& env0, bool& hadSolveItem0) : env(env0), hadSolveItem(hadSolveItem0) {}
2496 bool enter(Item* i) { return !(i->isa<ConstraintI>() && env.failed()); }
2497 void vVarDeclI(VarDeclI* v) {
2498 v->e()->ann().remove(constants().ann.output_var);
2499 v->e()->ann().removeCall(constants().ann.output_array);
2500 if (v->e()->ann().contains(constants().ann.output_only)) return;
2501 if (v->e()->type().ispar() && !v->e()->type().isopt() && !v->e()->type().cv() &&
2502 v->e()->type().dim() > 0 && v->e()->ti()->domain() == NULL &&
2503 (v->e()->type().bt() == Type::BT_INT || v->e()->type().bt() == Type::BT_FLOAT)) {
2504 // Compute bounds for array literals
2505 CallStackItem csi(env, v->e());
2506 GCLock lock;
2507 ArrayLit* al = eval_array_lit(env, v->e()->e());
2508 v->e()->e(al);
2509 checkIndexSets(env, v->e(), v->e()->e());
2510 if (v->e()->type().bt() == Type::BT_INT && v->e()->type().st() == Type::ST_PLAIN) {
2511 IntVal lb = IntVal::infinity();
2512 IntVal ub = -IntVal::infinity();
2513 for (unsigned int i = 0; i < al->size(); i++) {
2514 IntVal vi = eval_int(env, (*al)[i]);
2515 lb = std::min(lb, vi);
2516 ub = std::max(ub, vi);
2517 }
2518 GCLock lock;
2519 // v->e()->ti()->domain(new SetLit(Location().introduce(), IntSetVal::a(lb, ub)));
2520 // v->e()->ti()->setComputedDomain(true);
2521 setComputedDomain(env, v->e(), new SetLit(Location().introduce(), IntSetVal::a(lb, ub)),
2522 true);
2523 } else if (v->e()->type().bt() == Type::BT_FLOAT &&
2524 v->e()->type().st() == Type::ST_PLAIN) {
2525 FloatVal lb = FloatVal::infinity();
2526 FloatVal ub = -FloatVal::infinity();
2527 for (unsigned int i = 0; i < al->size(); i++) {
2528 FloatVal vi = eval_float(env, (*al)[i]);
2529 lb = std::min(lb, vi);
2530 ub = std::max(ub, vi);
2531 }
2532 GCLock lock;
2533 // v->e()->ti()->domain(new SetLit(Location().introduce(), FloatSetVal::a(lb, ub)));
2534 // v->e()->ti()->setComputedDomain(true);
2535 setComputedDomain(env, v->e(),
2536 new SetLit(Location().introduce(), FloatSetVal::a(lb, ub)), true);
2537 }
2538 } else if (v->e()->type().isvar() || v->e()->type().isann()) {
2539 (void)flatten_id(env, Ctx(), v->e()->id(), NULL, constants().var_true, true);
2540 } else {
2541 if (v->e()->e() == NULL) {
2542 if (!v->e()->type().isann())
2543 throw EvalError(env, v->e()->loc(), "Undefined parameter", v->e()->id()->v());
2544 } else {
2545 CallStackItem csi(env, v->e());
2546 GCLock lock;
2547 Location v_loc = v->e()->e()->loc();
2548 if (!v->e()->e()->type().cv()) {
2549 v->e()->e(eval_par(env, v->e()->e()));
2550 } else {
2551 EE ee = flat_exp(env, Ctx(), v->e()->e(), NULL, constants().var_true);
2552 v->e()->e(ee.r());
2553 }
2554 if (v->e()->type().dim() > 0) {
2555 checkIndexSets(env, v->e(), v->e()->e());
2556 if (v->e()->ti()->domain() != NULL) {
2557 ArrayLit* al = eval_array_lit(env, v->e()->e());
2558 for (unsigned int i = 0; i < al->size(); i++) {
2559 if (!checkParDomain(env, (*al)[i], v->e()->ti()->domain())) {
2560 throw EvalError(env, v_loc, "parameter value out of range");
2561 }
2562 }
2563 }
2564 } else {
2565 if (v->e()->ti()->domain() != NULL) {
2566 if (!checkParDomain(env, v->e()->e(), v->e()->ti()->domain())) {
2567 throw EvalError(env, v_loc, "parameter value out of range");
2568 }
2569 }
2570 }
2571 }
2572 }
2573 }
2574 void vConstraintI(ConstraintI* ci) {
2575 (void)flat_exp(env, Ctx(), ci->e(), constants().var_true, constants().var_true);
2576 }
2577 void vSolveI(SolveI* si) {
2578 if (hadSolveItem) throw FlatteningError(env, si->loc(), "Only one solve item allowed");
2579 hadSolveItem = true;
2580 GCLock lock;
2581 SolveI* nsi = NULL;
2582 switch (si->st()) {
2583 case SolveI::ST_SAT:
2584 nsi = SolveI::sat(Location());
2585 break;
2586 case SolveI::ST_MIN: {
2587 Ctx ctx;
2588 ctx.i = C_NEG;
2589 nsi = SolveI::min(Location().introduce(),
2590 flat_exp(env, ctx, si->e(), NULL, constants().var_true).r());
2591 } break;
2592 case SolveI::ST_MAX: {
2593 Ctx ctx;
2594 ctx.i = C_POS;
2595 nsi = SolveI::max(Location().introduce(),
2596 flat_exp(env, Ctx(), si->e(), NULL, constants().var_true).r());
2597 } break;
2598 }
2599 for (ExpressionSetIter it = si->ann().begin(); it != si->ann().end(); ++it) {
2600 nsi->ann().add(flat_exp(env, Ctx(), *it, NULL, constants().var_true).r());
2601 }
2602 env.flat_addItem(nsi);
2603 }
2604 } _fv(env, hadSolveItem);
2605 iterItems<FV>(_fv, e.model());
2606
2607 if (!hadSolveItem) {
2608 GCLock lock;
2609 e.envi().flat_addItem(SolveI::sat(Location().introduce()));
2610 }
2611
2612 std::vector<VarDecl*> deletedVarDecls;
2613
2614 // Create output model
2615 if (opt.keepOutputInFzn) {
2616 copyOutput(env);
2617 } else {
2618 createOutput(env, deletedVarDecls, opt.outputMode, opt.outputObjective, opt.outputOutputItem);
2619 }
2620
2621 // Flatten remaining redefinitions
2622 Model& m = *e.flat();
2623 int startItem = 0;
2624 int endItem = m.size() - 1;
2625
2626 FunctionI* int_lin_eq;
2627 {
2628 std::vector<Type> int_lin_eq_t(3);
2629 int_lin_eq_t[0] = Type::parint(1);
2630 int_lin_eq_t[1] = Type::varint(1);
2631 int_lin_eq_t[2] = Type::parint(0);
2632 GCLock lock;
2633 FunctionI* fi = env.model->matchFn(env, constants().ids.int_.lin_eq, int_lin_eq_t, false);
2634 int_lin_eq = (fi && fi->e()) ? fi : NULL;
2635 }
2636 FunctionI* array_bool_and;
2637 FunctionI* array_bool_or;
2638 FunctionI* array_bool_clause;
2639 FunctionI* array_bool_clause_reif;
2640 FunctionI* bool_xor;
2641 {
2642 std::vector<Type> array_bool_andor_t(2);
2643 array_bool_andor_t[0] = Type::varbool(1);
2644 array_bool_andor_t[1] = Type::varbool(0);
2645 GCLock lock;
2646 FunctionI* fi =
2647 env.model->matchFn(env, ASTString("array_bool_and"), array_bool_andor_t, false);
2648 array_bool_and = (fi && fi->e()) ? fi : NULL;
2649 fi = env.model->matchFn(env, ASTString("array_bool_or"), array_bool_andor_t, false);
2650 array_bool_or = (fi && fi->e()) ? fi : NULL;
2651
2652 array_bool_andor_t[1] = Type::varbool(1);
2653 fi = env.model->matchFn(env, ASTString("bool_clause"), array_bool_andor_t, false);
2654 array_bool_clause = (fi && fi->e()) ? fi : NULL;
2655
2656 array_bool_andor_t.push_back(Type::varbool());
2657 fi = env.model->matchFn(env, ASTString("bool_clause_reif"), array_bool_andor_t, false);
2658 array_bool_clause_reif = (fi && fi->e()) ? fi : NULL;
2659
2660 std::vector<Type> bool_xor_t(3);
2661 bool_xor_t[0] = Type::varbool();
2662 bool_xor_t[1] = Type::varbool();
2663 bool_xor_t[2] = Type::varbool();
2664 fi = env.model->matchFn(env, constants().ids.bool_xor, bool_xor_t, false);
2665 bool_xor = (fi && fi->e()) ? fi : NULL;
2666 }
2667
2668 std::vector<VarDeclI*> removedItems;
2669 env.collectVarDecls(true);
2670
2671 while (startItem <= endItem || !env.modifiedVarDecls.empty()) {
2672 if (env.failed()) return;
2673 std::vector<int> agenda;
2674 for (int i = startItem; i <= endItem; i++) {
2675 agenda.push_back(i);
2676 }
2677 for (unsigned int i = 0; i < env.modifiedVarDecls.size(); i++) {
2678 agenda.push_back(env.modifiedVarDecls[i]);
2679 }
2680 env.modifiedVarDecls.clear();
2681
2682 for (int ai = 0; ai < agenda.size(); ai++) {
2683 int i = agenda[ai];
2684 VarDeclI* vdi = m[i]->dyn_cast<VarDeclI>();
2685 bool keptVariable = true;
2686 /// Look at constraints
2687 if (vdi != NULL && !isOutput(vdi->e())) {
2688 if (0 < env.vo.occurrences(vdi->e())) {
2689 const auto it = env.vo._m.find(vdi->e()->id());
2690 if (env.vo._m.end() != it) {
2691 bool hasRedundantOccurrenciesOnly = true;
2692 for (const auto& c : it->second) {
2693 if (auto constrI = c->dyn_cast<ConstraintI>())
2694 if (auto call = constrI->e()->dyn_cast<Call>())
2695 if (call->id() == "mzn_reverse_map_var") continue; // all good
2696 hasRedundantOccurrenciesOnly = false;
2697 break;
2698 }
2699 if (hasRedundantOccurrenciesOnly) {
2700 removedItems.push_back(vdi);
2701 env.flat_removeItem(vdi);
2702 env.vo.removeAllOccurrences(vdi->e());
2703 keptVariable = false;
2704 for (const auto& c : it->second) {
2705 env.flat_removeItem(c);
2706 }
2707 }
2708 }
2709 } else { // 0 occurrencies
2710 if (vdi->e()->e() && vdi->e()->ti()->domain()) {
2711 if (vdi->e()->type().isvar() && vdi->e()->type().isbool() &&
2712 !vdi->e()->type().isopt() &&
2713 Expression::equal(vdi->e()->ti()->domain(), constants().lit_true)) {
2714 GCLock lock;
2715 ConstraintI* ci = new ConstraintI(vdi->loc(), vdi->e()->e());
2716 if (vdi->e()->introduced()) {
2717 removedItems.push_back(vdi);
2718 env.flat_removeItem(vdi);
2719 keptVariable = false;
2720 } else {
2721 vdi->e()->e(NULL);
2722 }
2723 env.flat_addItem(ci);
2724 } else if (vdi->e()->type().ispar() || vdi->e()->ti()->computedDomain()) {
2725 removedItems.push_back(vdi);
2726 keptVariable = false;
2727 }
2728 } else {
2729 removedItems.push_back(vdi);
2730 env.flat_removeItem(vdi);
2731 keptVariable = false;
2732 }
2733 }
2734 }
2735 if (vdi && keptVariable && vdi->e()->type().dim() > 0 && vdi->e()->type().isvar()) {
2736 vdi->e()->ti()->domain(NULL);
2737 }
2738 if (vdi && keptVariable && vdi->e()->type().isint() && vdi->e()->type().isvar() &&
2739 vdi->e()->ti()->domain() != NULL) {
2740 GCLock lock;
2741 IntSetVal* dom = eval_intset(env, vdi->e()->ti()->domain());
2742
2743 bool needRangeDomain = onlyRangeDomains;
2744 if (!needRangeDomain && dom->size() > 0) {
2745 if (dom->min(0).isMinusInfinity() || dom->max(dom->size() - 1).isPlusInfinity())
2746 needRangeDomain = true;
2747 }
2748 if (needRangeDomain) {
2749 if (dom->min(0).isMinusInfinity() || dom->max(dom->size() - 1).isPlusInfinity()) {
2750 TypeInst* nti = copy(env, vdi->e()->ti())->cast<TypeInst>();
2751 nti->domain(NULL);
2752 vdi->e()->ti(nti);
2753 if (dom->min(0).isFinite()) {
2754 std::vector<Expression*> args(2);
2755 args[0] = IntLit::a(dom->min(0));
2756 args[1] = vdi->e()->id();
2757 Call* call = new Call(Location().introduce(), constants().ids.int_.le, args);
2758 call->type(Type::varbool());
2759 call->decl(env.model->matchFn(env, call, false));
2760 env.flat_addItem(new ConstraintI(Location().introduce(), call));
2761 } else if (dom->max(dom->size() - 1).isFinite()) {
2762 std::vector<Expression*> args(2);
2763 args[0] = vdi->e()->id();
2764 args[1] = IntLit::a(dom->max(dom->size() - 1));
2765 Call* call = new Call(Location().introduce(), constants().ids.int_.le, args);
2766 call->type(Type::varbool());
2767 call->decl(env.model->matchFn(env, call, false));
2768 env.flat_addItem(new ConstraintI(Location().introduce(), call));
2769 }
2770 } else if (dom->size() > 1) {
2771 SetLit* newDom = new SetLit(Location().introduce(),
2772 IntSetVal::a(dom->min(0), dom->max(dom->size() - 1)));
2773 TypeInst* nti = copy(env, vdi->e()->ti())->cast<TypeInst>();
2774 nti->domain(newDom);
2775 vdi->e()->ti(nti); /// TODO: WHY WAS THIS COMMENTED OUT IN DEBUG???
2776 }
2777 if (dom->size() > 1) {
2778 IntVal firstHole = dom->max(0) + 1;
2779 IntSetRanges domr(dom);
2780 ++domr;
2781 for (; domr(); ++domr) {
2782 for (IntVal i = firstHole; i < domr.min(); i++) {
2783 std::vector<Expression*> args(2);
2784 args[0] = vdi->e()->id();
2785 args[1] = IntLit::a(i);
2786 Call* call = new Call(vdi->e()->loc(), constants().ids.int_.ne, args);
2787 call->type(Type::varbool());
2788 call->decl(env.model->matchFn(env, call, false));
2789 // Give distinct call stacks for each int_ne added
2790 CallStackItem csi(env, IntLit::a(i));
2791 env.flat_addItem(new ConstraintI(Location().introduce(), call));
2792 firstHole = domr.max().plus(1);
2793 }
2794 }
2795 }
2796 }
2797 }
2798 if (vdi && keptVariable && vdi->e()->type().isfloat() && vdi->e()->type().isvar() &&
2799 vdi->e()->ti()->domain() != NULL) {
2800 GCLock lock;
2801 FloatSetVal* vdi_dom = eval_floatset(env, vdi->e()->ti()->domain());
2802 FloatVal vmin = vdi_dom->min();
2803 FloatVal vmax = vdi_dom->max();
2804 if (vmin == -FloatVal::infinity() && vmax == FloatVal::infinity()) {
2805 vdi->e()->ti()->domain(NULL);
2806 } else if (vmin == -FloatVal::infinity()) {
2807 vdi->e()->ti()->domain(NULL);
2808 std::vector<Expression*> args(2);
2809 args[0] = vdi->e()->id();
2810 args[1] = FloatLit::a(vmax);
2811 Call* call = new Call(Location().introduce(), constants().ids.float_.le, args);
2812 call->type(Type::varbool());
2813 call->decl(env.model->matchFn(env, call, false));
2814 env.flat_addItem(new ConstraintI(Location().introduce(), call));
2815 } else if (vmax == FloatVal::infinity()) {
2816 vdi->e()->ti()->domain(NULL);
2817 std::vector<Expression*> args(2);
2818 args[0] = FloatLit::a(vmin);
2819 args[1] = vdi->e()->id();
2820 Call* call = new Call(Location().introduce(), constants().ids.float_.le, args);
2821 call->type(Type::varbool());
2822 call->decl(env.model->matchFn(env, call, false));
2823 env.flat_addItem(new ConstraintI(Location().introduce(), call));
2824 } else if (vdi_dom->size() > 1) {
2825 BinOp* dom_ranges = new BinOp(vdi->e()->ti()->domain()->loc().introduce(),
2826 FloatLit::a(vmin), BOT_DOTDOT, FloatLit::a(vmax));
2827 vdi->e()->ti()->domain(dom_ranges);
2828
2829 std::vector<Expression*> ranges;
2830 for (FloatSetRanges vdi_r(vdi_dom); vdi_r(); ++vdi_r) {
2831 ranges.push_back(FloatLit::a(vdi_r.min()));
2832 ranges.push_back(FloatLit::a(vdi_r.max()));
2833 }
2834 ArrayLit* al = new ArrayLit(Location().introduce(), ranges);
2835 al->type(Type::parfloat(1));
2836 std::vector<Expression*> args(2);
2837 args[0] = vdi->e()->id();
2838 args[1] = al;
2839 Call* call = new Call(Location().introduce(), constants().ids.float_.dom, args);
2840 call->type(Type::varbool());
2841 call->decl(env.model->matchFn(env, call, false));
2842 env.flat_addItem(new ConstraintI(Location().introduce(), call));
2843 }
2844 }
2845 }
2846
2847 // rewrite some constraints if there are redefinitions
2848 for (int ai = 0; ai < agenda.size(); ai++) {
2849 int i = agenda[ai];
2850 if (VarDeclI* vdi = m[i]->dyn_cast<VarDeclI>()) {
2851 VarDecl* vd = vdi->e();
2852 if (!vdi->removed() && vd->e()) {
2853 bool isTrueVar =
2854 vd->type().isbool() && Expression::equal(vd->ti()->domain(), constants().lit_true);
2855 if (Call* c = vd->e()->dyn_cast<Call>()) {
2856 GCLock lock;
2857 Call* nc = NULL;
2858 if (c->id() == constants().ids.lin_exp) {
2859 if (int_lin_eq) {
2860 std::vector<Expression*> args(c->n_args());
2861 ArrayLit* le_c = follow_id(c->arg(0))->cast<ArrayLit>();
2862 std::vector<Expression*> nc_c(le_c->size());
2863 for (unsigned int i = static_cast<unsigned int>(nc_c.size()); i--;)
2864 nc_c[i] = (*le_c)[i];
2865 nc_c.push_back(IntLit::a(-1));
2866 args[0] = new ArrayLit(Location().introduce(), nc_c);
2867 args[0]->type(Type::parint(1));
2868 ArrayLit* le_x = follow_id(c->arg(1))->cast<ArrayLit>();
2869 std::vector<Expression*> nx(le_x->size());
2870 for (unsigned int i = static_cast<unsigned int>(nx.size()); i--;)
2871 nx[i] = (*le_x)[i];
2872 nx.push_back(vd->id());
2873 args[1] = new ArrayLit(Location().introduce(), nx);
2874 args[1]->type(Type::varint(1));
2875 IntVal d = c->arg(2)->cast<IntLit>()->v();
2876 args[2] = IntLit::a(-d);
2877 args[2]->type(Type::parint(0));
2878 nc = new Call(c->loc().introduce(), ASTString("int_lin_eq"), args);
2879 nc->type(Type::varbool());
2880 nc->decl(int_lin_eq);
2881 }
2882 } else if (c->id() == constants().ids.exists) {
2883 if (array_bool_or) {
2884 std::vector<Expression*> args(2);
2885 args[0] = c->arg(0);
2886 args[1] = vd->id();
2887 nc = new Call(c->loc().introduce(), array_bool_or->id(), args);
2888 nc->type(Type::varbool());
2889 nc->decl(array_bool_or);
2890 }
2891 } else if (!isTrueVar && c->id() == constants().ids.forall) {
2892 if (array_bool_and) {
2893 std::vector<Expression*> args(2);
2894 args[0] = c->arg(0);
2895 args[1] = vd->id();
2896 nc = new Call(c->loc().introduce(), array_bool_and->id(), args);
2897 nc->type(Type::varbool());
2898 nc->decl(array_bool_and);
2899 }
2900 } else if (isTrueVar && c->id() == constants().ids.clause && array_bool_clause) {
2901 std::vector<Expression*> args(2);
2902 args[0] = c->arg(0);
2903 args[1] = c->arg(1);
2904 nc = new Call(c->loc().introduce(), array_bool_clause->id(), args);
2905 nc->type(Type::varbool());
2906 nc->decl(array_bool_clause);
2907 } else if (c->id() == constants().ids.clause && array_bool_clause_reif) {
2908 std::vector<Expression*> args(3);
2909 args[0] = c->arg(0);
2910 args[1] = c->arg(1);
2911 args[2] = vd->id();
2912 nc = new Call(c->loc().introduce(), array_bool_clause_reif->id(), args);
2913 nc->type(Type::varbool());
2914 nc->decl(array_bool_clause_reif);
2915 } else {
2916 if (isTrueVar) {
2917 FunctionI* decl = env.model->matchFn(env, c, false);
2918 env.cse_map_remove(c);
2919 if (decl->e() || c->id() == constants().ids.forall) {
2920 if (decl->e()) addPathAnnotation(env, decl->e());
2921 c->decl(decl);
2922 nc = c;
2923 }
2924 } else {
2925 std::vector<Expression*> args(c->n_args());
2926 for (unsigned int i = static_cast<unsigned int>(args.size()); i--;)
2927 args[i] = c->arg(i);
2928 args.push_back(vd->id());
2929 ASTString cid = c->id();
2930 if (cid == constants().ids.clause && array_bool_clause_reif) {
2931 nc = new Call(c->loc().introduce(), array_bool_clause_reif->id(), args);
2932 nc->type(Type::varbool());
2933 nc->decl(array_bool_clause_reif);
2934 } else {
2935 if (c->type().isbool() && vd->type().isbool()) {
2936 if (env.fopts.enable_imp && vd->ann().contains(constants().ctx.pos)) {
2937 cid = env.halfReifyId(c->id());
2938 if (env.model->matchFn(env, cid, args, false) == NULL) {
2939 cid = env.reifyId(c->id());
2940 }
2941 } else {
2942 cid = env.reifyId(c->id());
2943 }
2944 }
2945 FunctionI* decl = env.model->matchFn(env, cid, args, false);
2946 if (decl && decl->e()) {
2947 addPathAnnotation(env, decl->e());
2948 nc = new Call(c->loc().introduce(), cid, args);
2949 nc->type(Type::varbool());
2950 nc->decl(decl);
2951 }
2952 }
2953 }
2954 }
2955 if (nc != NULL) {
2956 CollectDecls cd(env.vo, deletedVarDecls, vdi);
2957 topDown(cd, c);
2958 vd->e(NULL);
2959 // Need to remove right hand side from CSE map, otherwise
2960 // flattening of nc could assume c has already been flattened
2961 // to vd
2962 env.cse_map_remove(c);
2963 /// TODO: check if removing variables here makes sense:
2964 // if (!isOutput(vd) && env.vo.occurrences(vd)==0) {
2965 // removedItems.push_back(vdi);
2966 // }
2967 if (nc != c) {
2968 makeDefinedVar(vd, nc);
2969 }
2970 StringLit* vsl = getLongestMznPathAnnotation(env, vdi->e());
2971 StringLit* csl = getLongestMznPathAnnotation(env, c);
2972 CallStackItem* vsi = NULL;
2973 CallStackItem* csi = NULL;
2974 if (vsl) vsi = new CallStackItem(env, vsl);
2975 if (csl) csi = new CallStackItem(env, csl);
2976 (void)flat_exp(env, Ctx(), nc, constants().var_true, constants().var_true);
2977 if (csi) delete csi;
2978 if (vsi) delete vsi;
2979 }
2980 }
2981 }
2982 } else if (ConstraintI* ci = m[i]->dyn_cast<ConstraintI>()) {
2983 if (!ci->removed()) {
2984 if (Call* c = ci->e()->dyn_cast<Call>()) {
2985 GCLock lock;
2986 Call* nc = NULL;
2987 if (c->id() == constants().ids.exists) {
2988 if (array_bool_or) {
2989 std::vector<Expression*> args(2);
2990 args[0] = c->arg(0);
2991 args[1] = constants().lit_true;
2992 nc = new Call(c->loc().introduce(), array_bool_or->id(), args);
2993 nc->type(Type::varbool());
2994 nc->decl(array_bool_or);
2995 }
2996 } else if (c->id() == constants().ids.forall) {
2997 if (array_bool_and) {
2998 std::vector<Expression*> args(2);
2999 args[0] = c->arg(0);
3000 args[1] = constants().lit_true;
3001 nc = new Call(c->loc().introduce(), array_bool_and->id(), args);
3002 nc->type(Type::varbool());
3003 nc->decl(array_bool_and);
3004 }
3005 } else if (c->id() == constants().ids.clause) {
3006 if (array_bool_clause) {
3007 std::vector<Expression*> args(2);
3008 args[0] = c->arg(0);
3009 args[1] = c->arg(1);
3010 nc = new Call(c->loc().introduce(), array_bool_clause->id(), args);
3011 nc->type(Type::varbool());
3012 nc->decl(array_bool_clause);
3013 }
3014 } else if (c->id() == constants().ids.bool_xor) {
3015 if (bool_xor) {
3016 std::vector<Expression*> args(3);
3017 args[0] = c->arg(0);
3018 args[1] = c->arg(1);
3019 args[2] = c->n_args() == 2 ? constants().lit_true : c->arg(2);
3020 nc = new Call(c->loc().introduce(), bool_xor->id(), args);
3021 nc->type(Type::varbool());
3022 nc->decl(bool_xor);
3023 }
3024 } else {
3025 FunctionI* decl = env.model->matchFn(env, c, false);
3026 if (decl && decl->e()) {
3027 nc = c;
3028 nc->decl(decl);
3029 }
3030 }
3031 if (nc != NULL) {
3032 CollectDecls cd(env.vo, deletedVarDecls, ci);
3033 topDown(cd, c);
3034 ci->e(constants().lit_true);
3035 env.flat_removeItem(i);
3036 StringLit* sl = getLongestMznPathAnnotation(env, c);
3037 CallStackItem* csi = NULL;
3038 if (sl) csi = new CallStackItem(env, sl);
3039 (void)flat_exp(env, Ctx(), nc, constants().var_true, constants().var_true);
3040 if (csi) delete csi;
3041 }
3042 }
3043 }
3044 }
3045 }
3046
3047 startItem = endItem + 1;
3048 endItem = m.size() - 1;
3049 }
3050
3051 for (unsigned int i = 0; i < removedItems.size(); i++) {
3052 if (env.vo.occurrences(removedItems[i]->e()) == 0) {
3053 CollectDecls cd(env.vo, deletedVarDecls, removedItems[i]);
3054 topDown(cd, removedItems[i]->e()->e());
3055 env.flat_removeItem(removedItems[i]);
3056 }
3057 }
3058
3059 // Add redefinitions for output variables that may have been redefined since createOutput
3060 for (unsigned int i = 0; i < env.output->size(); i++) {
3061 if (VarDeclI* vdi = (*env.output)[i]->dyn_cast<VarDeclI>()) {
3062 IdMap<KeepAlive>::iterator it;
3063 if (vdi->e()->e() == NULL &&
3064 (it = env.reverseMappers.find(vdi->e()->id())) != env.reverseMappers.end()) {
3065 GCLock lock;
3066 Call* rhs = copy(env, env.cmap, it->second())->cast<Call>();
3067 std::vector<Type> tv(rhs->n_args());
3068 for (unsigned int i = rhs->n_args(); i--;) {
3069 tv[i] = rhs->arg(i)->type();
3070 tv[i].ti(Type::TI_PAR);
3071 }
3072 FunctionI* decl = env.output->matchFn(env, rhs->id(), tv, false);
3073 Type t;
3074 if (decl == NULL) {
3075 FunctionI* origdecl = env.model->matchFn(env, rhs->id(), tv, false);
3076 if (origdecl == NULL) {
3077 throw FlatteningError(
3078 env, rhs->loc(),
3079 "function " + rhs->id().str() + " is used in output, par version needed");
3080 }
3081 if (!isBuiltin(origdecl)) {
3082 decl = copy(env, env.cmap, origdecl)->cast<FunctionI>();
3083 CollectOccurrencesE ce(env.output_vo, decl);
3084 topDown(ce, decl->e());
3085 topDown(ce, decl->ti());
3086 for (unsigned int i = decl->params().size(); i--;) topDown(ce, decl->params()[i]);
3087 env.output->registerFn(env, decl);
3088 env.output->addItem(decl);
3089 } else {
3090 decl = origdecl;
3091 }
3092 }
3093 rhs->decl(decl);
3094 outputVarDecls(env, vdi, rhs);
3095
3096 removeIsOutput(vdi->e()->flat());
3097 vdi->e()->e(rhs);
3098 }
3099 }
3100 }
3101
3102 for (unsigned int i = 0; i < m.size(); i++) {
3103 if (ConstraintI* ci = m[i]->dyn_cast<ConstraintI>()) {
3104 if (Call* c = ci->e()->dyn_cast<Call>()) {
3105 if (c->decl() == constants().var_redef) {
3106 CollectDecls cd(env.vo, deletedVarDecls, ci);
3107 topDown(cd, c);
3108 env.flat_removeItem(i);
3109 }
3110 }
3111 }
3112 }
3113
3114 while (!deletedVarDecls.empty()) {
3115 VarDecl* cur = deletedVarDecls.back();
3116 deletedVarDecls.pop_back();
3117 if (env.vo.occurrences(cur) == 0 && !isOutput(cur)) {
3118 if (CollectDecls::varIsFree(cur)) {
3119 IdMap<int>::iterator cur_idx = env.vo.idx.find(cur->id());
3120 if (cur_idx != env.vo.idx.end() && !m[cur_idx->second]->removed()) {
3121 CollectDecls cd(env.vo, deletedVarDecls, m[cur_idx->second]->cast<VarDeclI>());
3122 topDown(cd, cur->e());
3123 env.flat_removeItem(cur_idx->second);
3124 }
3125 }
3126 }
3127 }
3128
3129 if (!opt.keepOutputInFzn) {
3130 finaliseOutput(env, deletedVarDecls);
3131 }
3132
3133 while (!deletedVarDecls.empty()) {
3134 VarDecl* cur = deletedVarDecls.back();
3135 deletedVarDecls.pop_back();
3136 if (env.vo.occurrences(cur) == 0 && !isOutput(cur)) {
3137 if (CollectDecls::varIsFree(cur)) {
3138 IdMap<int>::iterator cur_idx = env.vo.idx.find(cur->id());
3139 if (cur_idx != env.vo.idx.end() && !m[cur_idx->second]->removed()) {
3140 CollectDecls cd(env.vo, deletedVarDecls, m[cur_idx->second]->cast<VarDeclI>());
3141 topDown(cd, cur->e());
3142 env.flat_removeItem(cur_idx->second);
3143 }
3144 }
3145 }
3146 }
3147
3148 cleanupOutput(env);
3149 } catch (ModelInconsistent&) {
3150 }
3151}
3152
3153void clearInternalAnnotations(Expression* e) {
3154 e->ann().remove(constants().ann.promise_total);
3155 e->ann().remove(constants().ann.maybe_partial);
3156 e->ann().remove(constants().ann.add_to_output);
3157 e->ann().remove(constants().ann.rhs_from_assignment);
3158 // Remove defines_var(x) annotation where x is par
3159 std::vector<Expression*> removeAnns;
3160 for (ExpressionSetIter anns = e->ann().begin(); anns != e->ann().end(); ++anns) {
3161 if (Call* c = (*anns)->dyn_cast<Call>()) {
3162 if (c->id() == constants().ann.defines_var && c->arg(0)->type().ispar()) {
3163 removeAnns.push_back(c);
3164 }
3165 }
3166 }
3167 for (unsigned int i = 0; i < removeAnns.size(); i++) {
3168 e->ann().remove(removeAnns[i]);
3169 }
3170}
3171
3172std::vector<Expression*> cleanup_vardecl(EnvI& env, VarDeclI* vdi, VarDecl* vd) {
3173 std::vector<Expression*> added_constraints;
3174
3175 // In FlatZinc par variables have RHSs, not domains
3176 if (vd->type().ispar()) {
3177 vd->ann().clear();
3178 vd->introduced(false);
3179 vd->ti()->domain(NULL);
3180 }
3181
3182 // In FlatZinc the RHS of a VarDecl must be a literal, Id or empty
3183 // Example:
3184 // var 1..5: x = function(y)
3185 // becomes:
3186 // var 1..5: x;
3187 // relation(x, y);
3188 if (vd->type().isvar() && vd->type().isbool()) {
3189 bool is_fixed = (vd->ti()->domain() != NULL);
3190 if (Expression::equal(vd->ti()->domain(), constants().lit_true)) {
3191 // Ex: var true: b = e()
3192
3193 // Store RHS
3194 Expression* ve = vd->e();
3195 vd->e(constants().lit_true);
3196 vd->ti()->domain(NULL);
3197 // Ex: var bool: b = true
3198
3199 // If vd had a RHS
3200 if (ve != NULL) {
3201 if (Call* vcc = ve->dyn_cast<Call>()) {
3202 // Convert functions to relations:
3203 // exists([x]) => array_bool_or([x],true)
3204 // forall([x]) => array_bool_and([x],true)
3205 // clause([x]) => bool_clause([x])
3206 ASTString cid;
3207 std::vector<Expression*> args;
3208 if (vcc->id() == constants().ids.exists) {
3209 cid = constants().ids.array_bool_or;
3210 args.push_back(vcc->arg(0));
3211 args.push_back(constants().lit_true);
3212 } else if (vcc->id() == constants().ids.forall) {
3213 cid = constants().ids.array_bool_and;
3214 args.push_back(vcc->arg(0));
3215 args.push_back(constants().lit_true);
3216 } else if (vcc->id() == constants().ids.clause) {
3217 cid = constants().ids.bool_clause;
3218 args.push_back(vcc->arg(0));
3219 args.push_back(vcc->arg(1));
3220 }
3221
3222 if (args.size() == 0) {
3223 // Post original RHS as stand alone constraint
3224 ve = vcc;
3225 } else {
3226 // Create new call, retain annotations from original RHS
3227 Call* nc = new Call(vcc->loc().introduce(), cid, args);
3228 nc->type(vcc->type());
3229 nc->ann().merge(vcc->ann());
3230 ve = nc;
3231 }
3232 } else if (Id* id = ve->dyn_cast<Id>()) {
3233 if (id->decl()->ti()->domain() != constants().lit_true) {
3234 // Inconsistent assignment: post bool_eq(y, true)
3235 std::vector<Expression*> args(2);
3236 args[0] = id;
3237 args[1] = constants().lit_true;
3238 GCLock lock;
3239 ve = new Call(Location().introduce(), constants().ids.bool_eq, args);
3240 } else {
3241 // Don't post this
3242 ve = constants().lit_true;
3243 }
3244 }
3245 // Post new constraint
3246 if (ve != constants().lit_true) {
3247 clearInternalAnnotations(ve);
3248 added_constraints.push_back(ve);
3249 }
3250 }
3251 } else {
3252 // Ex: var false: b = e()
3253 if (vd->e() != NULL) {
3254 if (vd->e()->eid() == Expression::E_CALL) {
3255 // Convert functions to relations:
3256 // var false: b = exists([x]) => array_bool_or([x], b)
3257 // var false: b = forall([x]) => array_bool_and([x], b)
3258 // var false: b = clause([x]) => bool_clause_reif([x], b)
3259 const Call* c = vd->e()->cast<Call>();
3260 GCLock lock;
3261 vd->e(NULL);
3262 ASTString cid;
3263 std::vector<Expression*> args(c->n_args());
3264 for (unsigned int i = args.size(); i--;) args[i] = c->arg(i);
3265 if (is_fixed) {
3266 args.push_back(constants().lit_false);
3267 } else {
3268 args.push_back(vd->id());
3269 }
3270 if (c->id() == constants().ids.exists) {
3271 cid = constants().ids.array_bool_or;
3272 } else if (c->id() == constants().ids.forall) {
3273 cid = constants().ids.array_bool_and;
3274 } else if (c->id() == constants().ids.clause) {
3275 cid = constants().ids.bool_clause_reif;
3276 } else {
3277 if (env.fopts.enable_imp && vd->ann().contains(constants().ctx.pos)) {
3278 cid = env.halfReifyId(c->id());
3279 if (env.model->matchFn(env, cid, args, false) == NULL) {
3280 cid = env.reifyId(c->id());
3281 }
3282 } else {
3283 cid = env.reifyId(c->id());
3284 }
3285 }
3286 Call* nc = new Call(c->loc().introduce(), cid, args);
3287 nc->type(c->type());
3288 FunctionI* decl = env.model->matchFn(env, nc, false);
3289 if (decl == NULL) {
3290 throw FlatteningError(
3291 env, c->loc(),
3292 "'" + c->id().str() +
3293 "' is used in a reified context but no reified version is available");
3294 }
3295 nc->decl(decl);
3296 if (!is_fixed) {
3297 makeDefinedVar(vd, nc);
3298 }
3299 nc->ann().merge(c->ann());
3300 clearInternalAnnotations(nc);
3301 added_constraints.push_back(nc);
3302 } else {
3303 assert(vd->e()->eid() == Expression::E_ID || vd->e()->eid() == Expression::E_BOOLLIT);
3304 }
3305 }
3306 if (Expression::equal(vd->ti()->domain(), constants().lit_false)) {
3307 vd->ti()->domain(NULL);
3308 vd->e(constants().lit_false);
3309 }
3310 }
3311 if (vdi != NULL && is_fixed && env.vo.occurrences(vd) == 0) {
3312 if (isOutput(vd)) {
3313 VarDecl* vd_output = (*env.output)[env.output_vo_flat.find(vd)]->cast<VarDeclI>()->e();
3314 if (vd_output->e() == NULL) {
3315 vd_output->e(vd->e());
3316 }
3317 }
3318 env.flat_removeItem(vdi);
3319 }
3320 } else if (vd->type().isvar() && vd->type().dim() == 0) {
3321 // Int or Float var
3322 if (vd->e() != NULL) {
3323 if (const Call* cc = vd->e()->dyn_cast<Call>()) {
3324 // Remove RHS from vd
3325 vd->e(NULL);
3326
3327 std::vector<Expression*> args(cc->n_args());
3328 ASTString cid;
3329 if (cc->id() == constants().ids.lin_exp) {
3330 // a = lin_exp([1],[b],5) => int_lin_eq([1,-1],[b,a],-5):: defines_var(a)
3331 ArrayLit* le_c = follow_id(cc->arg(0))->cast<ArrayLit>();
3332 std::vector<Expression*> nc(le_c->size());
3333 for (unsigned int i = static_cast<unsigned int>(nc.size()); i--;) nc[i] = (*le_c)[i];
3334 if (le_c->type().bt() == Type::BT_INT) {
3335 cid = constants().ids.int_.lin_eq;
3336 nc.push_back(IntLit::a(-1));
3337 args[0] = new ArrayLit(Location().introduce(), nc);
3338 args[0]->type(Type::parint(1));
3339 ArrayLit* le_x = follow_id(cc->arg(1))->cast<ArrayLit>();
3340 std::vector<Expression*> nx(le_x->size());
3341 for (unsigned int i = static_cast<unsigned int>(nx.size()); i--;) nx[i] = (*le_x)[i];
3342 nx.push_back(vd->id());
3343 args[1] = new ArrayLit(Location().introduce(), nx);
3344 args[1]->type(le_x->type());
3345 IntVal d = cc->arg(2)->cast<IntLit>()->v();
3346 args[2] = IntLit::a(-d);
3347 } else {
3348 // float
3349 cid = constants().ids.float_.lin_eq;
3350 nc.push_back(FloatLit::a(-1.0));
3351 args[0] = new ArrayLit(Location().introduce(), nc);
3352 args[0]->type(Type::parfloat(1));
3353 ArrayLit* le_x = follow_id(cc->arg(1))->cast<ArrayLit>();
3354 std::vector<Expression*> nx(le_x->size());
3355 for (unsigned int i = static_cast<unsigned int>(nx.size()); i--;) nx[i] = (*le_x)[i];
3356 nx.push_back(vd->id());
3357 args[1] = new ArrayLit(Location().introduce(), nx);
3358 args[1]->type(le_x->type());
3359 FloatVal d = cc->arg(2)->cast<FloatLit>()->v();
3360 args[2] = FloatLit::a(-d);
3361 }
3362 } else {
3363 if (cc->id() == "card") {
3364 // card is 'set_card' in old FlatZinc
3365 cid = constants().ids.set_card;
3366 } else {
3367 cid = cc->id();
3368 }
3369 for (unsigned int i = static_cast<unsigned int>(args.size()); i--;) args[i] = cc->arg(i);
3370 args.push_back(vd->id());
3371 }
3372 Call* nc = new Call(cc->loc().introduce(), cid, args);
3373 nc->type(cc->type());
3374 makeDefinedVar(vd, nc);
3375 nc->ann().merge(cc->ann());
3376
3377 clearInternalAnnotations(nc);
3378 added_constraints.push_back(nc);
3379 } else {
3380 // RHS must be literal or Id
3381 assert(vd->e()->eid() == Expression::E_ID || vd->e()->eid() == Expression::E_INTLIT ||
3382 vd->e()->eid() == Expression::E_FLOATLIT ||
3383 vd->e()->eid() == Expression::E_BOOLLIT || vd->e()->eid() == Expression::E_SETLIT);
3384 }
3385 }
3386 } else if (vd->type().dim() > 0) {
3387 // vd is an array
3388
3389 // If RHS is an Id, follow id to RHS
3390 // a = [1,2,3]; b = a;
3391 // vd = b => vd = [1,2,3]
3392 if (!vd->e()->isa<ArrayLit>()) {
3393 vd->e(follow_id(vd->e()));
3394 }
3395
3396 // If empty array or 1 indexed, continue
3397 if (vd->ti()->ranges().size() == 1 && vd->ti()->ranges()[0]->domain() != NULL &&
3398 vd->ti()->ranges()[0]->domain()->isa<SetLit>()) {
3399 IntSetVal* isv = vd->ti()->ranges()[0]->domain()->cast<SetLit>()->isv();
3400 if (isv && (isv->size() == 0 || isv->min(0) == 1)) return added_constraints;
3401 }
3402
3403 // Array should be 1 indexed since ArrayLit is 1 indexed
3404 assert(vd->e() != NULL);
3405 ArrayLit* al = NULL;
3406 Expression* e = vd->e();
3407 while (al == NULL) {
3408 switch (e->eid()) {
3409 case Expression::E_ARRAYLIT:
3410 al = e->cast<ArrayLit>();
3411 break;
3412 case Expression::E_ID:
3413 e = e->cast<Id>()->decl()->e();
3414 break;
3415 default:
3416 assert(false);
3417 }
3418 }
3419 al->make1d();
3420 IntSetVal* isv = IntSetVal::a(1, al->length());
3421 if (vd->ti()->ranges().size() == 1) {
3422 vd->ti()->ranges()[0]->domain(new SetLit(Location().introduce(), isv));
3423 } else {
3424 std::vector<TypeInst*> r(1);
3425 r[0] = new TypeInst(vd->ti()->ranges()[0]->loc(), vd->ti()->ranges()[0]->type(),
3426 new SetLit(Location().introduce(), isv));
3427 ASTExprVec<TypeInst> ranges(r);
3428 TypeInst* ti = new TypeInst(vd->ti()->loc(), vd->ti()->type(), ranges, vd->ti()->domain());
3429 vd->ti(ti);
3430 }
3431 }
3432
3433 // Remove boolean context annotations used only on compilation
3434 vd->ann().remove(constants().ctx.mix);
3435 vd->ann().remove(constants().ctx.pos);
3436 vd->ann().remove(constants().ctx.neg);
3437 vd->ann().remove(constants().ctx.root);
3438 vd->ann().remove(constants().ann.promise_total);
3439 vd->ann().remove(constants().ann.add_to_output);
3440 vd->ann().remove(constants().ann.mzn_check_var);
3441 vd->ann().remove(constants().ann.rhs_from_assignment);
3442 vd->ann().removeCall(constants().ann.mzn_check_enum_var);
3443
3444 return added_constraints;
3445}
3446
3447Expression* cleanup_constraint(EnvI& env, std::unordered_set<Item*>& globals, Expression* ce) {
3448 clearInternalAnnotations(ce);
3449
3450 if (Call* vc = ce->dyn_cast<Call>()) {
3451 for (unsigned int i = 0; i < vc->n_args(); i++) {
3452 // Change array indicies to be 1 indexed
3453 if (ArrayLit* al = vc->arg(i)->dyn_cast<ArrayLit>()) {
3454 if (al->dims() > 1 || al->min(0) != 1) {
3455 al->make1d();
3456 }
3457 }
3458 }
3459 // Convert functions to relations:
3460 // exists([x]) => array_bool_or([x],true)
3461 // forall([x]) => array_bool_and([x],true)
3462 // clause([x]) => bool_clause([x])
3463 // bool_xor([x],[y]) => bool_xor([x],[y],true)
3464 if (vc->id() == constants().ids.exists) {
3465 GCLock lock;
3466 vc->id(constants().ids.array_bool_or);
3467 std::vector<Expression*> args(2);
3468 args[0] = vc->arg(0);
3469 args[1] = constants().lit_true;
3470 ASTExprVec<Expression> argsv(args);
3471 vc->args(argsv);
3472 vc->decl(env.model->matchFn(env, vc, false));
3473 } else if (vc->id() == constants().ids.forall) {
3474 GCLock lock;
3475 vc->id(constants().ids.array_bool_and);
3476 std::vector<Expression*> args(2);
3477 args[0] = vc->arg(0);
3478 args[1] = constants().lit_true;
3479 ASTExprVec<Expression> argsv(args);
3480 vc->args(argsv);
3481 vc->decl(env.model->matchFn(env, vc, false));
3482 } else if (vc->id() == constants().ids.clause) {
3483 GCLock lock;
3484 vc->id(constants().ids.bool_clause);
3485 vc->decl(env.model->matchFn(env, vc, false));
3486 } else if (vc->id() == constants().ids.bool_xor && vc->n_args() == 2) {
3487 GCLock lock;
3488 std::vector<Expression*> args(3);
3489 args[0] = vc->arg(0);
3490 args[1] = vc->arg(1);
3491 args[2] = constants().lit_true;
3492 ASTExprVec<Expression> argsv(args);
3493 vc->args(argsv);
3494 vc->decl(env.model->matchFn(env, vc, false));
3495 }
3496
3497 // If vc->decl() is a solver builtin and has not been added to the
3498 // FlatZinc, add it
3499 if (vc->decl() && vc->decl() != constants().var_redef && !vc->decl()->from_stdlib() &&
3500 globals.find(vc->decl()) == globals.end()) {
3501 env.flat_addItem(vc->decl());
3502 globals.insert(vc->decl());
3503 }
3504 return ce;
3505 } else if (Id* id = ce->dyn_cast<Id>()) {
3506 // Ex: constraint b; => constraint bool_eq(b, true);
3507 std::vector<Expression*> args(2);
3508 args[0] = id;
3509 args[1] = constants().lit_true;
3510 GCLock lock;
3511 return new Call(Location().introduce(), constants().ids.bool_eq, args);
3512 } else if (BoolLit* bl = ce->dyn_cast<BoolLit>()) {
3513 // Ex: true => delete; false => bool_eq(false, true);
3514 if (!bl->v()) {
3515 GCLock lock;
3516 std::vector<Expression*> args(2);
3517 args[0] = constants().lit_false;
3518 args[1] = constants().lit_true;
3519 Call* neq = new Call(Location().introduce(), constants().ids.bool_eq, args);
3520 return neq;
3521 } else {
3522 return NULL;
3523 }
3524 } else {
3525 return ce;
3526 }
3527}
3528
3529void oldflatzinc(Env& e) {
3530 Model* m = e.flat();
3531
3532 // Mark annotations and optional variables for removal
3533 for (unsigned int i = 0; i < m->size(); i++) {
3534 Item* item = (*m)[i];
3535 if (VarDeclI* vdi = item->dyn_cast<VarDeclI>()) {
3536 if (item->cast<VarDeclI>()->e()->type().ot() == Type::OT_OPTIONAL ||
3537 item->cast<VarDeclI>()->e()->type().bt() == Type::BT_ANN) {
3538 e.envi().flat_removeItem(i);
3539 }
3540 }
3541 }
3542
3543 EnvI& env = e.envi();
3544
3545 int msize = m->size();
3546
3547 // Predicate declarations of solver builtins
3548 std::unordered_set<Item*> globals;
3549
3550 // Record indices of VarDeclIs with Id RHS for sorting & unification
3551 std::vector<int> declsWithIds;
3552 for (int i = 0; i < msize; i++) {
3553 if ((*m)[i]->removed()) continue;
3554 if (VarDeclI* vdi = (*m)[i]->dyn_cast<VarDeclI>()) {
3555 GCLock lock;
3556 VarDecl* vd = vdi->e();
3557 std::vector<Expression*> added_constraints = cleanup_vardecl(e.envi(), vdi, vd);
3558 // Record whether this VarDecl is equal to an Id (aliasing)
3559 if (vd->e() && vd->e()->isa<Id>()) {
3560 declsWithIds.push_back(i);
3561 vdi->e()->payload(-static_cast<int>(i) - 1);
3562 } else {
3563 vdi->e()->payload(i);
3564 }
3565 for (auto nc : added_constraints) {
3566 Expression* new_ce = cleanup_constraint(e.envi(), globals, nc);
3567 if (new_ce) {
3568 e.envi().flat_addItem(new ConstraintI(Location().introduce(), new_ce));
3569 }
3570 }
3571 } else if (ConstraintI* ci = (*m)[i]->dyn_cast<ConstraintI>()) {
3572 Expression* new_ce = cleanup_constraint(e.envi(), globals, ci->e());
3573 if (new_ce) {
3574 ci->e(new_ce);
3575 } else {
3576 ci->remove();
3577 }
3578 } else if (FunctionI* fi = (*m)[i]->dyn_cast<FunctionI>()) {
3579 if (Let* let = Expression::dyn_cast<Let>(fi->e())) {
3580 GCLock lock;
3581 std::vector<Expression*> new_let;
3582 for (unsigned int i = 0; i < let->let().size(); i++) {
3583 Expression* let_e = let->let()[i];
3584 if (VarDecl* vd = let_e->dyn_cast<VarDecl>()) {
3585 std::vector<Expression*> added_constraints = cleanup_vardecl(e.envi(), NULL, vd);
3586 new_let.push_back(vd);
3587 for (auto nc : added_constraints) new_let.push_back(nc);
3588 } else {
3589 Expression* new_ce = cleanup_constraint(e.envi(), globals, let_e);
3590 if (new_ce) {
3591 new_let.push_back(new_ce);
3592 }
3593 }
3594 }
3595 fi->e(new Let(let->loc(), new_let, let->in()));
3596 }
3597 } else if (SolveI* si = (*m)[i]->dyn_cast<SolveI>()) {
3598 if (si->e() && si->e()->type().ispar()) {
3599 // Introduce VarDecl if objective expression is par
3600 GCLock lock;
3601 TypeInst* ti = new TypeInst(Location().introduce(), si->e()->type(), NULL);
3602 VarDecl* constantobj = new VarDecl(Location().introduce(), ti, e.envi().genId(), si->e());
3603 si->e(constantobj->id());
3604 e.envi().flat_addItem(new VarDeclI(Location().introduce(), constantobj));
3605 }
3606 }
3607 }
3608
3609 // Sort VarDecls in FlatZinc so that VarDecls are declared before use
3610 std::vector<VarDeclI*> sortedVarDecls(declsWithIds.size());
3611 int vdCount = 0;
3612 for (unsigned int i = 0; i < declsWithIds.size(); i++) {
3613 VarDecl* cur = (*m)[declsWithIds[i]]->cast<VarDeclI>()->e();
3614 std::vector<int> stack;
3615 while (cur && cur->payload() < 0) {
3616 stack.push_back(cur->payload());
3617 if (Id* id = cur->e()->dyn_cast<Id>()) {
3618 cur = id->decl();
3619 } else {
3620 cur = NULL;
3621 }
3622 }
3623 for (unsigned int i = static_cast<unsigned int>(stack.size()); i--;) {
3624 VarDeclI* vdi = (*m)[-stack[i] - 1]->cast<VarDeclI>();
3625 vdi->e()->payload(-vdi->e()->payload() - 1);
3626 sortedVarDecls[vdCount++] = vdi;
3627 }
3628 }
3629 for (unsigned int i = 0; i < declsWithIds.size(); i++) {
3630 (*m)[declsWithIds[i]] = sortedVarDecls[i];
3631 }
3632
3633 // Remove marked items
3634 m->compact();
3635 e.envi().output->compact();
3636
3637 for (IdMap<VarOccurrences::Items>::iterator it = env.vo._m.begin(); it != env.vo._m.end(); ++it) {
3638 std::vector<Item*> toRemove;
3639 for (VarOccurrences::Items::iterator iit = it->second.begin(); iit != it->second.end(); ++iit) {
3640 if ((*iit)->removed()) {
3641 toRemove.push_back(*iit);
3642 }
3643 }
3644 for (unsigned int i = 0; i < toRemove.size(); i++) {
3645 it->second.erase(toRemove[i]);
3646 }
3647 }
3648
3649 class Cmp {
3650 public:
3651 bool operator()(Item* i, Item* j) {
3652 if (i->iid() == Item::II_FUN || j->iid() == Item::II_FUN) {
3653 if (i->iid() == j->iid()) return false;
3654 return i->iid() == Item::II_FUN;
3655 }
3656 if (i->iid() == Item::II_SOL) {
3657 assert(j->iid() != i->iid());
3658 return false;
3659 }
3660 if (j->iid() == Item::II_SOL) {
3661 assert(j->iid() != i->iid());
3662 return true;
3663 }
3664 if (i->iid() == Item::II_VD) {
3665 if (j->iid() != i->iid()) return true;
3666 if (i->cast<VarDeclI>()->e()->type().ispar() && j->cast<VarDeclI>()->e()->type().isvar())
3667 return true;
3668 if (j->cast<VarDeclI>()->e()->type().ispar() && i->cast<VarDeclI>()->e()->type().isvar())
3669 return false;
3670 if (i->cast<VarDeclI>()->e()->type().dim() == 0 &&
3671 j->cast<VarDeclI>()->e()->type().dim() != 0)
3672 return true;
3673 if (i->cast<VarDeclI>()->e()->type().dim() != 0 &&
3674 j->cast<VarDeclI>()->e()->type().dim() == 0)
3675 return false;
3676 if (i->cast<VarDeclI>()->e()->e() == NULL && j->cast<VarDeclI>()->e()->e() != NULL)
3677 return true;
3678 if (i->cast<VarDeclI>()->e()->e() && j->cast<VarDeclI>()->e()->e() &&
3679 !i->cast<VarDeclI>()->e()->e()->isa<Id>() && j->cast<VarDeclI>()->e()->e()->isa<Id>())
3680 return true;
3681 }
3682 return false;
3683 }
3684 } _cmp;
3685 // Perform final sorting
3686 std::stable_sort(m->begin(), m->end(), _cmp);
3687}
3688
3689FlatModelStatistics statistics(Model* m) {
3690 Model* flat = m;
3691 FlatModelStatistics stats;
3692 for (unsigned int i = 0; i < flat->size(); i++) {
3693 if (!(*flat)[i]->removed()) {
3694 if (VarDeclI* vdi = (*flat)[i]->dyn_cast<VarDeclI>()) {
3695 Type t = vdi->e()->type();
3696 if (t.isvar() && t.dim() == 0) {
3697 if (t.is_set())
3698 stats.n_set_vars++;
3699 else if (t.isint())
3700 stats.n_int_vars++;
3701 else if (t.isbool())
3702 stats.n_bool_vars++;
3703 else if (t.isfloat())
3704 stats.n_float_vars++;
3705 }
3706 } else if (ConstraintI* ci = (*flat)[i]->dyn_cast<ConstraintI>()) {
3707 if (Call* call = ci->e()->dyn_cast<Call>()) {
3708 if (call->id().endsWith("_reif")) {
3709 stats.n_reif_ct++;
3710 } else if (call->id().endsWith("_imp")) {
3711 stats.n_imp_ct++;
3712 }
3713 if (call->n_args() > 0) {
3714 Type all_t;
3715 for (unsigned int i = 0; i < call->n_args(); i++) {
3716 Type t = call->arg(i)->type();
3717 if (t.isvar()) {
3718 if (t.st() == Type::ST_SET)
3719 all_t = t;
3720 else if (t.bt() == Type::BT_FLOAT && all_t.st() != Type::ST_SET)
3721 all_t = t;
3722 else if (t.bt() == Type::BT_INT && all_t.bt() != Type::BT_FLOAT &&
3723 all_t.st() != Type::ST_SET)
3724 all_t = t;
3725 else if (t.bt() == Type::BT_BOOL && all_t.bt() != Type::BT_INT &&
3726 all_t.bt() != Type::BT_FLOAT && all_t.st() != Type::ST_SET)
3727 all_t = t;
3728 }
3729 }
3730 if (all_t.isvar()) {
3731 if (all_t.st() == Type::ST_SET)
3732 stats.n_set_ct++;
3733 else if (all_t.bt() == Type::BT_INT)
3734 stats.n_int_ct++;
3735 else if (all_t.bt() == Type::BT_BOOL)
3736 stats.n_bool_ct++;
3737 else if (all_t.bt() == Type::BT_FLOAT)
3738 stats.n_float_ct++;
3739 }
3740 }
3741 }
3742 }
3743 }
3744 }
3745 return stats;
3746}
3747
3748} // namespace MiniZinc