#include <stdlib.h>
#include <string.h>
#include "fmpz.h"
#include "gr.h"
#include "gr/impl.h"
#include "gr_vec.h"
#include "gr_poly.h"
#include "gr_generic.h"
#include "gr_special.h"
static const char * default_var = "x";
static void
polynomial_init(gr_poly_t res, gr_ctx_t ctx)
{
gr_poly_init(res, POLYNOMIAL_ELEM_CTX(ctx));
}
static int polynomial_ctx_write(gr_stream_t out, gr_ctx_t ctx)
{
gr_stream_write(out, "Ring of polynomials over ");
gr_ctx_write(out, POLYNOMIAL_ELEM_CTX(ctx));
return GR_SUCCESS;
}
static int _gr_gr_poly_ctx_set_gen_name(gr_ctx_t ctx, const char * s)
{
slong len;
len = strlen(s);
if (POLYNOMIAL_CTX(ctx)->var == default_var)
POLYNOMIAL_CTX(ctx)->var = NULL;
POLYNOMIAL_CTX(ctx)->var = flint_realloc(POLYNOMIAL_CTX(ctx)->var, len + 1);
memcpy(POLYNOMIAL_CTX(ctx)->var, s, len + 1);
return GR_SUCCESS;
}
static int _gr_gr_poly_ctx_set_gen_names(gr_ctx_t ctx, const char ** s)
{
return _gr_gr_poly_ctx_set_gen_name(ctx, s[0]);
}
int
_gr_gr_poly_ctx_gen_name(char ** name, slong i, gr_ctx_t ctx)
{
if (i != 0)
return GR_DOMAIN;
char * var = POLYNOMIAL_CTX(ctx)->var;
size_t len = strlen(var);
* name = flint_malloc(len + 1);
if (* name == NULL)
return GR_UNABLE;
strncpy(* name, var, len + 1);
return GR_SUCCESS;
}
static gr_ptr _gr_gr_poly_ctx_base(gr_ctx_t ctx)
{
return POLYNOMIAL_ELEM_CTX(ctx);
}
static void
polynomial_ctx_clear(gr_ctx_t ctx)
{
if (POLYNOMIAL_CTX(ctx)->var != default_var)
{
flint_free(POLYNOMIAL_CTX(ctx)->var);
}
}
static truth_t
polynomial_ctx_is_ring(gr_ctx_t ctx)
{
return gr_ctx_is_ring(POLYNOMIAL_ELEM_CTX(ctx));
}
static truth_t
polynomial_ctx_is_commutative_ring(gr_ctx_t ctx)
{
return gr_ctx_is_commutative_ring(POLYNOMIAL_ELEM_CTX(ctx));
}
static truth_t
polynomial_ctx_is_integral_domain(gr_ctx_t ctx)
{
return gr_ctx_is_integral_domain(POLYNOMIAL_ELEM_CTX(ctx));
}
static truth_t
polynomial_ctx_is_unique_factorization_domain(gr_ctx_t ctx)
{
return gr_ctx_is_unique_factorization_domain(POLYNOMIAL_ELEM_CTX(ctx));
}
static truth_t
polynomial_ctx_is_rational_vector_space(gr_ctx_t ctx)
{
return gr_ctx_is_rational_vector_space(POLYNOMIAL_ELEM_CTX(ctx));
}
static truth_t
polynomial_ctx_is_real_vector_space(gr_ctx_t ctx)
{
return gr_ctx_is_real_vector_space(POLYNOMIAL_ELEM_CTX(ctx));
}
static truth_t
polynomial_ctx_is_complex_vector_space(gr_ctx_t ctx)
{
return gr_ctx_is_complex_vector_space(POLYNOMIAL_ELEM_CTX(ctx));
}
static truth_t
polynomial_ctx_is_approx_commutative_ring(gr_ctx_t ctx)
{
return gr_ctx_is_approx_commutative_ring(POLYNOMIAL_ELEM_CTX(ctx));
}
static truth_t
polynomial_ctx_is_threadsafe(gr_ctx_t ctx)
{
return gr_ctx_is_threadsafe(POLYNOMIAL_ELEM_CTX(ctx));
}
static void
polynomial_clear(gr_poly_t res, gr_ctx_t ctx)
{
gr_poly_clear(res, POLYNOMIAL_ELEM_CTX(ctx));
}
static void
polynomial_swap(gr_poly_t poly1, gr_poly_t poly2, gr_ctx_t ctx)
{
gr_poly_swap(poly1, poly2, POLYNOMIAL_ELEM_CTX(ctx));
}
static void
polynomial_set_shallow(gr_poly_t res, const gr_poly_t x, const gr_ctx_t ctx)
{
*res = *x;
}
static int
polynomial_write(gr_stream_t out, gr_poly_t poly, gr_ctx_t ctx)
{
if (poly->length == 0)
{
gr_stream_write(out, "0");
return GR_SUCCESS;
}
return gr_poly_write(out, poly, POLYNOMIAL_CTX(ctx)->var, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_randtest(gr_poly_t res, flint_rand_t state, gr_ctx_t ctx)
{
return gr_poly_randtest(res, state, n_randint(state, 5), POLYNOMIAL_ELEM_CTX(ctx));
}
static truth_t
polynomial_equal(const gr_poly_t poly1, const gr_poly_t poly2, gr_ctx_t ctx)
{
return gr_poly_equal(poly1, poly2, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_set(gr_poly_t res, const gr_poly_t mat, gr_ctx_t ctx)
{
return gr_poly_set(res, mat, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_set_si(gr_poly_t res, slong v, gr_ctx_t ctx)
{
return gr_poly_set_si(res, v, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_set_ui(gr_poly_t res, ulong v, gr_ctx_t ctx)
{
return gr_poly_set_ui(res, v, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_set_fmpz(gr_poly_t res, const fmpz_t v, gr_ctx_t ctx)
{
return gr_poly_set_fmpz(res, v, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_set_fmpq(gr_poly_t res, const fmpq_t v, gr_ctx_t ctx)
{
return gr_poly_set_fmpq(res, v, POLYNOMIAL_ELEM_CTX(ctx));
}
#include "fmpz_poly.h"
static int
polynomial_set_other(gr_poly_t res, gr_srcptr x, gr_ctx_t x_ctx, gr_ctx_t ctx)
{
if (x_ctx == ctx)
{
return polynomial_set(res, x, ctx);
}
else if (x_ctx == POLYNOMIAL_ELEM_CTX(ctx))
{
return gr_poly_set_scalar(res, x, x_ctx);
}
else if (x_ctx->which_ring == GR_CTX_GR_POLY && !strcmp(POLYNOMIAL_CTX(x_ctx)->var, POLYNOMIAL_CTX(ctx)->var))
{
return gr_poly_set_gr_poly_other(res, x, POLYNOMIAL_ELEM_CTX(x_ctx), POLYNOMIAL_ELEM_CTX(ctx));
}
else if (x_ctx->which_ring == GR_CTX_FMPZ_POLY)
{
return gr_poly_set_fmpz_poly(res, x, POLYNOMIAL_ELEM_CTX(ctx));
}
else if (x_ctx->which_ring == GR_CTX_FMPQ_POLY)
{
return gr_poly_set_fmpq_poly(res, x, POLYNOMIAL_ELEM_CTX(ctx));
}
else if (x_ctx->which_ring == GR_CTX_GR_VEC)
{
gr_poly_t tmp;
tmp->coeffs = ((gr_vec_struct *) x)->entries;
tmp->length = ((gr_vec_struct *) x)->length;
return gr_poly_set_gr_poly_other(res, tmp, VECTOR_CTX(x_ctx)->base_ring, POLYNOMIAL_ELEM_CTX(ctx));
}
else
{
int status = GR_SUCCESS;
gr_poly_fit_length(res, 1, POLYNOMIAL_ELEM_CTX(ctx));
status = gr_set_other(res->coeffs, x, x_ctx, POLYNOMIAL_ELEM_CTX(ctx));
if (status == GR_SUCCESS)
{
_gr_poly_set_length(res, 1, POLYNOMIAL_ELEM_CTX(ctx));
_gr_poly_normalise(res, POLYNOMIAL_ELEM_CTX(ctx));
}
else
_gr_poly_set_length(res, 0, POLYNOMIAL_ELEM_CTX(ctx));
return status;
}
}
static int
polynomial_set_interval_mid_rad(gr_poly_t res, const gr_poly_t m, const gr_poly_t r, gr_ctx_t ctx)
{
if (r->length == 0)
{
return gr_poly_set(res, m, POLYNOMIAL_ELEM_CTX(ctx));
}
else
{
slong i, mlen, rlen, len;
int status = GR_SUCCESS;
gr_ptr zero = NULL;
gr_ctx_ptr cctx = POLYNOMIAL_ELEM_CTX(ctx);
if (res == r)
{
gr_poly_t t;
gr_poly_init(t, cctx);
status = polynomial_set_interval_mid_rad(t, m, r, ctx);
gr_poly_swap(res, t, cctx);
gr_poly_clear(t, cctx);
return status;
}
mlen = m->length;
rlen = r->length;
len = FLINT_MAX(mlen, rlen);
gr_poly_fit_length(res, len, cctx);
_gr_poly_set_length(res, len, cctx);
for (i = 0; i < len; i++)
{
if (i < mlen && i < rlen)
{
status |= gr_set_interval_mid_rad(gr_poly_coeff_ptr(res, i, cctx),
gr_poly_coeff_srcptr(m, i, cctx),
gr_poly_coeff_srcptr(r, i, cctx), cctx);
}
else if (i < mlen)
{
status |= gr_set(gr_poly_coeff_ptr(res, i, cctx),
gr_poly_coeff_srcptr(m, i, cctx), cctx);
}
else if (i < rlen)
{
if (zero == NULL)
zero = gr_heap_init(cctx);
status |= gr_set_interval_mid_rad(gr_poly_coeff_ptr(res, i, cctx),
zero,
gr_poly_coeff_srcptr(r, i, cctx), cctx);
}
}
if (zero != NULL)
gr_heap_clear(zero, cctx);
_gr_poly_normalise(res, cctx);
return status;
}
}
static int
polynomial_zero(gr_poly_t res, gr_ctx_t ctx)
{
return gr_poly_zero(res, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_one(gr_poly_t res, gr_ctx_t ctx)
{
return gr_poly_one(res, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_neg_one(gr_poly_t res, gr_ctx_t ctx)
{
return gr_poly_neg_one(res, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_i(gr_poly_t res, gr_ctx_t ctx)
{
int status;
gr_poly_fit_length(res, 1, POLYNOMIAL_ELEM_CTX(ctx));
_gr_poly_set_length(res, 1, POLYNOMIAL_ELEM_CTX(ctx));
status = gr_i(res->coeffs, POLYNOMIAL_ELEM_CTX(ctx));
_gr_poly_normalise(res, POLYNOMIAL_ELEM_CTX(ctx));
return status;
}
static int
polynomial_pi(gr_poly_t res, gr_ctx_t ctx)
{
int status;
gr_poly_fit_length(res, 1, POLYNOMIAL_ELEM_CTX(ctx));
_gr_poly_set_length(res, 1, POLYNOMIAL_ELEM_CTX(ctx));
status = gr_pi(res->coeffs, POLYNOMIAL_ELEM_CTX(ctx));
_gr_poly_normalise(res, POLYNOMIAL_ELEM_CTX(ctx));
return status;
}
static int
polynomial_gen(gr_poly_t res, gr_ctx_t ctx)
{
return gr_poly_gen(res, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_gens_recursive(gr_vec_t vec, gr_ctx_t ctx)
{
int status;
gr_vec_t vec1;
slong i, n;
gr_vec_init(vec1, 0, POLYNOMIAL_ELEM_CTX(ctx));
status = gr_gens_recursive(vec1, POLYNOMIAL_ELEM_CTX(ctx));
n = vec1->length;
gr_vec_set_length(vec, n + 1, ctx);
for (i = 0; i < n; i++)
status |= gr_poly_set_scalar(gr_vec_entry_ptr(vec, i, ctx),
gr_vec_entry_srcptr(vec1, i, POLYNOMIAL_ELEM_CTX(ctx)),
POLYNOMIAL_ELEM_CTX(ctx));
status |= gr_poly_gen(gr_vec_entry_ptr(vec, n, ctx), POLYNOMIAL_ELEM_CTX(ctx));
gr_vec_clear(vec1, POLYNOMIAL_ELEM_CTX(ctx));
return status;
}
static truth_t
polynomial_is_zero(const gr_poly_t poly, gr_ctx_t ctx)
{
return gr_poly_is_zero(poly, POLYNOMIAL_ELEM_CTX(ctx));
}
static truth_t
polynomial_is_one(const gr_poly_t poly, gr_ctx_t ctx)
{
return gr_poly_is_one(poly, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_neg(gr_poly_t res, const gr_poly_t mat, gr_ctx_t ctx)
{
return gr_poly_neg(res, mat, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_add_ui(gr_poly_t res, const gr_poly_t poly, ulong c, gr_ctx_t ctx)
{
return gr_poly_add_ui(res, poly, c, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_add_si(gr_poly_t res, const gr_poly_t poly, slong c, gr_ctx_t ctx)
{
return gr_poly_add_si(res, poly, c, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_add_fmpz(gr_poly_t res, const gr_poly_t poly, const fmpz_t c, gr_ctx_t ctx)
{
return gr_poly_add_fmpz(res, poly, c, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_add_fmpq(gr_poly_t res, const gr_poly_t poly, const fmpq_t c, gr_ctx_t ctx)
{
return gr_poly_add_fmpq(res, poly, c, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_add(gr_poly_t res, const gr_poly_t poly1, const gr_poly_t poly2, gr_ctx_t ctx)
{
return gr_poly_add(res, poly1, poly2, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_sub_ui(gr_poly_t res, const gr_poly_t poly, ulong c, gr_ctx_t ctx)
{
return gr_poly_sub_ui(res, poly, c, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_sub_si(gr_poly_t res, const gr_poly_t poly, slong c, gr_ctx_t ctx)
{
return gr_poly_sub_si(res, poly, c, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_sub_fmpz(gr_poly_t res, const gr_poly_t poly, const fmpz_t c, gr_ctx_t ctx)
{
return gr_poly_sub_fmpz(res, poly, c, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_sub_fmpq(gr_poly_t res, const gr_poly_t poly, const fmpq_t c, gr_ctx_t ctx)
{
return gr_poly_sub_fmpq(res, poly, c, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_sub(gr_poly_t res, const gr_poly_t poly1, const gr_poly_t poly2, gr_ctx_t ctx)
{
return gr_poly_sub(res, poly1, poly2, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_mul_ui(gr_poly_t res, const gr_poly_t poly, ulong c, gr_ctx_t ctx)
{
return gr_poly_mul_ui(res, poly, c, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_mul_si(gr_poly_t res, const gr_poly_t poly, slong c, gr_ctx_t ctx)
{
return gr_poly_mul_si(res, poly, c, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_mul_fmpz(gr_poly_t res, const gr_poly_t poly, const fmpz_t c, gr_ctx_t ctx)
{
return gr_poly_mul_fmpz(res, poly, c, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_mul_fmpq(gr_poly_t res, const gr_poly_t poly, const fmpq_t c, gr_ctx_t ctx)
{
return gr_poly_mul_fmpq(res, poly, c, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_mul(gr_poly_t res, const gr_poly_t poly1, const gr_poly_t poly2, gr_ctx_t ctx)
{
if (POLYNOMIAL_CTX(ctx)->degree_limit != WORD_MAX)
{
if (poly1->length != 0 && poly2->length != 0 &&
poly1->length + poly2->length > POLYNOMIAL_CTX(ctx)->degree_limit)
return GR_UNABLE;
}
return gr_poly_mul(res, poly1, poly2, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_mul_other(gr_poly_t res, const gr_poly_t poly, gr_srcptr x, gr_ctx_t x_ctx, gr_ctx_t ctx)
{
if (x_ctx == POLYNOMIAL_ELEM_CTX(ctx))
{
return gr_poly_mul_scalar(res, poly, x, x_ctx);
}
else if (x_ctx->which_ring == GR_CTX_GR_POLY &&
POLYNOMIAL_ELEM_CTX(x_ctx) == POLYNOMIAL_ELEM_CTX(ctx) &&
!strcmp(POLYNOMIAL_CTX(x_ctx)->var, POLYNOMIAL_CTX(ctx)->var))
{
return polynomial_mul(res, poly, x, ctx);
}
else
{
gr_poly_t t;
int status = GR_SUCCESS;
polynomial_init(t, ctx);
status = polynomial_set_other(t, x, x_ctx, ctx);
if (status == GR_SUCCESS)
status = polynomial_mul(res, poly, t, ctx);
polynomial_clear(t, ctx);
return status;
}
}
static int
polynomial_other_mul(gr_poly_t res, gr_srcptr x, gr_ctx_t x_ctx, const gr_poly_t poly, gr_ctx_t ctx)
{
if (x_ctx == POLYNOMIAL_ELEM_CTX(ctx))
{
return gr_poly_scalar_mul(res, x, poly, x_ctx);
}
else if (x_ctx->which_ring == GR_CTX_GR_POLY &&
POLYNOMIAL_ELEM_CTX(x_ctx) == POLYNOMIAL_ELEM_CTX(ctx) &&
!strcmp(POLYNOMIAL_CTX(x_ctx)->var, POLYNOMIAL_CTX(ctx)->var))
{
return polynomial_mul(res, x, poly, ctx);
}
else
{
gr_poly_t t;
int status = GR_SUCCESS;
polynomial_init(t, ctx);
status = polynomial_set_other(t, x, x_ctx, ctx);
if (status == GR_SUCCESS)
status = polynomial_mul(res, t, poly, ctx);
polynomial_clear(t, ctx);
return status;
}
}
static int
polynomial_div(gr_poly_t res, const gr_poly_t x, const gr_poly_t y, const gr_ctx_t ctx)
{
if (y->length == 1)
{
if (res == y)
{
gr_ptr t;
int status = GR_SUCCESS;
GR_TMP_INIT(t, POLYNOMIAL_ELEM_CTX(ctx));
status |= gr_set(t, y->coeffs, POLYNOMIAL_ELEM_CTX(ctx));
status |= gr_poly_div_scalar(res, x, t, POLYNOMIAL_ELEM_CTX(ctx));
GR_TMP_CLEAR(t, POLYNOMIAL_ELEM_CTX(ctx));
return status;
}
else
{
return gr_poly_div_scalar(res, x, y->coeffs, POLYNOMIAL_ELEM_CTX(ctx));
}
}
else
{
gr_poly_t r;
int status;
gr_poly_init(r, POLYNOMIAL_ELEM_CTX(ctx));
status = gr_poly_divrem(res, r, x, y, POLYNOMIAL_ELEM_CTX(ctx));
if (status == GR_SUCCESS)
{
truth_t is_zero = gr_poly_is_zero(r, POLYNOMIAL_ELEM_CTX(ctx));
if (is_zero == T_FALSE)
status = GR_DOMAIN;
if (is_zero == T_UNKNOWN)
status = GR_UNABLE;
}
gr_poly_clear(r, POLYNOMIAL_ELEM_CTX(ctx));
return status;
}
}
static int
polynomial_divexact(gr_poly_t res, const gr_poly_t x, const gr_poly_t y, const gr_ctx_t ctx)
{
return gr_poly_divexact(res, x, y, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_euclidean_div(gr_poly_t res, const gr_poly_t x, const gr_poly_t y, const gr_ctx_t ctx)
{
gr_poly_t r;
int status;
gr_poly_init(r, POLYNOMIAL_ELEM_CTX(ctx));
status = gr_poly_divrem(res, r, x, y, POLYNOMIAL_ELEM_CTX(ctx));
gr_poly_clear(r, POLYNOMIAL_ELEM_CTX(ctx));
return status;
}
static int
polynomial_euclidean_rem(gr_poly_t res, const gr_poly_t x, const gr_poly_t y, const gr_ctx_t ctx)
{
gr_poly_t q;
int status;
gr_poly_init(q, POLYNOMIAL_ELEM_CTX(ctx));
status = gr_poly_divrem(q, res, x, y, POLYNOMIAL_ELEM_CTX(ctx));
gr_poly_clear(q, POLYNOMIAL_ELEM_CTX(ctx));
return status;
}
static int
polynomial_euclidean_divrem(gr_poly_t res1, gr_poly_t res2, const gr_poly_t x, const gr_poly_t y, const gr_ctx_t ctx)
{
return gr_poly_divrem(res1, res2, x, y, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_inv(gr_poly_t res, const gr_poly_t poly, gr_ctx_t ctx)
{
return gr_poly_inv(res, poly, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_pow_ui(gr_poly_t res, const gr_poly_t poly, ulong exp, gr_ctx_t ctx)
{
return gr_poly_pow_ui(res, poly, exp, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_pow_fmpz(gr_poly_t res, const gr_poly_t poly, const fmpz_t exp, gr_ctx_t ctx)
{
return gr_poly_pow_fmpz(res, poly, exp, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_pow_si(gr_poly_t res, const gr_poly_t poly, slong exp, gr_ctx_t ctx)
{
int status;
fmpz_t t;
fmpz_init_set_si(t, exp);
status = gr_poly_pow_fmpz(res, poly, t, POLYNOMIAL_ELEM_CTX(ctx));
fmpz_clear(t);
return status;
}
static int
polynomial_derivative_gen(gr_poly_t res, const gr_poly_t poly, slong var, gr_ctx_t ctx)
{
return (var == 0) ? gr_poly_derivative(res, poly, POLYNOMIAL_ELEM_CTX(ctx)) : GR_DOMAIN;
}
static int
polynomial_gcd(gr_poly_t res, const gr_poly_t x, const gr_poly_t y, const gr_ctx_t ctx)
{
return gr_poly_gcd(res, x, y, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_canonical_associate(gr_poly_t ux, gr_poly_t u, const gr_poly_t x, gr_ctx_t ctx)
{
return gr_poly_canonical_associate(ux, u, x, POLYNOMIAL_ELEM_CTX(ctx));
}
static int
polynomial_factor(gr_ptr c, gr_vec_t fac, gr_vec_t mult, const gr_poly_t pol, int flags, const gr_ctx_t ctx)
{
gr_ctx_struct * cctx = POLYNOMIAL_ELEM_CTX(ctx);
return GR_FACTOR_OP(cctx, POLY_FACTOR)(c, fac, mult, pol, flags, cctx);
}
#define MUL_KS_CUTOFF 5
#define MUL_KS_DEPTH_LIMIT 3
static int
want_KS(gr_ctx_t cctx, slong depth)
{
if (cctx->methods[GR_METHOD_POLY_MULLOW] == (gr_funcptr) _gr_poly_mullow_generic)
return 0;
if (depth > MUL_KS_DEPTH_LIMIT)
return 0;
if (cctx->which_ring == GR_CTX_GR_POLY)
return want_KS(POLYNOMIAL_ELEM_CTX(cctx), depth + 1);
return 1;
}
static int
_polynomial_gr_poly_mullow(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, slong n, gr_ctx_t ctx)
{
gr_ctx_struct * cctx = POLYNOMIAL_ELEM_CTX(ctx);
if (len1 < MUL_KS_CUTOFF || len2 < MUL_KS_CUTOFF || n < MUL_KS_CUTOFF)
return _gr_poly_mullow_classical(res, poly1, len1, poly2, len2, n, ctx);
if (!want_KS(cctx, 0))
return _gr_poly_mullow_classical(res, poly1, len1, poly2, len2, n, ctx);
return _gr_poly_mullow_bivariate_KS(res, poly1, len1, poly2, len2, n, ctx);
}
static int
_polynomial_gr_poly_mulmid(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, slong nlo, slong nhi, gr_ctx_t ctx)
{
gr_ctx_struct * cctx = POLYNOMIAL_ELEM_CTX(ctx);
if (len1 < MUL_KS_CUTOFF || len2 < MUL_KS_CUTOFF || nhi < MUL_KS_CUTOFF
|| len1 + len2 - 1 - nlo < MUL_KS_CUTOFF || 2 * (nhi - nlo) < MUL_KS_CUTOFF)
return _gr_poly_mulmid_classical(res, poly1, len1, poly2, len2, nlo, nhi, ctx);
if (!want_KS(cctx, 0))
return _gr_poly_mulmid_classical(res, poly1, len1, poly2, len2, nlo, nhi, ctx);
return _gr_poly_mulmid_bivariate_KS(res, poly1, len1, poly2, len2, nlo, nhi, ctx);
}
int _gr_poly_methods_initialized = 0;
gr_static_method_table _gr_poly_methods;
gr_method_tab_input _gr_poly_methods_input[] =
{
{GR_METHOD_CTX_WRITE, (gr_funcptr) polynomial_ctx_write},
{GR_METHOD_CTX_CLEAR, (gr_funcptr) polynomial_ctx_clear},
{GR_METHOD_CTX_IS_RING, (gr_funcptr) polynomial_ctx_is_ring},
{GR_METHOD_CTX_IS_COMMUTATIVE_RING, (gr_funcptr) polynomial_ctx_is_commutative_ring},
{GR_METHOD_CTX_IS_INTEGRAL_DOMAIN, (gr_funcptr) polynomial_ctx_is_integral_domain},
{GR_METHOD_CTX_IS_UNIQUE_FACTORIZATION_DOMAIN, (gr_funcptr) polynomial_ctx_is_unique_factorization_domain},
{GR_METHOD_CTX_IS_FIELD, (gr_funcptr) gr_generic_ctx_predicate_false},
{GR_METHOD_CTX_IS_RATIONAL_VECTOR_SPACE, (gr_funcptr) polynomial_ctx_is_rational_vector_space},
{GR_METHOD_CTX_IS_REAL_VECTOR_SPACE, (gr_funcptr) polynomial_ctx_is_real_vector_space},
{GR_METHOD_CTX_IS_COMPLEX_VECTOR_SPACE, (gr_funcptr) polynomial_ctx_is_complex_vector_space},
{GR_METHOD_CTX_IS_APPROX_COMMUTATIVE_RING, (gr_funcptr) polynomial_ctx_is_approx_commutative_ring},
{GR_METHOD_CTX_IS_THREADSAFE, (gr_funcptr) polynomial_ctx_is_threadsafe},
{GR_METHOD_CTX_SET_GEN_NAME, (gr_funcptr) _gr_gr_poly_ctx_set_gen_name},
{GR_METHOD_CTX_SET_GEN_NAMES, (gr_funcptr) _gr_gr_poly_ctx_set_gen_names},
{GR_METHOD_CTX_NGENS, (gr_funcptr) gr_generic_ctx_ngens_1},
{GR_METHOD_CTX_GEN_NAME, (gr_funcptr) _gr_gr_poly_ctx_gen_name},
{GR_METHOD_CTX_BASE, (gr_funcptr) _gr_gr_poly_ctx_base},
{GR_METHOD_INIT, (gr_funcptr) polynomial_init},
{GR_METHOD_CLEAR, (gr_funcptr) polynomial_clear},
{GR_METHOD_SWAP, (gr_funcptr) polynomial_swap},
{GR_METHOD_SET_SHALLOW, (gr_funcptr) polynomial_set_shallow},
{GR_METHOD_RANDTEST, (gr_funcptr) polynomial_randtest},
{GR_METHOD_WRITE, (gr_funcptr) polynomial_write},
{GR_METHOD_ZERO, (gr_funcptr) polynomial_zero},
{GR_METHOD_ONE, (gr_funcptr) polynomial_one},
{GR_METHOD_NEG_ONE, (gr_funcptr) polynomial_neg_one},
{GR_METHOD_GEN, (gr_funcptr) polynomial_gen},
{GR_METHOD_GENS, (gr_funcptr) gr_generic_gens_single},
{GR_METHOD_GENS_RECURSIVE, (gr_funcptr) polynomial_gens_recursive},
{GR_METHOD_IS_ZERO, (gr_funcptr) polynomial_is_zero},
{GR_METHOD_IS_ONE, (gr_funcptr) polynomial_is_one},
{GR_METHOD_EQUAL, (gr_funcptr) polynomial_equal},
{GR_METHOD_SET, (gr_funcptr) polynomial_set},
{GR_METHOD_SET_UI, (gr_funcptr) polynomial_set_ui},
{GR_METHOD_SET_SI, (gr_funcptr) polynomial_set_si},
{GR_METHOD_SET_FMPZ, (gr_funcptr) polynomial_set_fmpz},
{GR_METHOD_SET_FMPQ, (gr_funcptr) polynomial_set_fmpq},
{GR_METHOD_SET_OTHER, (gr_funcptr) polynomial_set_other},
{GR_METHOD_SET_INTERVAL_MID_RAD, (gr_funcptr) polynomial_set_interval_mid_rad},
{GR_METHOD_SET_STR, (gr_funcptr) gr_generic_set_str_balance_additions},
{GR_METHOD_NEG, (gr_funcptr) polynomial_neg},
{GR_METHOD_ADD_UI, (gr_funcptr) polynomial_add_ui},
{GR_METHOD_ADD_SI, (gr_funcptr) polynomial_add_si},
{GR_METHOD_ADD_FMPZ, (gr_funcptr) polynomial_add_fmpz},
{GR_METHOD_ADD_FMPQ, (gr_funcptr) polynomial_add_fmpq},
{GR_METHOD_ADD, (gr_funcptr) polynomial_add},
{GR_METHOD_SUB_UI, (gr_funcptr) polynomial_sub_ui},
{GR_METHOD_SUB_SI, (gr_funcptr) polynomial_sub_si},
{GR_METHOD_SUB_FMPZ, (gr_funcptr) polynomial_sub_fmpz},
{GR_METHOD_SUB_FMPQ, (gr_funcptr) polynomial_sub_fmpq},
{GR_METHOD_SUB, (gr_funcptr) polynomial_sub},
{GR_METHOD_MUL, (gr_funcptr) polynomial_mul},
{GR_METHOD_MUL_OTHER, (gr_funcptr) polynomial_mul_other},
{GR_METHOD_OTHER_MUL, (gr_funcptr) polynomial_other_mul},
{GR_METHOD_MUL_UI, (gr_funcptr) polynomial_mul_ui},
{GR_METHOD_MUL_SI, (gr_funcptr) polynomial_mul_si},
{GR_METHOD_MUL_FMPZ, (gr_funcptr) polynomial_mul_fmpz},
{GR_METHOD_MUL_FMPQ, (gr_funcptr) polynomial_mul_fmpq},
{GR_METHOD_POW_UI, (gr_funcptr) polynomial_pow_ui},
{GR_METHOD_POW_SI, (gr_funcptr) polynomial_pow_si},
{GR_METHOD_POW_FMPZ, (gr_funcptr) polynomial_pow_fmpz},
{GR_METHOD_DIV, (gr_funcptr) polynomial_div},
{GR_METHOD_DIVEXACT, (gr_funcptr) polynomial_divexact},
{GR_METHOD_INV, (gr_funcptr) polynomial_inv},
{GR_METHOD_DERIVATIVE_GEN, (gr_funcptr) polynomial_derivative_gen},
{GR_METHOD_EUCLIDEAN_DIV, (gr_funcptr) polynomial_euclidean_div},
{GR_METHOD_EUCLIDEAN_REM, (gr_funcptr) polynomial_euclidean_rem},
{GR_METHOD_EUCLIDEAN_DIVREM, (gr_funcptr) polynomial_euclidean_divrem},
{GR_METHOD_I, (gr_funcptr) polynomial_i},
{GR_METHOD_PI, (gr_funcptr) polynomial_pi},
{GR_METHOD_CANONICAL_ASSOCIATE, (gr_funcptr) polynomial_canonical_associate},
{GR_METHOD_GCD, (gr_funcptr) polynomial_gcd},
{GR_METHOD_FACTOR, (gr_funcptr) polynomial_factor},
{GR_METHOD_POLY_MULLOW, (gr_funcptr) _polynomial_gr_poly_mullow},
{GR_METHOD_POLY_MULMID, (gr_funcptr) _polynomial_gr_poly_mulmid},
{0, (gr_funcptr) NULL},
};
void
gr_ctx_init_gr_poly(gr_ctx_t ctx, gr_ctx_t base_ring)
{
ctx->which_ring = GR_CTX_GR_POLY;
ctx->sizeof_elem = sizeof(gr_poly_struct);
ctx->size_limit = WORD_MAX;
POLYNOMIAL_CTX(ctx)->base_ring = (gr_ctx_struct *) base_ring;
POLYNOMIAL_CTX(ctx)->degree_limit = WORD_MAX;
POLYNOMIAL_CTX(ctx)->var = (char *) default_var;
ctx->methods = _gr_poly_methods;
if (!_gr_poly_methods_initialized)
{
gr_method_tab_init(_gr_poly_methods, _gr_poly_methods_input);
_gr_poly_methods_initialized = 1;
}
}