/* * Add -a * r * b1 to b */ void arith_buffer_sub_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_submul(&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_submul(&aux->coeff, &p1->coeff, a); // since aux->coeff is 0 initially aux->prod = r1; *q = aux; q = &aux->next; b->nterms ++; } p1 = p1->next; } }
/* * 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 ++; } }
/* * Phase and period of p * - p is c + (a_1/b_1) x_1 + ... + (a_n/b_n) x_n where * a_i/b_i is an irreducible fraction * - let D = gcd(a_1,..., a_n) and L = lcm(b_1,...,b_n) * then period = D/L and phase = c - floor(c/period) * period */ void monarray_period_and_phase(monomial_t *p, rational_t *period, rational_t *phase) { rational_t aux; monomial_t *c; int32_t v; /* * c := the constant monomial of p or NULL if p's constant is zero */ c = NULL; v = p->var; if (v == const_idx) { c = p; p ++; v = p->var; } if (v < max_idx) { /* * p is not a constant: compute D and L * we use period for D and phase for L */ q_get_num(period, &p->coeff); // D := |a_1| if (q_is_neg(period)) { q_neg(period); } q_get_den(phase, &p->coeff); // L := b_1 q_init(&aux); for (;;) { p ++; v = p->var; if (v >= max_idx) break; q_get_num(&aux, &p->coeff); q_gcd(period, &aux); // D := gcd(D, a_i) q_get_den(&aux, &p->coeff); q_lcm(phase, &aux); // L := lcm(L, b_i) } assert(q_is_pos(period) && q_is_pos(phase)); q_div(period, phase); // period := D/L /* * Phase: constant modulo D/L */ if (c == NULL) { q_clear(phase); // no constant: phase = 0 } else { q_set(&aux, &c->coeff); q_div(&aux, period); q_floor(&aux); // aux = floor(c/period) q_set(phase, &c->coeff); q_submul(phase, &aux, period); // phase = c - aux * period assert(q_is_nonneg(phase) && q_lt(phase, period)); } q_clear(&aux); } else { /* * p is constant: period := 0, phase = constant coeff */ q_clear(period); if (c == NULL) { q_clear(phase); } else { q_set(phase, &c->coeff); } } }