/*
Copyright (C) 2011 William Hart
Copyright (C) 2011 Sebastian Pancratz
Copyright (C) 2013 Mike Hansen
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 .
*/
#ifdef T
#include "templates.h"
#include
#include "mpn_extras.h"
#define __set(B, lenB, A, lenA) \
do { \
_TEMPLATE(T, vec_set)((B), (A), (lenA), ctx); \
(lenB) = (lenA); \
} while (0)
#define __rem(R, lenR, A, lenA, B, lenB, invB) \
do { \
if ((lenA) >= (lenB)) \
{ \
_TEMPLATE(T, poly_rem)((R), (A), (lenA), (B), (lenB), (invB), ctx); \
(lenR) = (lenB) - 1; \
TEMPLATE(CAP_T, VEC_NORM)(R, lenR, ctx); \
} \
else \
{ \
_TEMPLATE(T, vec_set)((R), (A), (lenA), ctx); \
(lenR) = (lenA); \
} \
} while (0)
/*
XXX: Incidentally, this implementation currently supports aliasing.
But since this may change in the future, no function other than
TEMPLATE(T, poly_gcd_hgcd)() should rely on this.
*/
slong
_TEMPLATE(T, poly_gcd_hgcd) (TEMPLATE(T, struct) * G,
const TEMPLATE(T, struct) * A, slong lenA,
const TEMPLATE(T, struct) * B, slong lenB,
const TEMPLATE(T, t) invB,
const TEMPLATE(T, ctx_t) ctx)
{
slong cutoff, lenG, lenJ, lenR;
TEMPLATE(T, struct) * J = _TEMPLATE(T, vec_init) (2 * lenB, ctx);
TEMPLATE(T, struct) * R = J + lenB;
TEMPLATE(T, t) inv;
if (fmpz_bits(TEMPLATE(T, ctx_prime) (ctx)) <= 8)
cutoff = TEMPLATE(CAP_T, POLY_SMALL_GCD_CUTOFF);
else
cutoff = TEMPLATE(CAP_T, POLY_GCD_CUTOFF);
__rem(R, lenR, A, lenA, B, lenB, invB);
if (lenR == 0)
{
__set(G, lenG, B, lenB);
}
else
{
TEMPLATE(T, init) (inv, ctx);
_TEMPLATE(T, poly_hgcd) (NULL, NULL, G, &(lenG), J, &(lenJ), B, lenB,
R, lenR, ctx);
while (lenJ != 0)
{
TEMPLATE(T, inv) (inv, J + lenJ - 1, ctx);
__rem(R, lenR, G, lenG, J, lenJ, inv);
if (lenR == 0)
{
__set(G, lenG, J, lenJ);
break;
}
if (lenJ < cutoff)
{
TEMPLATE(T, inv) (inv, R + lenR - 1, ctx);
lenG =
_TEMPLATE(T, poly_gcd_euclidean) (G, J, lenJ, R, lenR, inv,
ctx);
break;
}
_TEMPLATE(T, poly_hgcd) (NULL, NULL, G, &(lenG), J, &(lenJ), J,
lenJ, R, lenR, ctx);
}
TEMPLATE(T, clear) (inv, ctx);
}
_TEMPLATE(T, vec_clear) (J, 2 * lenB, ctx);
return lenG;
}
void TEMPLATE(T, poly_gcd_hgcd) (TEMPLATE(T, poly_t) G,
const TEMPLATE(T, poly_t) A,
const TEMPLATE(T, poly_t) B,
const TEMPLATE(T, ctx_t) ctx)
{
if (A->length < B->length)
{
TEMPLATE(T, poly_gcd_hgcd) (G, B, A, ctx);
}
else /* lenA >= lenB >= 0 */
{
slong lenA = A->length, lenB = B->length, lenG;
TEMPLATE(T, poly_t) tG;
TEMPLATE(T, t) invB;
TEMPLATE(T, struct) * g;
if (lenA == 0) /* lenA = lenB = 0 */
{
TEMPLATE(T, poly_zero) (G, ctx);
}
else if (lenB == 0) /* lenA > lenB = 0 */
{
TEMPLATE(T, poly_make_monic) (G, A, ctx);
}
else /* lenA >= lenB >= 1 */
{
if (G == A || G == B)
{
TEMPLATE(T, poly_init2) (tG, FLINT_MIN(lenA, lenB), ctx);
g = tG->coeffs;
}
else
{
TEMPLATE(T, poly_fit_length) (G, FLINT_MIN(lenA, lenB), ctx);
g = G->coeffs;
}
TEMPLATE(T, init) (invB, ctx);
TEMPLATE(T, inv) (invB, B->coeffs + lenB - 1, ctx);
lenG = _TEMPLATE(T, poly_gcd_hgcd) (g, A->coeffs, lenA,
B->coeffs, lenB, invB, ctx);
if (G == A || G == B)
{
TEMPLATE(T, poly_swap) (tG, G, ctx);
TEMPLATE(T, poly_clear) (tG, ctx);
}
G->length = lenG;
if (G->length == 1)
TEMPLATE(T, one) (G->coeffs, ctx);
else
TEMPLATE(T, poly_make_monic) (G, G, ctx);
TEMPLATE(T, clear) (invB, ctx);
}
}
}
#undef __set
#undef __rem
#endif