/* * Expanded form for a product c * p * - c is a normalized bitvector constant * - p is a power product stored in a pp_buffer object * - n = bitsize of p * - the expansion is returned in a bvarith_buffer or bvarith64_buffer object * - the result is normalized */ void expand_bvpprod64(bvexp_table_t *table, bvarith64_buffer_t *buffer, pp_buffer_t *p, uint32_t n, uint64_t c) { bv_vartable_t *vtbl; bvmlist64_t *q; pp_buffer_t *aux; pprod_t *r; uint64_t a; uint32_t i, m, e, d; thvar_t x; assert(buffer->store == &table->store64 && buffer->ptbl == &table->pprods); bvarith64_buffer_prepare(buffer, n); bvarith64_buffer_set_one(buffer); aux = p; vtbl = table->vtbl; if (total_degree_test64(table, vtbl, p)) { /* * Expansion of c * x_1^d_1 ... x_n^ d_n: * - for a constant x_i, update c to c * a^d_i (where a = value of c) * - if x_i is expanded to q_i, update buffer to buffer * q_i ^ d_i * - otherwise, x_i^d_i is copied into the aux buffer */ aux = &table->pp; pp_buffer_reset(aux); m = p->len; for (i=0; i<m; i++) { x = p->prod[i].var; d = p->prod[i].exp; if (bvvar_is_const64(vtbl, x)) { a = bvvar_val64(vtbl, x); c *= upower64(a, d); } else { q = bvexp_def64(table, x); if (q != NULL && mlist64_is_short(q, &e) && d * e <= BVEXP_DEGREE_LIMIT) { // replace x^d by q^d in buffer bvarith64_buffer_mul_mlist_power(buffer, q, d, &table->aux64); } else { // copy x^d into aux pp_buffer_mul_varexp(aux, x, d); } } } c = norm64(c, n); pp_buffer_normalize(aux); } /* * The result is c * aux * buffer */ r = pprod_from_buffer(&table->pprods, aux); bvarith64_buffer_mul_mono(buffer, c, r); bvarith64_buffer_normalize(buffer); }
void expand_bvpprod(bvexp_table_t *table, bvarith_buffer_t *buffer, pp_buffer_t *p, uint32_t n, uint32_t *c) { bv_vartable_t *vtbl; bvmlist_t *q; pp_buffer_t *aux; pprod_t *r; uint32_t *a; uint32_t i, m, d, e, k; thvar_t x; assert(buffer->store == &table->store && buffer->ptbl == &table->pprods); bvarith_buffer_prepare(buffer, n); bvarith_buffer_set_one(buffer); aux = p; vtbl = table->vtbl; if (total_degree_test(table, vtbl, p)) { aux = &table->pp; pp_buffer_reset(aux); // make a copy of c in the internal bvconst buffer bvconstant_copy(&table->bvconst, n, c); c = table->bvconst.data; k = (n + 31) >> 5; m = p->len; for (i=0; i<m; i++) { x = p->prod[i].var; d = p->prod[i].exp; if (bvvar_is_const(vtbl, x)) { a = bvvar_val(vtbl, x); bvconst_mulpower(c, k, a, d); } else { q = bvexp_def(table, x); if (q != NULL && mlist_is_short(q, &e) && d * e <= BVEXP_DEGREE_LIMIT) { bvarith_buffer_mul_mlist_power(buffer, q, d, &table->aux); } else { pp_buffer_mul_varexp(aux, x, d); } } } // normalize bvconst_normalize(c, n); pp_buffer_normalize(aux); } /* * The result is c * aux * buffer */ r = pprod_from_buffer(&table->pprods, aux); bvarith_buffer_mul_mono(buffer, c, r); bvarith_buffer_normalize(buffer); }
/* * Empty the table */ void reset_bvexp_table(bvexp_table_t *table) { bvexp_table_remove_vars(table, 0); /* * The two aux buffers must be deleted first since their content may become * invalid pointers afer the reset_objstore calls. Just calling * bvarith..._prepare is not enough as it keeps the end_marker in * table->aux/table->aux64. */ delete_bvarith_buffer(&table->aux); delete_bvarith64_buffer(&table->aux64); pp_buffer_reset(&table->pp); reset_objstore(&table->store); reset_objstore(&table->store64); reset_pprod_table(&table->pprods); // Recreate the buffers aux and aux64 init_bvarith_buffer(&table->aux, &table->pprods, &table->store); init_bvarith64_buffer(&table->aux64, &table->pprods, &table->store64); }
int main() { pprod_t *p1, *p2; uint32_t i, j; int32_t cmp; p[0] = empty_pp; p[1] = var_pp(0); p[2] = var_pp(1); p[3] = var_pp(0x3fffffff); init_pp_buffer(&buffer, 0); p[4] = pp_buffer_getprod(&buffer); // empty pp_buffer_reset(&buffer); pp_buffer_mul_var(&buffer, 0); p[5] = pp_buffer_getprod(&buffer); // x_0 pp_buffer_reset(&buffer); pp_buffer_mul_var(&buffer, 0); pp_buffer_mul_var(&buffer, 1); pp_buffer_mul_var(&buffer, 0); p[6] = pp_buffer_getprod(&buffer); // x_0^2 x_1 pp_buffer_reset(&buffer); pp_buffer_mul_varexp(&buffer, 1, 2); pp_buffer_mul_varexp(&buffer, 4, 3); p[7] = pp_buffer_getprod(&buffer); // x_1^2 x_4^3 pp_buffer_set_varexp(&buffer, 3, 2); pp_buffer_mul_varexp(&buffer, 1, 4); p[8] = pp_buffer_getprod(&buffer); // x_3^2 x_1^4 pp_buffer_set_pprod(&buffer, p[7]); pp_buffer_mul_pprod(&buffer, p[1]); pp_buffer_mul_pprod(&buffer, p[8]); p[9] = pp_buffer_getprod(&buffer); for (i=0; i<NUM_PRODS; i++) { printf("p[%"PRIu32"] = ", i); print_pprod(stdout, p[i]); printf(" total degree = %"PRIu32"\n", pprod_degree(p[i])); for (j=0; j<5; j++) { printf(" degree of x_%"PRIu32" = %"PRIu32"\n", j, pprod_var_degree(p[i], j)); } printf("----\n"); } printf("\n"); for (i=0; i<NUM_PRODS; i++) { p1 = p[i]; for (j=0; j<NUM_PRODS; j++) { p2 = p[j]; printf("p1: "); print_pprod0(stdout, p1); printf("p2: "); print_pprod0(stdout, p2); if (pprod_equal(p1, p2)) { printf("equal products\n"); } if (pprod_divides(p1, p2)) { printf("p1 divides p2\n"); } if (pprod_divisor(&buffer, p1, p2)) { printf("p2/p1: "); print_pp_buffer0(stdout, &buffer); } if (pprod_divides(p2, p1)) { printf("p2 divides p1\n"); } if (pprod_divisor(&buffer, p2, p1)) { printf("p1/p2: "); print_pp_buffer0(stdout, &buffer); } cmp = pprod_lex_cmp(p1, p2); if (cmp < 0) { printf("p1 < p2 in lex order\n"); } else if (cmp > 0) { printf("p1 > p2 in lex order\n"); } else { printf("p1 = p2 in lex order\n"); } if (pprod_precedes(p1, p2)) { printf("p1 < p2 in deglex ordering\n"); } if (pprod_precedes(p2, p1)) { printf("p2 < p1 in deglex ordering\n"); } printf("----\n"); } } for (i=0; i<10; i++) { free_pprod(p[i]); } delete_pp_buffer(&buffer); return 0; }