/*
Copyright (C) 2021 William Hart
This file is part of FLINT.
FLINT is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. See .
*/
#include
#include
#include "flint.h"
#include "fmpz_mod_vec.h"
#include "fmpz_mod_poly.h"
int _fmpz_mod_poly_divides(fmpz * Q, const fmpz * A, slong lenA,
const fmpz * B, slong lenB, fmpz_mod_ctx_t ctx)
{
fmpz * R;
fmpz_t invB;
slong i, lenQ = lenA - lenB + 1;
int res = 1;
const fmpz * p = fmpz_mod_ctx_modulus(ctx);
if (lenA < 40 && lenB < 20)
return _fmpz_mod_poly_divides_classical(Q, A, lenA, B, lenB, ctx);
R = _fmpz_vec_init(lenB - 1);
fmpz_init(invB);
fmpz_invmod(invB, B + lenB - 1, p);
if (lenA < 2*lenB - 1)
{
slong offset = 0;
fmpz * P;
P = (fmpz *) _fmpz_vec_init(2*lenQ - 1);
_fmpz_vec_zero(R, lenB - 1);
_fmpz_mod_poly_div(Q, A, lenA, B, lenB, invB, p);
while (offset < lenB - 1)
{
if (offset + 2*lenQ - 1 < lenB)
{
_fmpz_mod_poly_mul(P, B + offset, lenQ, Q, lenQ, p);
_fmpz_mod_poly_add(R + offset, R + offset, 2*lenQ - 1, P, 2*lenQ - 1, p);
} else
{
_fmpz_mod_poly_mullow(P, Q, lenQ, B + offset, lenQ, p, lenB - offset - 1);
_fmpz_mod_poly_add(R + offset, R + offset, lenB - offset - 1, P, lenB - offset - 1, p);
}
for (i = 0; i < FLINT_MIN(lenQ, lenB - offset - 1); i++)
{
if (!fmpz_equal(R + offset + i, A + offset + i))
{
res = 0;
break;
}
}
offset += lenQ;
}
_fmpz_vec_clear(P, 2*lenQ - 1);
} else
{
_fmpz_mod_poly_divrem(Q, R, A, lenA, B, lenB, invB, p);
for (i = 0; i < lenB - 1; i++)
{
if (!fmpz_is_zero(R + i))
{
res = 0;
break;
}
}
}
fmpz_clear(invB);
_fmpz_vec_clear(R, lenB - 1);
if (res == 0)
_fmpz_vec_zero(Q, lenQ);
return res;
}
int fmpz_mod_poly_divides(fmpz_mod_poly_t Q, const fmpz_mod_poly_t A, const fmpz_mod_poly_t B, fmpz_mod_ctx_t ctx)
{
fmpz_mod_poly_t tQ;
fmpz * q;
slong lenA, lenB;
int res;
lenA = A->length;
lenB = B->length;
if (lenB == 0 || lenA < lenB)
{
fmpz_mod_poly_zero(Q, ctx);
return lenA == 0;
}
if (Q == A || Q == B)
{
fmpz_mod_poly_init2(tQ, lenA - lenB + 1, ctx);
q = tQ->coeffs;
}
else
{
fmpz_mod_poly_fit_length(Q, lenA - lenB + 1, ctx);
q = Q->coeffs;
}
res = _fmpz_mod_poly_divides(q, A->coeffs, lenA, B->coeffs, lenB, ctx);
if (Q == A || Q == B)
{
fmpz_mod_poly_swap(tQ, Q, ctx);
fmpz_mod_poly_clear(tQ, ctx);
}
_fmpz_mod_poly_set_length(Q, lenA - lenB + 1);
_fmpz_mod_poly_normalise(Q);
return res;
}