A set of benchmarks to compare a new prototype MiniZinc implementation
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#ifndef __MINIZINC_VALUES_HH__
13#define __MINIZINC_VALUES_HH__
14
15#include <minizinc/exception.hh>
16#include <minizinc/gc.hh>
17
18#include <algorithm>
19#include <cmath>
20#include <functional>
21#include <limits>
22#include <string>
23#include <vector>
24
25#ifdef min
26#undef min
27#endif
28#ifdef max
29#undef max
30#endif
31
32namespace MiniZinc {
33class IntVal;
34}
35namespace std {
36MiniZinc::IntVal abs(const MiniZinc::IntVal& x);
37}
38
39namespace MiniZinc {
40
41class FloatVal;
42
43class IntVal {
44 friend IntVal operator+(const IntVal& x, const IntVal& y);
45 friend IntVal operator-(const IntVal& x, const IntVal& y);
46 friend IntVal operator*(const IntVal& x, const IntVal& y);
47 friend IntVal operator/(const IntVal& x, const IntVal& y);
48 friend IntVal operator%(const IntVal& x, const IntVal& y);
49 friend IntVal std::abs(const MiniZinc::IntVal& x);
50 friend bool operator==(const IntVal& x, const IntVal& y);
51 friend class FloatVal;
52
53private:
54 long long int _v;
55 bool _infinity;
56 IntVal(long long int v, bool infinity) : _v(v), _infinity(infinity) {}
57
58 static long long int safePlus(long long int x, long long int y) {
59 if (x < 0) {
60 if (y < std::numeric_limits<long long int>::min() - x)
61 throw ArithmeticError("integer overflow");
62 } else {
63 if (y > std::numeric_limits<long long int>::max() - x)
64 throw ArithmeticError("integer overflow");
65 }
66 return x + y;
67 }
68 static long long int safeMinus(long long int x, long long int y) {
69 if (x < 0) {
70 if (y > x - std::numeric_limits<long long int>::min())
71 throw ArithmeticError("integer overflow");
72 } else {
73 if (y < x - std::numeric_limits<long long int>::max())
74 throw ArithmeticError("integer overflow");
75 }
76 return x - y;
77 }
78 static long long int safeMult(long long int x, long long int y) {
79 if (y == 0) return 0;
80 long long unsigned int x_abs = (x < 0 ? 0 - x : x);
81 long long unsigned int y_abs = (y < 0 ? 0 - y : y);
82 if (x_abs > std::numeric_limits<long long int>::max() / y_abs)
83 throw ArithmeticError("integer overflow");
84 return x * y;
85 }
86 static long long int safeDiv(long long int x, long long int y) {
87 if (y == 0) throw ArithmeticError("integer division by zero");
88 if (x == 0) return 0;
89 if (x == std::numeric_limits<long long int>::min() && y == -1)
90 throw ArithmeticError("integer overflow");
91 return x / y;
92 }
93 static long long int safeMod(long long int x, long long int y) {
94 if (y == 0) throw ArithmeticError("integer division by zero");
95 if (y == -1) return 0;
96 return x % y;
97 }
98
99public:
100 IntVal(void) : _v(0), _infinity(false) {}
101 IntVal(long long int v) : _v(v), _infinity(false) {}
102 IntVal(const FloatVal& v);
103
104 long long int toInt(void) const {
105 if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
106 return _v;
107 }
108
109 long long int toIntUnsafe(void) const;
110
111 bool isFinite(void) const { return !_infinity; }
112 bool isPlusInfinity(void) const { return _infinity && _v == 1; }
113 bool isMinusInfinity(void) const { return _infinity && _v == -1; }
114
115 IntVal& operator+=(const IntVal& x) {
116 if (!(isFinite() && x.isFinite()))
117 throw ArithmeticError("arithmetic operation on infinite value");
118 _v = safePlus(_v, x._v);
119 return *this;
120 }
121 IntVal& operator-=(const IntVal& x) {
122 if (!(isFinite() && x.isFinite()))
123 throw ArithmeticError("arithmetic operation on infinite value");
124 _v = safeMinus(_v, x._v);
125 return *this;
126 }
127 IntVal& operator*=(const IntVal& x) {
128 if (!(isFinite() && x.isFinite()))
129 throw ArithmeticError("arithmetic operation on infinite value");
130 _v = safeMult(_v, x._v);
131 return *this;
132 }
133 IntVal& operator/=(const IntVal& x) {
134 if (!(isFinite() && x.isFinite()))
135 throw ArithmeticError("arithmetic operation on infinite value");
136 _v = safeDiv(_v, x._v);
137 return *this;
138 }
139 IntVal operator-() const {
140 IntVal r = *this;
141 r._v = safeMinus(0, _v);
142 return r;
143 }
144 IntVal& operator++() {
145 if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
146 _v = safePlus(_v, 1);
147 return *this;
148 }
149 IntVal operator++(int) {
150 if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
151 IntVal ret = *this;
152 _v = safePlus(_v, 1);
153 return ret;
154 }
155 IntVal& operator--() {
156 if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
157 _v = safeMinus(_v, 1);
158 return *this;
159 }
160 IntVal operator--(int) {
161 if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
162 IntVal ret = *this;
163 _v = safeMinus(_v, 1);
164 return ret;
165 }
166 IntVal pow(const IntVal& exponent) {
167 if (!exponent.isFinite() || !isFinite())
168 throw ArithmeticError("arithmetic operation on infinite value");
169 if (exponent == 0) return 1;
170 if (exponent == 1) return *this;
171 IntVal result = 1;
172 for (int i = 0; i < exponent.toInt(); i++) {
173 result *= *this;
174 }
175 return result;
176 }
177
178 static const IntVal minint(void);
179 static const IntVal maxint(void);
180 static const IntVal infinity(void);
181
182 /// Infinity-safe addition
183 IntVal plus(int x) const {
184 if (isFinite())
185 return safePlus(_v, x);
186 else
187 return *this;
188 }
189 /// Infinity-safe subtraction
190 IntVal minus(int x) const {
191 if (isFinite())
192 return safeMinus(_v, x);
193 else
194 return *this;
195 }
196
197 size_t hash(void) const {
198 std::hash<long long int> longhash;
199 return longhash(_v);
200 }
201};
202
203inline long long int IntVal::toIntUnsafe(void) const { return _v; }
204
205inline bool operator==(const IntVal& x, const IntVal& y) {
206 return x._infinity == y._infinity && x._v == y._v;
207}
208inline bool operator<=(const IntVal& x, const IntVal& y) {
209 return y.isPlusInfinity() || x.isMinusInfinity() ||
210 (x.isFinite() && y.isFinite() && x.toInt() <= y.toInt());
211}
212inline bool operator<(const IntVal& x, const IntVal& y) {
213 return (y.isPlusInfinity() && !x.isPlusInfinity()) ||
214 (x.isMinusInfinity() && !y.isMinusInfinity()) ||
215 (x.isFinite() && y.isFinite() && x.toInt() < y.toInt());
216}
217inline bool operator>=(const IntVal& x, const IntVal& y) { return y <= x; }
218inline bool operator>(const IntVal& x, const IntVal& y) { return y < x; }
219inline bool operator!=(const IntVal& x, const IntVal& y) { return !(x == y); }
220inline IntVal operator+(const IntVal& x, const IntVal& y) {
221 if (!(x.isFinite() && y.isFinite()))
222 throw ArithmeticError("arithmetic operation on infinite value");
223 return IntVal::safePlus(x._v, y._v);
224}
225inline IntVal operator-(const IntVal& x, const IntVal& y) {
226 if (!(x.isFinite() && y.isFinite()))
227 throw ArithmeticError("arithmetic operation on infinite value");
228 return IntVal::safeMinus(x._v, y._v);
229}
230inline IntVal operator*(const IntVal& x, const IntVal& y) {
231 if (!x.isFinite()) {
232 if (y.isFinite() && (y._v == 1 || y._v == -1))
233 return IntVal(IntVal::safeMult(x._v, y._v), !x.isFinite());
234 } else if (!y.isFinite()) {
235 if (x.isFinite() && (y._v == 1 || y._v == -1))
236 return IntVal(IntVal::safeMult(x._v, y._v), true);
237 } else {
238 return IntVal::safeMult(x._v, y._v);
239 }
240 throw ArithmeticError("arithmetic operation on infinite value");
241}
242inline IntVal operator/(const IntVal& x, const IntVal& y) {
243 if (y.isFinite() && (y._v == 1 || y._v == -1))
244 return IntVal(IntVal::safeMult(x._v, y._v), !x.isFinite());
245 if (!(x.isFinite() && y.isFinite()))
246 throw ArithmeticError("arithmetic operation on infinite value");
247 return IntVal::safeDiv(x._v, y._v);
248}
249inline IntVal operator%(const IntVal& x, const IntVal& y) {
250 if (!(x.isFinite() && y.isFinite()))
251 throw ArithmeticError("arithmetic operation on infinite value");
252 return IntVal::safeMod(x._v, y._v);
253}
254template <class Char, class Traits>
255std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,
256 const IntVal& s) {
257 if (s.isMinusInfinity())
258 return os << "-infinity";
259 else if (s.isPlusInfinity())
260 return os << "infinity";
261 else
262 return os << s.toInt();
263}
264
265} // namespace MiniZinc
266
267namespace std {
268inline MiniZinc::IntVal abs(const MiniZinc::IntVal& x) {
269 if (!x.isFinite()) return MiniZinc::IntVal::infinity();
270 return x < 0 ? MiniZinc::IntVal::safeMinus(0, x._v) : x;
271}
272
273inline MiniZinc::IntVal min(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) {
274 return x <= y ? x : y;
275}
276inline MiniZinc::IntVal max(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) {
277 return x >= y ? x : y;
278}
279
280template <>
281struct equal_to<MiniZinc::IntVal> {
282public:
283 bool operator()(const MiniZinc::IntVal& s0, const MiniZinc::IntVal& s1) const { return s0 == s1; }
284};
285
286inline MiniZinc::FloatVal abs(const MiniZinc::FloatVal&);
287} // namespace std
288
289namespace std {
290template <>
291struct hash<MiniZinc::IntVal> {
292public:
293 size_t operator()(const MiniZinc::IntVal& s) const { return s.hash(); }
294};
295} // namespace std
296
297namespace MiniZinc {
298
299class FloatVal {
300 friend FloatVal operator+(const FloatVal& x, const FloatVal& y);
301 friend FloatVal operator-(const FloatVal& x, const FloatVal& y);
302 friend FloatVal operator*(const FloatVal& x, const FloatVal& y);
303 friend FloatVal operator/(const FloatVal& x, const FloatVal& y);
304 friend FloatVal std::abs(const MiniZinc::FloatVal& x);
305 friend bool operator==(const FloatVal& x, const FloatVal& y);
306 friend class IntVal;
307
308private:
309 double _v;
310 bool _infinity;
311 void checkOverflow(void) {
312 if (!std::isfinite(_v)) throw ArithmeticError("overflow in floating point operation");
313 }
314 FloatVal(double v, bool infinity) : _v(v), _infinity(infinity) { checkOverflow(); }
315
316public:
317 FloatVal(void) : _v(0.0), _infinity(false) {}
318 FloatVal(double v) : _v(v), _infinity(false) { checkOverflow(); }
319 FloatVal(const IntVal& v) : _v(static_cast<double>(v._v)), _infinity(!v.isFinite()) {}
320
321 double toDouble(void) const {
322 if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
323 return _v;
324 }
325
326 bool isFinite(void) const { return !_infinity; }
327 bool isPlusInfinity(void) const { return _infinity && _v == 1.0; }
328 bool isMinusInfinity(void) const { return _infinity && _v == -1.0; }
329
330 FloatVal& operator+=(const FloatVal& x) {
331 if (!(isFinite() && x.isFinite()))
332 throw ArithmeticError("arithmetic operation on infinite value");
333 _v += x._v;
334 checkOverflow();
335 return *this;
336 }
337 FloatVal& operator-=(const FloatVal& x) {
338 if (!(isFinite() && x.isFinite()))
339 throw ArithmeticError("arithmetic operation on infinite value");
340 _v -= x._v;
341 checkOverflow();
342 return *this;
343 }
344 FloatVal& operator*=(const FloatVal& x) {
345 if (!(isFinite() && x.isFinite()))
346 throw ArithmeticError("arithmetic operation on infinite value");
347 _v *= x._v;
348 checkOverflow();
349 return *this;
350 }
351 FloatVal& operator/=(const FloatVal& x) {
352 if (!(isFinite() && x.isFinite()))
353 throw ArithmeticError("arithmetic operation on infinite value");
354 _v = _v / x._v;
355 checkOverflow();
356 return *this;
357 }
358 FloatVal operator-() const {
359 FloatVal r = *this;
360 r._v = -r._v;
361 return r;
362 }
363 FloatVal& operator++() {
364 if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
365 _v = _v + 1;
366 checkOverflow();
367 return *this;
368 }
369 FloatVal operator++(int) {
370 if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
371 FloatVal ret = *this;
372 _v = _v + 1;
373 checkOverflow();
374 return ret;
375 }
376 FloatVal& operator--() {
377 if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
378 _v = _v - 1;
379 checkOverflow();
380 return *this;
381 }
382 FloatVal operator--(int) {
383 if (!isFinite()) throw ArithmeticError("arithmetic operation on infinite value");
384 FloatVal ret = *this;
385 _v = _v - 1;
386 checkOverflow();
387 return ret;
388 }
389
390 static const FloatVal infinity(void);
391
392 /// Infinity-safe addition
393 FloatVal plus(int x) {
394 if (isFinite())
395 return (*this) + x;
396 else
397 return *this;
398 }
399 /// Infinity-safe subtraction
400 FloatVal minus(int x) {
401 if (isFinite())
402 return (*this) - x;
403 else
404 return *this;
405 }
406
407 size_t hash(void) const {
408 std::hash<double> doublehash;
409 return doublehash(_v);
410 }
411};
412
413inline bool operator==(const FloatVal& x, const FloatVal& y) {
414 return x._infinity == y._infinity && x._v == y._v;
415}
416inline bool operator<=(const FloatVal& x, const FloatVal& y) {
417 return y.isPlusInfinity() || x.isMinusInfinity() ||
418 (x.isFinite() && y.isFinite() && x.toDouble() <= y.toDouble());
419}
420inline bool operator<(const FloatVal& x, const FloatVal& y) {
421 return (y.isPlusInfinity() && !x.isPlusInfinity()) ||
422 (x.isMinusInfinity() && !y.isMinusInfinity()) ||
423 (x.isFinite() && y.isFinite() && x.toDouble() < y.toDouble());
424}
425inline bool operator>=(const FloatVal& x, const FloatVal& y) { return y <= x; }
426inline bool operator>(const FloatVal& x, const FloatVal& y) { return y < x; }
427inline bool operator!=(const FloatVal& x, const FloatVal& y) { return !(x == y); }
428inline FloatVal operator+(const FloatVal& x, const FloatVal& y) {
429 if (!(x.isFinite() && y.isFinite()))
430 throw ArithmeticError("arithmetic operation on infinite value");
431 return x.toDouble() + y.toDouble();
432}
433inline FloatVal operator-(const FloatVal& x, const FloatVal& y) {
434 if (!(x.isFinite() && y.isFinite()))
435 throw ArithmeticError("arithmetic operation on infinite value");
436 return x.toDouble() - y.toDouble();
437}
438inline FloatVal operator*(const FloatVal& x, const FloatVal& y) {
439 if (!(x.isFinite() && y.isFinite()))
440 throw ArithmeticError("arithmetic operation on infinite value");
441 return x.toDouble() * y.toDouble();
442}
443inline FloatVal operator/(const FloatVal& x, const FloatVal& y) {
444 if (!(x.isFinite() && y.isFinite()))
445 throw ArithmeticError("arithmetic operation on infinite value");
446 return x.toDouble() / y.toDouble();
447}
448template <class Char, class Traits>
449std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,
450 const FloatVal& s) {
451 if (s.isMinusInfinity())
452 return os << "-infinity";
453 else if (s.isPlusInfinity())
454 return os << "infinity";
455 else
456 return os << s.toDouble();
457}
458
459inline IntVal::IntVal(const FloatVal& v)
460 : _v(static_cast<long long int>(v._v)), _infinity(!v.isFinite()) {}
461
462} // namespace MiniZinc
463
464namespace std {
465inline MiniZinc::FloatVal abs(const MiniZinc::FloatVal& x) {
466 if (!x.isFinite()) return MiniZinc::FloatVal::infinity();
467 return x.toDouble() < 0 ? MiniZinc::FloatVal(-x.toDouble()) : x;
468}
469
470inline MiniZinc::FloatVal min(const MiniZinc::FloatVal& x, const MiniZinc::FloatVal& y) {
471 return x <= y ? x : y;
472}
473inline MiniZinc::FloatVal max(const MiniZinc::FloatVal& x, const MiniZinc::FloatVal& y) {
474 return x >= y ? x : y;
475}
476
477inline MiniZinc::FloatVal floor(const MiniZinc::FloatVal& x) {
478 if (!x.isFinite()) return x;
479 return floor(x.toDouble());
480}
481inline MiniZinc::FloatVal ceil(const MiniZinc::FloatVal& x) {
482 if (!x.isFinite()) return x;
483 return ceil(x.toDouble());
484}
485
486template <>
487struct equal_to<MiniZinc::FloatVal> {
488public:
489 bool operator()(const MiniZinc::FloatVal& s0, const MiniZinc::FloatVal& s1) const {
490 return s0 == s1;
491 }
492};
493} // namespace std
494
495namespace std {
496template <>
497struct hash<MiniZinc::FloatVal> {
498public:
499 size_t operator()(const MiniZinc::FloatVal& s) const { return s.hash(); }
500};
501} // namespace std
502
503namespace MiniZinc {
504
505typedef unsigned long long int UIntVal;
506
507/// An integer set value
508class IntSetVal : public ASTChunk {
509public:
510 /// Contiguous range
511 struct Range {
512 /// Range minimum
513 IntVal min;
514 /// Range maximum
515 IntVal max;
516 /// Construct range from \a m to \a n
517 Range(IntVal m, IntVal n) : min(m), max(n) {}
518 /// Default constructor
519 Range(void) {}
520 };
521
522private:
523 /// Return range at position \a i
524 Range& get(int i) { return reinterpret_cast<Range*>(_data)[i]; }
525 /// Return range at position \a i
526 const Range& get(int i) const { return reinterpret_cast<const Range*>(_data)[i]; }
527 /// Construct empty set
528 IntSetVal(void) : ASTChunk(0) {}
529 /// Construct set of single range
530 IntSetVal(IntVal m, IntVal n);
531 /// Construct set from \a s
532 IntSetVal(const std::vector<Range>& s) : ASTChunk(sizeof(Range) * s.size()) {
533 for (unsigned int i = static_cast<unsigned int>(s.size()); i--;) get(i) = s[i];
534 }
535
536 /// Disabled
537 IntSetVal(const IntSetVal& r);
538 /// Disabled
539 IntSetVal& operator=(const IntSetVal& r);
540
541public:
542 /// Return number of ranges
543 int size(void) const { return static_cast<int>(_size / sizeof(Range)); }
544 /// Return minimum, or infinity if set is empty
545 IntVal min(void) const { return size() == 0 ? IntVal::infinity() : get(0).min; }
546 /// Return maximum, or minus infinity if set is empty
547 IntVal max(void) const { return size() == 0 ? -IntVal::infinity() : get(size() - 1).max; }
548 /// Return minimum of range \a i
549 IntVal min(int i) const {
550 assert(i < size());
551 return get(i).min;
552 }
553 /// Return maximum of range \a i
554 IntVal max(int i) const {
555 assert(i < size());
556 return get(i).max;
557 }
558 /// Return width of range \a i
559 IntVal width(int i) const {
560 assert(i < size());
561 if (min(i).isFinite() && max(i).isFinite())
562 return max(i) - min(i) + 1;
563 else
564 return IntVal::infinity();
565 }
566 /// Return cardinality
567 IntVal card(void) const {
568 IntVal c = 0;
569 for (unsigned int i = size(); i--;) {
570 if (width(i).isFinite())
571 c += width(i);
572 else
573 return IntVal::infinity();
574 }
575 return c;
576 }
577
578 /// Allocate empty set from context
579 static IntSetVal* a(void) {
580 IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(0));
581 new (r) IntSetVal();
582 return r;
583 }
584
585 /// Allocate set \f$\{m,n\}\f$ from context
586 static IntSetVal* a(IntVal m, IntVal n) {
587 if (m > n) {
588 return a();
589 } else {
590 IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(sizeof(Range)));
591 new (r) IntSetVal(m, n);
592 return r;
593 }
594 }
595
596 /// Allocate set using iterator \a i
597 template <class I>
598 static IntSetVal* ai(I& i) {
599 std::vector<Range> s;
600 for (; i(); ++i) s.push_back(Range(i.min(), i.max()));
601 IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(sizeof(Range) * s.size()));
602 new (r) IntSetVal(s);
603 return r;
604 }
605
606 /// Allocate set from vector \a s0 (may contain duplicates)
607 static IntSetVal* a(const std::vector<IntVal>& s0) {
608 if (s0.size() == 0) return a();
609 std::vector<IntVal> s = s0;
610 std::sort(s.begin(), s.end());
611 std::vector<Range> ranges;
612 IntVal min = s[0];
613 IntVal max = min;
614 for (unsigned int i = 1; i < s.size(); i++) {
615 if (s[i] > max + 1) {
616 ranges.push_back(Range(min, max));
617 min = s[i];
618 max = min;
619 } else {
620 max = s[i];
621 }
622 }
623 ranges.push_back(Range(min, max));
624 IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(sizeof(Range) * ranges.size()));
625 new (r) IntSetVal(ranges);
626 return r;
627 }
628 static IntSetVal* a(const std::vector<Range>& ranges) {
629 IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(sizeof(Range) * ranges.size()));
630 new (r) IntSetVal(ranges);
631 return r;
632 }
633
634 /// Check if set contains \a v
635 bool contains(const IntVal& v) {
636 for (int i = 0; i < size(); i++) {
637 if (v < min(i)) return false;
638 if (v <= max(i)) return true;
639 }
640 return false;
641 }
642
643 /// Check if it is equal to \a s
644 bool equal(const IntSetVal* s) {
645 if (size() != s->size()) return false;
646 for (int i = 0; i < size(); i++)
647 if (min(i) != s->min(i) || max(i) != s->max(i)) return false;
648 return true;
649 }
650
651 /// Mark for garbage collection
652 void mark(void) { _gc_mark = 1; }
653};
654
655/// Iterator over an IntSetVal
656class IntSetRanges {
657 /// The set value
658 const IntSetVal* rs;
659 /// The current range
660 int n;
661
662public:
663 /// Constructor
664 IntSetRanges(const IntSetVal* r) : rs(r), n(0) {}
665 /// Check if iterator is still valid
666 bool operator()(void) const { return n < rs->size(); }
667 /// Move to next range
668 void operator++(void) { ++n; }
669 /// Return minimum of current range
670 IntVal min(void) const { return rs->min(n); }
671 /// Return maximum of current range
672 IntVal max(void) const { return rs->max(n); }
673 /// Return width of current range
674 IntVal width(void) const { return rs->width(n); }
675};
676
677template <class Char, class Traits>
678std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,
679 const IntSetVal& s) {
680 if (s.size() == 0) {
681 os << "1..0";
682 } else if (s.size() == 1) {
683 // Print the range
684 IntSetRanges isr(&s);
685 os << isr.min() << ".." << isr.max();
686 } else {
687 // Print each element of the set
688 bool first = true;
689 os << "{";
690 for (IntSetRanges isr(&s); isr(); ++isr) {
691 if (!first) os << ", ";
692 first = false;
693 for (IntVal v = isr.min(); v < isr.max(); ++v) {
694 os << v;
695 }
696 }
697 os << "}";
698 }
699 return os;
700}
701
702/// An integer set value
703class FloatSetVal : public ASTChunk {
704public:
705 /// Contiguous range
706 struct Range {
707 /// Range minimum
708 FloatVal min;
709 /// Range maximum
710 FloatVal max;
711 /// Construct range from \a m to \a n
712 Range(FloatVal m, FloatVal n) : min(m), max(n) {}
713 /// Default constructor
714 Range(void) {}
715 };
716
717private:
718 /// Return range at position \a i
719 Range& get(int i) { return reinterpret_cast<Range*>(_data)[i]; }
720 /// Return range at position \a i
721 const Range& get(int i) const { return reinterpret_cast<const Range*>(_data)[i]; }
722 /// Construct empty set
723 FloatSetVal(void) : ASTChunk(0) {}
724 /// Construct set of single range
725 FloatSetVal(FloatVal m, FloatVal n);
726 /// Construct set from \a s
727 FloatSetVal(const std::vector<Range>& s) : ASTChunk(sizeof(Range) * s.size()) {
728 for (unsigned int i = static_cast<unsigned int>(s.size()); i--;) get(i) = s[i];
729 }
730
731 /// Disabled
732 FloatSetVal(const FloatSetVal& r);
733 /// Disabled
734 FloatSetVal& operator=(const FloatSetVal& r);
735
736public:
737 /// Return number of ranges
738 int size(void) const { return static_cast<int>(_size / sizeof(Range)); }
739 /// Return minimum, or infinity if set is empty
740 FloatVal min(void) const { return size() == 0 ? FloatVal::infinity() : get(0).min; }
741 /// Return maximum, or minus infinity if set is empty
742 FloatVal max(void) const { return size() == 0 ? -FloatVal::infinity() : get(size() - 1).max; }
743 /// Return minimum of range \a i
744 FloatVal min(int i) const {
745 assert(i < size());
746 return get(i).min;
747 }
748 /// Return maximum of range \a i
749 FloatVal max(int i) const {
750 assert(i < size());
751 return get(i).max;
752 }
753 /// Return width of range \a i
754 FloatVal width(int i) const {
755 assert(i < size());
756 if (min(i).isFinite() && max(i).isFinite() && min(i) == max(i))
757 return 1;
758 else
759 return IntVal::infinity();
760 }
761 /// Return cardinality
762 FloatVal card(void) const {
763 FloatVal c = 0;
764 for (unsigned int i = size(); i--;) {
765 if (width(i).isFinite())
766 c += width(i);
767 else
768 return FloatVal::infinity();
769 }
770 return c;
771 }
772
773 /// Allocate empty set from context
774 static FloatSetVal* a(void) {
775 FloatSetVal* r = static_cast<FloatSetVal*>(ASTChunk::alloc(0));
776 new (r) FloatSetVal();
777 return r;
778 }
779
780 /// Allocate set \f$\{m,n\}\f$ from context
781 static FloatSetVal* a(FloatVal m, FloatVal n) {
782 if (m > n) {
783 return a();
784 } else {
785 FloatSetVal* r = static_cast<FloatSetVal*>(ASTChunk::alloc(sizeof(Range)));
786 new (r) FloatSetVal(m, n);
787 return r;
788 }
789 }
790
791 /// Allocate set using iterator \a i
792 template <class I>
793 static FloatSetVal* ai(I& i) {
794 std::vector<Range> s;
795 for (; i(); ++i) s.push_back(Range(i.min(), i.max()));
796 FloatSetVal* r = static_cast<FloatSetVal*>(ASTChunk::alloc(sizeof(Range) * s.size()));
797 new (r) FloatSetVal(s);
798 return r;
799 }
800
801 /// Allocate set from vector \a s0 (may contain duplicates)
802 static FloatSetVal* a(const std::vector<FloatVal>& s0) {
803 if (s0.size() == 0) return a();
804 std::vector<FloatVal> s = s0;
805 std::sort(s.begin(), s.end());
806 std::vector<Range> ranges;
807 FloatVal min = s[0];
808 FloatVal max = min;
809 for (unsigned int i = 1; i < s.size(); i++) {
810 if (s[i] > max) {
811 ranges.push_back(Range(min, max));
812 min = s[i];
813 max = min;
814 } else {
815 max = s[i];
816 }
817 }
818 ranges.push_back(Range(min, max));
819 FloatSetVal* r = static_cast<FloatSetVal*>(ASTChunk::alloc(sizeof(Range) * ranges.size()));
820 new (r) FloatSetVal(ranges);
821 return r;
822 }
823 static FloatSetVal* a(const std::vector<Range>& ranges) {
824 FloatSetVal* r = static_cast<FloatSetVal*>(ASTChunk::alloc(sizeof(Range) * ranges.size()));
825 new (r) FloatSetVal(ranges);
826 return r;
827 }
828
829 /// Check if set contains \a v
830 bool contains(const FloatVal& v) {
831 for (int i = 0; i < size(); i++) {
832 if (v < min(i)) return false;
833 if (v <= max(i)) return true;
834 }
835 return false;
836 }
837
838 /// Check if it is equal to \a s
839 bool equal(const FloatSetVal* s) {
840 if (size() != s->size()) return false;
841 for (int i = 0; i < size(); i++)
842 if (min(i) != s->min(i) || max(i) != s->max(i)) return false;
843 return true;
844 }
845
846 /// Mark for garbage collection
847 void mark(void) { _gc_mark = 1; }
848};
849
850/// Iterator over an IntSetVal
851class FloatSetRanges {
852 /// The set value
853 const FloatSetVal* rs;
854 /// The current range
855 int n;
856
857public:
858 /// Constructor
859 FloatSetRanges(const FloatSetVal* r) : rs(r), n(0) {}
860 /// Check if iterator is still valid
861 bool operator()(void) const { return n < rs->size(); }
862 /// Move to next range
863 void operator++(void) { ++n; }
864 /// Return minimum of current range
865 FloatVal min(void) const { return rs->min(n); }
866 /// Return maximum of current range
867 FloatVal max(void) const { return rs->max(n); }
868 /// Return width of current range
869 FloatVal width(void) const { return rs->width(n); }
870};
871
872template <class Char, class Traits>
873std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,
874 const FloatSetVal& s) {
875 for (FloatSetRanges isr(&s); isr(); ++isr) os << isr.min() << ".." << isr.max() << " ";
876 return os;
877}
878} // namespace MiniZinc
879
880#endif