#include "fmpz_vec.h"
#include "fmpz_poly.h"
#include "fmpq.h"
#include "fmpq_poly.h"
void
_fmpq_poly_power_sums(fmpz * res, fmpz_t rden, const fmpz * poly, slong len,
slong n)
{
if (fmpz_is_one(poly + len - 1))
{
_fmpz_poly_power_sums_naive(res, poly, len, n);
fmpz_one(rden);
}
else if (len == 2)
{
fmpz_t a;
slong i;
fmpz_init(a);
fmpz_set(a, poly + 1);
fmpz_set(rden, poly);
if (fmpz_sgn(a) < 0)
fmpz_neg(a, a);
else
fmpz_neg(rden, rden);
fmpz_one(res);
for (i = 1; i < n; i++)
fmpz_mul(res + i, res + i - 1, rden);
fmpz_one(rden);
for (i = n - 2; i >= 0; i--)
{
fmpz_mul(rden, rden, a);
fmpz_mul(res + i, res + i, rden);
}
fmpz_set(res, rden);
fmpz_clear(a);
}
else
{
slong i, k;
fmpz_one(rden);
for (k = 1; k < FLINT_MIN(n, len); k++)
{
fmpz_mul_si(res + k, poly + len - 1 - k, -k);
fmpz_mul(res + k, res + k, rden);
_fmpz_vec_scalar_mul_fmpz(res + 1, res + 1, k - 2, poly + len - 1);
_fmpz_vec_dot_general(res + k, res + k, 1, poly + len - 1 - k + 1, res + 1, 0, k - 1);
fmpz_mul(rden, rden, poly + len - 1);
}
for (k = len; k < n; k++)
{
_fmpz_vec_scalar_mul_fmpz(res + k - len + 1, res + k - len + 1, len - 2, poly + len - 1);
_fmpz_vec_dot_general(res + k, NULL, 1, poly, res + k - len + 1, 0, len - 1);
}
_fmpz_vec_scalar_mul_fmpz(res + n - len + 1, res + n - len + 1, len - 2, poly + len - 1);
fmpz_one(rden);
for (i = n - len; i > 0; i--)
{
fmpz_mul(rden, rden, poly + len - 1);
fmpz_mul(res + i, res + i, rden);
}
fmpz_pow_ui(rden, poly + len - 1, n - 1);
fmpz_mul_ui(res, rden, len - 1);
}
}
void
fmpq_poly_power_sums(fmpq_poly_t res, const fmpq_poly_t poly, slong n)
{
if (poly->length == 0)
{
flint_throw(FLINT_ERROR, "(fmpq_poly_power_sums_naive): Zero polynomial.\n");
}
else if (n <= 0 || poly->length == 1)
{
fmpq_poly_zero(res);
return;
}
else if (n == 1)
{
fmpq_poly_fit_length(res, 1);
fmpz_set_ui(res->coeffs, fmpq_poly_degree(poly));
fmpz_one(res->den);
_fmpq_poly_set_length(res, 1);
return;
}
else if (poly == res)
{
fmpq_poly_t t;
fmpq_poly_init(t);
fmpq_poly_fit_length(t, n);
_fmpq_poly_power_sums(t->coeffs, t->den, poly->coeffs,
poly->length, n);
fmpq_poly_swap(res, t);
fmpq_poly_clear(t);
}
else
{
fmpq_poly_fit_length(res, n);
_fmpq_poly_power_sums(res->coeffs, res->den, poly->coeffs,
poly->length, n);
}
_fmpq_poly_set_length(res, n);
_fmpq_poly_normalise(res);
fmpq_poly_canonicalise(res);
}