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