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  * Buffer for construction of bitvector polynomials
21  */
22 
23 #include <assert.h>
24 #include <stdbool.h>
25 
26 #include "terms/bv64_constants.h"
27 #include "terms/bv_constants.h"
28 #include "terms/bvpoly_buffers.h"
29 #include "utils/hash_functions.h"
30 #include "utils/memalloc.h"
31 #include "utils/prng.h"
32 
33 
34 /***********************
35  *  CREATION/DELETION  *
36  **********************/
37 
38 /*
39  * Initialize buffer
40  * - i_size and m_size are initialized to the default
41  * - bitsize is set to 0
42  * - w_size is 0
43  */
init_bvpoly_buffer(bvpoly_buffer_t * buffer)44 void init_bvpoly_buffer(bvpoly_buffer_t *buffer) {
45   int32_t *tmp;
46   uint32_t i, n;
47 
48   assert(DEF_BVPOLYBUFFER_ISIZE < MAX_BVPOLYBUFFER_ISIZE &&
49          DEF_BVPOLYBUFFER_SIZE < MAX_BVPOLYBUFFER_SIZE);
50 
51   n = DEF_BVPOLYBUFFER_ISIZE;
52   tmp = (int32_t *) safe_malloc(n * sizeof(int32_t));
53   for (i=0; i<n; i++) {
54     tmp[i] = -1;
55   }
56   buffer->index = tmp;
57   buffer->i_size = n;
58 
59   n = DEF_BVPOLYBUFFER_SIZE;
60   buffer->var = (int32_t *) safe_malloc(n * sizeof(int32_t));
61   buffer->c = (uint64_t *) safe_malloc(n * sizeof(uint64_t));
62   buffer->m_size = n;
63 
64   buffer->p = NULL; // allocated only if needed
65   buffer->w_size = 0;
66 
67   buffer->nterms = 0;
68   buffer->bitsize = 0;
69   buffer->width = 0;
70 }
71 
72 
73 /*
74  * Delete: free memory
75  */
delete_bvpoly_buffer(bvpoly_buffer_t * buffer)76 void delete_bvpoly_buffer(bvpoly_buffer_t *buffer) {
77   uint32_t **p;
78   uint32_t i, n;
79 
80   safe_free(buffer->index);
81   safe_free(buffer->var);
82   safe_free(buffer->c);
83 
84   buffer->index = NULL;
85   buffer->var = NULL;
86   buffer->c = NULL;
87 
88   p = buffer->p;
89   if (p != NULL) {
90     n = buffer->m_size;
91     for (i=0; i<n; i++) {
92       safe_free(p[i]);
93     }
94     safe_free(p);
95     buffer->p = NULL;
96   }
97 }
98 
99 
100 /*
101  * Allocate the internal p array if it's NULL
102  * - its size is buffer->m_size
103  * - all its elements are initialized to NULL
104  */
bvpoly_alloc_coeff_array(bvpoly_buffer_t * buffer)105 static void bvpoly_alloc_coeff_array(bvpoly_buffer_t *buffer) {
106   uint32_t **p;
107   uint32_t i, n;
108 
109   p = buffer->p;
110   if (p == NULL) {
111     n = buffer->m_size;
112     p = (uint32_t **) safe_malloc(n * sizeof(uint32_t *));
113     for (i=0; i<n; i++) {
114       p[i] = NULL;
115     }
116     buffer->p = p;
117   }
118 }
119 
120 
121 /*
122  * Free all elements of array p
123  * - this is used when they are too small for the current width
124  */
bvpoly_reset_coeff_array(bvpoly_buffer_t * buffer)125 static void bvpoly_reset_coeff_array(bvpoly_buffer_t *buffer) {
126   uint32_t **p;
127   uint32_t i, n;
128 
129   p = buffer->p;
130   assert(p != NULL);
131 
132   n = buffer->m_size;
133   for (i=0; i<n; i++) {
134     if (p[i] == NULL) break;
135     safe_free(p[i]);
136     p[i] = NULL;
137   }
138 }
139 
140 
141 /*
142  * Reset buffer and prepare for construction of a polynomial
143  * with the given bitsize.
144  * - bitsize must be positive
145  * - allocate the p vector if bitsize > 64
146  * - make sure the w_size is large enough
147  */
reset_bvpoly_buffer(bvpoly_buffer_t * buffer,uint32_t bitsize)148 void reset_bvpoly_buffer(bvpoly_buffer_t *buffer, uint32_t bitsize) {
149   uint32_t w, w_size;
150   uint32_t i, n;
151   int32_t x;
152 
153   assert(bitsize > 0);
154 
155   w = (bitsize + 31) >> 5;
156   buffer->bitsize = bitsize;
157   buffer->width = w;
158 
159   // clear the variable indices
160   n = buffer->nterms;
161   for (i=0; i<n; i++) {
162     x = buffer->var[i];
163     assert(buffer->index[x] == i);
164     buffer->index[x] = -1;
165   }
166   buffer->nterms = 0;
167 
168   if (bitsize > 64) {
169     bvpoly_alloc_coeff_array(buffer);
170     w_size = buffer->w_size;
171     if (w_size < w) {
172       bvpoly_reset_coeff_array(buffer);
173       // new w_size = max(2 * current w_size, w)
174       w_size <<= 1;
175       if (w_size < w) {
176         w_size = w;
177       }
178       buffer->w_size = w_size;
179     }
180   }
181 }
182 
183 
184 
185 
186 /*
187  * Extend the index array and initialize new elements to -1
188  * - this makes sure the index array is large enough to store index[x]
189  * - x must be >= buffer->i_size
190  */
bvpoly_buffer_resize_index(bvpoly_buffer_t * buffer,int32_t x)191 static void bvpoly_buffer_resize_index(bvpoly_buffer_t *buffer, int32_t x) {
192   int32_t *tmp;
193   uint32_t i, n;
194 
195   assert(buffer->i_size <= x && x < max_idx);
196 
197   // the new size is max(1.5 * current_size, x +1)
198   n = buffer->i_size;
199   n += n>>1;
200   if (n <= x) {
201     n = x+1;
202   }
203 
204   if (n >= MAX_BVPOLYBUFFER_ISIZE) {
205     out_of_memory();
206   }
207 
208   tmp = (int32_t *) safe_realloc(buffer->index, n * sizeof(int32_t));
209   for (i=buffer->i_size; i<n; i++) {
210     tmp[i] = -1;
211   }
212 
213   buffer->index = tmp;
214   buffer->i_size = n;
215 }
216 
217 
218 
219 
220 /*
221  * Increase the size of arrays var and c, and p if it's non NULL.
222  * - if p is non-null, the new elements of p are initialized to NULL
223  */
bvpoly_buffer_extend_mono(bvpoly_buffer_t * buffer)224 static void bvpoly_buffer_extend_mono(bvpoly_buffer_t *buffer) {
225   uint32_t **p;
226   uint32_t i, n;
227 
228   n = buffer->m_size + 1;
229   n += n>>1;
230   if (n >= MAX_BVPOLYBUFFER_SIZE) {
231     out_of_memory();
232   }
233 
234   buffer->var = (int32_t *) safe_realloc(buffer->var, n * sizeof(int32_t));
235   buffer->c = (uint64_t *) safe_realloc(buffer->c, n * sizeof(uint64_t));
236 
237   p = buffer->p;
238   if (p != NULL) {
239     p = (uint32_t **) safe_realloc(p, n * sizeof(uint32_t *));
240     for (i=buffer->m_size; i<n; i++) {
241       p[i] = NULL;
242     }
243     buffer->p = p;
244   }
245 
246   buffer->m_size = n;
247 }
248 
249 
250 
251 /*
252  * Allocate a new monomial and return its index i
253  * - if needed, make the var, c, and p arrays larger
254  * - set the coefficient c[i] or p[i] to 0
255  *   (also allocate a large enough array p[i])
256  */
bvpoly_buffer_alloc_mono(bvpoly_buffer_t * buffer)257 static int32_t bvpoly_buffer_alloc_mono(bvpoly_buffer_t *buffer) {
258   uint32_t i;
259 
260   i = buffer->nterms;
261   if (i == buffer->m_size) {
262     bvpoly_buffer_extend_mono(buffer);
263   }
264   assert(i < buffer->m_size);
265 
266   if (buffer->bitsize > 64) {
267     assert(buffer->p != NULL);
268     if (buffer->p[i] == NULL) {
269       buffer->p[i] = (uint32_t *) safe_malloc(buffer->w_size * sizeof(uint32_t));
270     }
271   }
272 
273   buffer->nterms = i+1;
274 
275   return i;
276 }
277 
278 
279 /*
280  * Get buffer->index[x] (resize the index array if needed)
281  */
bvpoly_buffer_get_index(bvpoly_buffer_t * buffer,int32_t x)282 static inline int32_t bvpoly_buffer_get_index(bvpoly_buffer_t *buffer, int32_t x) {
283   assert(0 <= x && x < max_idx);
284   if (x >= buffer->i_size) {
285     bvpoly_buffer_resize_index(buffer, x);
286   }
287   return buffer->index[x];
288 }
289 
290 
291 /*
292  * Return buffer->index[x] (no allocation if x is not in the index array)
293  * - return -1 if x is not in the index array
294  */
bvpoly_buffer_find_index(bvpoly_buffer_t * buffer,int32_t x)295 static inline int32_t bvpoly_buffer_find_index(bvpoly_buffer_t *buffer, int32_t x) {
296   int32_t i;
297 
298   assert(0 <= x && x < max_idx);
299 
300   i = -1;
301   if (x < buffer->i_size) {
302     i = buffer->index[x];
303   }
304   return i;
305 }
306 
307 
308 
309 /************************
310  *  MONOMIAL ADDITION   *
311  ***********************/
312 
313 /*
314  * Add monomial a * x to buffer
315  * - buffer->bitsize must be no more than 64
316  */
bvpoly_buffer_add_mono64(bvpoly_buffer_t * buffer,int32_t x,uint64_t a)317 void bvpoly_buffer_add_mono64(bvpoly_buffer_t *buffer, int32_t x, uint64_t a) {
318   int32_t i;
319 
320   assert(0 < buffer->bitsize && buffer->bitsize <= 64);
321 
322   i = bvpoly_buffer_get_index(buffer, x);
323   if (i >= 0) {
324     assert(i < buffer->nterms && buffer->var[i] == x);
325     buffer->c[i] += a;
326   } else {
327     i = bvpoly_buffer_alloc_mono(buffer);
328     buffer->index[x] = i;
329     buffer->var[i] = x;
330     buffer->c[i] = a;
331   }
332 }
333 
334 
335 /*
336  * Subtract monomial a * x from buffer
337  * - buffer->bitsize must be no more than 64
338  */
bvpoly_buffer_sub_mono64(bvpoly_buffer_t * buffer,int32_t x,uint64_t a)339 void bvpoly_buffer_sub_mono64(bvpoly_buffer_t *buffer, int32_t x, uint64_t a) {
340   int32_t i;
341 
342   assert(0 < buffer->bitsize && buffer->bitsize <= 64);
343 
344   i = bvpoly_buffer_get_index(buffer, x);
345   if (i >= 0) {
346     assert(i < buffer->nterms && buffer->var[i] == x);
347     buffer->c[i] -= a;
348   } else {
349     i = bvpoly_buffer_alloc_mono(buffer);
350     buffer->index[x] = i;
351     buffer->var[i] = x;
352     buffer->c[i] = -a; // 2-complement
353   }
354 }
355 
356 
357 /*
358  * Add a * b * x to buffer
359  * - buffer->bitsize must be no more than 64
360  */
bvpoly_buffer_addmul_mono64(bvpoly_buffer_t * buffer,int32_t x,uint64_t a,uint64_t b)361 void bvpoly_buffer_addmul_mono64(bvpoly_buffer_t *buffer, int32_t x, uint64_t a, uint64_t b) {
362   int32_t i;
363 
364   assert(0 < buffer->bitsize && buffer->bitsize <= 64);
365 
366   i = bvpoly_buffer_get_index(buffer, x);
367   if (i >= 0) {
368     assert(i < buffer->nterms && buffer->var[i] == x);
369     buffer->c[i] += a * b;
370   } else {
371     i = bvpoly_buffer_alloc_mono(buffer);
372     buffer->index[x] = i;
373     buffer->var[i] = x;
374     buffer->c[i] = a * b;
375   }
376 }
377 
378 
379 /*
380  * Subtract a * b * x from buffer
381  * - buffer->bitsize must be no more than 64
382  */
bvpoly_buffer_submul_mono64(bvpoly_buffer_t * buffer,int32_t x,uint64_t a,uint64_t b)383 void bvpoly_buffer_submul_mono64(bvpoly_buffer_t *buffer, int32_t x, uint64_t a, uint64_t b) {
384   int32_t i;
385 
386   assert(0 < buffer->bitsize && buffer->bitsize <= 64);
387 
388   i = bvpoly_buffer_get_index(buffer, x);
389   if (i >= 0) {
390     assert(i < buffer->nterms && buffer->var[i] == x);
391     buffer->c[i] -= a * b;
392   } else {
393     i = bvpoly_buffer_alloc_mono(buffer);
394     buffer->index[x] = i;
395     buffer->var[i] = x;
396     buffer->c[i] = -(a * b);
397   }
398 }
399 
400 
401 
402 
403 
404 
405 /*
406  * Add monomial a * x to buffer
407  * - buffer->bitsize must be more than 64
408  * - a must be an array of w words (where w = ceil(bitsize / 32)
409  */
bvpoly_buffer_add_monomial(bvpoly_buffer_t * buffer,int32_t x,uint32_t * a)410 void bvpoly_buffer_add_monomial(bvpoly_buffer_t *buffer, int32_t x, uint32_t *a) {
411   uint32_t w;
412   int32_t i;
413 
414   assert(64 < buffer->bitsize);
415   w = buffer->width;
416   i = bvpoly_buffer_get_index(buffer, x);
417   if (i >= 0) {
418     assert(i < buffer->nterms && buffer->var[i] == x && buffer->p[i] != NULL);
419     bvconst_add(buffer->p[i], w, a);
420   } else {
421     i = bvpoly_buffer_alloc_mono(buffer);
422     buffer->index[x] = i;
423     buffer->var[i] = x;
424     bvconst_set(buffer->p[i], w, a);
425   }
426 }
427 
428 
429 /*
430  * Subtract monomial a * x from buffer
431  * - buffer->bitsize must be more than 64
432  * - a must be an array of w words (where w = ceil(bitsize / 32)
433  */
bvpoly_buffer_sub_monomial(bvpoly_buffer_t * buffer,int32_t x,uint32_t * a)434 void bvpoly_buffer_sub_monomial(bvpoly_buffer_t *buffer, int32_t x, uint32_t *a) {
435   uint32_t w;
436   int32_t i;
437 
438   assert(64 < buffer->bitsize);
439   w = buffer->width;
440   i = bvpoly_buffer_get_index(buffer, x);
441   if (i >= 0) {
442     assert(i < buffer->nterms && buffer->var[i] == x && buffer->p[i] != NULL);
443     bvconst_sub(buffer->p[i], w, a);
444   } else {
445     i = bvpoly_buffer_alloc_mono(buffer);
446     buffer->index[x] = i;
447     buffer->var[i] = x;
448     bvconst_negate2(buffer->p[i], w, a);
449   }
450 }
451 
452 /*
453  * Add monomial a * b * x to buffer
454  * - buffer->bitsize must be more than 64
455  * - a and b must be arrays of w words (where w = ceil(bitsize / 32)
456  */
bvpoly_buffer_addmul_monomial(bvpoly_buffer_t * buffer,int32_t x,uint32_t * a,uint32_t * b)457 void bvpoly_buffer_addmul_monomial(bvpoly_buffer_t *buffer, int32_t x, uint32_t *a, uint32_t *b) {
458   uint32_t w;
459   int32_t i;
460 
461   assert(64 < buffer->bitsize);
462   w = buffer->width;
463   i = bvpoly_buffer_get_index(buffer, x);
464   if (i >= 0) {
465     assert(i < buffer->nterms && buffer->var[i] == x && buffer->p[i] != NULL);
466     bvconst_addmul(buffer->p[i], w, a, b);
467   } else {
468     i = bvpoly_buffer_alloc_mono(buffer);
469     buffer->index[x] = i;
470     buffer->var[i] = x;
471     bvconst_clear(buffer->p[i], w);
472     bvconst_addmul(buffer->p[i], w, a, b);
473   }
474 }
475 
476 
477 /*
478  * Subtract monomial a * b * x from buffer
479  * - buffer->bitsize must be more than 64
480  * - a and b must be arrays of w words (where w = ceil(bitsize / 32)
481  */
bvpoly_buffer_submul_monomial(bvpoly_buffer_t * buffer,int32_t x,uint32_t * a,uint32_t * b)482 void bvpoly_buffer_submul_monomial(bvpoly_buffer_t *buffer, int32_t x, uint32_t *a, uint32_t *b) {
483   uint32_t w;
484   int32_t i;
485 
486   assert(64 < buffer->bitsize);
487   w = buffer->width;
488   i = bvpoly_buffer_get_index(buffer, x);
489   if (i >= 0) {
490     assert(i < buffer->nterms && buffer->var[i] == x && buffer->p[i] != NULL);
491     bvconst_submul(buffer->p[i], w, a, b);
492   } else {
493     i = bvpoly_buffer_alloc_mono(buffer);
494     buffer->index[x] = i;
495     buffer->var[i] = x;
496     bvconst_clear(buffer->p[i], w);
497     bvconst_submul(buffer->p[i], w, a, b);
498   }
499 }
500 
501 
502 
503 
504 
505 /*
506  * Add x to buffer (i.e., monomial 1 * x)
507  */
bvpoly_buffer_add_var(bvpoly_buffer_t * buffer,int32_t x)508 void bvpoly_buffer_add_var(bvpoly_buffer_t *buffer, int32_t x) {
509   uint32_t w;
510   int32_t i;
511 
512   w = buffer->width;
513   i = bvpoly_buffer_get_index(buffer, x);
514   if (i >= 0) {
515     assert(i < buffer->nterms && buffer->var[i] == x);
516     if (w <= 2) {
517       buffer->c[i] ++;
518     } else {
519       bvconst_add_one(buffer->p[i], w);
520     }
521   } else {
522     i = bvpoly_buffer_alloc_mono(buffer);
523     buffer->index[x] = i;
524     buffer->var[i] = x;
525     if (w <= 2) {
526       buffer->c[i] = 1;
527     } else {
528       bvconst_set_one(buffer->p[i], w);
529     }
530   }
531 }
532 
533 
534 
535 /*
536  * Subtract x from buffer (i.e., monomial 1 * x)
537  */
bvpoly_buffer_sub_var(bvpoly_buffer_t * buffer,int32_t x)538 void bvpoly_buffer_sub_var(bvpoly_buffer_t *buffer, int32_t x) {
539   uint32_t w;
540   int32_t i;
541 
542   w = buffer->width;
543   i = bvpoly_buffer_get_index(buffer, x);
544   if (i >= 0) {
545     assert(i < buffer->nterms && buffer->var[i] == x);
546     if (w <= 2) {
547       buffer->c[i] --;
548     } else {
549       bvconst_sub_one(buffer->p[i], w);
550     }
551   } else {
552     i = bvpoly_buffer_alloc_mono(buffer);
553     buffer->index[x] = i;
554     buffer->var[i] = x;
555     if (w <= 2) {
556       buffer->c[i] = ((uint64_t) -1);
557     } else {
558       bvconst_set_minus_one(buffer->p[i], w);
559     }
560   }
561 }
562 
563 
564 
565 /*************************
566  *  POLYNOMIAL ADDITION  *
567  ************************/
568 
569 /*
570  * Polynomials with 64bit coefficients or less
571  */
bvpoly_buffer_add_poly64(bvpoly_buffer_t * buffer,bvpoly64_t * p)572 void bvpoly_buffer_add_poly64(bvpoly_buffer_t *buffer, bvpoly64_t *p) {
573   uint32_t i, n;
574 
575   assert(p->bitsize == buffer->bitsize);
576 
577   n = p->nterms;
578   for (i=0; i<n; i++) {
579     bvpoly_buffer_add_mono64(buffer, p->mono[i].var, p->mono[i].coeff);
580   }
581 }
582 
583 
bvpoly_buffer_sub_poly64(bvpoly_buffer_t * buffer,bvpoly64_t * p)584 void bvpoly_buffer_sub_poly64(bvpoly_buffer_t *buffer, bvpoly64_t *p) {
585   uint32_t i, n;
586 
587   assert(p->bitsize == buffer->bitsize);
588 
589   n = p->nterms;
590   for (i=0; i<n; i++) {
591     bvpoly_buffer_sub_mono64(buffer, p->mono[i].var, p->mono[i].coeff);
592   }
593 }
594 
595 
bvpoly_buffer_addmul_poly64(bvpoly_buffer_t * buffer,bvpoly64_t * p,uint64_t a)596 void bvpoly_buffer_addmul_poly64(bvpoly_buffer_t *buffer, bvpoly64_t *p, uint64_t a) {
597   uint32_t i, n;
598 
599   assert(p->bitsize == buffer->bitsize);
600 
601   n = p->nterms;
602   for (i=0; i<n; i++) {
603     bvpoly_buffer_addmul_mono64(buffer, p->mono[i].var, p->mono[i].coeff, a);
604   }
605 }
606 
607 
bvpoly_buffer_submul_poly64(bvpoly_buffer_t * buffer,bvpoly64_t * p,uint64_t a)608 void bvpoly_buffer_submul_poly64(bvpoly_buffer_t *buffer, bvpoly64_t *p, uint64_t a) {
609   uint32_t i, n;
610 
611   assert(p->bitsize == buffer->bitsize);
612 
613   n = p->nterms;
614   for (i=0; i<n; i++) {
615     bvpoly_buffer_submul_mono64(buffer, p->mono[i].var, p->mono[i].coeff, a);
616   }
617 }
618 
619 
620 /*
621  * Generic polynomials
622  */
bvpoly_buffer_add_poly(bvpoly_buffer_t * buffer,bvpoly_t * p)623 void bvpoly_buffer_add_poly(bvpoly_buffer_t *buffer, bvpoly_t *p) {
624   uint32_t i, n;
625 
626   assert(p->bitsize == buffer->bitsize);
627 
628   n = p->nterms;
629   for (i=0; i<n; i++) {
630     bvpoly_buffer_add_monomial(buffer, p->mono[i].var, p->mono[i].coeff);
631   }
632 }
633 
634 
bvpoly_buffer_sub_poly(bvpoly_buffer_t * buffer,bvpoly_t * p)635 void bvpoly_buffer_sub_poly(bvpoly_buffer_t *buffer, bvpoly_t *p) {
636   uint32_t i, n;
637 
638   assert(p->bitsize == buffer->bitsize);
639 
640   n = p->nterms;
641   for (i=0; i<n; i++) {
642     bvpoly_buffer_sub_monomial(buffer, p->mono[i].var, p->mono[i].coeff);
643   }
644 }
645 
646 
bvpoly_buffer_addmul_poly(bvpoly_buffer_t * buffer,bvpoly_t * p,uint32_t * a)647 void bvpoly_buffer_addmul_poly(bvpoly_buffer_t *buffer, bvpoly_t *p, uint32_t *a) {
648   uint32_t i, n;
649 
650   assert(p->bitsize == buffer->bitsize);
651 
652   n = p->nterms;
653   for (i=0; i<n; i++) {
654     bvpoly_buffer_addmul_monomial(buffer, p->mono[i].var, p->mono[i].coeff, a);
655   }
656 }
657 
658 
bvpoly_buffer_submul_poly(bvpoly_buffer_t * buffer,bvpoly_t * p,uint32_t * a)659 void bvpoly_buffer_submul_poly(bvpoly_buffer_t *buffer, bvpoly_t *p, uint32_t *a) {
660   uint32_t i, n;
661 
662   assert(p->bitsize == buffer->bitsize);
663 
664   n = p->nterms;
665   for (i=0; i<n; i++) {
666     bvpoly_buffer_submul_monomial(buffer, p->mono[i].var, p->mono[i].coeff, a);
667   }
668 }
669 
670 
671 /*
672  * Add b to buffer
673  */
bvpoly_buffer_add_buffer(bvpoly_buffer_t * buffer,bvpoly_buffer_t * b)674 void bvpoly_buffer_add_buffer(bvpoly_buffer_t *buffer, bvpoly_buffer_t *b) {
675   uint32_t i, n;
676 
677   assert(buffer->bitsize == b->bitsize);
678 
679   n = b->nterms;
680   if (b->bitsize <= 64) {
681     for (i=0; i<n; i++) {
682       bvpoly_buffer_add_mono64(buffer, b->var[i], b->c[i]);
683     }
684   } else {
685     for (i=0; i<n; i++) {
686       bvpoly_buffer_add_monomial(buffer, b->var[i], b->p[i]);
687     }
688   }
689 }
690 
691 
692 
693 
694 
695 /*******************
696  *  SUBSTITUTIONS  *
697  ******************/
698 
699 /*
700  * For debugging: check whether x occurs in polynomial p
701  */
702 #ifndef NDEBUG
703 
var_occurs_in_bvpoly64(bvpoly64_t * p,int32_t x)704 static bool var_occurs_in_bvpoly64(bvpoly64_t *p, int32_t x) {
705   uint32_t i, n;
706 
707   n = p->nterms;
708   for (i=0; i<n; i++) {
709     if (p->mono[i].var == x) {
710       return true;
711     }
712   }
713   return false;
714 }
715 
var_occurs_in_bvpoly(bvpoly_t * p,int32_t x)716 static bool var_occurs_in_bvpoly(bvpoly_t *p, int32_t x) {
717   uint32_t i, n;
718 
719   n = p->nterms;
720   for (i=0; i<n; i++) {
721     if (p->mono[i].var == x) {
722       return true;
723     }
724   }
725   return false;
726 }
727 
728 
729 
730 #endif
731 
732 /*
733  * Replace variable x by polynomial p in buffer.
734  * There are two versions: one for 64bit or less, one for more than 64bits
735  * - x must be a variable (i.e., x != const_idx)
736  * - x must not occur in p
737  */
bvpoly_buffer_subst_poly64(bvpoly_buffer_t * buffer,int32_t x,bvpoly64_t * p)738 void bvpoly_buffer_subst_poly64(bvpoly_buffer_t *buffer, int32_t x, bvpoly64_t *p) {
739   uint64_t a;
740   int32_t i;
741 
742   assert(p->bitsize == buffer->bitsize && x != const_idx && !var_occurs_in_bvpoly64(p, x));
743 
744   i = bvpoly_buffer_find_index(buffer, x);
745   if (i >= 0) {
746     assert(buffer->var[i] == x);
747     a = buffer->c[i];
748     bvpoly_buffer_addmul_poly64(buffer, p, a);
749     buffer->c[i] = 0; // clear the coefficient of x in buffer
750   }
751 }
752 
753 
bvpoly_buffer_subst_poly(bvpoly_buffer_t * buffer,int32_t x,bvpoly_t * p)754 void bvpoly_buffer_subst_poly(bvpoly_buffer_t *buffer, int32_t x, bvpoly_t *p) {
755   uint32_t *a;
756   uint32_t w;
757   int32_t i;
758 
759   assert(p->bitsize == buffer->bitsize && x != const_idx && !var_occurs_in_bvpoly(p, x));
760 
761   i = bvpoly_buffer_find_index(buffer, x);
762   if (i >= 0) {
763     assert(buffer->var[i] == x);
764     a = buffer->p[i];
765     /*
766      * Since x does not occur in p, a will not be overwritten
767      * during addmul. So we don't need a local copy of a.
768      */
769     bvpoly_buffer_addmul_poly(buffer, p, a);
770 
771     // clear the coefficient of x in buffer
772     w = buffer->width;
773     bvconst_clear(a, w);
774   }
775 }
776 
777 
778 
779 
780 /*******************
781  *  NORMALIZATION  *
782  ******************/
783 
784 /*
785  * Utility for sorting: swap monomials at indices i and j
786  */
swap_monomials(bvpoly_buffer_t * buffer,uint32_t i,uint32_t j)787 static void swap_monomials(bvpoly_buffer_t *buffer, uint32_t i, uint32_t j) {
788   int32_t x, y;
789   uint64_t aux;
790   uint32_t *p;
791 
792   assert(i < buffer->nterms && j < buffer->nterms);
793 
794   x = buffer->var[i];
795   y = buffer->var[j];
796 
797   assert(buffer->index[x] == i && buffer->index[y] == j);
798 
799   buffer->index[x] = j;
800   buffer->index[y] = i;
801   buffer->var[i] = y;
802   buffer->var[j] = x;
803   if (buffer->bitsize <= 64) {
804     aux = buffer->c[i];
805     buffer->c[i] = buffer->c[j];
806     buffer->c[j] = aux;
807   } else {
808     p = buffer->p[i];
809     buffer->p[i] = buffer->p[j];
810     buffer->p[j] = p;
811   }
812 }
813 
814 
815 
816 /*
817  * SORT
818  */
819 
820 /*
821  * Sort monomials at indices between l and (h-1)
822  * - use insertion or quicksort
823  */
824 static void sort_buffer(bvpoly_buffer_t *buffer, uint32_t l, uint32_t h);
825 
826 /*
827  * Insertion sort
828  */
isort_buffer(bvpoly_buffer_t * buffer,uint32_t l,uint32_t h)829 static void isort_buffer(bvpoly_buffer_t *buffer, uint32_t l, uint32_t h) {
830   uint32_t i, j;
831   int32_t x;
832 
833   assert(l <= h);
834 
835   for (i=l+1; i<h; i++) {
836     x = buffer->var[i];
837     j = i;
838     do {
839       j --;
840       if (buffer->var[j] < x) break;
841       swap_monomials(buffer, j, j+1);
842     } while (j > l);
843   }
844 }
845 
846 /*
847  * Quick sort: requires h > l
848  */
qsort_buffer(bvpoly_buffer_t * buffer,uint32_t l,uint32_t h)849 static void qsort_buffer(bvpoly_buffer_t *buffer, uint32_t l, uint32_t h) {
850   uint32_t i, j;
851   int32_t x;
852   uint32_t seed = PRNG_DEFAULT_SEED;
853 
854   assert(h > l);
855 
856   // random pivot
857   i = l + random_uint(&seed, h - l);
858 
859   // move it to position l
860   swap_monomials(buffer, i, l);
861   x = buffer->var[l];
862 
863   i = l;
864   j = h;
865   do { j--; } while (buffer->var[j] > x);
866   do { i++; } while (i <= j && buffer->var[i] < x);
867 
868   while (i < j) {
869     swap_monomials(buffer, i, j);
870     do { j--; } while (buffer->var[j] > x);
871     do { i++; } while (buffer->var[i] < x);
872   }
873 
874   // swap pivot and monomial j
875   swap_monomials(buffer, l, j);
876 
877   sort_buffer(buffer, l, j);
878   sort_buffer(buffer, j+1, h);
879 }
880 
881 
sort_buffer(bvpoly_buffer_t * buffer,uint32_t l,uint32_t h)882 static void sort_buffer(bvpoly_buffer_t *buffer, uint32_t l, uint32_t h) {
883   if (h < l + 4) {
884     isort_buffer(buffer, l, h);
885   } else {
886     qsort_buffer(buffer, l, h);
887   }
888 }
889 
890 
891 
892 /*
893  * Sort all monomials
894  */
poly_buffer_sort(bvpoly_buffer_t * buffer)895 static inline void poly_buffer_sort(bvpoly_buffer_t *buffer) {
896   sort_buffer(buffer, 0, buffer->nterms);
897 }
898 
899 
900 
901 /*
902  * AFTER SORTING
903  */
904 
905 /*
906  * Reduce all coefficients modulo 2^bitsize
907  * - remove the zero coefficients
908  */
bvpoly_buffer_reduce_coefficients(bvpoly_buffer_t * buffer)909 static void bvpoly_buffer_reduce_coefficients(bvpoly_buffer_t *buffer) {
910   uint32_t *p;
911   uint64_t mask;
912   uint32_t i, j, n, b, w;
913   int32_t x;
914 
915 
916   b = buffer->bitsize;
917   n = buffer->nterms;
918   if (b > 64) {
919     /*
920      * Large coefficients
921      */
922     w = buffer->width;
923     j = 0;
924     for (i=0; i<n; i++) {
925       assert(j <= i);
926       x = buffer->var[i];
927       p = buffer->p[i];
928       bvconst_normalize(p, b);
929       if (bvconst_is_zero(p, w)) {
930         // remove monomial i
931         buffer->index[x] = -1;
932       } else {
933         if (j < i) {
934           // move monomial i to position j
935           buffer->index[x] = j;
936           buffer->var[j] = x;
937           buffer->p[i] = buffer->p[j]; // swap rather than copy p[i] into p[j]
938           buffer->p[j] = p;
939         }
940         j ++;
941       }
942     }
943     buffer->nterms = j;
944 
945   } else {
946     /*
947      * Small coefficients
948      */
949     mask = mask64(b);
950     j = 0;
951     for (i=0; i<n; i++) {
952       assert(j <= i);
953       x = buffer->var[i];
954       buffer->c[i] &= mask; // clear high-order bits
955       if (buffer->c[i] == 0) {
956         // remove monomial i
957         buffer->index[x] = -1;
958       } else {
959         if (j < i) {
960           // move monomial i to position j
961           buffer->index[x] = j;
962           buffer->var[j] = x;
963           buffer->c[j] = buffer->c[i];
964         }
965         j ++;
966       }
967     }
968     buffer->nterms = j;
969   }
970 }
971 
972 
973 
974 /*
975  * For debugging: check whether buffer is normalized
976  */
977 #ifndef NDEBUG
978 
bvpoly_buffer_is_normalized(bvpoly_buffer_t * buffer)979 static bool bvpoly_buffer_is_normalized(bvpoly_buffer_t *buffer) {
980   uint32_t i, n, b, w;
981   uint64_t c;
982 
983   n = buffer->nterms;
984   // check that the variables are in increasing order
985   for (i=1; i<n; i++) {
986     if (buffer->var[i-1] >= buffer->var[i]) {
987       return false;
988     }
989   }
990 
991   // check that the coefficients are normalized and non-zero
992   b = buffer->bitsize;
993   if (b > 64) {
994     w = buffer->width;
995     for (i=0; i<n; i++) {
996       if (bvconst_is_zero(buffer->p[i], w) ||
997           ! bvconst_is_normalized(buffer->p[i], b)) {
998         return false;
999       }
1000     }
1001   } else {
1002     for (i=0; i<n; i++) {
1003       c = buffer->c[i];
1004       if (c == 0 || c != norm64(c, b)) {
1005         return false;
1006       }
1007     }
1008   }
1009 
1010   return true;
1011 }
1012 
1013 #endif
1014 
1015 
1016 /*
1017  * Normalize buffer:
1018  * - normalize all the coefficients (reduce them modulo 2^n where n = bitsize)
1019  * - sort the terms in increasing order of variables
1020  *   (the constant term comes first if any)
1021  * - remove all terms with a zero coefficient
1022  */
normalize_bvpoly_buffer(bvpoly_buffer_t * buffer)1023 void normalize_bvpoly_buffer(bvpoly_buffer_t *buffer) {
1024   poly_buffer_sort(buffer);
1025   bvpoly_buffer_reduce_coefficients(buffer);
1026   assert(bvpoly_buffer_is_normalized(buffer));
1027 }
1028 
1029 
1030 
1031 /*
1032  * Convert b to a bvpoly64 object
1033  * - b must be normalized and have bitsize <= 64
1034  * - the resulting object can be deleted using safe_free (or free_bvpoly64)
1035  */
bvpoly_buffer_getpoly64(bvpoly_buffer_t * b)1036 bvpoly64_t *bvpoly_buffer_getpoly64(bvpoly_buffer_t *b) {
1037   bvpoly64_t *p;
1038   uint32_t i, n, size;
1039 
1040   assert(b->bitsize > 0 && b->bitsize <= 64);
1041   assert(bvpoly_buffer_is_normalized(b));
1042 
1043   size = b->bitsize;
1044   n = b->nterms;
1045   p = alloc_bvpoly64(n, size);
1046   for (i=0; i<n; i++) {
1047     p->mono[i].var = b->var[i];
1048     p->mono[i].coeff = b->c[i];
1049   }
1050 
1051   return p;
1052 }
1053 
1054 
1055 
1056 /*
1057  * Convert b to a bvpoly object
1058  * - b must be normalized and have bitsize > 64
1059  * - the resulting bvpoly can be deleted using free_bvpoly
1060  */
bvpoly_buffer_getpoly(bvpoly_buffer_t * b)1061 bvpoly_t *bvpoly_buffer_getpoly(bvpoly_buffer_t *b) {
1062   bvpoly_t *p;
1063   uint32_t *c;
1064   uint32_t i, n, size, w;;
1065 
1066   assert(b->bitsize > 64);
1067   assert(bvpoly_buffer_is_normalized(b));
1068 
1069   size = b->bitsize;
1070   w = b->width;
1071   n = b->nterms;
1072   p = alloc_bvpoly(n, size);
1073   for (i=0; i<n; i++) {
1074     // allocate a bvconst c and copy p[i] into c
1075     c = bvconst_alloc(w);
1076     bvconst_set(c, w, b->p[i]);
1077     bvconst_normalize(c, size); // redundant since b is normalized?
1078 
1079     p->mono[i].var = b->var[i];
1080     p->mono[i].coeff = c;
1081   }
1082 
1083   return p;
1084 }
1085 
1086 
1087 
1088 /*
1089  * Check whether b is equal to a bvpoly64 p
1090  * - b must be normalized
1091  */
bvpoly_buffer_equal_poly64(bvpoly_buffer_t * b,bvpoly64_t * p)1092 bool bvpoly_buffer_equal_poly64(bvpoly_buffer_t *b, bvpoly64_t *p) {
1093   uint32_t i, n;
1094 
1095   assert(bvpoly_buffer_is_normalized(b));
1096 
1097   n = b->nterms;
1098   if (b->bitsize != p->bitsize || n != p->nterms) {
1099     return false;
1100   }
1101 
1102   for (i=0; i<n; i++) {
1103     if (b->var[i] != p->mono[i].var || b->c[i] != p->mono[i].coeff) {
1104       return false;
1105     }
1106   }
1107 
1108   return true;
1109 }
1110 
1111 
1112 
1113 /*
1114  * Check whether b is equal to a bvpoly p
1115  * - b must be normalized
1116  */
bvpoly_buffer_equal_poly(bvpoly_buffer_t * b,bvpoly_t * p)1117 bool bvpoly_buffer_equal_poly(bvpoly_buffer_t *b, bvpoly_t *p) {
1118   uint32_t i, n, w;
1119 
1120   assert(bvpoly_buffer_is_normalized(b));
1121 
1122   n = b->nterms;
1123   if (b->bitsize != p->bitsize || n != p->nterms) {
1124     return false;
1125   }
1126 
1127   w = b->width;
1128   assert(p->width == w);
1129 
1130   for (i=0; i<n; i++) {
1131     if (b->var[i] != p->mono[i].var ||
1132         bvconst_neq(b->p[i], p->mono[i].coeff, w)) {
1133       return false;
1134     }
1135   }
1136 
1137   return true;
1138 }
1139 
1140 
1141 /*
1142  * Check whether b1 and b2 are equal
1143  * - both must be normalized
1144  */
bvpoly_buffer_equal(bvpoly_buffer_t * b1,bvpoly_buffer_t * b2)1145 bool bvpoly_buffer_equal(bvpoly_buffer_t *b1, bvpoly_buffer_t *b2) {
1146   uint32_t i, n, w;
1147 
1148   n = b1->nterms;
1149   if (b1->bitsize != b2->bitsize || n != b2->nterms) {
1150     return false;
1151   }
1152 
1153   if (b1->bitsize <= 64) {
1154     for (i=0; i<n; i++) {
1155       if (b1->var[i] != b2->var[i] || b1->c[i] != b2->c[i]) {
1156 	return false;
1157       }
1158     }
1159   } else {
1160     w = b1->width;
1161     assert(w == b2->width);
1162     for (i=0; i<n; i++) {
1163       if (b1->var[i] != b2->var[i] || bvconst_neq(b1->p[i], b2->p[i], w)) {
1164 	return false;
1165       }
1166     }
1167   }
1168 
1169   return true;
1170 }
1171 
1172 
1173 
1174 /*
1175  * Hash function1
1176  * - b must be normalized and have bitsize <= 64
1177  *
1178  * This follows the definition of hash_bvpoly64 in bv64_polynomials:
1179  * - if b is equal to a bvpoly64 p then
1180  *   hash_bvpoly64(p) == bvpoly_buffer_hash64(b)
1181  */
bvpoly_buffer_hash64(bvpoly_buffer_t * b)1182 uint32_t bvpoly_buffer_hash64(bvpoly_buffer_t *b) {
1183   uint32_t h, n, size, i;
1184 
1185   assert(b->bitsize > 0 && b->bitsize <= 64);
1186   assert(bvpoly_buffer_is_normalized(b));
1187 
1188   n = b->nterms;
1189   h = HASH_BVPOLY64_SEED + n;
1190   size = b->bitsize;
1191   for (i=0; i<n; i++) {
1192     h = jenkins_hash_mix3((uint32_t) (b->c[i] >> 32), (uint32_t) b->c[i], h);
1193     h = jenkins_hash_mix3(b->var[i], size, h);
1194   }
1195 
1196   return h;
1197 }
1198 
1199 
1200 /*
1201  * Hash function2:
1202  * - b must be normalized and have bitsize > 64
1203  *
1204  * This follows the definition of hash_bvpoly in bv_polynomials.
1205  * - if b is equal to a bvpoly p then
1206  *   hash_bvpoly(p) == bvpoly_buffer_hash(b)
1207  */
bvpoly_buffer_hash(bvpoly_buffer_t * b)1208 uint32_t bvpoly_buffer_hash(bvpoly_buffer_t *b) {
1209   uint32_t h, n, size, i, k;
1210 
1211   assert(b->bitsize > 64);
1212   assert(bvpoly_buffer_is_normalized(b));
1213 
1214   n = b->nterms;
1215   h = HASH_BVPOLY_SEED + n;
1216   k = b->width;
1217   size = b->bitsize;
1218 
1219   for (i=0; i<n; i++) {
1220     h = jenkins_hash_array(b->p[i], k, h);
1221     h = jenkins_hash_mix3(b->var[i], size, h);
1222   }
1223 
1224   return h;
1225 }
1226 
1227 
1228 
1229 
1230 
1231 /*
1232  * Check whether the coefficient i is +1 or -1
1233  */
1234 // c = coefficient, n = number of bits
bvconst64_is_unit(uint64_t c,uint32_t n)1235 static bool bvconst64_is_unit(uint64_t c, uint32_t n) {
1236   assert(c == norm64(c, n));
1237   return c == 1 || c == mask64(n);
1238 }
1239 
1240 // c = coefficient, n = number of bits, w = number of words
bvconst_is_unit(uint32_t * c,uint32_t n,uint32_t w)1241 static bool bvconst_is_unit(uint32_t *c, uint32_t n, uint32_t w) {
1242   assert(bvconst_is_normalized(c, n));
1243   assert(w == (n + 31) >> 5);
1244   return bvconst_is_one(c, w) || bvconst_is_minus_one(c, n);
1245 }
1246 
bvpoly_buffer_coeff_is_unit(const bvpoly_buffer_t * b,uint32_t i)1247 static bool bvpoly_buffer_coeff_is_unit(const bvpoly_buffer_t *b, uint32_t i) {
1248   uint32_t n;
1249 
1250   assert(i < b->nterms);
1251   n = b->bitsize;
1252   if (n <= 64) {
1253     return bvconst64_is_unit(b->c[i], n);
1254   } else {
1255     return bvconst_is_unit(b->p[i], n, b->width);
1256   }
1257 }
1258 
bvpoly_buffer_coeff_is_one(const bvpoly_buffer_t * b,uint32_t i)1259 static bool bvpoly_buffer_coeff_is_one(const bvpoly_buffer_t *b, uint32_t i) {
1260   uint32_t n;
1261 
1262   assert(i < b->nterms);
1263   n = b->bitsize;
1264   if (n <= 64) {
1265     assert(b->c[i] == norm64(b->c[i], n));
1266     return b->c[i] == 1;
1267   } else {
1268     assert(bvconst_is_normalized(b->p[i], n));
1269     return bvconst_is_one(b->p[i], b->width);
1270   }
1271 }
1272 
bvpoly_buffer_coeff_is_minus_one(const bvpoly_buffer_t * b,uint32_t i)1273 static bool bvpoly_buffer_coeff_is_minus_one(const bvpoly_buffer_t *b, uint32_t i) {
1274   uint32_t n;
1275 
1276   assert(i < b->nterms);
1277   n = b->bitsize;
1278   if (n <= 64) {
1279     assert(b->c[i] == norm64(b->c[i], n));
1280     return b->c[i] == mask64(n);
1281   } else {
1282     assert(bvconst_is_normalized(b->p[i], n));
1283     return bvconst_is_minus_one(b->p[i], n);
1284   }
1285 }
1286 
1287 /*
1288  * Check whether b is of the form +x
1289  * - if so return the variable into *x
1290  * - b must be normalized
1291  */
bvpoly_buffer_is_var(const bvpoly_buffer_t * b,int32_t * x)1292 bool bvpoly_buffer_is_var(const bvpoly_buffer_t *b, int32_t *x) {
1293   if (b->nterms == 1 && b->var[0] != const_idx && bvpoly_buffer_coeff_is_one(b, 0)) {
1294     *x = b->var[0];
1295     return true;
1296   }
1297   return false;
1298 }
1299 
1300 /*
1301  * Check whether b is of the form +x or -x
1302  * - if so, return the variable into *x
1303  * - b must be normalized
1304  */
bvpoly_buffer_is_pm_var(const bvpoly_buffer_t * b,int32_t * x)1305 bool bvpoly_buffer_is_pm_var(const bvpoly_buffer_t *b, int32_t *x) {
1306   if (b->nterms == 1 && b->var[0] != const_idx && bvpoly_buffer_coeff_is_unit(b, 0)) {
1307     *x = b->var[0];
1308     return true;
1309   }
1310 
1311   return false;
1312 }
1313 
1314 /*
1315  * Check whether b is of the form x1 - x2
1316  * - if so, return the variables in *x1 and *x2.
1317  * - b must be normalized
1318  */
bvpoly_buffer_is_var_minus_var(const bvpoly_buffer_t * b,int32_t * x1,int32_t * x2)1319 bool bvpoly_buffer_is_var_minus_var(const bvpoly_buffer_t *b, int32_t *x1, int32_t *x2) {
1320   if (b->nterms == 2 && b->var[0] != const_idx) {
1321     assert(b->var[1] != const_idx);
1322 
1323     if (bvpoly_buffer_coeff_is_one(b, 0) && bvpoly_buffer_coeff_is_minus_one(b, 1)) {
1324       *x1 = b->var[0];
1325       *x2 = b->var[1];
1326       return true;
1327     }
1328 
1329     if (bvpoly_buffer_coeff_is_minus_one(b, 0) && bvpoly_buffer_coeff_is_one(b, 1)) {
1330       *x1 = b->var[1];
1331       *x2 = b->var[0];
1332       return true;
1333     }
1334   }
1335 
1336   return false;
1337 }
1338 
1339