#include "longlong.h"
#include "gr_vec.h"
#include "gr_poly.h"
#define _gr_poly_mul_monic _gr_poly_mul
int
_gr_poly_interpolation_weights(gr_ptr w,
const gr_ptr * tree, slong len, gr_ctx_t ctx)
{
gr_ptr tmp;
slong i, n, height;
int status = GR_SUCCESS;
slong sz = ctx->sizeof_elem;
if (len == 0)
return status;
if (len == 1)
return gr_one(w, ctx);
GR_TMP_INIT_VEC(tmp, len + 1, ctx);
height = FLINT_CLOG2(len);
n = WORD(1) << (height - 1);
status |= _gr_poly_mul_monic(tmp, tree[height-1], n + 1,
GR_ENTRY(tree[height-1], (n + 1), sz), (len - n + 1), ctx);
status |= _gr_poly_derivative(tmp, tmp, len + 1, ctx);
status |= _gr_poly_evaluate_vec_fast_precomp(w, tmp, len, tree, len, ctx);
for (i = 0; i < len; i++)
status |= gr_inv(GR_ENTRY(w, i, sz), GR_ENTRY(w, i, sz), ctx);
GR_TMP_CLEAR_VEC(tmp, len + 1, ctx);
return status;
}
int
_gr_poly_interpolate_fast_precomp(gr_ptr poly,
gr_srcptr ys, const gr_ptr * tree, gr_srcptr weights,
slong len, gr_ctx_t ctx)
{
gr_ptr t, u, pa, pb;
slong i, pow, left;
int status = GR_SUCCESS;
slong sz = ctx->sizeof_elem;
if (len == 0)
return status;
GR_TMP_INIT_VEC(t, 2 * len, ctx);
u = GR_ENTRY(t, len, sz);
status |= _gr_vec_mul(poly, weights, ys, len, ctx);
for (i = 0; i < FLINT_CLOG2(len); i++)
{
pow = (WORD(1) << i);
pa = tree[i];
pb = poly;
left = len;
while (left >= 2 * pow)
{
status |= _gr_poly_mul(t, pa, pow + 1, GR_ENTRY(pb, pow, sz), pow, ctx);
status |= _gr_poly_mul(u, GR_ENTRY(pa, pow + 1, sz), pow + 1, pb, pow, ctx);
status |= _gr_vec_add(pb, t, u, 2 * pow, ctx);
left -= 2 * pow;
pa = GR_ENTRY(pa, 2 * pow + 2, sz);
pb = GR_ENTRY(pb, 2 * pow, sz);
}
if (left > pow)
{
status |= _gr_poly_mul(t, pa, pow + 1, GR_ENTRY(pb, pow, sz), left - pow, ctx);
status |= _gr_poly_mul(u, pb, pow, GR_ENTRY(pa, pow + 1, sz), left - pow + 1, ctx);
status |= _gr_vec_add(pb, t, u, left, ctx);
}
}
GR_TMP_CLEAR_VEC(t, 2 * len, ctx);
return status;
}
int
_gr_poly_interpolate_fast(gr_ptr poly,
gr_srcptr xs, gr_srcptr ys, slong len, gr_ctx_t ctx)
{
gr_ptr * tree;
gr_ptr w;
int status = GR_SUCCESS;
tree = _gr_poly_tree_alloc(len, ctx);
GR_TMP_INIT_VEC(w, len, ctx);
status |= _gr_poly_tree_build(tree, xs, len, ctx);
status |= _gr_poly_interpolation_weights(w, tree, len, ctx);
status |= _gr_poly_interpolate_fast_precomp(poly, ys, tree, w, len, ctx);
GR_TMP_CLEAR_VEC(w, len, ctx);
_gr_poly_tree_free(tree, len, ctx);
return status;
}
int
gr_poly_interpolate_fast(gr_poly_t poly, const gr_vec_t xs, const gr_vec_t ys, gr_ctx_t ctx)
{
int status;
slong n = xs->length;
if (n != ys->length)
return GR_DOMAIN;
gr_poly_fit_length(poly, n, ctx);
status = _gr_poly_interpolate_fast(poly->coeffs, xs->entries, ys->entries, n, ctx);
_gr_poly_set_length(poly, n, ctx);
_gr_poly_normalise(poly, ctx);
return status;
}