1 /*
2 * This file is part of the Yices SMT Solver.
3 * Copyright (C) 2017 SRI International.
4 *
5 * Yices is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * Yices is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Yices. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /*
20 * Abstract objects used by the array solver to construct models.
21 * - an array variable is modeled as a mapping from [tau1 ... tau_n -> sigma]
22 * - tau_1 ... tau_n and sigma are types defined in the global type table
23 *
24 * An array A is specified via a finite number of mappings
25 * [x_11 ... x_1n -> y_1]
26 * ...
27 * [x_m1 ... x_mn -> y_m]
28 * + a default value y_0
29 * The tuples (x_i1, ..., x_in) are pairwise distinct.
30 * This means
31 * A[x_i1 ... x_in] = y_i for (i=1, ..., m)
32 * A[i_1, ..., i_n] = y_0 for all other input
33 *
34 * This module provides support for building the objects x_ij and y_k,
35 * and for representing the arrays and mappings. Each atomic element
36 * - x_ij or y_k is either an egraph class or a fresh constant of some type tau
37 * created by the solver.
38 * - the egraph can later convert the abstract values into concrete objects.
39 */
40
41 #include <stdbool.h>
42
43 #include "model/abstract_values.h"
44 #include "utils/hash_functions.h"
45 #include "utils/memalloc.h"
46 #include "utils/prng.h"
47
48
49
50
51 /********************
52 * PARTICLE TABLE *
53 *******************/
54
55 /*
56 * Initialization: use default size
57 */
init_particle_table(particle_table_t * table)58 static void init_particle_table(particle_table_t *table) {
59 uint32_t n;
60
61 n = DEF_PARTICLE_TABLE_SIZE;
62 assert(n < MAX_PARTICLE_TABLE_SIZE);
63
64 table->size = n;
65 table->nobjects = 0;
66 table->kind = (uint8_t *) safe_malloc(n * sizeof(uint8_t));
67 table->desc = (particle_desc_t *) safe_malloc(n * sizeof(particle_desc_t));
68 table->concrete = (value_t *) safe_malloc(n * sizeof(value_t));
69 table->mark = allocate_bitvector(n);
70
71 init_int_htbl(&table->htbl, 0);
72 }
73
74
75 /*
76 * Make the table larger
77 */
extend_particle_table(particle_table_t * table)78 static void extend_particle_table(particle_table_t *table) {
79 uint32_t n;
80
81 n = table->size + 1;
82 n += n>>1;
83 if (n >= MAX_PARTICLE_TABLE_SIZE) {
84 out_of_memory();
85 }
86
87 table->size = n;
88 table->kind = (uint8_t *) safe_realloc(table->kind, n * sizeof(uint8_t));
89 table->desc = (particle_desc_t *) safe_realloc(table->desc, n * sizeof(particle_desc_t));
90 table->concrete = (value_t *) safe_realloc(table->concrete, n * sizeof(value_t));
91 table->mark = extend_bitvector(table->mark, n);
92 }
93
94
95 /*
96 * Allocate a new index
97 */
allocate_particle(particle_table_t * table)98 static particle_t allocate_particle(particle_table_t *table) {
99 particle_t i;
100
101 i = table->nobjects;
102 if (i == table->size) {
103 extend_particle_table(table);
104 }
105 assert(i < table->size);
106 table->nobjects = i+1;
107
108 return i;
109 }
110
111
112 /*
113 * Delete all descriptors
114 */
particle_table_delete_descriptors(particle_table_t * table)115 static void particle_table_delete_descriptors(particle_table_t *table) {
116 uint32_t i, n;
117
118 n = table->nobjects;
119 for (i=0; i<n; i++) {
120 if (table->kind[i] == TUPLE_PARTICLE) {
121 safe_free(table->desc[i].ptr);
122 }
123 }
124 }
125
126
127 /*
128 * Delete the table
129 */
delete_particle_table(particle_table_t * table)130 static void delete_particle_table(particle_table_t *table) {
131 particle_table_delete_descriptors(table);
132 safe_free(table->kind);
133 safe_free(table->desc);
134 safe_free(table->concrete);
135 delete_bitvector(table->mark);
136 delete_int_htbl(&table->htbl);
137
138 table->kind = NULL;
139 table->desc = NULL;
140 table->concrete = NULL;
141 table->mark = NULL;
142 }
143
144
145
146 /*
147 * PARTICLE CONSTRUCTORS
148 */
149
150 /*
151 * Create a fresh particle of type tau
152 */
mk_fresh_particle(particle_table_t * table,type_t tau)153 static particle_t mk_fresh_particle(particle_table_t *table, type_t tau) {
154 particle_t i;
155
156 i = allocate_particle(table);
157 table->kind[i] = FRESH_PARTICLE;
158 table->desc[i].integer = tau;
159 table->concrete[i] = null_value;
160 clr_bit(table->mark, i);
161
162 return i;
163 }
164
165
166 /*
167 * Create particle for label l
168 */
mk_label_particle(particle_table_t * table,elabel_t l)169 static particle_t mk_label_particle(particle_table_t *table, elabel_t l) {
170 particle_t i;
171
172 i = allocate_particle(table);
173 table->kind[i] = LABEL_PARTICLE;
174 table->desc[i].integer = l;
175 table->concrete[i] = null_value;
176 clr_bit(table->mark, i);
177
178 return i;
179 }
180
181
182 /*
183 * Create particle for tuple a[0 ... n-1]
184 */
mk_tuple_particle(particle_table_t * table,uint32_t n,particle_t * a)185 static particle_t mk_tuple_particle(particle_table_t *table, uint32_t n, particle_t *a) {
186 particle_tuple_t *d;
187 particle_t i;
188 uint32_t j;
189
190 assert(n < MAX_PARTICLE_TUPLE_ARITY);
191
192 d = (particle_tuple_t *) safe_malloc(sizeof(particle_tuple_t) + n * sizeof(particle_t));
193 d->nelems = n;
194 for (j=0; j<n; j++) {
195 d->elem[j] = a[j];
196 }
197
198 i = allocate_particle(table);
199 table->kind[i] = TUPLE_PARTICLE;
200 table->desc[i].ptr = d;
201 table->concrete[i] = null_value;
202 clr_bit(table->mark, i);
203
204 return i;
205 }
206
207
208 /*
209 * HASH CONSING
210 */
211
212 /*
213 * Hash consing is used for tuples and labels
214 */
215 typedef struct label_hobj_s {
216 int_hobj_t m;
217 particle_table_t *table;
218 elabel_t label;
219 } label_hobj_t;
220
221 typedef struct tuple_hobj_s {
222 int_hobj_t m;
223 particle_table_t *table;
224 uint32_t nelems;
225 particle_t *elem;
226 } tuple_hobj_t;
227
228
229 /*
230 * Hash functions
231 */
hash_label(label_hobj_t * o)232 static uint32_t hash_label(label_hobj_t *o) {
233 return jenkins_hash_int32(o->label);
234 }
235
hash_tuple(tuple_hobj_t * o)236 static uint32_t hash_tuple(tuple_hobj_t *o) {
237 return jenkins_hash_intarray(o->elem, o->nelems);
238 }
239
240
241 /*
242 * Test equality
243 */
equal_label_particle(label_hobj_t * o,particle_t i)244 static bool equal_label_particle(label_hobj_t *o, particle_t i) {
245 particle_table_t *table;
246
247 table = o->table;
248 return table->kind[i] == LABEL_PARTICLE && table->desc[i].integer == o->label;
249 }
250
equal_tuple_particle(tuple_hobj_t * o,particle_t i)251 static bool equal_tuple_particle(tuple_hobj_t *o, particle_t i) {
252 particle_table_t *table;
253 particle_tuple_t *d;
254 uint32_t j, n;
255
256 table = o->table;
257 if (table->kind[i] != TUPLE_PARTICLE) {
258 return false;
259 }
260
261 d = (particle_tuple_t *) table->desc[i].ptr;
262 n = d->nelems;
263 if (n != o->nelems) {
264 return false;
265 }
266
267 for (j=0; j<n; j++) {
268 if (d->elem[j] != o->elem[j]) {
269 return false;
270 }
271 }
272
273 return true;
274 }
275
276
277 /*
278 * Constructors
279 */
build_label_particle(label_hobj_t * o)280 static particle_t build_label_particle(label_hobj_t *o) {
281 return mk_label_particle(o->table, o->label);
282 }
283
build_tuple_particle(tuple_hobj_t * o)284 static particle_t build_tuple_particle(tuple_hobj_t *o) {
285 return mk_tuple_particle(o->table, o->nelems, o->elem);
286 }
287
288
289 /*
290 * Hash consing
291 */
get_label_particle(particle_table_t * table,elabel_t l)292 static particle_t get_label_particle(particle_table_t *table, elabel_t l) {
293 label_hobj_t label_hobj;
294
295 label_hobj.m.hash = (hobj_hash_t) hash_label;
296 label_hobj.m.eq = (hobj_eq_t) equal_label_particle;
297 label_hobj.m.build = (hobj_build_t) build_label_particle;
298 label_hobj.table = table;
299 label_hobj.label = l;
300
301 return int_htbl_get_obj(&table->htbl, (int_hobj_t *) &label_hobj);
302 }
303
get_tuple_particle(particle_table_t * table,uint32_t n,particle_t * a)304 static particle_t get_tuple_particle(particle_table_t *table, uint32_t n, particle_t *a) {
305 tuple_hobj_t tuple_hobj;
306
307 tuple_hobj.m.hash = (hobj_hash_t) hash_tuple;
308 tuple_hobj.m.eq = (hobj_eq_t) equal_tuple_particle;
309 tuple_hobj.m.build = (hobj_build_t) build_tuple_particle ;
310 tuple_hobj.table = table;
311 tuple_hobj.nelems = n;
312 tuple_hobj.elem = a;
313
314 return int_htbl_get_obj(&table->htbl, (int_hobj_t*) &tuple_hobj);
315 }
316
317
318
319
320
321
322
323 /***********************
324 * SETS OF PARTICLES *
325 **********************/
326
327 /*
328 * Allocate and initialize a set (use default size)
329 * - n = arity
330 * - tau[0, ..., n-1] = types for that set
331 */
new_particle_set(uint32_t n,type_t * tau)332 static particle_set_t *new_particle_set(uint32_t n, type_t *tau) {
333 particle_set_t *set;
334 uint32_t i;
335
336 assert(DEF_PSET_SIZE < MAX_PSET_SIZE && n < MAX_PARTICLE_TUPLE_ARITY && n > 0);
337
338 set = (particle_set_t *) safe_malloc(sizeof(particle_set_t) + n * sizeof(type_t));
339 set->size = DEF_PSET_SIZE;
340 set->nelems = 0;
341 set->data = (particle_t *) safe_malloc(DEF_PSET_SIZE * sizeof(particle_t));
342 set->arity = n;
343
344 for (i=0; i<n; i++) {
345 set->type[i] = tau[i];
346 }
347
348 return set;
349 }
350
351
352 /*
353 * Special case: arity 1
354 */
new_particle_set1(type_t tau)355 static inline particle_set_t *new_particle_set1(type_t tau) {
356 return new_particle_set(1, &tau);
357 }
358
359
360 /*
361 * Delete set
362 */
free_particle_set(particle_set_t * set)363 static void free_particle_set(particle_set_t *set) {
364 safe_free(set->data);
365 safe_free(set);
366 }
367
368
369 /*
370 * Make the data vector larger
371 */
extend_particle_set(particle_set_t * set)372 static void extend_particle_set(particle_set_t *set) {
373 uint32_t n;
374
375 n = set->size + 1;
376 n += n>>1;
377 if (n >= MAX_PSET_SIZE) {
378 out_of_memory();
379 }
380 set->data = (particle_t *) safe_realloc(set->data, n * sizeof(particle_t));
381 set->size = n;
382 }
383
384
385 /*
386 * Add particle x at the end of set
387 */
add_particle_to_set(particle_set_t * set,particle_t x)388 static void add_particle_to_set(particle_set_t *set, particle_t x) {
389 uint32_t i;
390
391 i = set->nelems;
392 if (i == set->size) {
393 extend_particle_set(set);
394 }
395 assert(i < set->size);
396 set->data[i] = x;
397 set->nelems = i+1;
398 }
399
400
401
402 /*
403 * Check whether set matches types tau[0 ... n-1]
404 */
particle_set_matches_types(particle_set_t * set,uint32_t n,type_t * tau)405 static bool particle_set_matches_types(particle_set_t *set, uint32_t n, type_t *tau) {
406 uint32_t i;
407
408 if (set->arity != n) {
409 return false;
410 }
411
412 for (i=0; i<n; i++) {
413 if (set->type[i] != tau[i]) {
414 return false;
415 }
416 }
417 return true;
418 }
419
420
421 /*
422 * Special case: arity = 1
423 */
particle_set_matches_type(particle_set_t * set,type_t tau)424 static inline bool particle_set_matches_type(particle_set_t *set, type_t tau) {
425 return set->arity == 1 && set->type[0] == tau;
426 }
427
428
429
430
431
432
433
434
435 /*
436 * Initialize set table: use default size
437 */
init_pset_table(pset_table_t * table)438 static void init_pset_table(pset_table_t *table) {
439 uint32_t n;
440
441 n = DEF_PSET_TABLE_SIZE;
442 assert(n < MAX_PSET_TABLE_SIZE);
443 table->size = n;
444 table->nsets = 0;
445 table->set = (particle_set_t **) safe_malloc(n * sizeof(particle_set_t *));
446 }
447
448
449 /*
450 * Make the table larger
451 */
extend_pset_table(pset_table_t * table)452 static void extend_pset_table(pset_table_t *table) {
453 uint32_t n;
454
455 n = table->size + 1;
456 n += n >> 1;
457 if (n >= MAX_PSET_TABLE_SIZE) {
458 out_of_memory();
459 }
460
461 table->size = n;
462 table->set = (particle_set_t **) safe_realloc(table->set, n * sizeof(particle_set_t *));
463 }
464
465
466 /*
467 * Allocate a new element in the table
468 */
allocate_pset(pset_table_t * table)469 static uint32_t allocate_pset(pset_table_t *table) {
470 uint32_t i;
471
472 i = table->nsets;
473 if (i == table->size) {
474 extend_pset_table(table);
475 }
476 assert(i < table->size);
477 table->nsets = i + 1;
478
479 return i;
480 }
481
482
483
484
485 /*
486 * Delete the table
487 */
delete_pset_table(pset_table_t * table)488 static void delete_pset_table(pset_table_t *table) {
489 uint32_t i, n;
490
491 n = table->nsets;
492 for (i=0; i<n; i++) {
493 free_particle_set(table->set[i]);
494 }
495 safe_free(table->set);
496 table->set = NULL;
497 }
498
499
500 /*
501 * Search for a set that matches tau[0 .. n-1] in the table
502 * - return NULL if there's none
503 */
find_pset_for_types(pset_table_t * table,uint32_t n,type_t * tau)504 static particle_set_t *find_pset_for_types(pset_table_t *table, uint32_t n, type_t *tau) {
505 particle_set_t *set;
506 uint32_t i, m;
507
508 m = table->nsets;
509 for (i=0; i<m; i++) {
510 set = table->set[i];
511 assert(set != NULL);
512 if (particle_set_matches_types(set, n, tau)) {
513 return set;
514 }
515 }
516
517 return NULL;
518 }
519
520
521 /*
522 * Special case: arity 1
523 */
find_pset_for_type(pset_table_t * table,type_t tau)524 static particle_set_t *find_pset_for_type(pset_table_t *table, type_t tau) {
525 particle_set_t *set;
526 uint32_t i, m;
527
528 m = table->nsets;
529 for (i=0; i<m; i++) {
530 set = table->set[i];
531 assert(set != NULL);
532 if (particle_set_matches_type(set, tau)) {
533 return set;
534 }
535 }
536
537 return NULL;
538 }
539
540
541 /*
542 * Search for a set that matches tau[0 ... n-1]
543 * - create a new empty set if there's no match
544 */
get_pset_for_types(pset_table_t * table,uint32_t n,type_t * tau)545 static particle_set_t *get_pset_for_types(pset_table_t *table, uint32_t n, type_t *tau) {
546 particle_set_t *set;
547 uint32_t i, m;
548
549 m = table->nsets;
550 for (i=0; i<m; i++) {
551 set = table->set[i];
552 assert(set != NULL);
553 if (particle_set_matches_types(set, n, tau)) {
554 return set;
555 }
556 }
557
558 i = allocate_pset(table);
559 set = new_particle_set(n, tau);
560 table->set[i] = set;
561
562 return set;
563 }
564
565
566 /*
567 * Special case: arity 1
568 */
get_pset_for_type(pset_table_t * table,type_t tau)569 static particle_set_t *get_pset_for_type(pset_table_t *table, type_t tau) {
570 particle_set_t *set;
571 uint32_t i, m;
572
573 m = table->nsets;
574 for (i=0; i<m; i++) {
575 set = table->set[i];
576 assert(set != NULL);
577 if (particle_set_matches_type(set, tau)) {
578 return set;
579 }
580 }
581
582 i = allocate_pset(table);
583 set = new_particle_set1(tau);
584 table->set[i] = set;
585
586 return set;
587 }
588
589
590
591 /*
592 * Add particle i to the set for types tau[0 ... n-1]
593 * - create a new set if necessary
594 */
add_particle_to_types(pset_table_t * table,uint32_t n,type_t * tau,particle_t i)595 static void add_particle_to_types(pset_table_t *table, uint32_t n, type_t *tau, particle_t i) {
596 particle_set_t *set;
597
598 set = get_pset_for_types(table, n, tau);
599 add_particle_to_set(set, i);
600 }
601
602
603 // arity 1
add_particle_to_type(pset_table_t * table,type_t tau,particle_t i)604 static void add_particle_to_type(pset_table_t *table, type_t tau, particle_t i) {
605 particle_set_t *set;
606
607 set = get_pset_for_type(table, tau);
608 add_particle_to_set(set, i);
609 }
610
611
612
613
614
615 /******************
616 * GLOBAL STORE *
617 *****************/
618
619 /*
620 * Initialization
621 */
init_pstore(pstore_t * store,type_table_t * ttbl)622 void init_pstore(pstore_t *store, type_table_t *ttbl) {
623 store->types = ttbl;
624 init_particle_table(&store->ptbl);
625 init_pset_table(&store->psets);
626 store->rank_size = 0;
627 store->card_size = 0;
628 store->rank = NULL;
629 store->card = NULL;
630 store->aux = NULL;
631 }
632
633
634 /*
635 * Deletion
636 */
delete_pstore(pstore_t * store)637 void delete_pstore(pstore_t *store) {
638 delete_particle_table(&store->ptbl);
639 delete_pset_table(&store->psets);
640 safe_free(store->rank);
641 safe_free(store->card);
642 safe_free(store->aux);
643 store->rank = NULL;
644 }
645
646
647
648 /*
649 * Particle labeled by l of type tau
650 */
pstore_labeled_particle(pstore_t * store,elabel_t l,type_t tau)651 particle_t pstore_labeled_particle(pstore_t *store, elabel_t l, type_t tau) {
652 particle_t i;
653 uint32_t n;
654
655 n = store->ptbl.nobjects;
656 i = get_label_particle(&store->ptbl, l);
657 if (store->ptbl.nobjects > n) {
658 // i is a new particle
659 assert(store->ptbl.nobjects == n+1);
660 add_particle_to_type(&store->psets, tau, i);
661 }
662
663 return i;
664 }
665
666
667 /*
668 * Fresh particle of type tau
669 */
pstore_fresh_particle(pstore_t * store,type_t tau)670 particle_t pstore_fresh_particle(pstore_t *store, type_t tau) {
671 particle_t i;
672
673 i = mk_fresh_particle(&store->ptbl, tau);
674 add_particle_to_type(&store->psets, tau, i);
675
676 return i;
677 }
678
679
680 /*
681 * Tuple particle
682 */
pstore_tuple_particle(pstore_t * store,uint32_t n,particle_t * a,type_t * tau)683 particle_t pstore_tuple_particle(pstore_t *store, uint32_t n, particle_t *a, type_t *tau) {
684 particle_t i;
685 uint32_t m;
686
687 m = store->ptbl.nobjects;
688 i = get_tuple_particle(&store->ptbl, n, a);
689 if (store->ptbl.nobjects > m) {
690 // i is a new particle
691 assert(store->ptbl.nobjects == m+1);
692 add_particle_to_types(&store->psets, n, tau, i);
693 }
694
695 return i;
696 }
697
698
699 /*
700 * Get the particle set for type tau
701 * - return NULL if there are no particles of that type
702 */
pstore_find_set_for_type(pstore_t * store,type_t tau)703 particle_set_t *pstore_find_set_for_type(pstore_t *store, type_t tau) {
704 return find_pset_for_type(&store->psets, tau);
705 }
706
707
708
709 /*
710 * Get the particle set for the tuple type (tau[0], ..., tau[n-1])
711 * - return NULL if there are no particles of that type.
712 */
pstore_find_set_for_types(pstore_t * store,uint32_t n,type_t * tau)713 particle_set_t *pstore_find_set_for_types(pstore_t *store, uint32_t n, type_t *tau) {
714 return find_pset_for_types(&store->psets, n, tau);
715 }
716
717
718
719
720
721
722 /*
723 * SET OPERATIONS
724 */
725
726 /*
727 * Mark all the particles in array a[0, ..., p-1]
728 */
set_particle_marks(pstore_t * store,uint32_t p,particle_t * a)729 static void set_particle_marks(pstore_t *store, uint32_t p, particle_t *a) {
730 uint32_t i;
731
732 for (i=0; i<p; i++) {
733 set_bit(store->ptbl.mark, a[i]);
734 }
735 }
736
737 /*
738 * Clear the mark of all particles in array a[0...p-1]
739 */
clear_particle_marks(pstore_t * store,uint32_t p,particle_t * a)740 static void clear_particle_marks(pstore_t *store, uint32_t p, particle_t *a) {
741 uint32_t i;
742
743 for (i=0; i<p; i++) {
744 clr_bit(store->ptbl.mark, a[i]);
745 }
746 }
747
748
749 /*
750 * Find an element in set that's not marked
751 * - return null_particle if all elements are marked
752 */
get_unmarked_particle(pstore_t * store,particle_set_t * set)753 static particle_t get_unmarked_particle(pstore_t *store, particle_set_t *set) {
754 uint32_t i, n;
755 particle_t k;
756
757 if (set != NULL) {
758 n = set->nelems;
759 for (i=0; i<n; i++) {
760 k = set->data[i];
761 if (! tst_bit(store->ptbl.mark, k)) {
762 return k;
763 }
764 }
765 }
766
767 return null_particle;
768 }
769
770
771
772 /*
773 * Return a particle of type tau that's distinct from all elements
774 * of array a.
775 * - p = size of array a
776 * - create a fresh particle of type tau
777 * - return null_particle if that's not possible (i.e., tau is finite
778 * and all its members occur in a).
779 */
get_distinct_particle(pstore_t * store,type_t tau,uint32_t p,particle_t * a)780 particle_t get_distinct_particle(pstore_t *store, type_t tau, uint32_t p, particle_t *a) {
781 particle_set_t *set;
782 particle_t k;
783 uint32_t card;
784
785 // search for an existing particle first
786 set_particle_marks(store, p, a);
787 set = get_pset_for_type(&store->psets, tau);
788 k = get_unmarked_particle(store, set);
789 clear_particle_marks(store, p, a);
790
791 if (k == null_particle) {
792 // create a fresh particle if the type isn't saturated
793 card = type_card(store->types, tau);
794 if (set->nelems < card) {
795 k = pstore_fresh_particle(store, tau);
796 }
797 }
798
799 return k;
800 }
801
802
803 /*
804 * Return a (fresh) particle of that tau that's distinct from all
805 * other particles of that type.
806 * - return null_particle if that's not possible.
807 */
get_new_particle(pstore_t * store,type_t tau)808 particle_t get_new_particle(pstore_t *store, type_t tau) {
809 particle_set_t *set;
810 uint32_t card;
811 particle_t k;
812
813 set = get_pset_for_type(&store->psets, tau);
814 card = type_card(store->types, tau);
815 k = null_particle;
816 if (set->nelems < card) {
817 k = pstore_fresh_particle(store, tau);
818 }
819
820 return k;
821 }
822
823
824
825 /*
826 * SUPPORT FOR BUILDING DISTINCT TUPLES
827 *
828 * Given an array a[0 ... p-1] of p particles, all of the same type
829 * tau[0] x ... x tau[n-1], we want to construct a particle k distinct
830 * from a[0] ... a[p-1]. To do this, we sort elements of a in
831 * lexicographic order. Because all types have finitely many particles,
832 * we can define the successor and predecessor (succ(a), pre(a)) of any
833 * element a of type tau[0] x ... x tau[n-1] in the lexicographic order
834 * (except the first and last elements). To find an element not in
835 * a[0 ... p-1], we search for a[i] such that a' = succ(a[i]) or pre(a[i])
836 * is not in the array then we return a'
837 *
838 * Lexicographic order: for all elements in set[tau], we assign
839 * a rank defined by rank[x] = i iff set[tau]->data[i] = x.
840 * By construction, we have rank[x] < rank[y] iff x < y (as integers).
841 * Then we use the lexicographic order (x_1, ..., x_n) < (y_1, ..., y_n)
842 * if for some k we have x_1 = y1, ..., x_{k-1} = y_{k-1} and x_k < y_k.
843 * The successor of (x_1,..., x_n) is obtained by increasing rank[x_n] by 1,
844 * if that's overflows, we set y_n = element of rank[0] in tau[n-1], then
845 * increase rank[x_{n-1}] by 1 and so forth.
846 */
847
848 /*
849 * Allocate or resize the rank array
850 * - initialize all ranks to -1
851 */
pstore_prepare_rank(pstore_t * store)852 static void pstore_prepare_rank(pstore_t *store) {
853 uint32_t i, n;
854
855 n = store->ptbl.nobjects;
856 if (store->rank_size < n) {
857 store->rank = safe_realloc(store->rank, n * sizeof(int32_t));
858 store->rank_size = n;
859 }
860
861 for (i=0; i<n; i++) {
862 store->rank[i] = -1;
863 }
864 }
865
866 #ifndef NDEBUG
867 /*
868 * For debugging: check that set is in increasing order
869 */
pset_is_sorted(particle_set_t * set)870 static bool pset_is_sorted(particle_set_t *set) {
871 uint32_t i, n;
872
873 n = set->nelems;
874 if (n > 1) {
875 n --;
876 for (i=0; i<n; i++) {
877 if (set->data[i] >= set->data[i+1]) {
878 return false;
879 }
880 }
881 }
882
883 return true;
884 }
885
886 #endif
887
888 /*
889 * Set the rank of all elements of type tau
890 */
pstore_ranks_for_type(pstore_t * store,type_t tau)891 static void pstore_ranks_for_type(pstore_t *store, type_t tau) {
892 particle_set_t *set;
893 uint32_t i, n;
894 particle_t x;
895
896 set = find_pset_for_type(&store->psets, tau);
897 if (set != NULL) {
898 assert(pset_is_sorted(set));
899 n = set->nelems;
900 for (i=0; i<n; i++) {
901 x = set->data[i];
902 store->rank[x] = i;
903 }
904 }
905 }
906
907
908 /*
909 * Size of set for the type tau
910 * - 0 if there's no particle of that type
911 */
pstore_size_for_type(pstore_t * store,type_t tau)912 static uint32_t pstore_size_for_type(pstore_t *store, type_t tau) {
913 particle_set_t *set;
914
915 set = pstore_find_set_for_type(store, tau);
916 if (set != NULL) {
917 return set->nelems;
918 } else {
919 return 0;
920 }
921 }
922
923
924 /*
925 * Allocate or resize card and aux arrays, and ranks
926 * - tau[0 .. n-1] = tuple types
927 * - return true if card[0, ..., n-1] are all positive
928 * - return false otherwise
929 */
pstore_prepare_for_tuple(pstore_t * store,uint32_t n,type_t * tau)930 static bool pstore_prepare_for_tuple(pstore_t *store, uint32_t n, type_t *tau) {
931 uint32_t i, s;
932
933 s = store->card_size;
934 if (s < n) {
935 store->card = (uint32_t *) safe_realloc(store->card, n * sizeof(uint32_t));
936 store->aux = (int32_t *) safe_realloc(store->aux, n * sizeof(int32_t));
937 store->card_size = n;
938 }
939
940 for (i=0; i<n; i++) {
941 pstore_ranks_for_type(store, tau[i]);
942 store->card[i] = pstore_size_for_type(store, tau[i]);
943 if (store->card[i] == 0) {
944 return false;
945 }
946 }
947
948 return true;
949 }
950
951
952
953 /*
954 * Check whether x < y in the lexicographic ordering
955 * - both x and y must be tuple particles of the same types
956 */
lexico_precedes(particle_table_t * table,particle_t x,particle_t y)957 static bool lexico_precedes(particle_table_t *table, particle_t x, particle_t y) {
958 particle_tuple_t *tx, *ty;
959 particle_t a, b;
960 uint32_t i, n;
961
962 assert(0 <= x && x < table->nobjects && 0 <= y && y < table->nobjects &&
963 table->kind[x] == TUPLE_PARTICLE && table->kind[y] == TUPLE_PARTICLE);
964
965 tx = (particle_tuple_t *) table->desc[x].ptr;
966 ty = (particle_tuple_t *) table->desc[y].ptr;
967 n = tx->nelems;
968 assert(n == ty->nelems);
969
970 for (i=0; i<n; i++) {
971 a = tx->elem[i];
972 b = ty->elem[i];
973 if (a < b) {
974 return true;
975 } else if (a > b) {
976 return false;
977 }
978 }
979
980 return false;
981 }
982
983
984 /*
985 * Sort array a[0 ... n-1] in lexicographic order
986 */
987 static void lexico_qsort(particle_table_t *table, particle_t *a, uint32_t n);
988
989 // insertion sort
lexico_isort(particle_table_t * table,particle_t * a,uint32_t n)990 static void lexico_isort(particle_table_t *table, particle_t *a, uint32_t n) {
991 uint32_t i, j;
992 particle_t x, y;
993
994 for (i=1; i<n; i++) {
995 x = a[i];
996 j = 0;
997 while (lexico_precedes(table, a[j], x)) {
998 j ++;
999 }
1000 while (j < i) {
1001 y = a[j]; a[j] = x; x = y;
1002 j ++;
1003 }
1004 a[j] = x;
1005 }
1006 }
1007
1008 // sort: either insertion sort or quick sort
lexico_sort(particle_table_t * table,particle_t * a,uint32_t n)1009 static void lexico_sort(particle_table_t *table, particle_t *a, uint32_t n) {
1010 if (n < 10) {
1011 lexico_isort(table, a, n);
1012 } else {
1013 lexico_qsort(table, a, n);
1014 }
1015 }
1016
1017
1018 // quick sort: n must be at least 2
lexico_qsort(particle_table_t * table,particle_t * a,uint32_t n)1019 static void lexico_qsort(particle_table_t *table, particle_t *a, uint32_t n) {
1020 uint32_t i, j;
1021 particle_t x, y;
1022 uint32_t seed = PRNG_DEFAULT_SEED;
1023
1024 // x = random pivot
1025 i = random_uint(&seed, n);
1026 x = a[i];
1027
1028 // swap x and a[0]
1029 a[i] = a[0];
1030 a[0] = x;
1031
1032 i = 0;
1033 j = n;
1034
1035 do { j--; } while (lexico_precedes(table, x, a[j]));
1036 do { i++; } while (i <= j && lexico_precedes(table, a[i], x));
1037
1038 while (i < j) {
1039 // we have a[i] >= x and a[j] <= x: swap a[i] and a[j]
1040 y = a[i]; a[i] = a[j]; a[j] = y;
1041
1042 do { j--; } while (lexico_precedes(table, x, a[j]));
1043 do { i++; } while (lexico_precedes(table, a[i], x));
1044 }
1045
1046 // swap pivot and a[j]
1047 a[0] = a[j];
1048 a[j] = x;
1049
1050 // recursion
1051 lexico_sort(table, a, j);
1052 j ++;
1053 lexico_sort(table, a + j, n - j);
1054 }
1055
1056
1057
1058 /*
1059 * Check whether x has a predecessor in lexico ordering
1060 * - x must be a tuple
1061 */
has_predecessor(pstore_t * store,particle_t x)1062 static bool has_predecessor(pstore_t *store, particle_t x) {
1063 particle_tuple_t *tx;
1064 particle_t y;
1065 uint32_t i, n;
1066
1067 tx = tuple_particle_desc(store, x);
1068 n = tx->nelems;
1069 assert(n <= store->card_size);
1070 for (i=0; i<n; i++) {
1071 y = tx->elem[i];
1072 assert(store->rank[y] >= 0 && store->rank[y] < store->card[i] );
1073 if (store->rank[y] > 0) {
1074 return true;
1075 }
1076 }
1077
1078 // all components have rank 0
1079 return false;
1080 }
1081
1082
1083 /*
1084 * Check whether x has a successor in the lexicographic ordering
1085 */
has_successor(pstore_t * store,particle_t x)1086 static bool has_successor(pstore_t *store, particle_t x) {
1087 particle_tuple_t *tx;
1088 particle_t y;
1089 uint32_t i, n;
1090
1091 tx = tuple_particle_desc(store, x);
1092 n = tx->nelems;
1093 assert(n <= store->card_size);
1094 for (i=0; i<n; i++) {
1095 y = tx->elem[i];
1096 assert(store->rank[y] >= 0 && store->rank[y] < store->card[i] );
1097 if (store->rank[y] < store->card[i] - 1) {
1098 return true;
1099 }
1100 }
1101
1102 // all components have maximal rank
1103 return false;
1104 }
1105
1106
1107 /*
1108 * Compute the predecessor of rank(x) as an array of n ranks
1109 * - the result is stored in aux[0] ... aux[n-1]
1110 */
rank_predecessor(pstore_t * store,particle_t x)1111 static void rank_predecessor(pstore_t *store, particle_t x) {
1112 particle_tuple_t *tx;
1113 particle_t y;
1114 uint32_t i, n;
1115 int32_t k;
1116
1117 tx = tuple_particle_desc(store, x);
1118 n = tx->nelems;
1119 assert(n <= store->card_size);
1120 for (i=0; i<n; i++) {
1121 y = tx->elem[i];
1122 store->aux[i] = store->rank[y];
1123 assert(0 <= store->aux[i] && store->aux[i] < store->card[i]);
1124 }
1125
1126 // decrement the ranks from right to left
1127 while (i > 0) {
1128 i --;
1129 k = store->aux[i];
1130 assert(k < store->card[i]);
1131 if (k == 0) {
1132 store->aux[i] = store->card[i] - 1;
1133 } else {
1134 store->aux[i] = k - 1;
1135 break;
1136 }
1137 }
1138 }
1139
1140
1141
1142 /*
1143 * Compute the successor of rank(x) as an array of n ranks
1144 * - the result is stored in aux[0] ... aux[n-1]
1145 */
rank_successor(pstore_t * store,particle_t x)1146 static void rank_successor(pstore_t *store, particle_t x) {
1147 particle_tuple_t *tx;
1148 particle_t y;
1149 uint32_t i, n;
1150 int32_t k;
1151
1152 tx = tuple_particle_desc(store, x);
1153 n = tx->nelems;
1154 assert(n <= store->card_size);
1155 for (i=0; i<n; i++) {
1156 y = tx->elem[i];
1157 store->aux[i] = store->rank[y];
1158 assert(0 <= store->aux[i] && store->aux[i] < store->card[i]);
1159 }
1160
1161 // increment the ranks from right to left
1162 while (i > 0) {
1163 i --;
1164 k = store->aux[i] + 1;
1165 if (k == store->card[i]) {
1166 store->aux[i] = 0;
1167 } else {
1168 assert(k < store->card[i]);
1169 store->aux[i] = k;
1170 break;
1171 }
1172 }
1173 }
1174
1175
1176 /*
1177 * Check whether (aux[0], ..., aux[n-1]) < (rank[x_1], ... , rank[x_n]) in lex order
1178 */
rank_lex_precedes(pstore_t * store,particle_t x)1179 static bool rank_lex_precedes(pstore_t *store, particle_t x) {
1180 particle_tuple_t *tx;
1181 particle_t y;
1182 uint32_t i, n;
1183 int32_t r, s;
1184
1185 tx = tuple_particle_desc(store, x);
1186 n = tx->nelems;
1187 assert(n <= store->card_size);
1188 for (i=0; i<n; i++) {
1189 y = tx->elem[i];
1190 s = store->rank[y];
1191 r = store->aux[i];
1192 if (r < s) {
1193 return true;
1194 } else if (r > s) {
1195 return false;
1196 }
1197 }
1198
1199 return false;
1200 }
1201
1202
1203
1204
1205 /*
1206 * Build the tuple defined by the ranks aux[0 ... n-1]
1207 */
pstore_tuple_from_ranks(pstore_t * store,uint32_t n,type_t * tau)1208 static particle_t pstore_tuple_from_ranks(pstore_t *store, uint32_t n, type_t *tau) {
1209 particle_set_t *set;
1210 particle_t y;
1211 int32_t k;
1212 uint32_t i;
1213
1214 // replace aux[i] by the variable of type tau[i] and rank aux[i]
1215 assert(n <= store->card_size);
1216 for (i=0; i<n; i++) {
1217 set = pstore_find_set_for_type(store, tau[i]);
1218 assert(set != NULL);
1219 k = store->aux[i];
1220 assert(0 <= k && k < store->card[i] && store->card[i] == set->nelems);
1221 y = set->data[k];
1222 assert(store->rank[y] == k);
1223 store->aux[i] = y;
1224 }
1225
1226 // build the tuple
1227 return pstore_tuple_particle(store, n, store->aux, tau);
1228 }
1229
1230
1231 /*
1232 * Build a new tuple distinct from all elements in array a
1233 * - a must be sorted in lexicographic order
1234 * - return null_particle if all possible tuples are already in a
1235 */
new_distinct_tuple(pstore_t * store,uint32_t n,type_t * tau,uint32_t p,particle_t * a)1236 static particle_t new_distinct_tuple(pstore_t *store, uint32_t n, type_t *tau, uint32_t p, particle_t *a) {
1237 uint32_t i;
1238 particle_t x, y;
1239
1240 if (p == 0) {
1241 // make the element of rank 0, ..., 0
1242 for (i=0; i<n; i++) {
1243 store->aux[i] = 0;
1244 }
1245 goto build;
1246 }
1247
1248 x = a[0];
1249 if (has_predecessor(store, x)) {
1250 rank_predecessor(store, x);
1251 goto build;
1252 }
1253
1254 p --;
1255 for (i=0; i<p; i++) {
1256 x = a[i];
1257 y = a[i+1];
1258 if (x != y) {
1259 assert(lexico_precedes(&store->ptbl, x, y) && has_successor(store, x));
1260 rank_successor(store, x);
1261 if (rank_lex_precedes(store, y)) goto build;
1262 }
1263 }
1264
1265 x = a[p];
1266 if (has_successor(store, x)) {
1267 rank_successor(store, x);
1268 goto build;
1269 }
1270
1271 return null_particle;
1272
1273 build:
1274 return pstore_tuple_from_ranks(store, n, tau);
1275 }
1276
1277
1278
1279
1280 /*
1281 * Try to construct a new tuple particle distinct from a[0] ... a[p-1]
1282 * - tau[0] ... tau[n-1] = type of the tuple to create
1283 * (that must be the type of a[0] ... a[p-1] too).
1284 */
make_distinct_tuple(pstore_t * store,uint32_t n,type_t * tau,uint32_t p,particle_t * a)1285 static particle_t make_distinct_tuple(pstore_t *store, uint32_t n, type_t *tau, uint32_t p, particle_t *a) {
1286 particle_t k;
1287
1288 pstore_prepare_rank(store);
1289 k = null_particle;
1290 if (pstore_prepare_for_tuple(store, n, tau)) {
1291 lexico_sort(&store->ptbl, a, p);
1292 k = new_distinct_tuple(store, n, tau, p, a);
1293 }
1294 return k;
1295 }
1296
1297
1298 /*
1299 * Create fresh elements in all of the types tau[0] ... tau[n-1]
1300 * then build a tuple from that.
1301 */
add_fresh_particles_and_build_tuple(pstore_t * store,uint32_t n,type_t * tau)1302 static particle_t add_fresh_particles_and_build_tuple(pstore_t *store, uint32_t n, type_t *tau) {
1303 particle_set_t *set;
1304 bool fresh_elem;
1305 uint32_t i, card, s;
1306
1307 // make sure aux is allocated
1308 s = store->card_size;
1309 if (s < n) {
1310 store->card = (uint32_t *) safe_realloc(store->card, n * sizeof(uint32_t));
1311 store->aux = (int32_t *) safe_realloc(store->aux, n * sizeof(int32_t));
1312 store->card_size = n;
1313 }
1314
1315 fresh_elem = false;
1316 i = n;
1317 while (i > 0) {
1318 i --;
1319 set = get_pset_for_type(&store->psets, tau[i]);
1320 card = type_card(store->types, tau[i]);
1321 if (set->nelems == 0 || (!fresh_elem && set->nelems< card)) {
1322 // create a fresh particle of type tau[i]
1323 store->aux[i] = pstore_fresh_particle(store, tau[i]);
1324 fresh_elem = true;
1325 } else {
1326 // use an existing particle (the first one)
1327 assert(set->nelems > 0);
1328 store->aux[i] = set->data[0];
1329 }
1330 }
1331
1332 if (fresh_elem) {
1333 return pstore_tuple_particle(store, n, store->aux, tau);
1334 } else {
1335 return null_particle;
1336 }
1337 }
1338
1339
1340
1341 /*
1342 * Get a particle of type (tau[0] x ... x tau[n-1]) that's distinct from
1343 * all elements of array a
1344 * - n must be at least 2 (for n=1 get_distinct_particle should be used)
1345 * - p = size of the array a
1346 */
get_distinct_tuple(pstore_t * store,uint32_t n,type_t * tau,uint32_t p,particle_t * a)1347 particle_t get_distinct_tuple(pstore_t *store, uint32_t n, type_t *tau, uint32_t p, particle_t *a) {
1348 particle_set_t *set;
1349 particle_t k;
1350
1351 // try an existing particle (in set)
1352 set_particle_marks(store, p, a);
1353 set = get_pset_for_types(&store->psets, n, tau);
1354 k = get_unmarked_particle(store, set);
1355 clear_particle_marks(store, p, a);
1356 if (k != null_particle) {
1357 goto done;
1358 }
1359
1360 // try to construct a new tuple
1361 k = make_distinct_tuple(store, n, tau, p, a);
1362 if (k != null_particle) {
1363 goto done;
1364 }
1365
1366 // try to create a new tuple by adding an element in tau[0] or ... or tau[n-1]
1367 k = add_fresh_particles_and_build_tuple(store, n, tau);
1368
1369 done:
1370 return k;
1371 }
1372
1373
1374 /*
1375 * Return a particle of type (tau[0], ..., tau[n-1]) that's distinct
1376 * from all other particles of that type in the store.
1377 * - n must be at least 2
1378 * - return null_particle if that's not possible.
1379 */
get_new_tuple(pstore_t * store,uint32_t n,type_t * tau)1380 particle_t get_new_tuple(pstore_t *store, uint32_t n, type_t *tau) {
1381 particle_set_t *set;
1382 particle_t *a;
1383 particle_t k;
1384 uint32_t i, s;
1385
1386 set = get_pset_for_types(&store->psets, n, tau);
1387
1388 // copy all elements of set in array a
1389 s = set->nelems;
1390 a = (particle_t *) safe_malloc(s * sizeof(particle_t));
1391 for (i=0; i<s; i++) {
1392 a[i] = set->data[i];
1393 }
1394
1395 // try to construct a new tuple
1396 k = make_distinct_tuple(store, n, tau, s, a);
1397 safe_free(a);
1398
1399 if (k == null_particle) {
1400 // try to create a new tuple by adding an element in tau[0] or ... or tau[n-1]
1401 k = add_fresh_particles_and_build_tuple(store, n, tau);
1402 }
1403
1404 return k;
1405 }
1406