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.
36  * - Each atomic element x_ij or y_k is either an egraph label
37  *   or a fresh constant of some type tau created by the solver.
38  * - The egraph can later convert the abstract values into concrete objects.
39  */
40 
41 #ifndef __ABSTRACT_VALUES_H
42 #define __ABSTRACT_VALUES_H
43 
44 #include <stdint.h>
45 #include <stdbool.h>
46 #include <assert.h>
47 
48 #include "model/concrete_values.h"
49 #include "solvers/egraph/egraph_base_types.h"
50 #include "terms/types.h"
51 #include "utils/bitvectors.h"
52 #include "utils/int_hash_tables.h"
53 
54 
55 /*
56  * Abstract values are called particles. They are identified by an
57  * integer index in a global table. We use hash consing. There are
58  * three kinds of abstract values:
59  *  LABEL (egraph label)
60  *  FRESH (fresh constant)
61  *  TUPLE
62  *
63  * We use TUPLE to represent n-ary maps. Rather than writing
64  *  [x_i1, ..., x_in -> y_i]
65  * we construct t = [x_i1, ..., x_in] and store [t -> y_i] in the
66  * array descriptor.
67  */
68 
69 /*
70  * Indices
71  */
72 typedef int32_t particle_t;
73 
74 /*
75  * null value
76  */
77 enum {
78   null_particle = -1,
79 };
80 
81 /*
82  * Particle types
83  */
84 typedef enum {
85   LABEL_PARTICLE,
86   FRESH_PARTICLE,
87   TUPLE_PARTICLE,
88 } particle_kind_t;
89 
90 
91 /*
92  * Descriptors: either an integer or a pointer
93  */
94 typedef union particle_desc_u {
95   int32_t integer;
96   void *ptr;
97 } particle_desc_t;
98 
99 
100 /*
101  * Tuple descriptor
102  */
103 typedef struct particle_tuple_s {
104   uint32_t nelems;
105   particle_t elem[0]; // real size = nelems
106 } particle_tuple_t;
107 
108 
109 #define MAX_PARTICLE_TUPLE_ARITY (UINT32_MAX/8)
110 
111 
112 /*
113  * Particle table
114  * - valid objects have indices between 0 and nobjects - 1
115  * - for each object i:
116  *     kind[i] = its kind
117  *     desc[i] = its descriptor
118  *     concrete[i] = its concretization
119  *     mark[i] = general purpose mark bit
120  * - other components:
121  *     htbl = hash table for hash consing
122  */
123 typedef struct particle_table_s {
124   uint32_t size;
125   uint32_t nobjects;
126   uint8_t *kind;
127   particle_desc_t *desc;
128   value_t *concrete;
129   byte_t *mark;
130 
131   int_htbl_t htbl;
132 } particle_table_t;
133 
134 
135 #define DEF_PARTICLE_TABLE_SIZE 200
136 #define MAX_PARTICLE_TABLE_SIZE (UINT32_MAX/sizeof(particle_desc_t))
137 
138 
139 
140 /*
141  * Descriptor for a set of particles of a tuple of types [tau_0,..., tau_n-1]
142  * - arity = number of types
143  * - type[0,.,,n-1] = tau_0 to tau_n-1
144  * For a simple type tau, we use n=1 and type[0] = tau
145  * - data = vector that contains all particles of that type
146  * - size = size of array data
147  * - nelems = number of elements in the array
148  */
149 typedef struct particle_set_s {
150   uint32_t size;
151   uint32_t nelems;
152   particle_t *data;
153   uint32_t arity;
154   type_t type[0];   // real size = arity
155 } particle_set_t;
156 
157 
158 #define DEF_PSET_SIZE 20
159 #define MAX_PSET_SIZE ((UINT32_MAX - sizeof(particle_set_t))/sizeof(type_t))
160 
161 
162 /*
163  * Table of these descriptors
164  * - pset[0 ... n-1] = all sets
165  * - size = size of the set array
166  * - nsets = n
167  * - there shouldn't be too many different types so we just use
168  *   sequential search to find the pset for a given type
169  *   (or tuple of types).
170  */
171 typedef struct pset_table_s {
172   uint32_t size;
173   uint32_t nsets;
174   particle_set_t **set;
175 } pset_table_t;
176 
177 
178 #define DEF_PSET_TABLE_SIZE 10
179 #define MAX_PSET_TABLE_SIZE (UINT32_MAX/sizeof(particle_set_t *))
180 
181 
182 
183 /*
184  * Global store:
185  * - store particles and particle_sets
186  * + pointer to the global type table
187  *
188  * Auxiliary buffers and arrays for constructing fresh tuples
189  * of types tau[0] ... tau[n-1]
190  * - rank array: for a particle x of type tau, rank[x] = i
191  *   iff set[tau]->data[i] = x
192  * - rank_size = size of the rank array
193  * - card array: card[k] = number of elements in tau[k]
194  * - aux array: must have size n
195  */
196 typedef struct pstore_s {
197   type_table_t *types;
198   particle_table_t ptbl;
199   pset_table_t psets;
200   // buffers
201   uint32_t rank_size;
202   uint32_t card_size;
203   int32_t *rank;
204   uint32_t *card;
205   int32_t *aux;
206 } pstore_t;
207 
208 
209 
210 
211 /*
212  * Initialize a store:
213  * - use default sizes for both ptbl and psets
214  * - ttbl = the type table
215  */
216 extern void init_pstore(pstore_t *store, type_table_t *ttbl);
217 
218 
219 /*
220  * Delete a store
221  */
222 extern void delete_pstore(pstore_t *store);
223 
224 
225 /*
226  * Get a particle for an egraph label l
227  * - tau = the particle type
228  * If that particle already exists it's returned.
229  * Otherwise it's created and added to the particle_set for tau
230  */
231 extern particle_t pstore_labeled_particle(pstore_t *store, elabel_t l, type_t tau);
232 
233 
234 /*
235  * Create a fresh particle of type tau
236  * - the particle is added to the set for tau
237  */
238 extern particle_t pstore_fresh_particle(pstore_t *store, type_t tau);
239 
240 
241 /*
242  * Create a tuple particle:
243  * - a[0] ... a[n-1] = components
244  * - tau[0] ... tau[n-1] = types of each component
245  */
246 extern particle_t pstore_tuple_particle(pstore_t *store, uint32_t n, particle_t *a, type_t *tau);
247 
248 
249 /*
250  * Map particle i to a concrete value v
251  * - i must be a valid particle index
252  * - until this function is called, concrete[i] is equal to null_value
253  */
pstore_make_concrete(pstore_t * store,particle_t i,value_t v)254 static inline void pstore_make_concrete(pstore_t *store, particle_t i, value_t v) {
255   assert(0 <= i && i < store->ptbl.nobjects);
256   store->ptbl.concrete[i] = v;
257 }
258 
259 
260 
261 /*
262  * Get the particle set for type tau
263  * - return NULL if there are no particles of that type
264  */
265 extern particle_set_t *pstore_find_set_for_type(pstore_t *store, type_t tau);
266 
267 
268 /*
269  * Get the particle set for the tuple type (tau[0], ..., tau[n-1])
270  * - return NULL if there are no particles of that type.
271  */
272 extern particle_set_t *pstore_find_set_for_types(pstore_t *store, uint32_t n, type_t *tau);
273 
274 
275 
276 /*
277  * Return a particle of type tau that's distinct from all elements
278  * of array a.
279  * - p = size of array a
280  * - return null_particle if that's not possible (i.e., tau is finite
281  *   and all its members occur in a).
282  */
283 extern particle_t get_distinct_particle(pstore_t *store, type_t tau, uint32_t p, particle_t *a);
284 
285 
286 /*
287  * Return a (fresh) particle of that tau that's distinct from all
288  * other particles of that type.
289  * - return null_particle if that's not possible.
290  */
291 extern particle_t get_new_particle(pstore_t *store, type_t tau);
292 
293 
294 /*
295  * Variant 1: get any particle of type tau
296  */
get_some_particle(pstore_t * store,type_t tau)297 static inline particle_t get_some_particle(pstore_t *store, type_t tau) {
298   return get_distinct_particle(store, tau, 0, NULL);
299 }
300 
301 
302 /*
303  * Variant 2: get a particle distinct from x
304  */
get_another_particle(pstore_t * store,type_t tau,particle_t x)305 static inline particle_t get_another_particle(pstore_t *store, type_t tau, particle_t x) {
306   return get_distinct_particle(store, tau, 1, &x);
307 }
308 
309 
310 
311 /*
312  * Return a particle of type (tau[0], ..., tau[n-1]) that's distinct
313  * from all particles in array a.
314  * - n must be a least 2
315  * - p = size of the array a
316  * - return null_particle if that's not possible
317  */
318 extern particle_t get_distinct_tuple(pstore_t *store, uint32_t n, type_t *tau,
319                                      uint32_t p, particle_t *a);
320 
321 
322 
323 /*
324  * Return a particle of type (tau[0], ..., tau[n-1]) that's distinct
325  * from all other particles of that type in the store.
326  * - n must be at least 2
327  * - return null_particle if that's not possible.
328  */
329 extern particle_t get_new_tuple(pstore_t *store, uint32_t n, type_t *tau);
330 
331 
332 
333 /*
334  * Number of particles in the store
335  */
pstore_num_particles(pstore_t * store)336 static inline uint32_t pstore_num_particles(pstore_t *store) {
337   return store->ptbl.nobjects;
338 }
339 
340 
341 /*
342  * Get kind and descriptor of a particle
343  */
valid_particle(pstore_t * store,particle_t i)344 static inline bool valid_particle(pstore_t *store, particle_t i) {
345   return 0 <= i && i < store->ptbl.nobjects;
346 }
347 
particle_kind(pstore_t * store,particle_t i)348 static inline particle_kind_t particle_kind(pstore_t *store, particle_t i) {
349   assert(valid_particle(store, i));
350   return (particle_kind_t) store->ptbl.kind[i];
351 }
352 
is_labeled_particle(pstore_t * store,particle_t i)353 static inline bool is_labeled_particle(pstore_t *store, particle_t i) {
354   return particle_kind(store, i) == LABEL_PARTICLE;
355 }
356 
is_fresh_particle(pstore_t * store,particle_t i)357 static inline bool is_fresh_particle(pstore_t *store, particle_t i) {
358   return particle_kind(store, i) == FRESH_PARTICLE;
359 }
360 
is_tuple_particle(pstore_t * store,particle_t i)361 static inline bool is_tuple_particle(pstore_t *store, particle_t i) {
362   return particle_kind(store, i) == TUPLE_PARTICLE;
363 }
364 
365 
366 // label of a labeled particle
particle_label(pstore_t * store,particle_t i)367 static inline elabel_t particle_label(pstore_t *store, particle_t i) {
368   assert(is_labeled_particle(store, i));
369   return (elabel_t) store->ptbl.desc[i].integer;
370 }
371 
372 // type of a fresh particle
fresh_particle_type(pstore_t * store,particle_t i)373 static inline type_t fresh_particle_type(pstore_t *store, particle_t i) {
374   assert(is_fresh_particle(store, i));
375   return (type_t) store->ptbl.desc[i].integer;
376 }
377 
378 // descriptor of a tuple particle
tuple_particle_desc(pstore_t * store,particle_t i)379 static inline particle_tuple_t *tuple_particle_desc(pstore_t *store, particle_t i) {
380   assert(is_tuple_particle(store, i));
381   return (particle_tuple_t *) store->ptbl.desc[i].ptr;
382 }
383 
384 // number of components of a tuple
tuple_particle_nelems(pstore_t * store,particle_t i)385 static inline uint32_t tuple_particle_nelems(pstore_t *store, particle_t i) {
386   return tuple_particle_desc(store, i)->nelems;
387 }
388 
389 // component k of the tuple
tuple_particle_elem(pstore_t * store,particle_t i,uint32_t k)390 static inline uint32_t tuple_particle_elem(pstore_t *store, particle_t i, uint32_t k) {
391   assert(k < tuple_particle_nelems(store, i));
392   return tuple_particle_desc(store, i)->elem[k];
393 }
394 
395 
396 // concrete value of a particle i
particle_concrete_value(pstore_t * store,particle_t i)397 static inline value_t particle_concrete_value(pstore_t *store, particle_t i) {
398   assert(valid_particle(store, i));
399   return store->ptbl.concrete[i];
400 }
401 
402 
403 
404 #endif /* __ABSTRACT_VALUES_H */
405