Generated on for Gecode by doxygen 1.15.0
tuple-set.cpp
Go to the documentation of this file.
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2/*
3 * Main authors:
4 * Linnea Ingmar <linnea.ingmar@hotmail.com>
5 * Mikael Zayenz Lagerkvist <lagerkvist@gecode.dev>
6 * Christian Schulte <schulte@gecode.dev>
7 *
8 * Copyright:
9 * Linnea Ingmar, 2017
10 * Mikael Zayenz Lagerkvist, 2007
11 * Christian Schulte, 2017
12 *
13 * This file is part of Gecode, the generic constraint
14 * development environment:
15 * http://www.gecode.dev
16 *
17 * Permission is hereby granted, free of charge, to any person obtaining
18 * a copy of this software and associated documentation files (the
19 * "Software"), to deal in the Software without restriction, including
20 * without limitation the rights to use, copy, modify, merge, publish,
21 * distribute, sublicense, and/or sell copies of the Software, and to
22 * permit persons to whom the Software is furnished to do so, subject to
23 * the following conditions:
24 *
25 * The above copyright notice and this permission notice shall be
26 * included in all copies or substantial portions of the Software.
27 *
28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 *
36 */
37
38#include <gecode/int.hh>
39#include <algorithm>
40#include <limits>
41
42namespace Gecode { namespace Int { namespace Extensional {
43
46
49 private:
51 int arity;
52 public:
54 TupleCompare(int a);
56 bool operator ()(const Tuple& a, const Tuple& b);
57 };
58
60 class PosCompare {
61 private:
63 int p;
64 public:
66 PosCompare(int p);
68 bool operator ()(const Tuple& a, const Tuple& b);
69 };
70
71
73 TupleCompare::TupleCompare(int a) : arity(a) {}
74
75 forceinline bool
77 for (int i=0; i<arity; i++)
78 if (a[i] < b[i])
79 return true;
80 else if (a[i] > b[i])
81 return false;
82 return false;
83 }
84
85
87 PosCompare::PosCompare(int p0) : p(p0) {}
88
89 forceinline bool
90 PosCompare::operator ()(const Tuple& a, const Tuple& b) {
91 return a[p] < b[p];
92 }
93
94
95}}}
96
97namespace Gecode {
98
99 /*
100 * Tuple set data
101 *
102 */
103 void
105 heap.rfree(range);
106 heap.rfree(range_base);
107 heap.rfree(support);
108 heap.rfree(sparse_offsets);
109 heap.rfree(sparse_tuples);
110 heap.rfree(sparse_tv);
112 heap.rfree(compressed_words);
113 range = nullptr;
114 range_base = nullptr;
115 support = nullptr;
116 sparse_n_vals = 0U;
117 sparse_offsets = nullptr;
118 sparse_tuples = nullptr;
119 sparse_tv = nullptr;
120 compressed_offsets = nullptr;
121 compressed_words = nullptr;
123 for (int a=0; a<arity; a++) {
124 vd[a].n = 0U;
125 vd[a].r = nullptr;
126 vd[a].base = nullptr;
127 }
128 }
129
132 switch (epk) {
133 case EPK_AUTO:
134 case EPK_DENSE:
135 return TS_DENSE;
136 case EPK_SPARSE:
137 return TS_SPARSE;
138 case EPK_DENSE_COMPRESSED:
139 return TS_DENSE_COMPRESSED;
140 default:
142 }
143 return TS_FAILED;
144 }
145
148 ExtensionalPropKind epk, bool dense_possible,
149 bool sparse_possible, bool compressed_possible,
150 bool support_bits_sparse, unsigned long long dense_bytes) const {
151 const unsigned long long dense_small_threshold =
152 2ULL * 1024ULL * 1024ULL;
153 switch (epk) {
154 case EPK_AUTO:
155 if (dense_possible &&
156 ((dense_bytes <= dense_small_threshold) || !support_bits_sparse))
157 return TS_DENSE;
158 if (compressed_possible)
159 return TS_DENSE_COMPRESSED;
160 if (dense_possible)
161 return TS_DENSE;
162 break;
163 case EPK_DENSE:
164 if (dense_possible)
165 return TS_DENSE;
166 break;
167 case EPK_SPARSE:
168 if (sparse_possible)
169 return TS_SPARSE;
170 break;
171 case EPK_DENSE_COMPRESSED:
172 if (compressed_possible)
173 return TS_DENSE_COMPRESSED;
174 break;
175 default:
177 }
178 throw Int::OutOfLimits("TupleSet::finalize()");
179 }
180
181 void
183 finalize(EPK_DENSE);
184 }
185
186 void
188 using namespace Int::Extensional;
189 assert(!terminal());
190
192
193 class FinalizeGuard {
194 protected:
195 Data& d;
196 bool committed;
197 public:
198 FinalizeGuard(Data& d0) : d(d0), committed(false) {}
199 ~FinalizeGuard(void) {
200 if (!committed) {
201 d.clear_support();
202 d.n_words = 0U;
205 d.key = 0U;
206 d.state = TS_FAILED;
207 }
208 }
209 void commit(State selected) {
210 assert((selected != TS_BUILDING) && (selected != TS_FAILED));
211 d.state = selected;
212 committed = true;
213 }
214 } guard(*this);
215
216 // Initialization
217 if (n_tuples == 0) {
218 const State selected = empty_state(epk);
219 heap.rfree(td);
220 td=nullptr;
221 guard.commit(selected);
222 return;
223 }
224
225 // Compact and copy data
226 Region region;
227 // Set up tuple pointers
228 Tuple* tuples = region.alloc<Tuple>(n_tuples);
229 {
230 for (int t=0; t<n_tuples; t++)
231 tuples[t] = td + t*arity;
232 TupleCompare tc(arity);
234 // Remove duplicates
235 int j=1;
236 for (int t=1; t<n_tuples; t++) {
237 for (int a=0; a<arity; a++)
238 if (tuples[t-1][a] != tuples[t][a])
239 goto notsame;
240 goto same;
241 notsame: ;
242 tuples[j++] = tuples[t];
243 same: ;
244 }
245 assert(j <= n_tuples);
246 n_tuples=j;
247 // Initialize hash key
248 key = static_cast<std::size_t>(n_tuples);
250 // Copy into now possibly smaller area
251 const unsigned long long n_tcells64 =
252 static_cast<unsigned long long>(n_tuples) *
253 static_cast<unsigned long long>(arity);
254 if (n_tcells64 > static_cast<unsigned long long>
255 (std::numeric_limits<unsigned long>::max()))
256 throw Int::OutOfLimits("TupleSet::finalize()");
257 const unsigned long n_tcells = static_cast<unsigned long>(n_tcells64);
258 for (int t=0; t<n_tuples; t++)
259 for (int a=0; a<arity; a++)
260 if (!Int::Limits::valid(tuples[t][a]))
261 throw Int::OutOfLimits("TupleSet::finalize()");
262 int* new_td = heap.alloc<int>(n_tcells);
263 for (int t=0; t<n_tuples; t++) {
264 for (int a=0; a<arity; a++) {
265 new_td[static_cast<unsigned long>(t) *
266 static_cast<unsigned long>(arity) +
267 static_cast<unsigned long>(a)] = tuples[t][a];
268 cmb_hash(key,tuples[t][a]);
269 }
270 tuples[t] = new_td + static_cast<unsigned long>(t) *
271 static_cast<unsigned long>(arity);
272 }
273 heap.rfree(td);
274 td = new_td;
275 }
276
277 // Only now compute how many words are needed!
278 n_words = BitSetData::data(static_cast<unsigned int>(n_tuples));
279
280 State selected = TS_BUILDING;
281 // Compute range information
282 {
283 /*
284 * Pass one: compute how many values and ranges are needed
285 */
286 // How many values
287 unsigned long long n_vals64 = 0ULL;
288 // How many ranges
289 unsigned long long n_ranges64 = 0ULL;
290 for (int a=0; a<arity; a++) {
291 // Sort tuple according to position
292 PosCompare pc(a);
294 // Scan values
295 {
296 int last_value=tuples[0][a];
297 n_vals64++; n_ranges64++;
298 for (int i=1; i<n_tuples; i++) {
299 assert(tuples[i-1][a] <= tuples[i][a]);
300 if (last_value+1 == tuples[i][a]) {
301 n_vals64++;
302 last_value=tuples[i][a];
303 } else if (last_value+1 < tuples[i][a]) {
304 n_vals64++; n_ranges64++;
305 last_value=tuples[i][a];
306 } else {
307 assert(last_value == tuples[i][a]);
308 }
309 }
310 }
311 }
312 const unsigned long long max_u64 =
313 std::numeric_limits<unsigned long long>::max();
314 const bool support_entries_overflow =
315 (n_words != 0U) &&
316 (n_vals64 > max_u64 / static_cast<unsigned long long>(n_words));
317 const unsigned long long n_support_entries64 =
318 support_entries_overflow ? max_u64 :
319 static_cast<unsigned long long>(n_words) * n_vals64;
320 const unsigned long long n_tcells64 =
321 static_cast<unsigned long long>(n_tuples) *
322 static_cast<unsigned long long>(arity);
323 const unsigned long long sparse_support_cells_per_entry =
324 static_cast<unsigned long long>(BitSetData::bpb / 4U);
325 const bool support_bits_sparse =
326 support_entries_overflow ||
327 (n_support_entries64 > max_u64 / sparse_support_cells_per_entry) ||
328 (n_tcells64 <=
329 n_support_entries64 * sparse_support_cells_per_entry);
330 const bool dense_possible = !support_entries_overflow &&
331 (n_support_entries64 <= static_cast<unsigned long long>
332 (std::numeric_limits<unsigned int>::max()));
333 unsigned int n_offsets = 0U;
334 const bool support_offsets_possible =
335 support_offsets_size(n_vals64,n_offsets);
336 const bool sparse_possible =
337 (n_tcells64 <=
338 static_cast<unsigned long long>(std::numeric_limits<unsigned int>::max())) &&
339 support_offsets_possible;
340 const bool compressed_possible = sparse_possible;
341 const unsigned long long dense_bytes =
342 (support_entries_overflow ||
343 (n_support_entries64 > max_u64 / sizeof(BitSetData))) ? max_u64 :
344 n_support_entries64 * static_cast<unsigned long long>(sizeof(BitSetData));
345
346 // AUTO keeps small or genuinely dense payloads dense. Larger sparse
347 // support matrices use the shared compressed representation; the sparse
348 // representation is selected only when explicitly requested.
349 selected = select_state(epk,dense_possible,sparse_possible,
350 compressed_possible,support_bits_sparse,
351 dense_bytes);
352 const bool build_dense = (selected == TS_DENSE);
353 const bool build_sparse = (selected == TS_SPARSE);
354 const bool build_compressed = (selected == TS_DENSE_COMPRESSED);
355 if ((n_vals64 > static_cast<unsigned long long>
356 (std::numeric_limits<unsigned int>::max())) ||
357 (n_ranges64 > static_cast<unsigned long long>
358 (std::numeric_limits<unsigned int>::max())))
359 throw Int::OutOfLimits("TupleSet::finalize()");
360 const unsigned int n_vals = static_cast<unsigned int>(n_vals64);
361 const unsigned int n_ranges = static_cast<unsigned int>(n_ranges64);
362 /*
363 * Pass 2: allocate memory and fill data structures
364 */
365 // Allocate memory for ranges
366 Range* range_cursor = range = heap.alloc<Range>(n_ranges);
367 // Allocate and initialize memory for support data.
368 support = nullptr;
369 sparse_n_vals = 0U;
370 sparse_offsets = nullptr;
371 sparse_tuples = nullptr;
372 sparse_tv = nullptr;
373 compressed_offsets = nullptr;
374 compressed_words = nullptr;
376 BitSetData* support_cursor = nullptr;
377 unsigned int n_support_entries_u32 = 0U;
378 if (build_dense) {
379 assert((n_words == 0U) ||
380 (n_vals <= std::numeric_limits<unsigned int>::max() / n_words));
381 n_support_entries_u32 = n_words * n_vals;
382 support_cursor = support = heap.alloc<BitSetData>(n_support_entries_u32);
383 for (unsigned int i=0; i<n_support_entries_u32; i++)
384 support_cursor[i].init();
385 }
386 for (int a=0; a<arity; a++) {
387 // Set range pointer
388 vd[a].r = range_cursor;
389 vd[a].base = nullptr;
390 // Sort tuple according to position
391 PosCompare pc(a);
393 // Update min and max
394 min = std::min(min,tuples[0][a]);
395 max = std::max(max,tuples[n_tuples-1][a]);
396 // Compress into non-overlapping ranges
397 {
398 unsigned int j=0U;
399 vd[a].r[0].max=vd[a].r[0].min=tuples[0][a];
400 for (int i=1; i<n_tuples; i++) {
401 assert(tuples[i-1][a] <= tuples[i][a]);
402 if (vd[a].r[j].max+1 == tuples[i][a]) {
403 vd[a].r[j].max=tuples[i][a];
404 } else if (vd[a].r[j].max+1 < tuples[i][a]) {
405 j++; vd[a].r[j].min=vd[a].r[j].max=tuples[i][a];
406 } else {
407 assert(vd[a].r[j].max == tuples[i][a]);
408 }
409 }
410 vd[a].n = j+1U;
411 range_cursor += j+1U;
412 }
413 // Set support pointer and set bits
414 for (unsigned int i=0U; i<vd[a].n; i++) {
415 vd[a].r[i].s = support_cursor;
416 if (build_dense)
417 support_cursor += n_words * vd[a].r[i].width();
418 }
419 if (build_dense) {
420 int j=0;
421 for (int i=0; i<n_tuples; i++) {
422 while (tuples[i][a] > vd[a].r[j].max)
423 j++;
424 set(const_cast<BitSetData*>
425 (vd[a].r[j].supports(n_words,tuples[i][a])),
426 tuple2idx(tuples[i]));
427 }
428 }
429 }
430 if (build_sparse || build_compressed) {
431 assert(support_offsets_possible);
432 assert(n_tcells64 <=
433 static_cast<unsigned long long>
434 (std::numeric_limits<unsigned int>::max()));
435 const unsigned int n_tcells = static_cast<unsigned int>(n_tcells64);
436 range_base = (n_ranges > 0U) ?
437 heap.alloc<unsigned int>(n_ranges) : nullptr;
438 unsigned int* base_cursor = range_base;
439 unsigned int first_support_id = 0U;
440 for (int a=0; a<arity; a++) {
441 vd[a].base = base_cursor;
442 for (unsigned int i=0U; i<vd[a].n; i++) {
443 vd[a].base[i] = first_support_id;
444 first_support_id += vd[a].r[i].width();
445 }
446 base_cursor += vd[a].n;
447 }
448 assert(first_support_id == n_vals);
449 assert((n_ranges == 0U) ||
450 (base_cursor == range_base + n_ranges));
451
452 unsigned int* support_offsets;
453 if (build_sparse) {
454 sparse_n_vals = n_vals;
455 sparse_offsets = heap.alloc<unsigned int>(n_offsets);
456 sparse_tv = (n_tcells > 0U) ?
457 heap.alloc<unsigned int>(n_tcells) : nullptr;
458 support_offsets = sparse_offsets;
459 } else {
460 support_offsets = region.alloc<unsigned int>(n_offsets);
461 }
462 for (unsigned int i=0U; i<n_offsets; i++)
463 support_offsets[i] = 0U;
464 for (unsigned int tid=0U;
465 tid<static_cast<unsigned int>(n_tuples); tid++) {
466 const Tuple t = td + tid*arity;
467 for (int a=0; a<arity; a++) {
468 const unsigned int range_index = vd[a].start(t[a]);
469 const unsigned int support_id =
470 vd[a].base[range_index] +
471 static_cast<unsigned int>
472 (t[a] - vd[a].r[range_index].min);
473 if (build_sparse)
474 sparse_tv[tid*arity+a] = support_id;
475 support_offsets[support_id+1U]++;
476 }
477 }
478
479 for (unsigned int i=1U; i<n_offsets; i++)
480 support_offsets[i] += support_offsets[i-1U];
481
482 if (build_sparse) {
483 sparse_tuples = (n_tcells > 0U) ?
484 heap.alloc<unsigned int>(n_tcells) : nullptr;
485 unsigned int* next_support = (n_vals > 0U) ?
486 region.alloc<unsigned int>(n_vals) : nullptr;
487 for (unsigned int i=0U; i<n_vals; i++)
488 next_support[i] = sparse_offsets[i];
489 for (unsigned int tid=0U;
490 tid<static_cast<unsigned int>(n_tuples); tid++) {
491 for (int a=0; a<arity; a++) {
492 const unsigned int support_id = sparse_tv[tid*arity+a];
493 sparse_tuples[next_support[support_id]++] = tid;
494 }
495 }
496 } else {
497 unsigned int* tuples_by_support = (n_tcells > 0U) ?
498 region.alloc<unsigned int>(n_tcells) : nullptr;
499 unsigned int* next_support = (n_vals > 0U) ?
500 region.alloc<unsigned int>(n_vals) : nullptr;
501 for (unsigned int i=0U; i<n_vals; i++)
502 next_support[i] = support_offsets[i];
503 // Tuple ids are visited in increasing order, so each support list
504 // is already sorted by tuple id (and hence by word index).
505 for (unsigned int tid=0U;
506 tid<static_cast<unsigned int>(n_tuples); tid++) {
507 const Tuple t = td + tid*arity;
508 for (int a=0; a<arity; a++) {
509 const unsigned int range_index = vd[a].start(t[a]);
510 const unsigned int support_id =
511 vd[a].base[range_index] +
512 static_cast<unsigned int>
513 (t[a] - vd[a].r[range_index].min);
514 tuples_by_support[next_support[support_id]++] = tid;
515 }
516 }
517
518 compressed_offsets = heap.alloc<unsigned int>(n_offsets);
519 compressed_offsets[0] = 0U;
520 unsigned long long entries64 = 0ULL;
521 for (unsigned int gid=0U; gid<n_vals; gid++) {
522 unsigned int count = 0U;
523 unsigned int last_widx = std::numeric_limits<unsigned int>::max();
524 for (unsigned int p=support_offsets[gid];
525 p<support_offsets[gid+1U]; p++) {
526 const unsigned int tid = tuples_by_support[p];
527 const unsigned int widx = tid / BitSetData::bpb;
528 if (widx != last_widx) {
529 count++;
530 last_widx = widx;
531 }
532 }
533 entries64 += static_cast<unsigned long long>(count);
534 if (entries64 >
535 static_cast<unsigned long long>(std::numeric_limits<unsigned int>::max()))
536 throw Int::OutOfLimits("TupleSet::finalize()");
537 compressed_offsets[gid+1U] = static_cast<unsigned int>(entries64);
538 }
539 compressed_n_entries = static_cast<unsigned int>(entries64);
541 heap.alloc<CSupportWord>(compressed_n_entries) : nullptr;
542
543 unsigned int out = 0U;
544 for (unsigned int gid=0U; gid<n_vals; gid++) {
545 unsigned int current_widx = std::numeric_limits<unsigned int>::max();
546 BitSetData bits;
547 bits.init(false);
548 const unsigned int begin = support_offsets[gid];
549 const unsigned int end = support_offsets[gid+1U];
550 for (unsigned int p=begin; p<end; p++) {
551 const unsigned int tid = tuples_by_support[p];
552 const unsigned int widx = tid / BitSetData::bpb;
553 if (widx != current_widx) {
554 if (current_widx != std::numeric_limits<unsigned int>::max()) {
555 compressed_words[out].widx = current_widx;
556 compressed_words[out].bits = bits;
557 out++;
558 }
559 current_widx = widx;
560 bits.init(false);
561 }
562 bits.set(tid % BitSetData::bpb);
563 }
564 if (current_widx != std::numeric_limits<unsigned int>::max()) {
565 compressed_words[out].widx = current_widx;
566 compressed_words[out].bits = bits;
567 out++;
568 }
569 assert(out == compressed_offsets[gid+1U]);
570 }
571 assert(out == compressed_n_entries);
572 }
573 }
574 if (build_dense)
575 assert(support_cursor == support + n_support_entries_u32);
576 assert(range_cursor == range + n_ranges);
577 }
579 throw Int::OutOfLimits("TupleSet::finalize()");
580 guard.commit(selected);
581 assert(finalized());
582 }
583
584 void
586 assert(n_free == 0);
587 int n = static_cast<int>(1+n_tuples*1.5);
588 td = heap.realloc<int>(td, n_tuples * arity, n * arity);
589 n_free = n - n_tuples;
590 }
591
594 heap.rfree(td);
595 heap.rfree(vd);
596 }
597
598
599 /*
600 * Tuple set
601 *
602 */
604 : SharedHandle(new Data(a)) {}
605 void
607 object(new Data(a));
608 }
610 : SharedHandle(ts) {}
611 TupleSet&
613 (void) SharedHandle::operator =(ts);
614 return *this;
615 }
616
618 : TupleSet(a,dfa,EPK_DENSE) {}
619
623 struct Edge {
624 int i_state;
625 int o_state;
626 };
628 struct State {
629 int i_deg;
630 int o_deg;
631 int n_tuples;
632 int* tuples;
633 };
635 struct Support {
636 int val;
637 int n_edges;
638 Edge* edges;
639 };
641 struct Layer {
642 State* states;
643 Support* supports;
644 int n_supports;
645 };
646 // Initialize
647 object(new Data(a));
648
649 Region r;
650 // Number of states
651 int max_states = dfa.n_states();
652 // Allocate memory for all layers and states
653 Layer* layers = r.alloc<Layer>(a+1);
654 State* states = r.alloc<State>(max_states*(a+1));
655
656 for (int i=0; i<max_states*(a+1); i++) {
657 states[i].i_deg = 0; states[i].o_deg = 0;
658 states[i].n_tuples = 0;
659 states[i].tuples = nullptr;
660 }
661 for (int i=0; i<a+1; i++) {
662 layers[i].states = states + i*max_states;
663 layers[i].n_supports = 0;
664 }
665
666 // Mark initial state as being reachable
667 layers[0].states[0].i_deg = 1;
668 layers[0].states[0].n_tuples = 1;
669 layers[0].states[0].tuples = r.alloc<int>(1);
670 assert(layers[0].states[0].tuples != nullptr);
671
672 // Allocate temporary memory for edges and supports
673 Edge* edges = r.alloc<Edge>(dfa.max_degree());
674 Support* supports = r.alloc<Support>(dfa.n_symbols());
675
676 // Forward pass: accumulate
677 for (int i=0; i<a; i++) {
678 int n_supports=0;
679 for (DFA::Symbols s(dfa); s(); ++s) {
680 int n_edges=0;
681 for (DFA::Transitions t(dfa,s.val()); t(); ++t) {
682 if (layers[i].states[t.i_state()].i_deg != 0) {
683 // Create edge
684 edges[n_edges].i_state = t.i_state();
685 edges[n_edges].o_state = t.o_state();
686 n_edges++;
687 // Adjust degrees
688 layers[i].states[t.i_state()].o_deg++;
689 layers[i+1].states[t.o_state()].i_deg++;
690 // Adjust number of tuples
691 layers[i+1].states[t.o_state()].n_tuples
692 += layers[i].states[t.i_state()].n_tuples;
693 }
694 assert(static_cast<unsigned int>(n_edges) <= dfa.max_degree());
695 }
696 // Found a support for the value
697 if (n_edges > 0) {
698 Support& support = supports[n_supports++];
699 support.val = s.val();
700 support.n_edges = n_edges;
701 support.edges = Heap::copy(r.alloc<Edge>(n_edges),edges,n_edges);
702 }
703 }
704 // Create supports
705 if (n_supports > 0) {
706 layers[i].supports =
707 Heap::copy(r.alloc<Support>(n_supports),supports,n_supports);
708 layers[i].n_supports = n_supports;
709 } else {
710 finalize(epk);
711 return;
712 }
713 }
714
715 // Mark final states as being reachable
716 for (int s=dfa.final_fst(); s<dfa.final_lst(); s++) {
717 if (layers[a].states[s].i_deg != 0U)
718 layers[a].states[s].o_deg = 1U;
719 }
720
721 // Backward pass: validate
722 for (int i=a; i--; ) {
723 for (int j = layers[i].n_supports; j--; ) {
724 Support& s = layers[i].supports[j];
725 for (int k = s.n_edges; k--; ) {
726 int i_state = s.edges[k].i_state;
727 int o_state = s.edges[k].o_state;
728 // State is unreachable
729 if (layers[i+1].states[o_state].o_deg == 0) {
730 // Adjust degree
731 --layers[i+1].states[o_state].i_deg;
732 --layers[i].states[i_state].o_deg;
733 // Remove edge
734 assert(s.n_edges > 0);
735 s.edges[k] = s.edges[--s.n_edges];
736 }
737 }
738 // Lost support
739 if (s.n_edges == 0)
740 layers[i].supports[j] = layers[i].supports[--layers[i].n_supports];
741 }
742 if (layers[i].n_supports == 0U) {
743 finalize(epk);
744 return;
745 }
746 }
747
748 // Generate tuples
749 for (int i=0; i<a; i++) {
750 for (int j = layers[i].n_supports; j--; ) {
751 Support& s = layers[i].supports[j];
752 for (int k = s.n_edges; k--; ) {
753 int i_state = s.edges[k].i_state;
754 int o_state = s.edges[k].o_state;
755 // Allocate memory for tuples if not done
756 if (layers[i+1].states[o_state].tuples == nullptr) {
757 int n_tuples = layers[i+1].states[o_state].n_tuples;
758 layers[i+1].states[o_state].tuples = r.alloc<int>((i+1)*n_tuples);
759 layers[i+1].states[o_state].n_tuples = 0;
760 }
761 int n = layers[i+1].states[o_state].n_tuples;
762 // Write tuples
763 for (int t=0; t < layers[i].states[i_state].n_tuples; t++) {
764 // Copy the first i number of digits from the previous layer
765 Heap::copy(&layers[i+1].states[o_state].tuples[n*(i+1)+t*(i+1)],
766 &layers[i].states[i_state].tuples[t*i], i);
767 // Write the last digit
768 layers[i+1].states[o_state].tuples[n*(i+1)+t*(i+1)+i] = s.val;
769 }
770 layers[i+1].states[o_state].n_tuples
771 += layers[i].states[i_state].n_tuples;
772 }
773 }
774 }
775
776 // Add tuples to tuple set
777 for (int s = dfa.final_fst(); s < dfa.final_lst(); s++) {
778 for (int i=0; i<layers[a].states[s].n_tuples; i++) {
779 int* tuple = &layers[a].states[s].tuples[i*a];
780 add(IntArgs(a,tuple));
781 }
782 }
783
784 finalize(epk);
785 }
786
787 bool
788 TupleSet::equal(const TupleSet& t) const {
789 assert(tuples() == t.tuples());
790 assert(arity() == t.arity());
791 assert(min() == t.min());
792 assert(max() == t.max());
793 for (int i=0; i<tuples(); i++)
794 for (int j=0; j<arity(); j++)
795 if ((*this)[i][j] != t[i][j])
796 return false;
797 return true;
798 }
799
800 void
802 if (!*this)
803 throw Int::UninitializedTupleSet("TupleSet::add()");
804 if (raw().terminal())
805 throw Int::AlreadyFinalized("TupleSet::add()");
806 if (t.size() != raw().arity)
807 throw Int::ArgumentSizeMismatch("TupleSet::add()");
808 Tuple a = raw().add();
809 for (int i=0; i<t.size(); i++)
810 a[i]=t[i];
811 }
812
813}
814
815// STATISTICS: int-prop
int size(void) const
Return size of array (number of elements).
Definition array.hpp:1597
Iterator for DFA symbols.
Definition int.hh:2246
Iterator for DFA transitions (sorted by symbols).
Definition int.hh:2223
Deterministic finite automaton (DFA).
Definition int.hh:2203
unsigned int max_degree(void) const
Return maximal degree (in-degree and out-degree) of any state.
Definition dfa.hpp:157
int n_states(void) const
Return the number of states.
Definition dfa.hpp:139
int final_lst(void) const
Return the number of the last final state.
Definition dfa.hpp:169
unsigned int n_symbols(void) const
Return the number of symbols.
Definition dfa.hpp:145
int final_fst(void) const
Return the number of the first final state.
Definition dfa.hpp:163
static T * copy(T *d, const T *s, long unsigned int n)
Copy n objects starting at s to d.
Definition heap.hpp:593
Passing integer arguments.
Definition int.hh:652
int min(int i) const
Return minimum of range at position i.
int max(int i) const
Return maximum of range at position i.
Exception: Tuple set already finalized
Exception: Arguments are of different size
Definition exception.hpp:73
PosCompare(int p)
Initialize with position p.
Definition tuple-set.cpp:87
bool operator()(const Tuple &a, const Tuple &b)
Comparison of tuples a and b.
Definition tuple-set.cpp:90
TupleCompare(int a)
Initialize with arity a.
Definition tuple-set.cpp:73
bool operator()(const Tuple &a, const Tuple &b)
Comparison of tuples a and b.
Definition tuple-set.cpp:76
Exception: Value out of limits
Definition exception.hpp:44
Exception: uninitialized tuple set
Handle to region.
Definition region.hpp:55
T * alloc(long unsigned int n)
Allocate block of n objects of type T from region.
Definition region.hpp:386
SharedHandle(void)
Create shared handle with no object pointing to.
SharedHandle::Object * object(void) const
Access to the shared object.
static const unsigned int bpb
Bits per base.
void init(bool setbits=false)
Initialize with all bits set if setbits.
static unsigned int data(unsigned int s)
Get number of data elements for s bits.
void set(unsigned int i)
Set bit i.
Compressed support data for one tuple-word block.
Definition int.hh:2393
Data stored for a Table.
Definition int.hh:2434
int max
Largest value.
Definition int.hh:2459
void clear_support(void)
Release partially or fully constructed support data.
unsigned int compressed_n_entries
Number of compressed support entries.
Definition int.hh:2487
int n_free
Number of free tuple entries of arity.
Definition int.hh:2455
bool terminal(void) const
Is datastructure no longer mutable.
Definition tuple-set.hpp:93
unsigned int * sparse_tuples
Sparse support tuple ids (size arity*n_tuples).
Definition int.hh:2479
void resize(void)
Resize tuple data.
BitSetData * support
Pointer to all support data.
Definition int.hh:2471
Data(int a)
Initialize as empty tuple set with arity a.
Definition tuple-set.hpp:66
unsigned int * compressed_offsets
Compressed support offsets (size n_vals+1).
Definition int.hh:2483
unsigned int n_words
Number of words for support.
Definition int.hh:2451
int min
Smallest value.
Definition int.hh:2457
State empty_state(ExtensionalPropKind epk) const
Select the state for an empty finalized tuple set.
static void set(BitSetData *d, unsigned int n)
Set bit n in bitset data d.
virtual ~Data(void)
Delete implementation.
unsigned int * sparse_offsets
Sparse support offsets (size sparse_n_vals+1).
Definition int.hh:2477
void finalize(void)
Finalize datastructure (disallows additions of more Tuples).
int n_tuples
Number of Tuples.
Definition int.hh:2453
unsigned int sparse_n_vals
Number of sparse support values.
Definition int.hh:2475
unsigned int * sparse_tv
Tuple cell to sparse support id map (size arity*n_tuples).
Definition int.hh:2481
int * td
Tuple data.
Definition int.hh:2463
State state
Tuple set lifecycle state and finalized representation.
Definition int.hh:2473
CSupportWord * compressed_words
Compressed support words (size compressed_n_entries).
Definition int.hh:2485
unsigned int tuple2idx(Tuple t) const
Map tuple address to index.
State
Tuple set lifecycle state and finalized representation.
Definition int.hh:2440
Range * range
Pointer to all ranges.
Definition int.hh:2467
State select_state(ExtensionalPropKind epk, bool dense_possible, bool sparse_possible, bool compressed_possible, bool support_bits_sparse, unsigned long long dense_bytes) const
Select the finalized state for the computed table layout.
ValueData * vd
Value data.
Definition int.hh:2465
std::size_t key
Hash key.
Definition int.hh:2461
Tuple add(void)
Return newly added tuple.
Definition tuple-set.hpp:98
unsigned int * range_base
Pointer to all range support ids.
Definition int.hh:2469
Range information.
Definition int.hh:2399
Class representing a set of tuples.
Definition int.hh:2382
TupleSet(void)
Construct an uninitialized tuple set.
void _add(const IntArgs &t)
Add tuple t to tuple set.
int tuples(void) const
Number of tuples.
int max(void) const
Return maximal value in all tuples.
bool finalized(void) const
Is tuple set successfully finalized.
TupleSet & add(const IntArgs &t)
Add tuple t to tuple set.
TupleSet & operator=(const TupleSet &t)
Assignment operator.
int * Tuple
Type of a tuple.
Definition int.hh:2389
void finalize(void)
Finalize tuple set with dense support data.
bool equal(const TupleSet &t) const
Test whether tuple set is equal to t.
int min(void) const
Return minimal value in all tuples.
Data & raw(void) const
Get raw data (must be initialized).
Gecode::Support::BitSetData BitSetData
Import bit set data type.
Definition int.hh:2391
void init(int a)
Initialize an uninitialized tuple set.
int arity(void) const
Arity of tuple set.
Heap heap
The single global heap.
Definition heap.cpp:44
ExtensionalPropKind
Support representation selection for extensional tuple sets.
Definition int.hh:2355
Extensional propagators
Definition int.hh:2335
TupleSet::Tuple Tuple
Tuple type.
const int min
Smallest allowed integer value.
Definition int.hh:122
bool valid(int n)
Return whether n is in range.
Definition limits.hpp:37
const int max
Largest allowed integer value.
Definition int.hh:120
Finite domain integers.
Definition lastval.hh:52
Support algorithms and datastructures
void quicksort(Type *l, Type *r, Less &less)
Standard quick sort.
Definition sort.hpp:130
Gecode toplevel namespace
void count(Home home, const IntVarArgs &x, int n, IntRelType irt, int m, IntPropLevel ipl=IPL_DEF)
Post propagator for .
Definition count.cpp:40
void cmb_hash(std::size_t &seed, const T h)
Combine hash value h into seed.
Definition hash.hpp:44
bool same(VarArgArray< Var > x, VarArgArray< Var > y)
Definition array.hpp:1927
#define forceinline
Definition config.hpp:141
#define GECODE_NEVER
Assert that this command is never executed.
Definition macros.hpp:56