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