this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2
3/*
4 * Main authors:
5 * Jip J. Dekker <jip.dekker@monash.edu>
6 * Guido Tack <guido.tack@monash.edu>
7 */
8
9/* This Source Code Form is subject to the terms of the Mozilla Public
10 * License, v. 2.0. If a copy of the MPL was not distributed with this
11 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
12
13#include <minizinc/eval_par.hh>
14#include <minizinc/interpreter.hh>
15#include <minizinc/interpreter/values.hh>
16#include <minizinc/interpreter/variable.hh>
17
18namespace MiniZinc {
19
20Variable::Variable(Interpreter* interpreter, Val domain, int ident)
21 : RefCountedObject(RefCountedObject::VAR, ident),
22 _prev(this),
23 _next(this),
24 _domain(domain),
25 _binding(true),
26 _aliased(false) {
27 assert(_domain.isVec());
28 _domain.addRef(interpreter);
29 _ann.addRef(interpreter);
30 addRef(interpreter);
31}
32
33Variable::Variable(Interpreter* interpreter, Val domain, bool binding, int ident, Val ann)
34 : RefCountedObject(RefCountedObject::VAR, ident),
35 _prev(this),
36 _next(this),
37 _domain(domain),
38 _ann(ann),
39 _binding(binding),
40 _aliased(false) {
41 assert(_domain.isVec());
42 _domain.addRef(interpreter);
43 _ann.addRef(interpreter);
44 if (binding) addRef(interpreter);
45 // insert into root variable list
46 Variable* v = interpreter->root();
47 interpreter->trail.trail_ptr(this, &_prev);
48 _prev = v->_prev;
49 interpreter->trail.trail_ptr(this, &_next);
50 _next = v;
51 interpreter->trail.trail_ptr(v->_prev, &v->_prev->_next);
52 v->_prev->_next = this;
53 interpreter->trail.trail_ptr(v, &v->_prev);
54 v->_prev = this;
55}
56
57bool Variable::setMin(Interpreter* interpreter, Val i, bool binding) {
58 assert(!aliased());
59 assert(_domain.isVec());
60 assert(_domain.size() % 2 == 0);
61 size_t j = 0;
62 while (j < _domain.size() && _domain[j] < i) {
63 ++j;
64 }
65 if (j == 0) {
66 return true;
67 }
68 if (j == _domain.size()) {
69 Val ndom(Vec::a(interpreter, interpreter->newIdent(), {}));
70 ndom.addRef(interpreter);
71 domain(interpreter, ndom, binding);
72 ndom.rmRef(interpreter);
73 return false;
74 }
75 std::vector<Val> dom;
76 if (j % 2 == 1) {
77 dom.emplace_back(i);
78 }
79 for (; j < _domain.size(); ++j) {
80 dom.push_back(_domain[j]);
81 }
82 Val ndom(Vec::a(interpreter, interpreter->newIdent(), dom));
83 ndom.addRef(interpreter);
84 domain(interpreter, ndom, binding);
85 ndom.rmRef(interpreter);
86 return true;
87}
88
89bool Variable::setMax(Interpreter* interpreter, Val i, bool binding) {
90 assert(!aliased());
91 assert(_domain.isVec());
92 assert(_domain.size() % 2 == 0);
93 int j = _domain.size() - 1;
94 while (j >= 0 && _domain[j] > i) {
95 --j;
96 }
97 if (j == _domain.size() - 1) {
98 return true;
99 }
100 if (j < 0) {
101 Val ndom(Vec::a(interpreter, interpreter->newIdent(), {}));
102 ndom.addRef(interpreter);
103 domain(interpreter, ndom, binding);
104 ndom.rmRef(interpreter);
105 return false;
106 }
107 std::vector<Val> dom;
108 for (size_t k = 0; k <= j; ++k) {
109 dom.push_back(_domain[k]);
110 }
111 if (j % 2 == 0) {
112 dom.emplace_back(i);
113 }
114 Val ndom(Vec::a(interpreter, interpreter->newIdent(), dom));
115 ndom.addRef(interpreter);
116 domain(interpreter, ndom, binding);
117 ndom.rmRef(interpreter);
118 return true;
119}
120
121bool Variable::setVal(Interpreter* interpreter, Val i, bool binding) {
122 assert(!aliased());
123 assert(_domain.isVec());
124 assert(_domain.size() % 2 == 0);
125 for (int j = 0; j < _domain.size(); j += 2) {
126 if (_domain[j] <= i && i <= _domain[j + 1]) {
127 this->binding(interpreter, binding);
128 alias(interpreter, i);
129 return true;
130 }
131 }
132 Val ndom(Vec::a(interpreter, interpreter->newIdent(), {}));
133 ndom.addRef(interpreter);
134 domain(interpreter, ndom, binding);
135 ndom.rmRef(interpreter);
136 return false;
137}
138
139bool Variable::intersectDom(Interpreter* interpreter, const std::vector<Val>& dom, bool binding) {
140 if (!isBounded()) {
141 Val ndom(Vec::a(interpreter, interpreter->newIdent(), dom));
142 ndom.addRef(interpreter);
143 domain(interpreter, ndom, binding);
144 ndom.rmRef(interpreter);
145 return true;
146 }
147 assert(!aliased());
148 assert(_domain.isVec());
149 assert(_domain.size() % 2 == 0);
150 VecSetRanges vsr1(_domain.toVec());
151 StdVecSetRanges vsr2(&dom);
152 Ranges::Inter<Val, VecSetRanges, StdVecSetRanges> inter(vsr1, vsr2);
153 std::vector<Val> result;
154 for (; inter(); ++inter) {
155 result.emplace_back(inter.min());
156 result.emplace_back(inter.max());
157 }
158 Val ndom(Vec::a(interpreter, interpreter->newIdent(), result));
159 ndom.addRef(interpreter);
160 domain(interpreter, ndom, binding);
161 ndom.rmRef(interpreter);
162 return !result.empty();
163}
164
165bool Variable::intersectDom(Interpreter* interpreter, Val dom, bool binding) {
166 assert(!dom.isVar());
167 if (dom.isInt()) {
168 return setVal(interpreter, dom);
169 }
170 // TODO: Allocation is not really necessary;
171 std::vector<Val> vdom(dom.size());
172 for (int i = 0; i < dom.size(); ++i) {
173 vdom[i] = dom[i];
174 }
175 return intersectDom(interpreter, vdom, binding);
176}
177
178void Variable::domain(Interpreter* interpreter, const Val& newDomain, bool binding0) {
179 assert(!aliased());
180 assert(!newDomain.isRCO() || newDomain.toRCO()->alive());
181 assert(_domain.isVec());
182 interpreter->trail.trail_domain(interpreter, this, _domain.toVec());
183 SubscriptionEvent sev;
184 if (newDomain.isInt()) {
185 alias(interpreter, newDomain);
186 sev = SEV_VAL;
187 } else if (newDomain.size() == 2 && newDomain[0] == newDomain[1]) {
188 alias(interpreter, newDomain[0]);
189 sev = SEV_VAL;
190 } else {
191 Val nd = newDomain;
192 nd.addRef(interpreter);
193 _domain.rmRef(interpreter);
194 _domain = newDomain;
195 sev = SEV_DOM;
196 }
197 for (auto& s : _subscriptions) {
198 if (sev == SEV_VAL || s.second == SES_ANY) {
199 interpreter->schedule(s.first, sev);
200 }
201 }
202 binding(interpreter, binding0);
203}
204void Variable::domain(Interpreter* interpreter, const std::vector<Val>& newDomain, bool binding0) {
205 if (!isBounded()) {
206 Val ndom(Vec::a(interpreter, interpreter->newIdent(), newDomain));
207 ndom.addRef(interpreter);
208 domain(interpreter, ndom, binding0);
209 ndom.rmRef(interpreter);
210 } else {
211 bool did_update = false;
212 if (newDomain.size() != _domain.size()) {
213 did_update = true;
214 } else {
215 for (int i = 0; i < newDomain.size(); i++) {
216 if (newDomain[i] != _domain[i]) {
217 did_update = true;
218 break;
219 }
220 }
221 }
222 if (did_update) {
223 Val ndv(Vec::a(interpreter, interpreter->newIdent(), newDomain));
224 ndv.addRef(interpreter);
225 domain(interpreter, ndv, binding0);
226 ndv.rmRef(interpreter);
227 }
228 }
229}
230
231void Variable::destroy(MiniZinc::Interpreter* interpreter) {
232 _model_ref_count = (1u << 31u) - 1u;
233 _domain.rmRef(interpreter);
234 _ann.rmRef(interpreter);
235 interpreter->trail.trail_ptr(_prev, &(_prev->_next));
236 _prev->_next = _next;
237 interpreter->trail.trail_ptr(_next, &(_next->_prev));
238 _next->_prev = _prev;
239 interpreter->trail.trail_ptr(this, &_next);
240 _next = this;
241 interpreter->trail.trail_ptr(this, &_prev);
242 _prev = this;
243
244 for (auto c : _definitions) {
245 c->destroy(interpreter);
246 }
247 _model_ref_count = 0;
248}
249
250void Variable::reconstruct(Interpreter* interpreter) {
251 /// TODO: what about subscriptions?
252 assert(_model_ref_count == 0);
253 _ann.addRef(interpreter);
254 _domain.addRef(interpreter);
255 for (auto c : _definitions) {
256 c->reconstruct(interpreter);
257 }
258 _model_ref_count = 0;
259}
260
261void Variable::addDefinition(Interpreter* interpreter, Constraint* c) {
262 _definitions.push_back(c);
263 if (this != interpreter->root()) {
264 // Remove reference counts for this variable from each argument in c
265 for (int i = 0; i < c->size(); i++) {
266 if (c->arg(i).isVar()) {
267 if (c->arg(i).timestamp() == _timestamp) {
268 RefCountedObject::rmRef(interpreter, this);
269 }
270 } else if (c->arg(i).isVec()) {
271 Val content = c->arg(i).toVec()->raw_data();
272 bool hasVar = false;
273 for (int j = 0; j < content.size(); j++) {
274 if (content[j].isVar() && content[j].timestamp() == _timestamp) {
275 hasVar = true;
276 break;
277 }
278 }
279 if (hasVar) {
280 if (!c->arg(i).unique() || !content.unique()) {
281 // make vectors unique so that we can safely decrement reference counts
282 std::vector<Val> vals(content.size());
283 for (int i = 0; i < vals.size(); i++) {
284 vals[i] = content[i];
285 }
286 Val v = Val(Vec::a(interpreter, interpreter->newIdent(), vals));
287 if (c->arg(i).toVec()->hasIndexSet()) {
288 v = Val(Vec::a(interpreter, interpreter->newIdent(),
289 {v, c->arg(i).toVec()->index_set()}));
290 }
291 c->arg(interpreter, i, Val(v));
292 }
293 for (int j = 0; j < content.size(); j++) {
294 if (content[j].timestamp() == _timestamp) {
295 RefCountedObject::rmRef(interpreter, this);
296 }
297 }
298 }
299 }
300 }
301 }
302 if (c->delayed()) {
303 interpreter->register_delayed(c, this);
304 }
305 interpreter->trail.trail_add_def(this, c);
306}
307
308void Variable::alias(Interpreter* interpreter, Val v) {
309 assert(!_aliased);
310 assert(!v.isVar() || v.toVar() != this);
311 // Move defining constraints to current context
312
313 for (Constraint* c : _definitions) {
314 for (int i = 0; i < c->size(); ++i) {
315 Val arg = c->arg(i);
316 if (arg.isVec()) {
317 _model_ref_count += arg.toVec()->count(Val(this));
318 } else {
319 _model_ref_count += (arg == Val(this));
320 }
321 }
322 interpreter->trail.trail_rm_def(this, c);
323 interpreter->pushConstraint(c);
324 }
325 _definitions.clear();
326
327 // Destroy old domain
328 _domain.rmRef(interpreter);
329 _ann.rmRef(interpreter);
330 _ann = 0;
331
332 // Reset reference count for binding status
333 // TODO: this may be incorrect if we are aliasing a variable with
334 // TODO: binding domain to one with non-binding domain
335 binding(interpreter, false);
336
337 // Transfer subscriptions to new value and schedule propagators
338 for (auto& s : _subscriptions) {
339 if (v.isVar()) {
340 v.toVar()->subscribe(s.first, s.second);
341 }
342 if (s.second == SES_VALUNIFY || s.second == SES_ANY) {
343 interpreter->schedule(s.first, SEV_UNIFY);
344 }
345 }
346 _subscriptions.clear();
347
348 // Set Alias
349 _aliased = true;
350 _domain = v;
351 v.addRef(interpreter);
352 interpreter->trail.trail_alias(interpreter, this);
353}
354
355void Variable::unalias(Interpreter* interpreter, Val dom) {
356 /// TODO!!!
357 // auto ref_count = _ref_count;
358 // _pred = proc;
359 // _size = size;
360 // _args[0].destroy(interpreter);
361 // _args[0] = arg0;
362 // for (int i = 0; i < _size; ++i) {
363 // _args[i].construct(interpreter);
364 // }
365 // // TODO: Transfer back subscriptions moved on aliasing?
366 // interpreter->subscribe(this);
367 // _ann.construct(interpreter);
368 // _domain->addRef(interpreter);
369 // _ref_count = ref_count;
370}
371
372void Variable::binding(Interpreter* interpreter, bool f) {
373 if (!_binding && f) {
374 addRef(interpreter);
375 } else if (_binding && !f) {
376 RefCountedObject::rmRef(interpreter, this);
377 }
378 _binding = f;
379}
380
381void Variable::subscribe(Constraint* c, const SubscriptionEventSet& events) {
382 Variable* sub = this;
383 while (sub && sub->aliased()) {
384 if (sub->_domain.isVar()) {
385 sub = sub->_domain.toVar();
386 } else {
387 sub = nullptr;
388 }
389 }
390 if (sub) {
391 sub->_subscriptions.insert(std::make_pair(c, events));
392 }
393}
394void Variable::unsubscribe(Constraint* c) {
395 Variable* sub = this;
396 while (sub && sub->aliased()) {
397 if (sub->_domain.isVar()) {
398 sub = sub->_domain.toVar();
399 } else {
400 sub = nullptr;
401 }
402 }
403 if (sub) {
404 sub->_subscriptions.erase(c);
405 }
406}
407
408void Variable::dump(Variable* head, const std::vector<BytecodeProc>& bs, std::ostream& os) {
409 Variable* d = head;
410 do {
411 d = d->next();
412 if (d != head) {
413 if (d->timestamp() >= 0) {
414 os << d->timestamp() << "(";
415 }
416 os << d << "." << d->_model_ref_count;
417 if (d->timestamp() >= 0) {
418 os << ")";
419 }
420 os << ":\t";
421 if (d->aliased()) {
422 os << " alias " << d->alias().toString() << "\n";
423 } else {
424 if (d->domain()) {
425 if (d->_binding) {
426 os << " binding";
427 }
428 os << " domain: " << Val(d->domain()).toString();
429 }
430 }
431 os << "\n";
432 if (!d->_subscriptions.empty()) {
433 os << " subscriptions: ";
434 for (auto& s : d->_subscriptions) {
435 os << s.first << " ";
436 }
437 os << "\n";
438 }
439 }
440 for (Constraint* c : d->_definitions) {
441 if (d != head) {
442 os << " ";
443 }
444 os << c << " " << bs[c->pred()].name << "(";
445 for (int i = 0; i < c->size(); i++) {
446 os << c->arg(i).toString();
447 if (i < c->size() - 1) os << ", ";
448 }
449 os << ")\n";
450 }
451 } while (d != head);
452}
453
454} // namespace MiniZinc