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