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 * Computation of the free variables of a term.
21 */
22
23 #include <assert.h>
24
25 #include "terms/free_var_collector.h"
26
27
28 /*
29 * Initialization
30 */
init_fvar_collector(fvar_collector_t * collect,term_table_t * ttbl)31 void init_fvar_collector(fvar_collector_t *collect, term_table_t *ttbl) {
32 collect->terms = ttbl;
33 init_ptr_hmap(&collect->map, 0); // default size
34 init_harray_store(&collect->store);
35 init_pstack(&collect->stack);
36 }
37
38
39 /*
40 * Delete the whole thing
41 */
delete_fvar_collector(fvar_collector_t * collect)42 void delete_fvar_collector(fvar_collector_t *collect) {
43 delete_ptr_hmap(&collect->map);
44 delete_harray_store(&collect->store);
45 delete_pstack(&collect->stack);
46 }
47
48
49 /*
50 * Reset: empty everything
51 */
reset_fvar_collector(fvar_collector_t * collect)52 void reset_fvar_collector(fvar_collector_t *collect) {
53 ptr_hmap_reset(&collect->map);
54 reset_harray_store(&collect->store);
55 reset_pstack(&collect->stack);
56 }
57
58
59
60 /*
61 * For debugging: check that a is sorted and does not contain duplicates
62 * and that all elements of a are variables.
63 */
64 #ifndef NDEBUG
good_var_set(term_table_t * terms,harray_t * a)65 static bool good_var_set(term_table_t *terms, harray_t *a) {
66 uint32_t i, n;
67 term_t x;
68
69 n = a->nelems;
70 x = NULL_TERM; // -1
71 for (i = 0; i<n; i++) {
72 if (a->data[i] <= x) return false; // not sorted or duplicate
73 x = a->data[i];
74 if (term_kind(terms, x) != VARIABLE) return false;
75 }
76
77 return true;
78 }
79
80 #endif
81
82
83 /*
84 * Empty set of variables
85 */
empty_fvar_set(fvar_collector_t * collect)86 static inline harray_t *empty_fvar_set(fvar_collector_t *collect) {
87 return empty_harray(&collect->store);
88 }
89
90
91 /*
92 * Singleton set: x = unique element
93 */
singleton_fvar_set(fvar_collector_t * collect,term_t x)94 static inline harray_t *singleton_fvar_set(fvar_collector_t *collect, term_t x) {
95 return singleton_harray(&collect->store, x);
96 }
97
98
99
100 /*
101 * Check whether the free var set for term index i is in the hash map
102 * - return NULL if it's not
103 */
lookup_free_vars(fvar_collector_t * collect,int32_t i)104 static harray_t *lookup_free_vars(fvar_collector_t *collect, int32_t i) {
105 ptr_hmap_pair_t *p;
106 harray_t *a;
107
108 a = NULL;
109 p = ptr_hmap_find(&collect->map, i);
110 if (p != NULL) {
111 a = p->val;
112 assert(a != NULL && good_var_set(collect->terms, a));
113 }
114 return a;
115 }
116
117
118 /*
119 * Store the free var set of i into the hash map
120 * - i: term index
121 * - a: set of variables of i
122 * There must not be anything mapped to i the the map yet.
123 */
cache_free_vars(fvar_collector_t * collect,int32_t i,harray_t * a)124 static void cache_free_vars(fvar_collector_t *collect, int32_t i, harray_t *a) {
125 ptr_hmap_pair_t *p;
126
127 p = ptr_hmap_get(&collect->map, i);
128 assert(p->val == NULL);
129 p->val = a;
130 }
131
132
133 /*
134 * Free variables in composite terms (other than forall)
135 */
free_vars_of_composite(fvar_collector_t * collect,composite_term_t * c)136 static harray_t *free_vars_of_composite(fvar_collector_t *collect, composite_term_t *c) {
137 harray_t **a;
138 harray_t *result;
139 uint32_t i, n;
140
141 n = c->arity;
142 a = (harray_t **) alloc_pstack_array(&collect->stack, n);
143 for (i=0; i<n; i++) {
144 a[i] = get_free_vars_of_term(collect, c->arg[i]);
145 }
146 result = merge_harrays(&collect->store, a, n);
147 free_pstack_array(&collect->stack, (void **) a);
148
149 return result;
150 }
151
free_vars_of_pprod(fvar_collector_t * collect,pprod_t * p)152 static harray_t *free_vars_of_pprod(fvar_collector_t *collect, pprod_t *p) {
153 harray_t **a;
154 harray_t *result;
155 uint32_t i, n;
156
157 n = p->len;
158 a = (harray_t **) alloc_pstack_array(&collect->stack, n);
159 for (i=0; i<n; i++) {
160 a[i] = get_free_vars_of_term(collect, p->prod[i].var);
161 }
162 result = merge_harrays(&collect->store, a, n);
163 free_pstack_array(&collect->stack, (void **) a);
164
165 return result;
166 }
167
free_vars_of_poly(fvar_collector_t * collect,polynomial_t * p)168 static harray_t *free_vars_of_poly(fvar_collector_t *collect, polynomial_t *p) {
169 harray_t **a;
170 harray_t *result;
171 monomial_t *mono;
172 uint32_t i, n;
173
174 n = p->nterms;
175 mono = p->mono;
176 // skip the constant term if any
177 if (mono[0].var == const_idx) {
178 n --;
179 mono ++;
180 }
181
182 a = (harray_t **) alloc_pstack_array(&collect->stack, n);
183 for (i=0; i<n; i++) {
184 a[i] = get_free_vars_of_term(collect, mono[i].var);
185 }
186 result = merge_harrays(&collect->store, a, n);
187 free_pstack_array(&collect->stack, (void **) a);
188
189 return result;
190 }
191
free_vars_of_bvpoly64(fvar_collector_t * collect,bvpoly64_t * p)192 static harray_t *free_vars_of_bvpoly64(fvar_collector_t *collect, bvpoly64_t *p) {
193 harray_t **a;
194 harray_t *result;
195 bvmono64_t *mono;
196 uint32_t i, n;
197
198 n = p->nterms;
199 mono = p->mono;
200 if (mono[0].var == const_idx) {
201 n--;
202 mono ++;
203 }
204 a = (harray_t **) alloc_pstack_array(&collect->stack, n);
205 for (i=0; i<n; i++) {
206 a[i] = get_free_vars_of_term(collect, mono[i].var);
207 }
208 result = merge_harrays(&collect->store, a, n);
209 free_pstack_array(&collect->stack, (void **) a);
210
211 return result;
212 }
213
free_vars_of_bvpoly(fvar_collector_t * collect,bvpoly_t * p)214 static harray_t *free_vars_of_bvpoly(fvar_collector_t *collect, bvpoly_t *p) {
215 harray_t **a;
216 harray_t *result;
217 bvmono_t *mono;
218 uint32_t i, n;
219
220 n = p->nterms;
221 mono = p->mono;
222 if (mono[0].var == const_idx) {
223 n--;
224 mono ++;
225 }
226
227 a = (harray_t **) alloc_pstack_array(&collect->stack, n);
228 for (i=0; i<n; i++) {
229 a[i] = get_free_vars_of_term(collect, mono[i].var);
230 }
231 result = merge_harrays(&collect->store, a, n);
232 free_pstack_array(&collect->stack, (void **) a);
233
234 return result;
235 }
236
237
238 /*
239 * Free variables in (FORALL x1, ..., xn: P) and (LAMBDA x1 ... x_n : t)
240 */
free_vars_of_binding(fvar_collector_t * collect,composite_term_t * p)241 static harray_t *free_vars_of_binding(fvar_collector_t *collect, composite_term_t *p) {
242 harray_t *a;
243 uint32_t n;
244
245 n = p->arity;
246 /*
247 * The bound variables are p->arg[0] to p->arg[n-2]
248 * The body is p->arg[n-1]
249 */
250 assert(n >= 2);
251 a = get_free_vars_of_term(collect, p->arg[n-1]);
252 a = harray_remove_elem(&collect->store, a, n-1, p->arg);
253
254 return a;
255 }
256
257
258 /*
259 * Free variables in a root atom r:
260 */
free_vars_of_root_atom(fvar_collector_t * collect,root_atom_t * r)261 static harray_t *free_vars_of_root_atom(fvar_collector_t *collect, root_atom_t *r) {
262 harray_t *a;
263 term_t x;
264
265 x = r->x;
266 a = get_free_vars_of_term(collect, r->p); // p = polynomial
267 a = harray_remove_elem(&collect->store, a, 1, &x); // x = bound variable in p(x, ...)
268
269 return a;
270 }
271
272
273
274 /*
275 * Compute the set of free variables in term t:
276 * - t must be defined in collect->terms
277 * - the set is returned as a harray structure a (cf. int_array_hsets)
278 * a->nelems = size of the set = n
279 * a->data[0 ... n-1] = variables of t listed in increasing order
280 */
get_free_vars_of_term(fvar_collector_t * collect,term_t t)281 harray_t *get_free_vars_of_term(fvar_collector_t *collect, term_t t) {
282 term_table_t *terms;
283 harray_t *result;
284 int32_t i;
285
286 terms = collect->terms;
287 i = index_of(t);
288 switch (kind_for_idx(terms, i)) {
289 case CONSTANT_TERM:
290 case ARITH_CONSTANT:
291 case BV64_CONSTANT:
292 case BV_CONSTANT:
293 case UNINTERPRETED_TERM:
294 result = empty_fvar_set(collect);
295 break;
296
297 case VARIABLE:
298 // we use pos_term(i) rather than t since t could be a negative term
299 // (i.e., neg_term(i) that represents (not v) for some Boolean variable v)
300 result = singleton_fvar_set(collect, pos_term(i));
301 break;
302
303 case ARITH_EQ_ATOM:
304 case ARITH_GE_ATOM:
305 case ARITH_IS_INT_ATOM:
306 case ARITH_FLOOR:
307 case ARITH_CEIL:
308 case ARITH_ABS:
309 result = get_free_vars_of_term(collect, integer_value_for_idx(terms, i));
310 break;
311
312 case ARITH_ROOT_ATOM:
313 result = lookup_free_vars(collect, i);
314 if (result == NULL) {
315 result = free_vars_of_root_atom(collect, root_atom_for_idx(terms, i));
316 cache_free_vars(collect, i, result);
317 }
318 break;
319
320 case ITE_TERM:
321 case ITE_SPECIAL:
322 case APP_TERM:
323 case UPDATE_TERM:
324 case TUPLE_TERM:
325 case EQ_TERM:
326 case DISTINCT_TERM:
327 case OR_TERM:
328 case XOR_TERM:
329 case ARITH_BINEQ_ATOM:
330 case ARITH_RDIV:
331 case ARITH_IDIV:
332 case ARITH_MOD:
333 case ARITH_DIVIDES_ATOM:
334 case BV_ARRAY:
335 case BV_DIV:
336 case BV_REM:
337 case BV_SDIV:
338 case BV_SREM:
339 case BV_SMOD:
340 case BV_SHL:
341 case BV_LSHR:
342 case BV_ASHR:
343 case BV_EQ_ATOM:
344 case BV_GE_ATOM:
345 case BV_SGE_ATOM:
346 result = lookup_free_vars(collect, i);
347 if (result == NULL) {
348 result = free_vars_of_composite(collect, composite_for_idx(terms, i));
349 cache_free_vars(collect, i, result);
350 }
351 break;
352
353 case FORALL_TERM:
354 case LAMBDA_TERM:
355 result = lookup_free_vars(collect, i);
356 if (result == NULL) {
357 result = free_vars_of_binding(collect, composite_for_idx(terms, i));
358 cache_free_vars(collect, i, result);
359 }
360 break;
361
362 case SELECT_TERM:
363 case BIT_TERM:
364 result = get_free_vars_of_term(collect, select_for_idx(terms, i)->arg);
365 break;
366
367 case POWER_PRODUCT:
368 result = lookup_free_vars(collect, i);
369 if (result == NULL) {
370 result = free_vars_of_pprod(collect, pprod_for_idx(terms, i));
371 cache_free_vars(collect, i, result);
372 }
373 break;
374
375 case ARITH_POLY:
376 result = lookup_free_vars(collect, i);
377 if (result == NULL) {
378 result = free_vars_of_poly(collect, polynomial_for_idx(terms, i));
379 cache_free_vars(collect, i, result);
380 }
381 break;
382
383 case BV64_POLY:
384 result = lookup_free_vars(collect, i);
385 if (result == NULL) {
386 result = free_vars_of_bvpoly64(collect, bvpoly64_for_idx(terms, i));
387 cache_free_vars(collect, i, result);
388 }
389 break;
390
391 case BV_POLY:
392 result = lookup_free_vars(collect, i);
393 if (result == NULL) {
394 result = free_vars_of_bvpoly(collect, bvpoly_for_idx(terms, i));
395 cache_free_vars(collect, i, result);
396 }
397 break;
398
399 default:
400 assert(false);
401 result = NULL;
402 break;
403 }
404
405 return result;
406 }
407
408
409
410 /*
411 * Check whether t is a ground term:
412 * - side effect: this computes the set of free variables of t
413 */
term_is_ground(fvar_collector_t * collect,term_t t)414 bool term_is_ground(fvar_collector_t *collect, term_t t) {
415 harray_t *a;
416
417 a = get_free_vars_of_term(collect, t);
418 return a->nelems == 0;
419 }
420
421
422 /*
423 * Filter for ptr_hmap: r is a pair <term, ptr>
424 * - r must be deleted if the term is dead
425 * - aux is a pointer to the term table
426 */
fvar_dead_hmap_pair(void * aux,const ptr_hmap_pair_t * r)427 static bool fvar_dead_hmap_pair(void *aux, const ptr_hmap_pair_t *r) {
428 return !live_term(aux, r->key);
429 }
430
431
432 /*
433 * Filter for the store:
434 * - a is a harray structure
435 * - aux is a pointer to the term table
436 * - a must be deleted if it contains a dead term
437 */
fvar_dead_harray(void * aux,const harray_t * a)438 static bool fvar_dead_harray(void *aux, const harray_t *a) {
439 uint32_t i, n;
440
441 n = a->nelems;
442 for (i=0; i<n; i++) {
443 if (!live_term(aux, a->data[i])) {
444 return true;
445 }
446 }
447
448 return false;
449 }
450
451
452
453 /*
454 * Cleanup: remove any references to deleted terms
455 * - this must be called after terms are removed from collect->terms
456 */
cleanup_fvar_collector(fvar_collector_t * collect)457 void cleanup_fvar_collector(fvar_collector_t *collect) {
458 // must delete records in the map first
459 ptr_hmap_remove_records(&collect->map, collect->terms, fvar_dead_hmap_pair);
460 harray_store_remove_arrays(&collect->store, collect->terms, fvar_dead_harray);
461 }
462