#include "padic_radix.h"
#include "fmpz.h"
#include "gr.h"
#include "gr_mat.h"
static int
_radix_integer_fits_digits(const radix_integer_t x, slong k, const radix_t radix)
{
slong e = radix->exp;
slong un = FLINT_ABS(x->size);
slong limbs = k / e;
slong rem = k - limbs * e;
if (rem == 0)
return un <= limbs;
if (un <= limbs)
return 1;
if (un == limbs + 1)
return x->d[limbs] < radix->bpow[rem];
return 0;
}
static int
_radix_integer_residue_eq_mod(const radix_integer_t x, const radix_integer_t y,
slong k, const radix_t radix)
{
slong e = radix->exp;
slong limbs, rem, i, xs, ys, sig, loop_to;
if (k <= 0)
return 1;
limbs = k / e;
rem = k - limbs * e;
xs = x->size;
ys = y->size;
sig = FLINT_MAX(xs, ys);
loop_to = FLINT_MIN(limbs, sig);
for (i = 0; i < loop_to; i++)
{
ulong xv = (i < xs) ? x->d[i] : 0;
ulong yv = (i < ys) ? y->d[i] : 0;
if (xv != yv)
return 0;
}
if (limbs >= sig)
return 1;
if (rem != 0)
{
ulong m = radix->bpow[rem];
ulong xv = (limbs < xs) ? x->d[limbs] : 0;
ulong yv = (limbs < ys) ? y->d[limbs] : 0;
xv = n_rem_precomp(xv, m, radix->bpow_div + rem);
yv = n_rem_precomp(yv, m, radix->bpow_div + rem);
if (xv != yv)
return 0;
}
return 1;
}
static int
_radix_units_congruent_mod(const radix_integer_t ux, const radix_integer_t uy,
slong k, const radix_t radix)
{
slong e = radix->exp;
slong content;
int res;
radix_integer_t rx, ry;
if (k <= 0)
return 1;
if (ux->size >= 0 && uy->size >= 0)
return _radix_integer_residue_eq_mod(ux, uy, k, radix);
content = (FLINT_MAX(FLINT_ABS(ux->size), FLINT_ABS(uy->size)) + 1) * e;
if (k > content)
{
if ((ux->size < 0) != (uy->size < 0))
return 0;
k = content;
}
radix_integer_init(rx, radix);
radix_integer_init(ry, radix);
radix_integer_mod_digits(rx, ux, k, radix);
radix_integer_mod_digits(ry, uy, k, radix);
res = radix_integer_equal(rx, ry, radix);
radix_integer_clear(rx, radix);
radix_integer_clear(ry, radix);
return res;
}
static int
_radix_integer_residue_is_one_mod(const radix_integer_t u, slong k, const radix_t radix)
{
slong e = radix->exp;
slong limbs, rem, i, us;
if (k <= 0)
return 1;
limbs = k / e;
rem = k - limbs * e;
us = u->size;
for (i = 0; i < limbs; i++)
{
ulong uv = (i < us) ? u->d[i] : 0;
ulong ov = (i == 0) ? 1 : 0;
if (uv != ov)
return 0;
}
if (rem != 0)
{
ulong m = radix->bpow[rem];
ulong uv = (limbs < us) ? u->d[limbs] : 0;
ulong ov = (limbs == 0) ? (UWORD(1) % m) : 0;
uv = n_rem_precomp(uv, m, radix->bpow_div + rem);
if (uv != ov)
return 0;
}
return 1;
}
static int
_radix_integer_residue_is_neg_one_mod(const radix_integer_t u, slong k, const radix_t radix)
{
slong e = radix->exp;
slong limbs, rem, i, us;
ulong full = LIMB_RADIX(radix) - 1;
if (k <= 0)
return 1;
limbs = k / e;
rem = k - limbs * e;
us = u->size;
for (i = 0; i < limbs; i++)
{
ulong uv = (i < us) ? u->d[i] : 0;
if (uv != full)
return 0;
}
if (rem != 0)
{
ulong m = radix->bpow[rem];
ulong uv = (limbs < us) ? u->d[limbs] : 0;
uv = n_rem_precomp(uv, m, radix->bpow_div + rem);
if (uv != m - 1)
return 0;
}
return 1;
}
static void
_padic_radix_canonicalise(padic_radix_t x, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
slong w;
if (x->u.size == 0)
{
x->v = 0;
return;
}
w = radix_integer_valuation_digits(&x->u, radix);
if (w != 0)
{
radix_integer_rshift_digits(&x->u, &x->u, w, radix);
x->v += w;
}
}
static slong
_padic_radix_target_prec(slong v, gr_ctx_t ctx)
{
slong a = PADIC_RADIX_CTX_PREC_ABS(ctx);
slong r = PADIC_RADIX_CTX_PREC_REL(ctx);
slong t;
if (r == PADIC_RADIX_PREC_INF)
{
t = PADIC_RADIX_PREC_INF;
}
else
{
t = v + r;
if (t < 0 || t > PADIC_RADIX_ERR_MAX)
t = (v >= 0) ? PADIC_RADIX_PREC_INF : t;
}
return FLINT_MIN(a, t);
}
static void
_padic_radix_reduce(padic_radix_t x, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
slong target, Neff, r;
if (x->u.size == 0)
{
x->v = 0;
if (x->N != PADIC_RADIX_EXACT)
x->N = FLINT_MIN(x->N, PADIC_RADIX_ERR_MAX);
return;
}
target = _padic_radix_target_prec(x->v, ctx);
Neff = (x->N == PADIC_RADIX_EXACT) ? target : FLINT_MIN(x->N, target);
if (Neff == PADIC_RADIX_PREC_INF)
return;
r = Neff - x->v;
if (r <= 0)
{
radix_integer_zero(&x->u, radix);
x->v = 0;
x->N = FLINT_MIN(Neff, PADIC_RADIX_ERR_MAX);
return;
}
if (x->N == PADIC_RADIX_EXACT && _radix_integer_fits_digits(&x->u, r, radix))
return;
radix_integer_mod_digits(&x->u, &x->u, r, radix);
if (x->u.size == 0)
x->v = 0;
x->N = FLINT_MIN(Neff, PADIC_RADIX_ERR_MAX);
}
static int
_padic_radix_finish(padic_radix_t res, gr_ctx_t ctx)
{
if (res->u.size < 0 && !PADIC_RADIX_CTX_SIGNED(ctx))
{
slong target = _padic_radix_target_prec(res->v, ctx);
if (target == PADIC_RADIX_PREC_INF)
return GR_UNABLE;
res->N = target;
}
_padic_radix_reduce(res, ctx);
return GR_SUCCESS;
}
void
padic_radix_init(padic_radix_t res, gr_ctx_t ctx)
{
radix_integer_init(&res->u, PADIC_RADIX_CTX_RADIX(ctx));
res->v = 0;
res->N = PADIC_RADIX_EXACT;
}
void
padic_radix_clear(padic_radix_t res, gr_ctx_t ctx)
{
radix_integer_clear(&res->u, PADIC_RADIX_CTX_RADIX(ctx));
}
void
padic_radix_swap(padic_radix_t x, padic_radix_t y, gr_ctx_t ctx)
{
FLINT_SWAP(padic_radix_struct, *x, *y);
}
void
padic_radix_set_shallow(padic_radix_t res, const padic_radix_t x, gr_ctx_t ctx)
{
*res = *x;
}
slong
padic_radix_get_error(const padic_radix_t x, gr_ctx_t ctx)
{
return x->N;
}
truth_t
padic_radix_is_exact(const padic_radix_t x, gr_ctx_t ctx)
{
return (x->N == PADIC_RADIX_EXACT) ? T_TRUE : T_FALSE;
}
int
padic_radix_zero(padic_radix_t res, gr_ctx_t ctx)
{
radix_integer_zero(&res->u, PADIC_RADIX_CTX_RADIX(ctx));
res->v = 0;
res->N = PADIC_RADIX_EXACT;
return GR_SUCCESS;
}
int
padic_radix_one(padic_radix_t res, gr_ctx_t ctx)
{
radix_integer_one(&res->u, PADIC_RADIX_CTX_RADIX(ctx));
res->v = 0;
res->N = PADIC_RADIX_EXACT;
_padic_radix_reduce(res, ctx);
return GR_SUCCESS;
}
static int
padic_radix_big_o_base_fmpz(padic_radix_t res, const padic_radix_t x, const fmpz_t exp, gr_ctx_t ctx)
{
if (x->v == 1 && radix_integer_is_one(&x->u, PADIC_RADIX_CTX_RADIX(ctx)) && res->N == PADIC_RADIX_EXACT)
{
if (fmpz_cmp_si(exp, -PADIC_RADIX_ERR_MAX) >= 0)
{
padic_radix_zero(res, ctx);
res->N = fmpz_cmp_si(exp, PADIC_RADIX_ERR_MAX) <= 0 ? *exp : PADIC_RADIX_ERR_MAX;
return GR_SUCCESS;
}
}
return GR_UNABLE;
}
int
padic_radix_set(padic_radix_t res, const padic_radix_t x, gr_ctx_t ctx)
{
if (res != x)
{
radix_integer_set(&res->u, &x->u, PADIC_RADIX_CTX_RADIX(ctx));
res->v = x->v;
res->N = x->N;
}
_padic_radix_reduce(res, ctx);
return GR_SUCCESS;
}
static int
_padic_radix_exact_set_finish(padic_radix_t res, gr_ctx_t ctx)
{
_padic_radix_canonicalise(res, ctx);
if (res->u.size != 0
&& (res->v > PADIC_RADIX_ERR_MAX || res->v < -PADIC_RADIX_ERR_MAX))
return GR_UNABLE;
return GR_SUCCESS;
}
int
padic_radix_exact_set_fmpz(padic_radix_t res, const fmpz_t c, gr_ctx_t ctx)
{
radix_integer_set_fmpz(&res->u, c, PADIC_RADIX_CTX_RADIX(ctx));
res->v = 0;
res->N = PADIC_RADIX_EXACT;
return _padic_radix_exact_set_finish(res, ctx);
}
int
padic_radix_exact_set_ui(padic_radix_t res, ulong c, gr_ctx_t ctx)
{
radix_integer_set_ui(&res->u, c, PADIC_RADIX_CTX_RADIX(ctx));
res->v = 0;
res->N = PADIC_RADIX_EXACT;
return _padic_radix_exact_set_finish(res, ctx);
}
int
padic_radix_exact_set_si(padic_radix_t res, slong c, gr_ctx_t ctx)
{
radix_integer_set_si(&res->u, c, PADIC_RADIX_CTX_RADIX(ctx));
res->v = 0;
res->N = PADIC_RADIX_EXACT;
return _padic_radix_exact_set_finish(res, ctx);
}
int
padic_radix_set_fmpz(padic_radix_t res, const fmpz_t c, gr_ctx_t ctx)
{
int status = padic_radix_exact_set_fmpz(res, c, ctx);
if (status != GR_SUCCESS)
return status;
return _padic_radix_finish(res, ctx);
}
int
padic_radix_set_ui(padic_radix_t res, ulong c, gr_ctx_t ctx)
{
int status = padic_radix_exact_set_ui(res, c, ctx);
if (status != GR_SUCCESS)
return status;
return _padic_radix_finish(res, ctx);
}
int
padic_radix_set_si(padic_radix_t res, slong c, gr_ctx_t ctx)
{
int status = padic_radix_exact_set_si(res, c, ctx);
if (status != GR_SUCCESS)
return status;
return _padic_radix_finish(res, ctx);
}
int
padic_radix_get_fmpz(fmpz_t res, const padic_radix_t x, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
if (x->N != PADIC_RADIX_EXACT)
return GR_UNABLE;
if (x->v < 0)
return GR_DOMAIN;
if (x->u.size == 0)
{
fmpz_zero(res);
return GR_SUCCESS;
}
if (x->v > ctx->size_limit)
return GR_UNABLE;
radix_integer_get_fmpz(res, &x->u, radix);
if (x->v != 0)
{
fmpz_t t;
fmpz_init(t);
fmpz_ui_pow_ui(t, GR_PADIC_RADIX_CTX(ctx)->p, x->v);
fmpz_mul(res, res, t);
fmpz_clear(t);
}
return GR_SUCCESS;
}
int
padic_radix_neg(padic_radix_t res, const padic_radix_t x, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
if (res != x)
padic_radix_set(res, x, ctx);
radix_integer_neg(&res->u, &res->u, radix);
if (res->N == PADIC_RADIX_EXACT)
return _padic_radix_finish(res, ctx);
{
slong r = res->N - res->v;
if (r <= 0)
{
radix_integer_zero(&res->u, radix);
res->v = 0;
}
else
{
radix_integer_mod_digits(&res->u, &res->u, r, radix);
if (res->u.size == 0)
res->v = 0;
}
}
return GR_SUCCESS;
}
static int
_padic_radix_finalize_assume_canonical(padic_radix_t res, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
if (res->N != PADIC_RADIX_EXACT)
{
if (res->N < -PADIC_RADIX_ERR_MAX)
return GR_UNABLE;
if (res->N > PADIC_RADIX_ERR_MAX)
res->N = PADIC_RADIX_ERR_MAX;
}
if (res->u.size != 0)
{
if (res->v > PADIC_RADIX_ERR_MAX)
{
slong newN = (res->N == PADIC_RADIX_EXACT)
? PADIC_RADIX_ERR_MAX
: FLINT_MIN(res->N, PADIC_RADIX_ERR_MAX);
radix_integer_zero(&res->u, radix);
res->v = 0;
res->N = newN;
}
else if (res->v < -PADIC_RADIX_ERR_MAX)
{
return GR_UNABLE;
}
}
if (res->N == PADIC_RADIX_EXACT)
return _padic_radix_finish(res, ctx);
_padic_radix_reduce(res, ctx);
return GR_SUCCESS;
}
int
_padic_radix_finalize(padic_radix_t res, gr_ctx_t ctx)
{
_padic_radix_canonicalise(res, ctx);
return _padic_radix_finalize_assume_canonical(res, ctx);
}
int
_padic_radix_add_sub_reference(padic_radix_t res, const padic_radix_t x,
const padic_radix_t y, int sub, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
slong vx = x->v, vy = y->v, Nx = x->N, Ny = y->N;
slong vmin = FLINT_MIN(vx, vy);
slong vmax = FLINT_MAX(vx, vy);
slong Nz, target, P, Nresult;
radix_integer_t T;
Nz = FLINT_MIN(Nx, Ny);
target = _padic_radix_target_prec(vmin, ctx);
if (Nz == PADIC_RADIX_EXACT)
P = target;
else if (target == PADIC_RADIX_PREC_INF)
P = Nz;
else
P = FLINT_MIN(Nz, target);
if (x->u.size == 0 || y->u.size == 0)
{
if (x->u.size == 0 && y->u.size == 0)
{
radix_integer_zero(&res->u, radix);
res->v = 0;
}
else if (x->u.size == 0)
{
if (sub)
radix_integer_neg(&res->u, &y->u, radix);
else
radix_integer_set(&res->u, &y->u, radix);
res->v = vy;
}
else
{
radix_integer_set(&res->u, &x->u, radix);
res->v = vx;
}
res->N = Nz;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
if (P != PADIC_RADIX_PREC_INF && vmin >= P)
{
radix_integer_zero(&res->u, radix);
res->v = 0;
res->N = P;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
if (vx == vy)
{
if (sub)
radix_integer_sub(&res->u, &x->u, &y->u, radix);
else
radix_integer_add(&res->u, &x->u, &y->u, radix);
res->v = vmin;
res->N = Nz;
return _padic_radix_finalize(res, ctx);
}
radix_integer_init(T, radix);
Nresult = Nz;
if (P != PADIC_RADIX_PREC_INF && vmax >= P)
{
Nresult = P;
if (vx < vy)
{
radix_integer_set(&res->u, &x->u, radix);
}
else
{
if (sub)
radix_integer_neg(&res->u, &y->u, radix);
else
radix_integer_set(&res->u, &y->u, radix);
}
}
else if (vx < vy)
{
radix_integer_lshift_digits(T, &y->u, vmax - vmin, radix);
if (sub)
radix_integer_sub(&res->u, &x->u, T, radix);
else
radix_integer_add(&res->u, &x->u, T, radix);
}
else
{
radix_integer_lshift_digits(T, &x->u, vmax - vmin, radix);
if (sub)
radix_integer_sub(&res->u, T, &y->u, radix);
else
radix_integer_add(&res->u, T, &y->u, radix);
}
radix_integer_clear(T, radix);
res->v = vmin;
res->N = Nresult;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
static int
_padic_radix_add_sub(padic_radix_t res, const padic_radix_t x,
const padic_radix_t y, int sub, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
slong vx = x->v, vy = y->v, Nx = x->N, Ny = y->N;
slong vmin = FLINT_MIN(vx, vy);
slong vmax = FLINT_MAX(vx, vy);
slong Nz, target, P, Nresult;
Nz = FLINT_MIN(Nx, Ny);
target = _padic_radix_target_prec(vmin, ctx);
if (Nz == PADIC_RADIX_EXACT)
P = target;
else if (target == PADIC_RADIX_PREC_INF)
P = Nz;
else
P = FLINT_MIN(Nz, target);
if (x->u.size == 0 || y->u.size == 0)
{
if (x->u.size == 0 && y->u.size == 0)
{
radix_integer_zero(&res->u, radix);
res->v = 0;
}
else if (x->u.size == 0)
{
if (sub)
radix_integer_neg(&res->u, &y->u, radix);
else
radix_integer_set(&res->u, &y->u, radix);
res->v = vy;
}
else
{
radix_integer_set(&res->u, &x->u, radix);
res->v = vx;
}
res->N = Nz;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
if (P != PADIC_RADIX_PREC_INF && vmin >= P)
{
radix_integer_zero(&res->u, radix);
res->v = 0;
res->N = P;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
if (vx == vy)
{
if (sub)
radix_integer_sub(&res->u, &x->u, &y->u, radix);
else
radix_integer_add(&res->u, &x->u, &y->u, radix);
res->v = vmin;
res->N = Nz;
return _padic_radix_finalize(res, ctx);
}
Nresult = Nz;
if (P != PADIC_RADIX_PREC_INF && vmax >= P)
{
Nresult = P;
if (vx < vy)
{
radix_integer_set(&res->u, &x->u, radix);
}
else
{
if (sub)
radix_integer_neg(&res->u, &y->u, radix);
else
radix_integer_set(&res->u, &y->u, radix);
}
}
else
{
const padic_radix_struct * lo = (vx < vy) ? x : y;
const padic_radix_struct * hi = (vx < vy) ? y : x;
slong d = vmax - vmin;
int negate = (sub && vx > vy);
if (sub)
radix_integer_sublsh(&res->u, &lo->u, &hi->u, d, radix);
else
radix_integer_addlsh(&res->u, &lo->u, &hi->u, d, radix);
if (negate)
radix_integer_neg(&res->u, &res->u, radix);
}
res->v = vmin;
res->N = Nresult;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
int
padic_radix_add(padic_radix_t res, const padic_radix_t x, const padic_radix_t y, gr_ctx_t ctx)
{
return _padic_radix_add_sub(res, x, y, 0, ctx);
}
int
padic_radix_sub(padic_radix_t res, const padic_radix_t x, const padic_radix_t y, gr_ctx_t ctx)
{
return _padic_radix_add_sub(res, x, y, 1, ctx);
}
int
_padic_radix_mul_reference(padic_radix_t res, const padic_radix_t x, const padic_radix_t y, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
slong vx = x->v, vy = y->v, Nx = x->N, Ny = y->N;
slong vz, Nz;
radix_integer_t U;
if ((x->u.size == 0 && Nx == PADIC_RADIX_EXACT)
|| (y->u.size == 0 && Ny == PADIC_RADIX_EXACT))
return padic_radix_zero(res, ctx);
vz = vx + vy;
Nz = PADIC_RADIX_EXACT;
if (Nx != PADIC_RADIX_EXACT)
Nz = FLINT_MIN(Nz, vy + Nx);
if (Ny != PADIC_RADIX_EXACT)
Nz = FLINT_MIN(Nz, vx + Ny);
radix_integer_init(U, radix);
radix_integer_mul(U, &x->u, &y->u, radix);
FLINT_SWAP(radix_integer_struct, res->u, *U);
res->v = vz;
res->N = Nz;
radix_integer_clear(U, radix);
return _padic_radix_finalize_assume_canonical(res, ctx);
}
int
padic_radix_mul(padic_radix_t res, const padic_radix_t x, const padic_radix_t y, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
slong e = radix->exp;
slong vx = x->v, vy = y->v, Nx = x->N, Ny = y->N;
slong vz, Nz, xn, yn, target;
if ((x->u.size == 0 && Nx == PADIC_RADIX_EXACT)
|| (y->u.size == 0 && Ny == PADIC_RADIX_EXACT))
return padic_radix_zero(res, ctx);
vz = vx + vy;
Nz = PADIC_RADIX_EXACT;
if (Nx != PADIC_RADIX_EXACT)
Nz = FLINT_MIN(Nz, vy + Nx);
if (Ny != PADIC_RADIX_EXACT)
Nz = FLINT_MIN(Nz, vx + Ny);
if (x->u.size == 0 || y->u.size == 0)
{
radix_integer_zero(&res->u, radix);
res->v = vz;
res->N = Nz;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
xn = FLINT_ABS(x->u.size);
yn = FLINT_ABS(y->u.size);
target = _padic_radix_target_prec(vz, ctx);
if (Nz == PADIC_RADIX_EXACT)
{
if (target == PADIC_RADIX_PREC_INF)
{
radix_integer_mul(&res->u, &x->u, &y->u, radix);
res->N = PADIC_RADIX_EXACT;
}
else
{
slong digits = target - vz;
slong maxD = (xn + yn) * e;
slong minD = (xn + yn - 2) * e + 1;
if (digits <= 0)
{
radix_integer_zero(&res->u, radix);
res->N = target;
}
else if (maxD <= digits)
{
radix_integer_mul(&res->u, &x->u, &y->u, radix);
res->N = PADIC_RADIX_EXACT;
}
else if (minD > digits)
{
slong n = (digits + e - 1) / e;
radix_integer_mullow_limbs(&res->u, &x->u, &y->u, n, radix);
res->N = target;
}
else
{
radix_integer_mul(&res->u, &x->u, &y->u, radix);
res->N = PADIC_RADIX_EXACT;
}
}
}
else
{
slong Neff = (target == PADIC_RADIX_PREC_INF) ? Nz : FLINT_MIN(Nz, target);
slong r = Neff - vz;
if (r <= 0)
{
radix_integer_zero(&res->u, radix);
res->N = Neff;
}
else
{
slong n = (r + e - 1) / e;
radix_integer_mullow_limbs(&res->u, &x->u, &y->u, n, radix);
res->N = Nz;
}
}
res->v = vz;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
static int
_padic_radix_div(padic_radix_t res, const padic_radix_t a, const padic_radix_t b, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
slong e = radix->exp;
slong va = a->v, vb = b->v, Na = a->N, Nb = b->N;
slong prec_abs = PADIC_RADIX_CTX_PREC_ABS(ctx);
slong prec_rel = PADIC_RADIX_CTX_PREC_REL(ctx);
slong vq, rel_a, rel_b, rel, relcap, krel, nlimbs;
radix_integer_t unit;
truth_t bz;
int invertible;
bz = padic_radix_is_zero(b, ctx);
if (bz == T_TRUE)
return GR_DOMAIN;
if (bz == T_UNKNOWN)
return GR_UNABLE;
if (a->u.size == 0 && Na == PADIC_RADIX_EXACT)
return padic_radix_zero(res, ctx);
vq = va - vb;
if (Na == PADIC_RADIX_EXACT && Nb == PADIC_RADIX_EXACT)
{
radix_integer_t qint;
int divides;
radix_integer_init(qint, radix);
divides = radix_integer_div(qint, &a->u, &b->u, radix);
if (divides)
{
FLINT_SWAP(radix_integer_struct, res->u, *qint);
res->v = vq;
res->N = PADIC_RADIX_EXACT;
radix_integer_clear(qint, radix);
return _padic_radix_finalize_assume_canonical(res, ctx);
}
radix_integer_clear(qint, radix);
}
rel_a = (Na == PADIC_RADIX_EXACT) ? PADIC_RADIX_PREC_INF : (Na - va);
rel_b = (Nb == PADIC_RADIX_EXACT) ? PADIC_RADIX_PREC_INF : (Nb - vb);
rel = FLINT_MIN(rel_a, rel_b);
relcap = PADIC_RADIX_PREC_INF;
if (prec_rel != PADIC_RADIX_PREC_INF)
relcap = prec_rel;
if (prec_abs != PADIC_RADIX_PREC_INF)
{
slong c = prec_abs - vq;
relcap = (relcap == PADIC_RADIX_PREC_INF) ? c : FLINT_MIN(relcap, c);
}
if (rel == PADIC_RADIX_PREC_INF && relcap == PADIC_RADIX_PREC_INF)
return GR_UNABLE;
if (rel == PADIC_RADIX_PREC_INF)
krel = relcap;
else if (relcap == PADIC_RADIX_PREC_INF)
krel = rel;
else
krel = FLINT_MIN(rel, relcap);
if (krel > PADIC_RADIX_ERR_MAX)
krel = PADIC_RADIX_ERR_MAX;
if (krel <= 0)
{
radix_integer_zero(&res->u, radix);
res->v = 0;
res->N = vq + krel;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
nlimbs = (krel + e - 1) / e;
radix_integer_init(unit, radix);
if (a->u.size == 0)
{
radix_integer_zero(unit, radix);
invertible = 1;
}
else
{
slong an = FLINT_MIN(FLINT_ABS(a->u.size), nlimbs);
slong bn = FLINT_MIN(FLINT_ABS(b->u.size), nlimbs);
slong sgn = a->u.size ^ b->u.size;
slong rn = nlimbs;
nn_ptr ud = radix_integer_fit_limbs(unit, nlimbs, radix);
invertible = radix_divmod_bn(ud, NULL, a->u.d, an, b->u.d, bn, nlimbs, radix);
if (invertible)
{
MPN_NORM(ud, rn);
unit->size = (sgn >= 0) ? rn : -rn;
}
}
if (!invertible)
{
radix_integer_clear(unit, radix);
return GR_UNABLE;
}
FLINT_SWAP(radix_integer_struct, res->u, *unit);
res->v = vq;
res->N = vq + krel;
radix_integer_clear(unit, radix);
return _padic_radix_finalize_assume_canonical(res, ctx);
}
int
padic_radix_div(padic_radix_t res, const padic_radix_t x, const padic_radix_t y, gr_ctx_t ctx)
{
return _padic_radix_div(res, x, y, ctx);
}
int
padic_radix_inv(padic_radix_t res, const padic_radix_t x, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
slong e = radix->exp;
slong vx = x->v, Nx = x->N;
slong prec_abs = PADIC_RADIX_CTX_PREC_ABS(ctx);
slong prec_rel = PADIC_RADIX_CTX_PREC_REL(ctx);
slong vq, rel, relcap, krel, nlimbs;
truth_t xz;
int invertible;
xz = padic_radix_is_zero(x, ctx);
if (xz == T_TRUE)
return GR_DOMAIN;
if (xz == T_UNKNOWN)
return GR_UNABLE;
vq = -vx;
if (Nx == PADIC_RADIX_EXACT && FLINT_ABS(x->u.size) == 1 && x->u.d[0] == 1)
{
radix_integer_fit_limbs(&res->u, 1, radix)[0] = 1;
res->u.size = (x->u.size > 0) ? 1 : -1;
res->v = vq;
res->N = PADIC_RADIX_EXACT;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
rel = (Nx == PADIC_RADIX_EXACT) ? PADIC_RADIX_PREC_INF : (Nx - vx);
relcap = PADIC_RADIX_PREC_INF;
if (prec_rel != PADIC_RADIX_PREC_INF)
relcap = prec_rel;
if (prec_abs != PADIC_RADIX_PREC_INF)
{
slong c = prec_abs - vq;
relcap = (relcap == PADIC_RADIX_PREC_INF) ? c : FLINT_MIN(relcap, c);
}
if (rel == PADIC_RADIX_PREC_INF && relcap == PADIC_RADIX_PREC_INF)
return GR_UNABLE;
if (rel == PADIC_RADIX_PREC_INF)
krel = relcap;
else if (relcap == PADIC_RADIX_PREC_INF)
krel = rel;
else
krel = FLINT_MIN(rel, relcap);
if (krel > PADIC_RADIX_ERR_MAX)
krel = PADIC_RADIX_ERR_MAX;
if (krel <= 0)
{
radix_integer_zero(&res->u, radix);
res->v = 0;
res->N = vq + krel;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
nlimbs = (krel + e - 1) / e;
invertible = radix_integer_invmod_limbs(&res->u, &x->u, nlimbs, radix);
if (!invertible)
flint_abort();
res->v = vq;
res->N = vq + krel;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
static int
_padic_radix_exact_unit_sqrt(padic_radix_t res, const padic_radix_t x, slong M,
const radix_t radix)
{
ulong p = DIGIT_RADIX(radix);
slong ncand = (p == 2) ? 4 : 2;
nn_ptr root, c, sq, d;
slong i, k, sqn, cn, rs, cmp_limbs;
int found = 0, neg = 0;
TMP_INIT;
if (x->u.size <= 0)
return 0;
TMP_START;
root = TMP_ALLOC(M * sizeof(ulong));
c = TMP_ALLOC(M * sizeof(ulong));
sq = TMP_ALLOC(2 * M * sizeof(ulong));
rs = FLINT_MIN(FLINT_ABS(res->u.size), M);
flint_mpn_copyi(root, res->u.d, rs);
flint_mpn_zero(root + rs, M - rs);
cmp_limbs = (M > 1) ? (M - 1) : 1;
for (k = 0; k < ncand && !found; k++)
{
if (k & 1)
radix_neg(c, root, M, radix);
else
flint_mpn_copyi(c, root, M);
if (k >= 2)
{
ulong h = UWORD(1) << (radix->exp - 1);
ulong t = c[M - 1] + h;
if (t >= LIMB_RADIX(radix))
t -= LIMB_RADIX(radix);
c[M - 1] = t;
}
radix_mulmid(sq, c, M, c, M, 0, 2 * M, radix);
sqn = 2 * M;
MPN_NORM(sq, sqn);
if (sqn == x->u.size)
{
int eq = 1;
for (i = 0; i < sqn; i++)
if (sq[i] != x->u.d[i]) { eq = 0; break; }
if (eq)
{
neg = 0;
for (i = 0; i < cmp_limbs; i++)
if (root[i] != c[i]) { neg = 1; break; }
found = 1;
}
}
}
if (found)
{
cn = M;
MPN_NORM(c, cn);
if (cn == 0)
cn = 1;
d = radix_integer_fit_limbs(&res->u, cn, radix);
flint_mpn_copyi(d, c, cn);
res->u.size = neg ? -cn : cn;
}
TMP_END;
return found;
}
int
padic_radix_sqrt(padic_radix_t res, const padic_radix_t x, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
slong e = radix->exp;
slong vx = x->v, Nx = x->N;
slong prec_abs = PADIC_RADIX_CTX_PREC_ABS(ctx);
slong prec_rel = PADIC_RADIX_CTX_PREC_REL(ctx);
slong vq, rel, relcap, krel, nlimbs, loss, kin, ndet;
truth_t xz;
int issquare, input_exact;
radix_integer_t unit;
input_exact = (Nx == PADIC_RADIX_EXACT);
xz = padic_radix_is_zero(x, ctx);
if (xz == T_TRUE)
return padic_radix_zero(res, ctx);
if (xz == T_UNKNOWN)
return GR_UNABLE;
if (vx & WORD(1))
return GR_DOMAIN;
vq = vx / 2;
if (Nx == PADIC_RADIX_EXACT && x->u.size == 1 && x->u.d[0] == 1)
{
radix_integer_fit_limbs(&res->u, 1, radix)[0] = 1;
res->u.size = 1;
res->v = vq;
res->N = PADIC_RADIX_EXACT;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
if (DIGIT_RADIX(radix) == 2 && Nx - vx < 3)
return GR_UNABLE;
loss = (DIGIT_RADIX(radix) == 2) ? 1 : 0;
rel = (Nx == PADIC_RADIX_EXACT) ? PADIC_RADIX_PREC_INF : (Nx - vx);
if (rel != PADIC_RADIX_PREC_INF)
rel = FLINT_MAX(rel - loss, 0);
relcap = PADIC_RADIX_PREC_INF;
if (prec_rel != PADIC_RADIX_PREC_INF)
relcap = prec_rel;
if (prec_abs != PADIC_RADIX_PREC_INF)
{
slong c = prec_abs - vq;
relcap = (relcap == PADIC_RADIX_PREC_INF) ? c : FLINT_MIN(relcap, c);
}
if (rel == PADIC_RADIX_PREC_INF && relcap == PADIC_RADIX_PREC_INF)
krel = PADIC_RADIX_PREC_INF;
else if (rel == PADIC_RADIX_PREC_INF)
krel = relcap;
else if (relcap == PADIC_RADIX_PREC_INF)
krel = rel;
else
krel = FLINT_MIN(rel, relcap);
if (krel != PADIC_RADIX_PREC_INF && krel > PADIC_RADIX_ERR_MAX)
krel = PADIC_RADIX_ERR_MAX;
kin = (krel == PADIC_RADIX_PREC_INF) ? PADIC_RADIX_PREC_INF
: (krel > PADIC_RADIX_ERR_MAX - loss ? PADIC_RADIX_ERR_MAX : krel + loss);
ndet = input_exact ? (FLINT_ABS(x->u.size) / 2 + 2) : 0;
if (krel == PADIC_RADIX_PREC_INF)
nlimbs = ndet;
else if (kin <= 0)
nlimbs = 1;
else
nlimbs = (kin + e - 1) / e;
if (input_exact && ndet > nlimbs)
nlimbs = ndet;
radix_integer_init(unit, radix);
radix_integer_mod_digits(unit, &x->u, e * nlimbs, radix);
issquare = radix_integer_sqrtmod_limbs(&res->u, unit, nlimbs, radix);
radix_integer_clear(unit, radix);
if (!issquare)
return GR_DOMAIN;
if (input_exact &&
_padic_radix_exact_unit_sqrt(res, x, (ndet > 0 ? ndet : nlimbs), radix))
{
res->v = vq;
res->N = PADIC_RADIX_EXACT;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
if (krel == PADIC_RADIX_PREC_INF)
return GR_UNABLE;
if (krel <= 0)
{
radix_integer_zero(&res->u, radix);
res->v = 0;
res->N = vq + krel;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
res->v = vq;
res->N = vq + krel;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
truth_t
padic_radix_is_square(const padic_radix_t x, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
ulong p = DIGIT_RADIX(radix);
truth_t xz;
xz = padic_radix_is_zero(x, ctx);
if (xz == T_TRUE)
return T_TRUE;
if (xz == T_UNKNOWN)
return T_UNKNOWN;
if (x->v & WORD(1))
return T_FALSE;
if (p == 2)
{
slong rel = (x->N == PADIC_RADIX_EXACT)
? PADIC_RADIX_PREC_INF : (x->N - x->v);
if (rel != PADIC_RADIX_PREC_INF && rel < 3)
return T_UNKNOWN;
}
ulong d = x->u.d[0];
if (x->u.size < 0)
d = p - d;
if (p == 2)
return ((d & 7) == 1) ? T_TRUE : T_FALSE;
return (n_jacobi_unsigned(nmod_set_ui(d, radix->b), p) == 1) ? T_TRUE : T_FALSE;
}
int
padic_radix_rsqrt(padic_radix_t res, const padic_radix_t x, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
slong e = radix->exp;
slong vx = x->v, Nx = x->N;
slong prec_abs = PADIC_RADIX_CTX_PREC_ABS(ctx);
slong prec_rel = PADIC_RADIX_CTX_PREC_REL(ctx);
slong vq, vr, rel, relcap, krel, nlimbs, loss, kin;
truth_t xz;
int issquare;
radix_integer_t unit;
xz = padic_radix_is_zero(x, ctx);
if (xz == T_TRUE)
return GR_DOMAIN;
if (xz == T_UNKNOWN)
return GR_UNABLE;
if (vx & WORD(1))
return GR_DOMAIN;
vq = vx / 2;
vr = -vq;
if (Nx == PADIC_RADIX_EXACT && x->u.size == 1 && x->u.d[0] == 1)
{
radix_integer_fit_limbs(&res->u, 1, radix)[0] = 1;
res->u.size = 1;
res->v = vr;
res->N = PADIC_RADIX_EXACT;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
loss = (DIGIT_RADIX(radix) == 2) ? 1 : 0;
rel = (Nx == PADIC_RADIX_EXACT) ? PADIC_RADIX_PREC_INF : (Nx - vx);
if (rel != PADIC_RADIX_PREC_INF)
rel = FLINT_MAX(rel - loss, 0);
relcap = PADIC_RADIX_PREC_INF;
if (prec_rel != PADIC_RADIX_PREC_INF)
relcap = prec_rel;
if (prec_abs != PADIC_RADIX_PREC_INF)
{
slong c = prec_abs - vr;
relcap = (relcap == PADIC_RADIX_PREC_INF) ? c : FLINT_MIN(relcap, c);
}
if (rel == PADIC_RADIX_PREC_INF && relcap == PADIC_RADIX_PREC_INF)
krel = PADIC_RADIX_PREC_INF;
else if (rel == PADIC_RADIX_PREC_INF)
krel = relcap;
else if (relcap == PADIC_RADIX_PREC_INF)
krel = rel;
else
krel = FLINT_MIN(rel, relcap);
if (krel != PADIC_RADIX_PREC_INF && krel > PADIC_RADIX_ERR_MAX)
krel = PADIC_RADIX_ERR_MAX;
kin = (krel == PADIC_RADIX_PREC_INF) ? PADIC_RADIX_PREC_INF
: (krel > PADIC_RADIX_ERR_MAX - loss ? PADIC_RADIX_ERR_MAX : krel + loss);
if (krel == PADIC_RADIX_PREC_INF || kin <= 0)
nlimbs = 1;
else
nlimbs = (kin + e - 1) / e;
radix_integer_init(unit, radix);
radix_integer_mod_digits(unit, &x->u, e * nlimbs, radix);
issquare = radix_integer_rsqrtmod_limbs(&res->u, unit, nlimbs, radix);
radix_integer_clear(unit, radix);
if (!issquare)
return GR_DOMAIN;
if (krel == PADIC_RADIX_PREC_INF)
return GR_UNABLE;
if (krel <= 0)
{
radix_integer_zero(&res->u, radix);
res->v = 0;
res->N = vr + krel;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
res->v = vr;
res->N = vr + krel;
return _padic_radix_finalize_assume_canonical(res, ctx);
}
truth_t
padic_radix_is_zero(const padic_radix_t x, gr_ctx_t ctx)
{
if (x->N == PADIC_RADIX_EXACT)
return (x->u.size == 0) ? T_TRUE : T_FALSE;
if (x->u.size == 0)
return T_UNKNOWN;
return (x->N > x->v) ? T_FALSE : T_UNKNOWN;
}
truth_t
padic_radix_is_one(const padic_radix_t x, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
if (x->N == PADIC_RADIX_EXACT)
return (x->v == 0 && radix_integer_is_one(&x->u, radix)) ? T_TRUE : T_FALSE;
if (x->N <= 0)
return T_UNKNOWN;
if (x->u.size == 0)
return T_UNKNOWN;
if (x->v != 0)
return T_FALSE;
return _radix_integer_residue_is_one_mod(&x->u, x->N, radix) ? T_UNKNOWN : T_FALSE;
}
truth_t
padic_radix_is_neg_one(const padic_radix_t x, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
if (x->N == PADIC_RADIX_EXACT)
return (x->v == 0 && radix_integer_is_neg_one(&x->u, radix)) ? T_TRUE : T_FALSE;
if (x->N <= 0)
return T_UNKNOWN;
if (x->v != 0)
return T_FALSE;
return _radix_integer_residue_is_neg_one_mod(&x->u, x->N, radix) ? T_UNKNOWN : T_FALSE;
}
truth_t
padic_radix_equal(const padic_radix_t x, const padic_radix_t y, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
slong err, vx = x->v, vy = y->v;
int xz, yz, eq;
if (x->N == PADIC_RADIX_EXACT && y->N == PADIC_RADIX_EXACT)
{
if (vx != vy)
return T_FALSE;
return radix_integer_equal(&x->u, &y->u, radix) ? T_TRUE : T_FALSE;
}
err = FLINT_MIN(x->N, y->N);
if (err <= 0)
return T_UNKNOWN;
xz = (x->u.size == 0);
yz = (y->u.size == 0);
if (xz && yz)
eq = 1;
else if (xz)
eq = (vy >= err);
else if (yz)
eq = (vx >= err);
else if (vx == vy)
eq = _radix_units_congruent_mod(&x->u, &y->u, err - vx, radix);
else
eq = (FLINT_MIN(vx, vy) >= err);
return eq ? T_UNKNOWN : T_FALSE;
}
truth_t
padic_radix_is_invertible(const padic_radix_t x, gr_ctx_t ctx)
{
return truth_not(padic_radix_is_zero(x, ctx));
}
int
padic_radix_randtest(padic_radix_t res, flint_rand_t state, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
int ctx_exact = (PADIC_RADIX_CTX_PREC_ABS(ctx) == PADIC_RADIX_PREC_INF
&& PADIC_RADIX_CTX_PREC_REL(ctx) == PADIC_RADIX_PREC_INF);
int limits = (PADIC_RADIX_CTX_FLAGS(ctx) & PADIC_RADIX_TEST_LIMITS)
&& PADIC_RADIX_CTX_PREC_REL(ctx) != PADIC_RADIX_PREC_INF
&& (n_randint(state, 2) == 0);
if (n_randint(state, 2))
radix_integer_set_si(&res->u, n_randint(state, 5) - 2, radix);
else
radix_integer_randtest_limbs(&res->u, state, 1 + n_randint(state, 10), radix);
if (!PADIC_RADIX_CTX_SIGNED(ctx))
radix_integer_abs(&res->u, &res->u, radix);
if (limits && (n_randint(state, 4) == 0))
{
slong big = PADIC_RADIX_ERR_MAX - n_randint(state, 4);
res->v = (n_randlimb(state) & 1) ? big : -big;
switch (n_randint(state, 3))
{
case 0: res->N = PADIC_RADIX_EXACT; break;
case 1: res->N = (n_randlimb(state) & 1) ? big : -big; break;
default: res->N = res->v + n_randint(state, 6); break;
}
}
else
{
res->v = n_randint(state, 4);
res->N = PADIC_RADIX_EXACT;
if (!ctx_exact && (n_randlimb(state) & 1))
res->N = res->v + n_randint(state, 6);
}
if (_padic_radix_finalize(res, ctx) != GR_SUCCESS)
padic_radix_zero(res, ctx);
return GR_SUCCESS;
}
int
padic_radix_write(gr_stream_t out, const padic_radix_t x, gr_ctx_t ctx)
{
radix_struct * radix = PADIC_RADIX_CTX_RADIX(ctx);
ulong p = GR_PADIC_RADIX_CTX(ctx)->p;
int status = GR_SUCCESS;
if (x->u.size == 0)
{
status |= gr_stream_write(out, "0");
}
else
{
slong size = x->u.size;
char * str;
if (PADIC_RADIX_CTX_DECIMAL(ctx))
str = radix_get_str_decimal(NULL, x->u.d, FLINT_ABS(size), size < 0, radix);
else
str = radix_get_str_sum(NULL, x->u.d, FLINT_ABS(size), size < 0, 1, radix);
if (x->v != 0)
status |= gr_stream_write(out, "(");
status |= gr_stream_write_free(out, str);
if (x->v != 0)
status |= gr_stream_write(out, ")");
if (x->v != 0)
{
status |= gr_stream_write(out, " * ");
status |= gr_stream_write_ui(out, p);
status |= gr_stream_write(out, "^");
status |= gr_stream_write_si(out, x->v);
}
}
if (x->N != PADIC_RADIX_EXACT)
{
status |= gr_stream_write(out, " + O(");
status |= gr_stream_write_ui(out, p);
status |= gr_stream_write(out, "^");
status |= gr_stream_write_si(out, x->N);
status |= gr_stream_write(out, ")");
}
return status;
}
void
padic_radix_ctx_clear(gr_ctx_t ctx)
{
radix_clear(PADIC_RADIX_CTX_RADIX(ctx));
flint_free(GR_PADIC_RADIX_CTX(ctx));
}
int
padic_radix_ctx_write(gr_stream_t out, gr_ctx_t ctx)
{
int status = GR_SUCCESS;
status |= gr_stream_write(out, "Radix ");
status |= gr_stream_write_ui(out, GR_PADIC_RADIX_CTX(ctx)->p);
status |= gr_stream_write(out, "-adic numbers");
status |= gr_stream_write(out, " (rel prec ");
if (PADIC_RADIX_CTX_PREC_REL(ctx) == PADIC_RADIX_PREC_INF)
status |= gr_stream_write(out, "inf");
else
status |= gr_stream_write_si(out, PADIC_RADIX_CTX_PREC_REL(ctx));
status |= gr_stream_write(out, ", abs prec ");
if (PADIC_RADIX_CTX_PREC_ABS(ctx) == PADIC_RADIX_PREC_INF)
status |= gr_stream_write(out, "inf");
else
status |= gr_stream_write_si(out, PADIC_RADIX_CTX_PREC_ABS(ctx));
status |= gr_stream_write(out, ")");
return status;
}
static truth_t
padic_radix_ctx_is_exact(gr_ctx_t ctx)
{
return (PADIC_RADIX_CTX_PREC_ABS(ctx) == PADIC_RADIX_PREC_INF
&& PADIC_RADIX_CTX_PREC_REL(ctx) == PADIC_RADIX_PREC_INF) ? T_TRUE : T_FALSE;
}
int _padic_radix_methods_initialized = 0;
gr_static_method_table _padic_radix_methods;
gr_method_tab_input _padic_radix_methods_input[] =
{
{GR_METHOD_CTX_CLEAR, (gr_funcptr) padic_radix_ctx_clear},
{GR_METHOD_CTX_WRITE, (gr_funcptr) padic_radix_ctx_write},
{GR_METHOD_CTX_IS_RING, (gr_funcptr) gr_generic_ctx_predicate_true},
{GR_METHOD_CTX_IS_COMMUTATIVE_RING,
(gr_funcptr) gr_generic_ctx_predicate_true},
{GR_METHOD_CTX_IS_INTEGRAL_DOMAIN,
(gr_funcptr) gr_generic_ctx_predicate_true},
{GR_METHOD_CTX_IS_FIELD, (gr_funcptr) gr_generic_ctx_predicate_true},
{GR_METHOD_CTX_IS_UNIQUE_FACTORIZATION_DOMAIN,
(gr_funcptr) gr_generic_ctx_predicate_true},
{GR_METHOD_CTX_IS_RATIONAL_VECTOR_SPACE,
(gr_funcptr) gr_generic_ctx_predicate_true},
{GR_METHOD_CTX_IS_FINITE_CHARACTERISTIC,
(gr_funcptr) gr_generic_ctx_predicate_false},
{GR_METHOD_CTX_IS_EXACT, (gr_funcptr) padic_radix_ctx_is_exact},
{GR_METHOD_INIT, (gr_funcptr) padic_radix_init},
{GR_METHOD_CLEAR, (gr_funcptr) padic_radix_clear},
{GR_METHOD_SWAP, (gr_funcptr) padic_radix_swap},
{GR_METHOD_SET_SHALLOW, (gr_funcptr) padic_radix_set_shallow},
{GR_METHOD_RANDTEST, (gr_funcptr) padic_radix_randtest},
{GR_METHOD_WRITE, (gr_funcptr) padic_radix_write},
{GR_METHOD_BIG_O_BASE_FMPZ, (gr_funcptr) padic_radix_big_o_base_fmpz},
{GR_METHOD_ZERO, (gr_funcptr) padic_radix_zero},
{GR_METHOD_ONE, (gr_funcptr) padic_radix_one},
{GR_METHOD_IS_ZERO, (gr_funcptr) padic_radix_is_zero},
{GR_METHOD_IS_ONE, (gr_funcptr) padic_radix_is_one},
{GR_METHOD_IS_NEG_ONE, (gr_funcptr) padic_radix_is_neg_one},
{GR_METHOD_IS_INVERTIBLE, (gr_funcptr) padic_radix_is_invertible},
{GR_METHOD_EQUAL, (gr_funcptr) padic_radix_equal},
{GR_METHOD_SET, (gr_funcptr) padic_radix_set},
{GR_METHOD_SET_SI, (gr_funcptr) padic_radix_set_si},
{GR_METHOD_SET_UI, (gr_funcptr) padic_radix_set_ui},
{GR_METHOD_SET_FMPZ, (gr_funcptr) padic_radix_set_fmpz},
{GR_METHOD_GET_FMPZ, (gr_funcptr) padic_radix_get_fmpz},
{GR_METHOD_NEG, (gr_funcptr) padic_radix_neg},
{GR_METHOD_ADD, (gr_funcptr) padic_radix_add},
{GR_METHOD_SUB, (gr_funcptr) padic_radix_sub},
{GR_METHOD_MUL, (gr_funcptr) padic_radix_mul},
{GR_METHOD_INV, (gr_funcptr) padic_radix_inv},
{GR_METHOD_DIV, (gr_funcptr) padic_radix_div},
{GR_METHOD_SQRT, (gr_funcptr) padic_radix_sqrt},
{GR_METHOD_RSQRT, (gr_funcptr) padic_radix_rsqrt},
{GR_METHOD_IS_SQUARE, (gr_funcptr) padic_radix_is_square},
{GR_METHOD_EXP, (gr_funcptr) padic_radix_exp},
{GR_METHOD_LOG, (gr_funcptr) padic_radix_log},
{GR_METHOD_VEC_DOT, (gr_funcptr) padic_radix_dot},
{GR_METHOD_VEC_DOT_REV, (gr_funcptr) padic_radix_dot_rev},
{GR_METHOD_VEC_DOT_STRIDED, (gr_funcptr) padic_radix_dot_strided},
{GR_METHOD_MAT_DET, (gr_funcptr) gr_mat_det_generic_field},
{0, (gr_funcptr) NULL},
};
int
gr_ctx_init_padic_radix(gr_ctx_t ctx, ulong p, slong prec_rel, slong prec_abs, int flags)
{
padic_radix_ctx_struct * pctx;
FLINT_ASSERT(n_is_prime(p));
ctx->which_ring = GR_CTX_PADIC_RADIX;
ctx->sizeof_elem = sizeof(padic_radix_struct);
ctx->size_limit = WORD_MAX;
GR_CTX_DATA_AS_PTR(ctx) = flint_malloc(sizeof(padic_radix_ctx_struct));
pctx = GR_PADIC_RADIX_CTX(ctx);
radix_init(&pctx->radix, p, 0);
pctx->p = p;
if (prec_rel == PADIC_RADIX_PREC_INF)
pctx->prec_rel = PADIC_RADIX_PREC_INF;
else
pctx->prec_rel = FLINT_MIN(FLINT_MAX(prec_rel, 0), PADIC_RADIX_ERR_MAX);
if (prec_abs == PADIC_RADIX_PREC_INF)
pctx->prec_abs = PADIC_RADIX_PREC_INF;
else
pctx->prec_abs = FLINT_MAX(FLINT_MIN(prec_abs, PADIC_RADIX_ERR_MAX),
-PADIC_RADIX_ERR_MAX);
pctx->flags = flags;
ctx->methods = _padic_radix_methods;
if (!_padic_radix_methods_initialized)
{
gr_method_tab_init(_padic_radix_methods, _padic_radix_methods_input);
_padic_radix_methods_initialized = 1;
}
return GR_SUCCESS;
}
int
gr_ctx_init_padic_radix_randtest(gr_ctx_t ctx, flint_rand_t state, slong maxprec)
{
ulong p = n_randtest_prime(state, 0);
slong prec_abs, prec_rel;
int flags = 0;
if (n_randint(state, 2))
flags |= PADIC_RADIX_SIGNED;
switch (n_randint(state, 4))
{
case 0:
prec_abs = 1 + n_randint(state, maxprec);
prec_rel = PADIC_RADIX_PREC_INF;
break;
case 1:
prec_abs = PADIC_RADIX_PREC_INF;
prec_rel = 1 + n_randint(state, maxprec);
break;
case 2:
prec_abs = 1 + n_randint(state, maxprec);
prec_rel = 1 + n_randint(state, maxprec);
break;
default:
prec_abs = PADIC_RADIX_PREC_INF;
prec_rel = PADIC_RADIX_PREC_INF;
break;
}
if (n_randint(state, 2))
flags |= PADIC_RADIX_TEST_LIMITS;
if (flags & PADIC_RADIX_TEST_LIMITS)
ctx->size_limit = (1 << 16);
return gr_ctx_init_padic_radix(ctx, p, prec_rel, prec_abs, flags);
}