#include <string.h>
#include "fmpq.h"
#include "gr_vec.h"
#include "gr_poly.h"
#include "gr_generic.h"
#include "gr_series.h"
#include "gr_series/impl.h"
static const char * default_var = "x";
void gr_series_mod_ctx_clear(gr_ctx_t ctx)
{
if (GR_SERIES_MOD_CTX(ctx)->var != default_var)
flint_free(GR_SERIES_MOD_CTX(ctx)->var);
}
int gr_series_mod_ctx_write(gr_stream_t out, gr_ctx_t ctx)
{
gr_stream_write(out, "Power series over ");
gr_ctx_write(out, GR_SERIES_MOD_ELEM_CTX(ctx));
gr_stream_write(out, " mod ");
gr_stream_write(out, GR_SERIES_MOD_CTX(ctx)->var);
gr_stream_write(out, "^");
gr_stream_write_si(out, GR_SERIES_MOD_N(ctx));
return GR_SUCCESS;
}
truth_t
gr_series_mod_ctx_is_ring(gr_ctx_t ctx)
{
if (GR_SERIES_MOD_N(ctx) == 0)
return T_TRUE;
return gr_ctx_is_ring(GR_SERIES_MOD_ELEM_CTX(ctx));
}
truth_t
gr_series_mod_ctx_is_commutative_ring(gr_ctx_t ctx)
{
if (GR_SERIES_MOD_N(ctx) == 0)
return T_TRUE;
return gr_ctx_is_commutative_ring(GR_SERIES_MOD_ELEM_CTX(ctx));
}
truth_t
gr_series_mod_ctx_is_integral_domain(gr_ctx_t ctx)
{
if (GR_SERIES_MOD_N(ctx) != 1)
return T_FALSE;
return gr_ctx_is_integral_domain(GR_SERIES_MOD_ELEM_CTX(ctx));
}
truth_t
gr_series_mod_ctx_is_rational_vector_space(gr_ctx_t ctx)
{
if (GR_SERIES_MOD_N(ctx) == 0)
return T_TRUE;
return gr_ctx_is_rational_vector_space(GR_SERIES_MOD_ELEM_CTX(ctx));
}
truth_t
gr_series_mod_ctx_is_real_vector_space(gr_ctx_t ctx)
{
if (GR_SERIES_MOD_N(ctx) == 0)
return T_TRUE;
return gr_ctx_is_real_vector_space(GR_SERIES_MOD_ELEM_CTX(ctx));
}
truth_t
gr_series_mod_ctx_is_complex_vector_space(gr_ctx_t ctx)
{
if (GR_SERIES_MOD_N(ctx) == 0)
return T_TRUE;
return gr_ctx_is_complex_vector_space(GR_SERIES_MOD_ELEM_CTX(ctx));
}
truth_t
gr_series_mod_ctx_is_field(gr_ctx_t ctx)
{
if (GR_SERIES_MOD_N(ctx) != 1)
return T_FALSE;
return gr_ctx_is_field(GR_SERIES_MOD_ELEM_CTX(ctx));
}
int gr_series_mod_ctx_set_gen_name(gr_ctx_t ctx, const char * s)
{
slong len;
len = strlen(s);
if (GR_SERIES_MOD_CTX(ctx)->var == default_var)
GR_SERIES_MOD_CTX(ctx)->var = NULL;
GR_SERIES_MOD_CTX(ctx)->var = flint_realloc(GR_SERIES_MOD_CTX(ctx)->var, len + 1);
memcpy(GR_SERIES_MOD_CTX(ctx)->var, s, len + 1);
return GR_SUCCESS;
}
int gr_series_mod_ctx_set_gen_names(gr_ctx_t ctx, const char ** s)
{
return gr_series_mod_ctx_set_gen_name(ctx, s[0]);
}
#define _gr_series_mod_ctx_gen_name _gr_series_ctx_gen_name
int
gr_series_mod_gens_recursive(gr_vec_t vec, gr_ctx_t ctx)
{
int status;
gr_vec_t vec1;
slong i, n;
gr_vec_init(vec1, 0, GR_SERIES_MOD_ELEM_CTX(ctx));
status = gr_gens_recursive(vec1, GR_SERIES_MOD_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, GR_SERIES_MOD_ELEM_CTX(ctx)),
GR_SERIES_MOD_ELEM_CTX(ctx));
status |= gr_poly_gen(gr_vec_entry_ptr(vec, n, ctx), GR_SERIES_MOD_ELEM_CTX(ctx));
gr_vec_clear(vec1, GR_SERIES_MOD_ELEM_CTX(ctx));
return status;
}
static gr_ptr _gr_series_mod_ctx_base(gr_ctx_t ctx) { return GR_SERIES_MOD_ELEM_CTX(ctx); }
void gr_series_mod_init(gr_poly_t res, gr_ctx_t ctx)
{
gr_poly_init(res, GR_SERIES_MOD_ELEM_CTX(ctx));
}
void gr_series_mod_clear(gr_poly_t res, gr_ctx_t ctx)
{
gr_poly_clear(res, GR_SERIES_MOD_ELEM_CTX(ctx));
}
void gr_series_mod_swap(gr_poly_t x, gr_poly_t y, gr_ctx_t ctx)
{
gr_poly_swap(x, y, GR_SERIES_MOD_ELEM_CTX(ctx));
}
int gr_series_mod_randtest(gr_poly_t res, flint_rand_t state, gr_ctx_t ctx)
{
return gr_poly_randtest(res, state, GR_SERIES_MOD_N(ctx), GR_SERIES_MOD_ELEM_CTX(ctx));
}
int gr_series_mod_write(gr_stream_t out, const gr_poly_t x, gr_ctx_t ctx)
{
int status = GR_SUCCESS;
status |= gr_poly_write(out, x, GR_SERIES_MOD_CTX(ctx)->var, GR_SERIES_MOD_ELEM_CTX(ctx));
gr_stream_write(out, " (mod ");
gr_stream_write(out, GR_SERIES_MOD_CTX(ctx)->var);
gr_stream_write(out, "^");
gr_stream_write_si(out, GR_SERIES_MOD_N(ctx));
gr_stream_write(out, ")");
return status;
}
int gr_series_mod_zero(gr_poly_t res, gr_ctx_t ctx)
{
return gr_poly_zero(res, GR_SERIES_MOD_ELEM_CTX(ctx));
}
int gr_series_mod_one(gr_poly_t res, gr_ctx_t ctx)
{
return (GR_SERIES_MOD_N(ctx) == 0) ? GR_SUCCESS : gr_poly_one(res, GR_SERIES_MOD_ELEM_CTX(ctx));
}
int gr_series_mod_gen(gr_poly_t res, gr_ctx_t ctx)
{
return (GR_SERIES_MOD_N(ctx) <= 1) ? gr_poly_zero(res, GR_SERIES_MOD_ELEM_CTX(ctx)) : gr_poly_gen(res, GR_SERIES_MOD_ELEM_CTX(ctx));
}
int gr_series_mod_set(gr_poly_t res, const gr_poly_t x, gr_ctx_t ctx)
{
return gr_poly_set(res, x, GR_SERIES_MOD_ELEM_CTX(ctx));
}
void gr_series_mod_set_shallow(gr_poly_t res, const gr_poly_t x, gr_ctx_t ctx)
{
*res = *x;
}
int gr_series_mod_set_si(gr_poly_t res, slong c, gr_ctx_t ctx)
{
return (GR_SERIES_MOD_N(ctx) == 0) ? GR_SUCCESS : gr_poly_set_si(res, c, GR_SERIES_MOD_ELEM_CTX(ctx));
}
int gr_series_mod_set_ui(gr_poly_t res, ulong c, gr_ctx_t ctx)
{
return (GR_SERIES_MOD_N(ctx) == 0) ? GR_SUCCESS : gr_poly_set_ui(res, c, GR_SERIES_MOD_ELEM_CTX(ctx));
}
int gr_series_mod_set_fmpz(gr_poly_t res, const fmpz_t c, gr_ctx_t ctx)
{
return (GR_SERIES_MOD_N(ctx) == 0) ? GR_SUCCESS : gr_poly_set_fmpz(res, c, GR_SERIES_MOD_ELEM_CTX(ctx));
}
int gr_series_mod_set_fmpq(gr_poly_t res, const fmpq_t c, gr_ctx_t ctx)
{
return (GR_SERIES_MOD_N(ctx) == 0) ? GR_SUCCESS : gr_poly_set_fmpq(res, c, GR_SERIES_MOD_ELEM_CTX(ctx));
}
truth_t gr_series_mod_is_zero(const gr_poly_t x, gr_ctx_t ctx)
{
return (GR_SERIES_MOD_N(ctx) == 0) ? T_TRUE : gr_poly_is_zero(x, GR_SERIES_MOD_ELEM_CTX(ctx));
}
truth_t gr_series_mod_is_one(const gr_poly_t x, gr_ctx_t ctx)
{
return (GR_SERIES_MOD_N(ctx) == 0) ? T_TRUE : gr_poly_is_one(x, GR_SERIES_MOD_ELEM_CTX(ctx));
}
truth_t gr_series_mod_equal(const gr_poly_t x, const gr_poly_t y, gr_ctx_t ctx)
{
return gr_poly_equal(x, y, GR_SERIES_MOD_ELEM_CTX(ctx));
}
int gr_series_mod_neg(gr_poly_t res, const gr_poly_t x, gr_ctx_t ctx)
{
return gr_poly_neg(res, x, GR_SERIES_MOD_ELEM_CTX(ctx));
}
int gr_series_mod_add(gr_poly_t res, const gr_poly_t x, const gr_poly_t y, gr_ctx_t ctx)
{
return gr_poly_add(res, x, y, GR_SERIES_MOD_ELEM_CTX(ctx));
}
int gr_series_mod_sub(gr_poly_t res, const gr_poly_t x, const gr_poly_t y, gr_ctx_t ctx)
{
return gr_poly_sub(res, x, y, GR_SERIES_MOD_ELEM_CTX(ctx));
}
int gr_series_mod_mul(gr_poly_t res, const gr_poly_t x, const gr_poly_t y, gr_ctx_t ctx)
{
return gr_poly_mullow(res, x, y, GR_SERIES_MOD_N(ctx), GR_SERIES_MOD_ELEM_CTX(ctx));
}
int gr_series_mod_inv(gr_poly_t res, const gr_poly_t x, gr_ctx_t ctx)
{
if (gr_ctx_is_approx_commutative_ring(ctx) != T_TRUE)
return GR_UNABLE;
return gr_poly_inv_series(res, x, GR_SERIES_MOD_N(ctx), GR_SERIES_MOD_ELEM_CTX(ctx));
}
int gr_series_mod_div(gr_poly_t res, const gr_poly_t x, const gr_poly_t y, gr_ctx_t ctx)
{
if (gr_ctx_is_approx_commutative_ring(ctx) != T_TRUE)
return GR_UNABLE;
return gr_poly_div_series(res, x, y, GR_SERIES_MOD_N(ctx), GR_SERIES_MOD_ELEM_CTX(ctx));
}
#define UNARY_POLY_WRAPPER(func) \
int \
gr_series_mod_ ## func(gr_poly_t res, const gr_poly_t x, gr_ctx_t ctx) \
{ \
return gr_poly_ ## func ## _series(res, x, GR_SERIES_MOD_N(ctx), GR_SERIES_MOD_ELEM_CTX(ctx)); \
} \
UNARY_POLY_WRAPPER(exp)
UNARY_POLY_WRAPPER(log)
UNARY_POLY_WRAPPER(rsqrt)
UNARY_POLY_WRAPPER(tan)
UNARY_POLY_WRAPPER(asin)
UNARY_POLY_WRAPPER(acos)
UNARY_POLY_WRAPPER(atan)
UNARY_POLY_WRAPPER(asinh)
UNARY_POLY_WRAPPER(acosh)
UNARY_POLY_WRAPPER(atanh)
int gr_series_mod_sqrt(gr_poly_t res, const gr_poly_t x, gr_ctx_t ctx)
{
slong n = GR_SERIES_MOD_N(ctx);
if (n == 0)
return GR_SUCCESS;
if (x->length == 0)
return gr_poly_zero(res, GR_SERIES_MOD_ELEM_CTX(ctx));
if (gr_is_zero(x->coeffs, GR_SERIES_MOD_ELEM_CTX(ctx)) != T_FALSE)
return GR_UNABLE;
return gr_poly_sqrt_series(res, x, n, GR_SERIES_MOD_ELEM_CTX(ctx));
}
static int
_set_truncate_poly(gr_poly_t res, const gr_poly_t x, gr_ctx_t x_elem_ctx, slong n, gr_ctx_t elem_ctx)
{
if (x_elem_ctx == elem_ctx)
{
return gr_poly_truncate(res, x, n, elem_ctx);
}
else
{
if (gr_poly_length(x, x_elem_ctx) <= n)
{
return gr_poly_set_gr_poly_other(res, x, x_elem_ctx, elem_ctx);
}
else
{
int status = GR_SUCCESS;
gr_poly_t t;
t->coeffs = x->coeffs;
t->length = n;
status |= gr_poly_set_gr_poly_other(res, t, x_elem_ctx, elem_ctx);
return status;
}
}
}
int
gr_series_mod_set_other(gr_poly_t res, gr_srcptr x, gr_ctx_t x_ctx, gr_ctx_t ctx)
{
if (x_ctx == ctx)
{
return gr_series_mod_set(res, x, ctx);
}
else if (x_ctx == GR_SERIES_MOD_ELEM_CTX(ctx))
{
return (GR_SERIES_MOD_N(ctx) == 0) ? GR_SUCCESS : gr_poly_set_scalar(res, x, GR_SERIES_MOD_ELEM_CTX(ctx));
}
else if (x_ctx->which_ring == GR_CTX_SERIES_MOD_GR_POLY && !strcmp(GR_SERIES_MOD_CTX(x_ctx)->var, GR_SERIES_MOD_CTX(ctx)->var))
{
if (GR_SERIES_MOD_N(ctx) <= GR_SERIES_MOD_N(x_ctx))
return _set_truncate_poly(res, x, GR_SERIES_MOD_ELEM_CTX(x_ctx), GR_SERIES_MOD_N(ctx), GR_SERIES_MOD_ELEM_CTX(ctx));
else
return GR_DOMAIN;
}
else if (x_ctx->which_ring == GR_CTX_GR_POLY && !strcmp(POLYNOMIAL_CTX(x_ctx)->var, GR_SERIES_MOD_CTX(ctx)->var))
{
return _set_truncate_poly(res, x, POLYNOMIAL_ELEM_CTX(x_ctx), GR_SERIES_MOD_N(ctx), GR_SERIES_MOD_ELEM_CTX(ctx));
}
else if (x_ctx->which_ring == GR_CTX_GR_SERIES && !strcmp(GR_SERIES_CTX(x_ctx)->var, GR_SERIES_MOD_CTX(ctx)->var))
{
if (((const gr_series_struct *) x)->error < GR_SERIES_MOD_N(ctx))
return GR_UNABLE;
else
return _set_truncate_poly(res, &((const gr_series_struct *) x)->poly, GR_SERIES_ELEM_CTX(x_ctx), GR_SERIES_MOD_N(ctx), GR_SERIES_MOD_ELEM_CTX(ctx));
}
else
{
int status = GR_SUCCESS;
gr_poly_fit_length(res, 1, GR_SERIES_MOD_ELEM_CTX(ctx));
status = gr_set_other(res->coeffs, x, x_ctx, GR_SERIES_MOD_ELEM_CTX(ctx));
if (status == GR_SUCCESS)
{
_gr_poly_set_length(res, 1, GR_SERIES_MOD_ELEM_CTX(ctx));
_gr_poly_normalise(res, GR_SERIES_MOD_ELEM_CTX(ctx));
}
else
_gr_poly_set_length(res, 0, GR_SERIES_MOD_ELEM_CTX(ctx));
status |= gr_poly_truncate(res, res, GR_SERIES_MOD_N(ctx), GR_SERIES_MOD_ELEM_CTX(ctx));
return status;
}
return GR_UNABLE;
}
int _gr_series_mod_methods_initialized = 0;
gr_static_method_table _gr_series_mod_methods;
gr_method_tab_input _gr_series_mod_methods_input[] =
{
{GR_METHOD_CTX_CLEAR, (gr_funcptr) gr_series_mod_ctx_clear},
{GR_METHOD_CTX_WRITE, (gr_funcptr) gr_series_mod_ctx_write},
{GR_METHOD_CTX_SET_GEN_NAME, (gr_funcptr) gr_series_mod_ctx_set_gen_name},
{GR_METHOD_CTX_SET_GEN_NAMES, (gr_funcptr) gr_series_mod_ctx_set_gen_names},
{GR_METHOD_CTX_NGENS, (gr_funcptr) gr_generic_ctx_ngens_1},
{GR_METHOD_CTX_GEN_NAME, (gr_funcptr) _gr_series_mod_ctx_gen_name},
{GR_METHOD_CTX_IS_RING, (gr_funcptr) gr_series_mod_ctx_is_ring},
{GR_METHOD_CTX_IS_COMMUTATIVE_RING, (gr_funcptr) gr_series_mod_ctx_is_commutative_ring},
{GR_METHOD_CTX_IS_INTEGRAL_DOMAIN, (gr_funcptr) gr_series_mod_ctx_is_integral_domain},
{GR_METHOD_CTX_IS_FIELD, (gr_funcptr) gr_series_mod_ctx_is_field},
{GR_METHOD_CTX_IS_RATIONAL_VECTOR_SPACE, (gr_funcptr) gr_series_mod_ctx_is_rational_vector_space},
{GR_METHOD_CTX_IS_REAL_VECTOR_SPACE, (gr_funcptr) gr_series_mod_ctx_is_real_vector_space},
{GR_METHOD_CTX_IS_COMPLEX_VECTOR_SPACE, (gr_funcptr) gr_series_mod_ctx_is_complex_vector_space},
{GR_METHOD_CTX_BASE, (gr_funcptr) _gr_series_mod_ctx_base},
{GR_METHOD_INIT, (gr_funcptr) gr_series_mod_init},
{GR_METHOD_CLEAR, (gr_funcptr) gr_series_mod_clear},
{GR_METHOD_SWAP, (gr_funcptr) gr_series_mod_swap},
{GR_METHOD_SET_SHALLOW, (gr_funcptr) gr_series_mod_set_shallow},
{GR_METHOD_RANDTEST, (gr_funcptr) gr_series_mod_randtest},
{GR_METHOD_WRITE, (gr_funcptr) gr_series_mod_write},
{GR_METHOD_ZERO, (gr_funcptr) gr_series_mod_zero},
{GR_METHOD_ONE, (gr_funcptr) gr_series_mod_one},
{GR_METHOD_IS_ZERO, (gr_funcptr) gr_series_mod_is_zero},
{GR_METHOD_IS_ONE, (gr_funcptr) gr_series_mod_is_one},
{GR_METHOD_EQUAL, (gr_funcptr) gr_series_mod_equal},
{GR_METHOD_GEN, (gr_funcptr) gr_series_mod_gen},
{GR_METHOD_GENS, (gr_funcptr) gr_generic_gens_single},
{GR_METHOD_GENS_RECURSIVE, (gr_funcptr) gr_series_mod_gens_recursive},
{GR_METHOD_SET, (gr_funcptr) gr_series_mod_set},
{GR_METHOD_SET_UI, (gr_funcptr) gr_series_mod_set_ui},
{GR_METHOD_SET_SI, (gr_funcptr) gr_series_mod_set_si},
{GR_METHOD_SET_FMPZ, (gr_funcptr) gr_series_mod_set_fmpz},
{GR_METHOD_SET_FMPQ, (gr_funcptr) gr_series_mod_set_fmpq},
{GR_METHOD_SET_OTHER, (gr_funcptr) gr_series_mod_set_other},
{GR_METHOD_SET_STR, (gr_funcptr) gr_generic_set_str_balance_additions},
{GR_METHOD_NEG, (gr_funcptr) gr_series_mod_neg},
{GR_METHOD_ADD, (gr_funcptr) gr_series_mod_add},
{GR_METHOD_SUB, (gr_funcptr) gr_series_mod_sub},
{GR_METHOD_MUL, (gr_funcptr) gr_series_mod_mul},
{GR_METHOD_INV, (gr_funcptr) gr_series_mod_inv},
{GR_METHOD_DIV, (gr_funcptr) gr_series_mod_div},
{GR_METHOD_SQRT, (gr_funcptr) gr_series_mod_sqrt},
{GR_METHOD_RSQRT, (gr_funcptr) gr_series_mod_rsqrt},
{GR_METHOD_EXP, (gr_funcptr) gr_series_mod_exp},
{GR_METHOD_LOG, (gr_funcptr) gr_series_mod_log},
{GR_METHOD_TAN, (gr_funcptr) gr_series_mod_tan},
{GR_METHOD_ASIN, (gr_funcptr) gr_series_mod_asin},
{GR_METHOD_ACOS, (gr_funcptr) gr_series_mod_acos},
{GR_METHOD_ATAN, (gr_funcptr) gr_series_mod_atan},
{GR_METHOD_ASINH, (gr_funcptr) gr_series_mod_asinh},
{GR_METHOD_ACOSH, (gr_funcptr) gr_series_mod_acosh},
{GR_METHOD_ATANH, (gr_funcptr) gr_series_mod_atanh},
{0, (gr_funcptr) NULL},
};
void
gr_series_mod_ctx_init(gr_ctx_t ctx, gr_ctx_t base_ring, slong n)
{
ctx->which_ring = GR_CTX_SERIES_MOD_GR_POLY;
ctx->sizeof_elem = sizeof(gr_poly_struct);
ctx->size_limit = WORD_MAX;
GR_SERIES_MOD_CTX(ctx)->base_ring = (gr_ctx_struct *) base_ring;
GR_SERIES_MOD_CTX(ctx)->var = (char *) default_var;
GR_SERIES_MOD_CTX(ctx)->n = FLINT_MAX(0, n);
ctx->methods = _gr_series_mod_methods;
if (!_gr_series_mod_methods_initialized)
{
gr_method_tab_init(_gr_series_mod_methods, _gr_series_mod_methods_input);
_gr_series_mod_methods_initialized = 1;
}
}
void
gr_ctx_init_series_mod_gr_poly(gr_ctx_t ctx, gr_ctx_t base_ring, slong n)
{
gr_series_mod_ctx_init(ctx, base_ring, n);
}