// check whether the subtree rooted at x is ordered static bool is_ordered(rba_buffer_t *b, uint32_t x) { uint32_t i, j; pprod_t *r, *s, *t; assert(x < b->num_nodes); if (x == 0) return true; i = b->child[x][0]; // left child j = b->child[x][1]; // right child r = b->mono[x].prod; s = b->mono[i].prod; t = b->mono[j].prod; // the expected order is s < r < t if (i != 0 && !pprod_precedes(s, r)) { printf("tree not ordered at node %"PRIu32" (for left child %"PRIu32")\n", x, i); fflush(stdout); return false; } if (j != 0 && !pprod_precedes(r, t)) { printf("tree not ordered at node %"PRIu32" (for right child = %"PRIu32")\n", x, j); fflush(stdout); return false; } return is_ordered(b, i) && is_ordered(b, j); }
/* * Add a * r * b1 to b */ void arith_buffer_add_mono_times_buffer(arith_buffer_t *b, arith_buffer_t *b1, rational_t *a, pprod_t *r) { mlist_t *p, *aux, *p1; mlist_t **q; pprod_t *r1; q = &b->list; p = *q; p1 = b1->list; while (p1->next != NULL) { r1 = pprod_mul(b->ptbl, p1->prod, r); while (pprod_precedes(p->prod, r1)) { q = &p->next; p = *q; } if (p->prod == r1) { q_addmul(&p->coeff, &p1->coeff, a); q = &p->next; p = *q; } else { assert(pprod_precedes(r1, p->prod)); aux = alloc_list_elem(b->store); aux->next = p; q_addmul(&aux->coeff, &p1->coeff, a); // since aux->coeff is 0 initially aux->prod = r1; *q = aux; q = &aux->next; b->nterms ++; } p1 = p1->next; } }
/* * Add -r to b */ void arith_buffer_sub_pp(arith_buffer_t *b, pprod_t *r) { mlist_t *p, *aux; mlist_t **q; q = &b->list; p = *q; assert(p == b->list); while (pprod_precedes(p->prod, r)) { q = &p->next; p = *q; } // p points to a monomial with p->prod >= r // q is either &p->list or &p0->next where p0 is p's predecessor if (p->prod == r) { q_sub_one(&p->coeff); } else { assert(pprod_precedes(r, p->prod)); aux = alloc_list_elem(b->store); aux->next = p; q_set_minus_one(&aux->coeff); aux->prod = r; *q = aux; b->nterms ++; } }
/* * Add - r * b1 to b */ void arith_buffer_sub_pp_times_buffer(arith_buffer_t *b, arith_buffer_t *b1, pprod_t *r) { mlist_t *p, *aux, *p1; mlist_t **q; pprod_t *r1; q = &b->list; p = *q; p1 = b1->list; while (p1->next != NULL) { r1 = pprod_mul(b->ptbl, p1->prod, r); while (pprod_precedes(p->prod, r1)) { q = &p->next; p = *q; } if (p->prod == r1) { q_sub(&p->coeff, &p1->coeff); q = &p->next; p = *q; } else { assert(pprod_precedes(r1, p->prod)); aux = alloc_list_elem(b->store); aux->next = p; q_set_neg(&aux->coeff, &p1->coeff); aux->prod = r1; *q = aux; q = &aux->next; b->nterms ++; } p1 = p1->next; } }
/* * Add -a * r to b */ void arith_buffer_sub_mono(arith_buffer_t *b, rational_t *a, pprod_t *r) { mlist_t *p, *aux; mlist_t **q; if (q_is_zero(a)) return; q = &b->list; p = *q; assert(p == b->list); while (pprod_precedes(p->prod, r)) { q = &p->next; p = *q; } // p points to a monomial with p->prod >= r // q is &b->list if p is first in the list // q is &p0->next where p0 = predecessor of p otherwise. if (p->prod == r) { q_sub(&p->coeff, a); } else { assert(pprod_precedes(r, p->prod)); aux = alloc_list_elem(b->store); aux->next = p; q_set_neg(&aux->coeff, a); aux->prod = r; *q = aux; b->nterms ++; } }
/* * Monomial of p whose pp equals r (or NULL) */ mlist_t *arith_buffer_get_mono(arith_buffer_t *b, pprod_t *r) { mlist_t *p; p = b->list; while (pprod_precedes(p->prod, r)) { p = p->next; } if (p->prod == r) { return p; } else { assert(pprod_precedes(r, p->prod)); return NULL; } }
/* * Add poly to buffer b */ void arith_buffer_add_monarray(arith_buffer_t *b, monomial_t *poly, pprod_t **pp) { mlist_t *p, *aux; mlist_t **q; pprod_t *r1; assert(good_pprod_array(poly, pp)); q = &b->list; p = *q; while (poly->var < max_idx) { // poly points to a pair (coeff, x_i) // r1 = power product for x_i r1 = *pp; while (pprod_precedes(p->prod, r1)) { q = &p->next; p = *q; } // p points to monomial whose prod is >= r1 in the deg-lex order // q is either &b->list or &p0->next where p0 is the predecessor // of p in the list if (p->prod == r1) { q_add(&p->coeff, &poly->coeff); q = &p->next; p = *q; } else { assert(pprod_precedes(r1, p->prod)); aux = alloc_list_elem(b->store); aux->next = p; q_set(&aux->coeff, &poly->coeff); aux->prod = r1; *q = aux; q = &aux->next; b->nterms ++; } // move to the next monomial of poly poly ++; pp ++; } }
/* * Subtract a * poly from b */ void arith_buffer_sub_mono_times_monarray(arith_buffer_t *b, monomial_t *poly, pprod_t **pp, rational_t *a, pprod_t *r) { mlist_t *p, *aux; mlist_t **q; pprod_t *r1; assert(good_pprod_array(poly, pp)); q = &b->list; p = *q; while (poly->var < max_idx) { // poly points to a pair (coeff, x_i) // r1 = r * power product for x_i r1 = pprod_mul(b->ptbl, *pp, r); while (pprod_precedes(p->prod, r1)) { q = &p->next; p = *q; } // p points to monomial whose prod is >= r1 in the deg-lex order // q points to the predecessor of p in the list if (p->prod == r1) { q_submul(&p->coeff, &poly->coeff, a); q = &p->next; p = *q; } else { assert(pprod_precedes(r1, p->prod)); aux = alloc_list_elem(b->store); aux->next = p; q_submul(&aux->coeff, &poly->coeff, a); // aux->coeff is initialized to 0 in alloc_list_elem aux->prod = r1; *q = aux; q = &aux->next; b->nterms ++; } // move to the next monomial of poly poly ++; pp ++; } }
/* * Add b1 to b */ void arith_buffer_add_buffer(arith_buffer_t *b, arith_buffer_t *b1) { mlist_t *p, *aux, *p1; mlist_t **q; pprod_t *r1; assert(b->ptbl == b1->ptbl); q = &b->list; p = *q; p1 = b1->list; while (p1->next != NULL) { r1 = p1->prod; while (pprod_precedes(p->prod, r1)) { q = &p->next; p = *q; } if (p->prod == r1) { q_add(&p->coeff, &p1->coeff); q = &p->next; p = *q; } else { assert(pprod_precedes(r1, p->prod)); aux = alloc_list_elem(b->store); aux->next = p; q_set(&aux->coeff, &p1->coeff); aux->prod = r1; *q = aux; q = &aux->next; b->nterms ++; } p1 = p1->next; } }
/* * Add (-a) * b1 to b */ void arith_buffer_sub_const_times_buffer(arith_buffer_t *b, arith_buffer_t *b1, rational_t *a) { mlist_t *p, *aux, *p1; mlist_t **q; pprod_t *r1; q = &b->list; p = *q; p1 = b1->list; while (p1->next != NULL) { r1 = p1->prod; while (pprod_precedes(p->prod, r1)) { q = &p->next; p = *q; } if (p->prod == r1) { q_submul(&p->coeff, &p1->coeff, a); q = &p->next; p = *q; } else { assert(pprod_precedes(r1, p->prod)); // aux->coeff is initialized to 0 in alloc_list_elem aux = alloc_list_elem(b->store); aux->next = p; q_submul(&aux->coeff, &p1->coeff, a); aux->prod = r1; *q = aux; q = &aux->next; b->nterms ++; } p1 = p1->next; } }
/* * For debugging: check that q contains valid power products * sorted in increasing deg-lex ordering. */ static bool good_pprod_array(monomial_t *poly, pprod_t **pp) { pprod_t *r; if (poly->var < max_idx) { r = *pp; poly ++; pp ++; while (poly->var < max_idx) { if (! pprod_precedes(r, *pp)) return false; r = *pp; pp ++; poly ++; } } return true; }
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; }