/* Copyright (C) 2011 William Hart Copyright (C) 2012 Sebastian Pancratz 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 "fmpz_vec.h" #include "fmpz_mod_poly.h" slong _fmpz_mod_poly_gcdinv_euclidean(fmpz *G, fmpz *S, const fmpz *A, slong lenA, const fmpz *B, slong lenB, const fmpz_t invA, const fmpz_t p) { _fmpz_vec_zero(G, lenA); _fmpz_vec_zero(S, lenB - 1); if (lenA == 1) { fmpz_set(G + 0, A + 0); fmpz_one(S + 0); return 1; } else { fmpz *Q, *R; slong i, lenQ, lenR; TMP_INIT; TMP_START; FMPZ_VEC_TMP_INIT(Q, 2*lenB); R = Q + lenB; _fmpz_mod_poly_divrem(Q, R, B, lenB, A, lenA, invA, p); lenR = lenA - 1; FMPZ_VEC_NORM(R, lenR); if (lenR == 0) { _fmpz_vec_set(G, A, lenA); fmpz_one(S + 0); FMPZ_VEC_TMP_CLEAR(Q, 2*lenB); TMP_END; return lenA; } else if (lenR == 1) { lenQ = lenB - lenA + 1; FMPZ_VEC_NORM(Q, lenQ); _fmpz_vec_swap(G, R, lenR); _fmpz_vec_swap(S, Q, lenQ); _fmpz_vec_neg(S, S, lenQ); for (i = 0; i < lenQ; i++) { if (fmpz_sgn(S + i) < 0) fmpz_add(S + i, S + i, p); } FMPZ_VEC_TMP_CLEAR(Q, 2*lenB); TMP_END; return 1; } else { fmpz_t inv; fmpz *D, *U1, *U2, *V3, *W; slong lenD, lenU1, lenU2, lenV3, lenW; fmpz_init(inv); FMPZ_VEC_TMP_INIT(W, 3*lenB + 2*lenA); D = W + lenB; U1 = D + lenA; U2 = U1 + lenB; V3 = U2 + lenB; lenQ = lenB - lenA + 1; FMPZ_VEC_NORM(Q, lenQ); fmpz_set_ui(U1, 1); lenU1 = 1; _fmpz_vec_set(D, A, lenA); lenD = lenA; _fmpz_vec_neg(U2, Q, lenQ); lenU2 = lenQ; lenV3 = 0; FMPZ_VEC_SWAP(V3, lenV3, R, lenR); do { fmpz_invmod(inv, V3 + (lenV3 - 1), p); _fmpz_mod_poly_divrem_basecase(Q, D, D, lenD, V3, lenV3, inv, p); lenQ = lenD - lenV3 + 1; lenD = lenV3 - 1; FMPZ_VEC_NORM(D, lenD); if (lenV3 != 0) { if (lenU2 >= lenQ) _fmpz_mod_poly_mul(W, U2, lenU2, Q, lenQ, p); else _fmpz_mod_poly_mul(W, Q, lenQ, U2, lenU2, p); lenW = lenQ + lenU2 - 1; _fmpz_mod_poly_sub(U1, U1, lenU1, W, lenW, p); lenU1 = FLINT_MAX(lenU1, lenW); FMPZ_VEC_NORM(U1, lenU1); } FMPZ_VEC_SWAP(U1, lenU1, U2, lenU2); FMPZ_VEC_SWAP(V3, lenV3, D, lenD); } while (lenV3 != 0); _fmpz_vec_swap(G, D, lenD); _fmpz_vec_swap(S, U1, lenU1); for (i = 0; i < lenU1; i++) { if (fmpz_sgn(S + i) < 0) fmpz_add(S + i, S + i, p); } FMPZ_VEC_TMP_CLEAR(W, 3*lenB + 2*lenA); FMPZ_VEC_TMP_CLEAR(Q, 2*lenB); fmpz_clear(inv); TMP_END; return lenD; } } } void fmpz_mod_poly_gcdinv_euclidean(fmpz_mod_poly_t G, fmpz_mod_poly_t S, const fmpz_mod_poly_t A, const fmpz_mod_poly_t B, const fmpz_mod_ctx_t ctx) { const slong lenA = A->length, lenB = B->length; fmpz_t inv; if (lenB < 2) { flint_printf("Exception (fmpz_mod_poly_gcdinv). lenB < 2.\n"); flint_abort(); } if (lenA >= lenB) { fmpz_mod_poly_t T; fmpz_mod_poly_init(T, ctx); fmpz_mod_poly_rem(T, A, B, ctx); fmpz_mod_poly_gcdinv_euclidean(G, S, T, B, ctx); fmpz_mod_poly_clear(T, ctx); return; } fmpz_init(inv); if (lenA == 0) { fmpz_mod_poly_zero(G, ctx); fmpz_mod_poly_zero(S, ctx); } else /* lenB >= lenA >= 1 */ { fmpz *g, *s; slong lenG; if (G == A || G == B) { g = _fmpz_vec_init(FLINT_MIN(lenA, lenB)); } else { fmpz_mod_poly_fit_length(G, FLINT_MIN(lenA, lenB), ctx); g = G->coeffs; } if (S == A || S == B) { s = _fmpz_vec_init(lenB); } else { fmpz_mod_poly_fit_length(S, lenB, ctx); s = S->coeffs; } fmpz_invmod(inv, fmpz_mod_poly_lead(A, ctx), fmpz_mod_ctx_modulus(ctx)); lenG = _fmpz_mod_poly_gcdinv_euclidean(g, s, A->coeffs, lenA, B->coeffs, lenB, inv, fmpz_mod_ctx_modulus(ctx)); if (G == A || G == B) { _fmpz_vec_clear(G->coeffs, G->alloc); G->coeffs = g; G->alloc = FLINT_MIN(lenA, lenB); } if (S == A || S == B) { _fmpz_vec_clear(S->coeffs, S->alloc); S->coeffs = s; S->alloc = lenB; } _fmpz_mod_poly_set_length(G, lenG); _fmpz_mod_poly_set_length(S, FLINT_MAX(lenB - lenG, 1)); _fmpz_mod_poly_normalise(S); if (!fmpz_is_one(fmpz_mod_poly_lead(G, ctx))) { fmpz_invmod(inv, fmpz_mod_poly_lead(G, ctx), fmpz_mod_ctx_modulus(ctx)); fmpz_mod_poly_scalar_mul_fmpz(G, G, inv, ctx); fmpz_mod_poly_scalar_mul_fmpz(S, S, inv, ctx); } fmpz_clear(inv); } }