#include "nmod.h"
#include "nmod_vec.h"
#include "nmod_poly.h"
#include "nmod_poly/impl.h"
#include "gr_poly.h"
void
_nmod_poly_div_series_basecase_preinv1(nn_ptr Qinv, nn_srcptr P, slong Plen,
nn_srcptr Q, slong Qlen, slong n, ulong q, nmod_t mod)
{
slong i, j, l;
ulong s;
Plen = FLINT_MIN(Plen, n);
Qlen = FLINT_MIN(Qlen, n);
if (Qlen == 1)
{
_nmod_vec_scalar_mul_nmod(Qinv, P, Plen, q, mod);
_nmod_vec_zero(Qinv + Plen, n - Plen);
}
else
{
Qinv[0] = nmod_mul(q, P[0], mod);
const dot_params_t params = _nmod_vec_dot_params(FLINT_MIN(n, Qlen), mod);
for (i = 1; i < n; i++)
{
l = FLINT_MIN(i, Qlen - 1);
NMOD_VEC_DOT(s, j, l, Q[j + 1], Qinv[i - 1 - j], mod, params);
if (i < Plen)
s = nmod_sub(P[i], s, mod);
else
s = nmod_neg(s, mod);
if (q != 1)
Qinv[i] = nmod_mul(s, q, mod);
else
Qinv[i] = s;
}
}
}
void
_nmod_poly_div_series_basecase(nn_ptr Qinv, nn_srcptr P, slong Plen,
nn_srcptr Q, slong Qlen, slong n, nmod_t mod)
{
ulong q;
q = Q[0];
if (q != 1)
q = n_invmod(q, mod.n);
_nmod_poly_div_series_basecase_preinv1(Qinv, P, Plen, Q, Qlen, n, q, mod);
}
void
nmod_poly_div_series_basecase(nmod_poly_t Q, const nmod_poly_t A,
const nmod_poly_t B, slong n)
{
slong Alen, Blen;
Blen = B->length;
if (n == 0 || Blen == 0 || B->coeffs[0] == 0)
{
flint_throw(FLINT_DIVZERO, "Exception (nmod_poly_div_series_basecase). Division by zero.\n");
}
Alen = A->length;
if (Alen == 0)
{
nmod_poly_zero(Q);
return;
}
if (Q != A && Q != B)
{
nmod_poly_fit_length(Q, n);
_nmod_poly_div_series_basecase(Q->coeffs, A->coeffs, Alen, B->coeffs, Blen, n, Q->mod);
}
else
{
nmod_poly_t t;
nmod_poly_init2(t, Q->mod.n, n);
_nmod_poly_div_series_basecase(t->coeffs, A->coeffs, Alen, B->coeffs, Blen, n, Q->mod);
nmod_poly_swap(Q, t);
nmod_poly_clear(t);
}
Q->length = n;
_nmod_poly_normalise(Q);
}
void
_nmod_poly_div_series(nn_ptr Q, nn_srcptr A, slong Alen,
nn_srcptr B, slong Blen, slong n, nmod_t mod)
{
Blen = FLINT_MIN(Blen, n);
if (Blen <= 5)
{
_nmod_poly_div_series_basecase(Q, A, Alen, B, Blen, n, mod);
}
else
{
gr_ctx_t ctx;
_gr_ctx_init_nmod(ctx, &mod);
GR_MUST_SUCCEED(_gr_poly_div_series(Q, A, Alen, B, Blen, n, ctx));
}
}
void
nmod_poly_div_series(nmod_poly_t Q, const nmod_poly_t A,
const nmod_poly_t B, slong n)
{
slong Alen, Blen;
Blen = B->length;
if (n == 0 || Blen == 0 || B->coeffs[0] == 0)
{
flint_throw(FLINT_DIVZERO, "Exception (nmod_poly_div_series). Division by zero.\n");
}
Alen = A->length;
if (Alen == 0)
{
nmod_poly_zero(Q);
return;
}
if (Q != A && Q != B)
{
nmod_poly_fit_length(Q, n);
_nmod_poly_div_series(Q->coeffs, A->coeffs, Alen, B->coeffs, Blen, n, Q->mod);
}
else
{
nmod_poly_t t;
nmod_poly_init2(t, Q->mod.n, n);
_nmod_poly_div_series(t->coeffs, A->coeffs, Alen, B->coeffs, Blen, n, Q->mod);
nmod_poly_swap(Q, t);
nmod_poly_clear(t);
}
Q->length = n;
_nmod_poly_normalise(Q);
}