/** * Takes two (primitive) coefficients over the same variable, makes them univariate by * substituting 0 for other variables (if any). Then it computes the * univariate gcd of these. If the coefficients were univariate already, or * the result is a constant (i.e. gcd = 1), the result is precise. */ int coefficient_gcd_pp_univariate(const lp_polynomial_context_t* ctx, coefficient_t* gcd, const coefficient_t* C1, const coefficient_t* C2) { assert(C1->type == COEFFICIENT_POLYNOMIAL); assert(C2->type == COEFFICIENT_POLYNOMIAL); if (trace_is_enabled("coefficient")) { tracef("coefficient_gcd_pp_univariate()\n"); tracef("C1 = "); coefficient_print(ctx, C1, trace_out); tracef("\n"); tracef("C2 = "); coefficient_print(ctx, C2, trace_out); tracef("\n"); } int C1_vanishes = integer_is_zero(ctx->K, coefficient_get_constant(coefficient_lc(C1))); int C2_vanishes = integer_is_zero(ctx->K, coefficient_get_constant(coefficient_lc(C2))); if (C1_vanishes || C2_vanishes) { // One of C1 or C2 vanishes in the univariate conversion, we're not precise enough return 0; } lp_variable_t x = VAR(C1); assert(x == VAR(C2)); lp_upolynomial_t* C1_u = coefficient_to_univariate(ctx, C1); lp_upolynomial_t* C2_u = coefficient_to_univariate(ctx, C2); lp_upolynomial_t* gcd_u = lp_upolynomial_gcd(C1_u, C2_u); coefficient_t gcd_tmp; coefficient_construct_from_univariate(ctx, &gcd_tmp, gcd_u, x); coefficient_swap(&gcd_tmp, gcd); coefficient_destruct(&gcd_tmp); lp_upolynomial_delete(C1_u); lp_upolynomial_delete(C2_u); lp_upolynomial_delete(gcd_u); if (trace_is_enabled("coefficient")) { tracef("coefficient_gcd_pp_univariate() => "); tracef("gcd = "); coefficient_print(ctx, gcd, trace_out); tracef("\n"); } if (gcd->type == COEFFICIENT_NUMERIC) { integer_assign_int(ctx->K, &gcd->value.num, 1); return 1; } else if (coefficient_is_univariate(C1) && coefficient_is_univariate(C2)) { return 1; } else { return 0; } }
void monomial_gcd_visit(const lp_polynomial_context_t* ctx, lp_monomial_t* m, void* data) { lp_monomial_t* gcd = (lp_monomial_t*) data; if (integer_is_zero(ctx->K, &gcd->a)) { lp_monomial_assign(ctx, gcd, m, 0); } else { lp_monomial_gcd(ctx, gcd, gcd, m); } }
int integer_square(integer_t target, integer_t source) { bool aliased; integer_t result; if(integer_is_zero(source)) { return integer_set_unsigned_value(target, 0); } aliased = (result == source); result = aliased ? integer_create(0) : target; VERIFY(GROW(result, 2 * LENGTH(source))); SET_SIGNED_LENGTH(result, 2 * LENGTH(source)); VERIFY(digits_square(DIGITS(result), DIGITS(source), LENGTH(source))); NORMALIZE(result); // TODO: call a karatsuba routine here... if(aliased) { EXCHANGE(target, result); integer_destroy(result); } return 0; }
// MCA: ExtendedGCD int integer_gcd_extended(integer_t gcd, integer_t U, integer_t V, integer_t A, integer_t B) { integer_t a, b, u, w, v, x, q, r; INSIST(gcd != U); INSIST(gcd != V); INSIST(U != V); a = integer_create(0); b = gcd; VERIFY(integer_absolute_value(a, A)); VERIFY(integer_absolute_value(b, B)); u = U; VERIFY(integer_set_unsigned_value(u, 1)); w = integer_create(0); v = V; VERIFY(integer_set_unsigned_value(v, 0)); x = integer_create(1); q = integer_create(0); r = integer_create(0); while(!integer_is_zero(b)) { VERIFY(integer_divide(q, r, a, b)); SWAP(a, b); SWAP(b, r); VERIFY(integer_multiply(r, q, w)); VERIFY(integer_subtract(u, u, r)); SWAP(u, w); VERIFY(integer_multiply(r, q, x)); VERIFY(integer_subtract(v, v, r)); SWAP(v, x); } EXCHANGE(gcd, a); EXCHANGE(U, u); EXCHANGE(V, v); integer_destroy(q); /* gcd is passed between a, b, and r */ if(b == gcd) { integer_destroy(a); integer_destroy(r); } else if(a == gcd) { integer_destroy(b); integer_destroy(r); } else { integer_destroy(a); integer_destroy(b); } /* U and V are passed between u, w and v, x respectively */ if(u == U) { integer_destroy(w); integer_destroy(x); } else { integer_destroy(u); integer_destroy(v); } return 0; }