1 /*
2 * This file is part of the Yices SMT Solver.
3 * Copyright (C) 2018 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 * Hash table that maps non-negative integers to rationals.
21 * This is used in the difference-logic profiler.
22 *
23 * This implementation supports only addition and query (not removal
24 * of entries).
25 */
26
27 #include <assert.h>
28
29 #include "terms/int_rational_hash_maps.h"
30 #include "utils/memalloc.h"
31
32 /*
33 * For debugging: check whether n is 0 or a power of 2
34 */
35 #ifndef NDEBUG
is_power_of_two(uint32_t n)36 static bool is_power_of_two(uint32_t n) {
37 return (n & (n - 1)) == 0;
38 }
39 #endif
40
41
42 /*
43 * Initialization:
44 * - n = initial size, must be a power of 2
45 * - if n = 0, the default size is used
46 */
init_int_rat_hmap(int_rat_hmap_t * hmap,uint32_t n)47 void init_int_rat_hmap(int_rat_hmap_t *hmap, uint32_t n) {
48 int_rat_hmap_rec_t *tmp;
49 uint32_t i;
50
51 if (n == 0) {
52 n = INT_RAT_HMAP_DEF_SIZE;
53 }
54
55 if (n > INT_RAT_HMAP_MAX_SIZE) {
56 out_of_memory();
57 }
58
59 assert(is_power_of_two(n));
60
61 tmp = (int_rat_hmap_rec_t *) safe_malloc(n * sizeof(int_rat_hmap_rec_t));
62 for (i=0; i<n; i++) {
63 tmp[i].key = -1;
64 q_init(&tmp[i].value);
65 }
66
67 hmap->data = tmp;
68 hmap->size = n;
69 hmap->nelems = 0;
70 hmap->resize_threshold = (uint32_t) (n * INT_RAT_HMAP_RESIZE_RATIO);
71 }
72
73
74 /*
75 * Delete: free memory
76 */
delete_int_rat_hmap(int_rat_hmap_t * hmap)77 void delete_int_rat_hmap(int_rat_hmap_t *hmap) {
78 int_rat_hmap_rec_t *tmp;
79 uint32_t i, n;
80
81 tmp = hmap->data;
82 n = hmap->size;
83 for (i=0; i<n; i++) {
84 q_clear(&tmp[i].value);
85 }
86
87 safe_free(tmp);
88 hmap->data = NULL;
89 }
90
91
92
93 /*
94 * Remove all records
95 */
reset_int_rat_hmap(int_rat_hmap_t * hmap)96 void reset_int_rat_hmap(int_rat_hmap_t *hmap) {
97 int_rat_hmap_rec_t *tmp;
98 uint32_t i, n;
99
100 tmp = hmap->data;
101 n = hmap->size;
102 for (i=0; i<n; i++) {
103 tmp[i].key = -1;
104 q_clear(&tmp[i].value);
105 }
106
107 hmap->nelems = 0;
108 }
109
110
111 /*
112 * Hash code for a 32bit key.
113 * This is Jenkins's hash function (cf. utils/hash_functions.c)
114 */
hash_key(int32_t k)115 static uint32_t hash_key(int32_t k) {
116 uint32_t x;
117
118 x = (uint32_t) k;
119 x = (x + 0x7ed55d16) + (x<<12);
120 x = (x ^ 0xc761c23c) ^ (x>>19);
121 x = (x + 0x165667b1) + (x<<5);
122 x = (x + 0xd3a2646c) ^ (x<<9);
123 x = (x + 0xfd7046c5) + (x<<3);
124 x = (x ^ 0xb55a4f09) ^ (x>>16);
125
126 return x;
127 }
128
129
130 /*
131 * Find record with key k. Return NULL if there's none.
132 * - k must be non-negative.
133 */
int_rat_hmap_find(int_rat_hmap_t * hmap,int32_t k)134 int_rat_hmap_rec_t *int_rat_hmap_find(int_rat_hmap_t *hmap, int32_t k) {
135 int_rat_hmap_rec_t *r;
136 uint32_t i, mask;
137
138 assert(k >= 0);
139 assert(hmap->nelems < hmap->size); // otherwise, this will loop
140 assert(is_power_of_two(hmap->size));
141
142 mask = hmap->size - 1;
143 i = hash_key(k) & mask;
144 for (;;) {
145 r = hmap->data + i;
146 if (r->key < 0) return NULL;
147 if (r->key == k) return r;
148 i ++;
149 i &= mask;
150 }
151 }
152
153
154 /*
155 * Copy record r into a fresh table a
156 * - mask = size of a - 1 (a'size is a power of two)
157 * - there must be room in a
158 * - warning: this makes a shallow copy of r->value.
159 * So we must not call q_clear(&r->value);
160 */
int_rat_hmap_clean_copy(int_rat_hmap_rec_t * a,int_rat_hmap_rec_t * r,uint32_t mask)161 static void int_rat_hmap_clean_copy(int_rat_hmap_rec_t *a, int_rat_hmap_rec_t *r, uint32_t mask) {
162 uint32_t i;
163
164 assert(r->key >= 0);
165
166 i = hash_key(r->key) & mask;
167 while (a[i].key >= 0) {
168 i ++;
169 i &= mask;
170 }
171
172 a[i] = *r;
173 }
174
175 /*
176 * Make the table twice as large.
177 */
int_rat_hmap_extend(int_rat_hmap_t * hmap)178 static void int_rat_hmap_extend(int_rat_hmap_t *hmap) {
179 int_rat_hmap_rec_t *tmp, *r;
180 uint32_t i, n, n2, mask;
181
182 n = hmap->size;
183 n2 = n << 1;
184 if (n2 > INT_RAT_HMAP_MAX_SIZE) {
185 out_of_memory();
186 }
187
188 assert(is_power_of_two(n2));
189
190 tmp = (int_rat_hmap_rec_t *) safe_malloc(n2 * sizeof(int_rat_hmap_rec_t));
191 for (i=0; i<n2; i++) {
192 tmp[i].key = -1;
193 q_init(&tmp[i].value);
194 }
195
196 mask = n2 -1;
197 r = hmap->data;
198 for (i=0; i<n; i++) {
199 if (r->key >= 0) {
200 int_rat_hmap_clean_copy(tmp, r, mask);
201 }
202 r ++;
203 }
204
205 // we don't clear the rationals of hmap->data
206 // since we made shallow copies in tmp.
207 safe_free(hmap->data);
208
209 hmap->data = tmp;
210 hmap->size = n2;
211 hmap->resize_threshold = (uint32_t) (n2 * INT_RAT_HMAP_RESIZE_RATIO);
212 }
213
214
215
216 /*
217 * Get record with key k
218 * - if one is in the table return it and set *new to false.
219 * - otherwise, create a fresh record with key k, value 0,
220 * and set *new to true.
221 * - k must be non-negative
222 */
int_rat_hmap_get(int_rat_hmap_t * hmap,int32_t k,bool * new)223 int_rat_hmap_rec_t *int_rat_hmap_get(int_rat_hmap_t *hmap, int32_t k, bool *new) {
224 int_rat_hmap_rec_t *r;
225 uint32_t i, mask;
226
227 assert(k >= 0);
228 assert(hmap->nelems < hmap->size); // otherwise, this will loop
229 assert(is_power_of_two(hmap->size));
230
231 *new = false;
232 mask = hmap->size - 1;
233 i = hash_key(k) & mask;
234 for (;;) {
235 r = hmap->data + i;
236 if (r->key == k) return r;
237 if (r->key < 0) break; // found an empty slot
238 i ++;
239 i &= mask;
240 }
241
242 *new = true;
243 r->key = k;
244 hmap->nelems ++;
245 if (hmap->nelems > hmap->resize_threshold) {
246 int_rat_hmap_extend(hmap);
247 r = int_rat_hmap_find(hmap, k);
248 assert(r != NULL);
249 }
250
251 return r;
252 }
253
254
255 /*
256 * Compute the sum of all values
257 */
int_rat_hmap_sum(int_rat_hmap_t * hmap,rational_t * sum)258 void int_rat_hmap_sum(int_rat_hmap_t *hmap, rational_t *sum) {
259 int_rat_hmap_rec_t *r;
260 uint32_t i, n;
261
262 q_clear(sum);
263 n = hmap->size;
264 r = hmap->data;
265 for (i=0; i<n; i++) {
266 if (r->key >= 0) {
267 q_add(sum, &r->value);
268 }
269 r ++;
270 }
271 }
272
273