#include "ca_poly.h"
#include "ca_poly/impl.h"
void
_ca_poly_div_series(ca_ptr Q,
ca_srcptr A, slong Alen,
ca_srcptr B, slong Blen, slong len, ca_ctx_t ctx)
{
Alen = FLINT_MIN(Alen, len);
Blen = FLINT_MIN(Blen, len);
if (CA_IS_SPECIAL(A) || CA_IS_SPECIAL(B))
{
if (ca_is_unknown(A, ctx) || ca_is_unknown(B, ctx))
_ca_vec_unknown(Q, len, ctx);
else
_ca_vec_undefined(Q, len, ctx);
return;
}
if (Blen >= 4 && _ca_vec_is_fmpq_vec(A, Alen, ctx)
&& _ca_vec_is_fmpq_vec(B, Blen, ctx) && !fmpq_is_zero(CA_FMPQ(B)))
{
fmpz *p, *r, *s;
fmpz_t pden, rden, sden;
p = _fmpz_vec_init(Alen);
r = _fmpz_vec_init(Blen);
s = _fmpz_vec_init(len);
fmpz_init(pden);
fmpz_init(rden);
fmpz_init(sden);
_ca_vec_fmpq_vec_get_fmpz_vec_den(p, pden, A, Alen, ctx);
_ca_vec_fmpq_vec_get_fmpz_vec_den(r, rden, B, Blen, ctx);
_fmpq_poly_div_series(s, sden, p, pden, Alen, r, rden, Blen, len);
_ca_vec_set_fmpz_vec_div_fmpz(Q, s, sden, len, ctx);
fmpz_clear(pden);
fmpz_clear(rden);
fmpz_clear(sden);
_fmpz_vec_clear(p, Alen);
_fmpz_vec_clear(r, Blen);
_fmpz_vec_clear(s, len);
return;
}
if (Blen == 1)
{
_ca_vec_scalar_div_ca(Q, A, Alen, B, ctx);
_ca_vec_zero(Q + Alen, len - Alen, ctx);
}
else
{
int is_one;
ca_field_ptr K;
ca_t q;
slong i;
if (Blen > 8)
{
K = _ca_vec_same_field2(A, Alen, B, Blen, ctx);
if (K != NULL && CA_FIELD_IS_NF(K))
{
if (len > 2 * qqbar_degree(CA_FIELD_NF_QQBAR(K)))
{
ca_ptr Binv;
Binv = _ca_vec_init(len, ctx);
_ca_poly_inv_series(Binv, B, Blen, len, ctx);
_ca_poly_mullow(Q, Binv, len, A, Alen, len, ctx);
_ca_vec_clear(Binv, len, ctx);
return;
}
}
}
ca_init(q, ctx);
ca_inv(q, B + 0, ctx);
ca_mul(Q, A + 0, q, ctx);
is_one = (ca_check_is_one(q, ctx) == T_TRUE);
for (i = 1; i < len; i++)
{
ca_dot(Q + i, (i < Alen) ? A + i : NULL, 1,
B + 1, 1, Q + i - 1, -1, FLINT_MIN(i, Blen - 1), ctx);
if (!is_one)
ca_mul(Q + i, Q + i, q, ctx);
}
ca_clear(q, ctx);
}
}
void
ca_poly_div_series(ca_poly_t Q, const ca_poly_t A, const ca_poly_t B, slong len, ca_ctx_t ctx)
{
if (len == 0)
{
ca_poly_zero(Q, ctx);
return;
}
if (B->length == 0)
{
ca_poly_fit_length(Q, len, ctx);
ca_unknown(Q->coeffs, ctx);
_ca_vec_undefined(Q->coeffs + 1, len - 1, ctx);
_ca_poly_set_length(Q, len, ctx);
return;
}
if (A->length == 0)
{
if (ca_check_is_zero(B->coeffs, ctx) == T_FALSE)
{
ca_poly_zero(Q, ctx);
}
else
{
ca_poly_fit_length(Q, len, ctx);
_ca_vec_unknown(Q->coeffs, len, ctx);
_ca_poly_set_length(Q, len, ctx);
}
return;
}
if (Q == A || Q == B)
{
ca_poly_t t;
ca_poly_init(t, ctx);
ca_poly_div_series(t, A, B, len, ctx);
ca_poly_swap(Q, t, ctx);
ca_poly_clear(t, ctx);
return;
}
ca_poly_fit_length(Q, len, ctx);
_ca_poly_div_series(Q->coeffs, A->coeffs, A->length, B->coeffs, B->length, len, ctx);
_ca_poly_set_length(Q, len, ctx);
_ca_poly_normalise(Q, ctx);
}