#include "nmod.h"
#include "nmod_poly.h"
void nmod_poly_extrapolate_geometric_precomp(nn_ptr oval, slong olen,
nn_srcptr ival, slong ilen,
slong offset,
const nmod_geometric_progression_t G)
{
FLINT_ASSERT((G->function & UWORD(4)) == UWORD(4));
FLINT_ASSERT((offset >= ilen && G->len >= offset+olen)
|| (offset <= -olen && G->len >= ilen-offset));
if (olen == 0)
return;
if (ilen == 0)
{
for (slong i = 0; i < olen; i++)
oval[i] = 0;
return;
}
if (ilen == 1)
{
for (slong i = 0; i < olen; i++)
oval[i] = ival[0];
return;
}
if (offset > 0)
{
TMP_INIT;
TMP_START;
nn_ptr tmp = TMP_ALLOC(ilen * sizeof(ulong));
for (slong i = 0; i < ilen; i++)
{
tmp[i] = nmod_mul(G->ext_s3[ilen-1-i], ival[i], G->mod);
tmp[i] = nmod_mul(G->ext_s2[i], tmp[i], G->mod);
}
_nmod_poly_mulmid(oval, G->ext_ff->coeffs + offset-ilen, ilen+olen-1, tmp, ilen, ilen-1, ilen+olen-1, G->mod);
for (slong j = 0; j < olen; j++)
{
oval[j] = nmod_mul(G->ext_s2[offset-ilen+j], oval[j], G->mod);
oval[j] = nmod_mul(G->ext_s1f[offset+j], oval[j], G->mod);
}
TMP_END;
}
else
{
TMP_INIT;
TMP_START;
nn_ptr tmp = TMP_ALLOC(FLINT_MAX(ilen, olen) * sizeof(ulong));
for (slong i = 0; i < ilen; i++)
{
tmp[i] = nmod_mul(G->ext_s2[ilen-1-i], ival[ilen-1-i], G->mod);
tmp[i] = nmod_mul(G->ext_s3[i], tmp[i], G->mod);
}
_nmod_poly_mulmid(oval, G->ext_fb->coeffs - (offset+olen), ilen+olen-1, tmp, ilen, ilen-1, ilen+olen-1, G->mod);
for (slong j = 0; j < olen; j++)
tmp[j] = oval[olen - 1 - j];
for (slong j = 0; j < olen; j++)
{
oval[j] = nmod_mul(G->ext_s3[-offset-1-j], tmp[j], G->mod);
oval[j] = nmod_mul(G->ext_s1b[ilen-1-offset-j], oval[j], G->mod);
}
TMP_END;
}
}
void nmod_poly_extrapolate_geometric(nn_ptr oval, slong olen,
nn_srcptr ival, slong ilen,
slong offset, ulong r, nmod_t mod)
{
if (olen == 0)
return;
if (ilen == 0)
{
for (slong i = 0; i < olen; i++)
oval[i] = 0;
return;
}
if (ilen == 1)
{
for (slong i = 0; i < olen; i++)
oval[i] = ival[0];
return;
}
nmod_geometric_progression_t G;
slong len = (offset > 0) ? offset+olen : ilen-offset;
_nmod_geometric_progression_init_function(G, r, len, mod, UWORD(4));
nmod_poly_extrapolate_geometric_precomp(oval, olen, ival, ilen, offset, G);
nmod_geometric_progression_clear(G);
}