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