#include "gr_vec.h"
#include "gr_poly.h"
#include "longlong.h"
int
_gr_poly_inflate(gr_ptr poly, slong len, slong n, gr_ctx_t ctx)
{
slong i, sz = ctx->sizeof_elem;
int status = GR_SUCCESS;
for (i = len - 1; i >= 1 && n > 1; i--)
{
gr_swap(GR_ENTRY(poly, i * n, sz), GR_ENTRY(poly, i, sz), ctx);
status |= _gr_vec_zero(GR_ENTRY(poly, (i - 1) * n + 1, sz), n - 1, ctx);
}
return status;
}
static int
_gr_poly_compose_axnc(gr_ptr res, gr_srcptr poly1, slong len1,
gr_srcptr c, gr_srcptr a, slong n, gr_ctx_t ctx)
{
slong i, sz = ctx->sizeof_elem;
int status = GR_SUCCESS;
status |= _gr_poly_taylor_shift(res, poly1, len1, c, ctx);
if (gr_is_one(a, ctx) != T_TRUE)
{
if (gr_is_neg_one(a, ctx) == T_TRUE)
{
for (i = 1; i < len1; i += 2)
status |= gr_neg(GR_ENTRY(res, i, sz), GR_ENTRY(res, i, sz), ctx);
}
else if (len1 == 2)
{
status |= gr_mul(GR_ENTRY(res, 1, sz), GR_ENTRY(res, 1, sz), a, ctx);
}
else
{
int maxbit = FLINT_CLOG2(len1);
gr_ptr t;
if (gr_ctx_is_finite(ctx) == T_TRUE || gr_ctx_has_real_prec(ctx) == T_TRUE)
{
GR_TMP_INIT_VEC(t, maxbit, ctx);
status |= gr_set(GR_ENTRY(t, 0, sz), a, ctx);
status |= gr_mul(GR_ENTRY(res, 1, sz), GR_ENTRY(res, 1, sz), a, ctx);
for (int j = 1; j < maxbit; ++j)
{
status |= gr_sqr(GR_ENTRY(t, j, sz), GR_ENTRY(t, j-1, sz), ctx);
status |= gr_mul(GR_ENTRY(res, 1<<j, sz), GR_ENTRY(res, 1<<j, sz), GR_ENTRY(t, j, sz), ctx);
}
for (i = ((slong) 1 << (maxbit-1)) + 1; i < len1; i++)
{
int bit = flint_ctz(i);
status |= gr_mul(GR_ENTRY(t, maxbit-1-bit, sz), GR_ENTRY(t, maxbit-1-bit, sz), a, ctx);
status |= gr_mul(GR_ENTRY(res, i>>bit, sz), GR_ENTRY(res, i>>bit, sz), GR_ENTRY(t, maxbit-1-bit, sz), ctx);
for (int j = bit; j > 0; --j)
{
status |= gr_sqr(GR_ENTRY(t, maxbit-j, sz), GR_ENTRY(t, maxbit-j-1, sz), ctx);
status |= gr_mul(GR_ENTRY(res, i>>(j-1), sz), GR_ENTRY(res, i>>(j-1), sz), GR_ENTRY(t, maxbit-j, sz), ctx);
}
}
for (i = (len1 + 1) >> 1; i < ((slong)1 << (maxbit-1)); i++)
{
int bit = flint_ctz(i);
status |= gr_mul(GR_ENTRY(t, maxbit-2-bit, sz), GR_ENTRY(t, maxbit-2-bit, sz), a, ctx);
status |= gr_mul(GR_ENTRY(res, i>>bit, sz), GR_ENTRY(res, i>>bit, sz), GR_ENTRY(t, maxbit-2-bit, sz), ctx);
for (int j = bit; j > 0; --j)
{
status |= gr_sqr(GR_ENTRY(t, maxbit-j-1, sz), GR_ENTRY(t, maxbit-j-2, sz), ctx);
status |= gr_mul(GR_ENTRY(res, i>>(j-1), sz), GR_ENTRY(res, i>>(j-1), sz), GR_ENTRY(t, maxbit-j-1, sz), ctx);
}
}
GR_TMP_CLEAR_VEC(t, maxbit, ctx);
}
else
{
GR_TMP_INIT(t, ctx);
status |= gr_set(t, a, ctx);
for (i = 1; i < len1; i++)
{
status |= gr_mul(GR_ENTRY(res, i, sz), GR_ENTRY(res, i, sz), t, ctx);
if (i + 1 < len1)
status |= gr_mul(t, t, a, ctx);
}
GR_TMP_CLEAR(t, ctx);
}
}
}
status |= _gr_poly_inflate(res, len1, n, ctx);
return status;
}
int
_gr_poly_compose(gr_ptr res,
gr_srcptr poly1, slong len1,
gr_srcptr poly2, slong len2, gr_ctx_t ctx)
{
slong sz;
if (len1 == 1)
return gr_set(res, poly1, ctx);
if (len2 == 1)
return _gr_poly_evaluate(res, poly1, len1, poly2, ctx);
sz = ctx->sizeof_elem;
if (_gr_vec_is_zero(GR_ENTRY(poly2, 1, sz), len2 - 2, ctx) == T_TRUE)
return _gr_poly_compose_axnc(res, poly1, len1, poly2, GR_ENTRY(poly2, len2 - 1, sz), len2 - 1, ctx);
if (len1 <= 7)
return _gr_poly_compose_horner(res, poly1, len1, poly2, len2, ctx);
return _gr_poly_compose_divconquer(res, poly1, len1, poly2, len2, ctx);
}
int gr_poly_compose(gr_poly_t res,
const gr_poly_t poly1, const gr_poly_t poly2, gr_ctx_t ctx)
{
const slong len1 = poly1->length;
const slong len2 = poly2->length;
if (len1 == 0)
{
return gr_poly_zero(res, ctx);
}
else if (len1 == 1 || len2 == 0)
{
return gr_poly_set_scalar(res, poly1->coeffs, ctx);
}
else
{
const slong lenr = (len1 - 1) * (len2 - 1) + 1;
int status;
if (res != poly1 && res != poly2)
{
gr_poly_fit_length(res, lenr, ctx);
status = _gr_poly_compose(res->coeffs, poly1->coeffs, len1, poly2->coeffs, len2, ctx);
}
else
{
gr_poly_t t;
gr_poly_init2(t, lenr, ctx);
status = _gr_poly_compose(t->coeffs, poly1->coeffs, len1, poly2->coeffs, len2, ctx);
gr_poly_swap(res, t, ctx);
gr_poly_clear(t, ctx);
}
_gr_poly_set_length(res, lenr, ctx);
_gr_poly_normalise(res, ctx);
return status;
}
}