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