diff --git a/doc/source/nmod_poly.rst b/doc/source/nmod_poly.rst index d528e90394..e802fdc3a3 100644 --- a/doc/source/nmod_poly.rst +++ b/doc/source/nmod_poly.rst @@ -1032,6 +1032,12 @@ Division Computes the remainder `R` on polynomial division of `A` by `B`. +.. function:: void _nmod_poly_divexact(mp_ptr Q, mp_srcptr A, slong lenA, mp_srcptr B, slong lenB, nmod_t mod) + void nmod_poly_divexact(nmod_poly_t Q, const nmod_poly_t A, const nmod_poly_t B) + + Computes the quotient `Q` of `A` and `B` assuming that the division + is exact. + .. function:: void _nmod_poly_inv_series_basecase(mp_ptr Qinv, mp_srcptr Q, slong Qlen, slong n, nmod_t mod) Given ``Q`` of length ``Qlen`` whose leading coefficient is invertible diff --git a/src/gr/nmod.c b/src/gr/nmod.c index aac855e7cc..323ebbda31 100644 --- a/src/gr/nmod.c +++ b/src/gr/nmod.c @@ -1002,6 +1002,19 @@ _gr_nmod_poly_divrem(mp_ptr Q, mp_ptr R, mp_srcptr A, slong lenA, } } +int +_gr_nmod_poly_divexact(mp_ptr Q, mp_srcptr A, slong lenA, mp_srcptr B, slong lenB, gr_ctx_t ctx) +{ + slong lenQ = lenA - lenB + 1; + + if (lenB <= 40 || lenQ <= 20) + return _gr_poly_divexact_basecase(Q, A, lenA, B, lenB, ctx); + else if (lenB <= 60 || lenQ <= 60) + return _gr_poly_divexact_basecase_bidirectional(Q, A, lenA, B, lenB, ctx); + else + return _gr_poly_divexact_bidirectional(Q, A, lenA, B, lenB, ctx); +} + /* basecase -> Newton cutoffs */ /* todo: better unbalanced tuning */ @@ -1434,6 +1447,7 @@ gr_method_tab_input __gr_nmod_methods_input[] = {GR_METHOD_VEC_RECIPROCALS, (gr_funcptr) _gr_nmod_vec_reciprocals}, {GR_METHOD_POLY_MULLOW, (gr_funcptr) _gr_nmod_poly_mullow}, {GR_METHOD_POLY_DIVREM, (gr_funcptr) _gr_nmod_poly_divrem}, + {GR_METHOD_POLY_DIVEXACT, (gr_funcptr) _gr_nmod_poly_divexact}, {GR_METHOD_POLY_INV_SERIES, (gr_funcptr) _gr_nmod_poly_inv_series}, {GR_METHOD_POLY_INV_SERIES_BASECASE, (gr_funcptr) _gr_nmod_poly_inv_series_basecase}, {GR_METHOD_POLY_DIV_SERIES, (gr_funcptr) _gr_nmod_poly_div_series}, diff --git a/src/gr_mat/minpoly_field.c b/src/gr_mat/minpoly_field.c index d67e4d0deb..e15b56edc1 100644 --- a/src/gr_mat/minpoly_field.c +++ b/src/gr_mat/minpoly_field.c @@ -165,6 +165,8 @@ gr_mat_minpoly_field(gr_poly_t p, const gr_mat_t X, gr_ctx_t ctx) } _gr_poly_set_length(b, r1 + 1, ctx); + /* todo: poly_divexact */ + /* todo: compute as (p * b) / g or (p / g) * b or p * (g / b) ? */ status |= gr_poly_gcd(g, p, b, ctx); status |= gr_poly_mul(p, p, b, ctx); status |= gr_poly_divrem(p, r, p, g, ctx); diff --git a/src/gr_poly/divexact_basecase.c b/src/gr_poly/divexact_basecase.c index 9c154869b0..d6994c9c10 100644 --- a/src/gr_poly/divexact_basecase.c +++ b/src/gr_poly/divexact_basecase.c @@ -48,6 +48,11 @@ _gr_poly_divexact_basecase(gr_ptr Q, slong sz = ctx->sizeof_elem; gr_ptr invB; + /* note: if we wanted to be clever, we could pick a pair of coefficients such + that the division is easy */ + if (Alen == Blen) + return gr_divexact(Q, GR_ENTRY(A, Alen - 1, sz), GR_ENTRY(B, Blen - 1, sz), ctx); + GR_TMP_INIT(invB, ctx); /* todo: we sometimes want to keep dividing, e.g. over RR with small coefficient */ diff --git a/src/n_poly.h b/src/n_poly.h index 3a76cff8b4..84848de029 100644 --- a/src/n_poly.h +++ b/src/n_poly.h @@ -410,6 +410,22 @@ void _n_poly_mod_div(n_poly_t Q, const n_poly_t A, const n_poly_t B, nmod_t mod) Q->length = lenA - lenB + 1; } +FLINT_FORCE_INLINE +void _n_poly_mod_divexact(n_poly_t Q, const n_poly_t A, const n_poly_t B, nmod_t mod) +{ + const slong lenA = A->length, lenB = B->length; + FLINT_ASSERT(lenB > 0); + FLINT_ASSERT(Q != A && Q != B); + if (lenA < lenB) + { + n_poly_zero(Q); + return; + } + n_poly_fit_length(Q, lenA - lenB + 1); + _nmod_poly_divexact(Q->coeffs, A->coeffs, lenA, B->coeffs, lenB, mod); + Q->length = lenA - lenB + 1; +} + FLINT_FORCE_INLINE void _n_poly_mod_rem(n_poly_t R, const n_poly_t A, const n_poly_t B, nmod_t mod) { @@ -472,6 +488,9 @@ void n_poly_mod_rem(n_poly_t R, const n_poly_t A, const n_poly_t B, void n_poly_mod_divrem(n_poly_t Q, n_poly_t R, const n_poly_t A, const n_poly_t B, nmod_t mod); +void n_poly_mod_divexact(n_poly_t Q, const n_poly_t A, const n_poly_t B, + nmod_t mod); + void n_poly_mod_mulmod(n_poly_t res, const n_poly_t poly1, const n_poly_t poly2, const n_poly_t f, nmod_t mod); diff --git a/src/n_poly/n_bpoly_mod.c b/src/n_poly/n_bpoly_mod.c index ff33616164..19b4e48e8a 100644 --- a/src/n_poly/n_bpoly_mod.c +++ b/src/n_poly/n_bpoly_mod.c @@ -81,7 +81,7 @@ void n_bpoly_mod_divexact_last(n_bpoly_t A, const n_poly_t b, nmod_t ctx) if (A->coeffs[i].length < 1) continue; - n_poly_mod_div(t, A->coeffs + i, b, ctx); + n_poly_mod_divexact(t, A->coeffs + i, b, ctx); n_poly_swap(A->coeffs + i, t); } } diff --git a/src/n_poly/n_bpoly_mod_gcd.c b/src/n_poly/n_bpoly_mod_gcd.c index f261e48d87..af27cefa15 100644 --- a/src/n_poly/n_bpoly_mod_gcd.c +++ b/src/n_poly/n_bpoly_mod_gcd.c @@ -225,8 +225,8 @@ int n_bpoly_mod_gcd_brown_smprime( n_poly_mod_gcd(cG, cA, cB, ctx); - n_poly_mod_div(cAbar, cA, cG, ctx); - n_poly_mod_div(cBbar, cB, cG, ctx); + n_poly_mod_divexact(cAbar, cA, cG, ctx); + n_poly_mod_divexact(cBbar, cB, cG, ctx); n_poly_mod_gcd(gamma, A->coeffs + A->length - 1, B->coeffs + B->length - 1, ctx); @@ -311,11 +311,11 @@ int n_bpoly_mod_gcd_brown_smprime( else { n_poly_mod_gcd(Gevalp, Aevalp, Bevalp, ctx); - n_poly_mod_div(Abarevalp, Aevalp, Gevalp, ctx); - n_poly_mod_div(Bbarevalp, Bevalp, Gevalp, ctx); + n_poly_mod_divexact(Abarevalp, Aevalp, Gevalp, ctx); + n_poly_mod_divexact(Bbarevalp, Bevalp, Gevalp, ctx); n_poly_mod_gcd(Gevalm, Aevalm, Bevalm, ctx); - n_poly_mod_div(Abarevalm, Aevalm, Gevalm, ctx); - n_poly_mod_div(Bbarevalm, Bevalm, Gevalm, ctx); + n_poly_mod_divexact(Abarevalm, Aevalm, Gevalm, ctx); + n_poly_mod_divexact(Bbarevalm, Bevalm, Gevalm, ctx); gstab = astab = bstab = 0; } diff --git a/src/n_poly/n_poly_mod.c b/src/n_poly/n_poly_mod.c index 5cb761ce3b..ef1aa2483b 100644 --- a/src/n_poly/n_poly_mod.c +++ b/src/n_poly/n_poly_mod.c @@ -339,6 +339,57 @@ void n_poly_mod_div(n_poly_t Q, const n_poly_t A, const n_poly_t B, nmod_t ctx) Q->length = A_len - B_len + 1; } +void n_poly_mod_divexact(n_poly_t Q, const n_poly_t A, const n_poly_t B, nmod_t ctx) +{ + n_poly_t tQ; + mp_ptr q; + slong A_len, B_len; + + B_len = B->length; + + if (B_len == 0) + { + if (ctx.n == 1) + { + n_poly_set(Q, A); + return; + } + else + { + flint_throw(FLINT_ERROR, "Exception (n_poly_mod_divexact). Division by zero.\n"); + } + } + + A_len = A->length; + + if (A_len < B_len) + { + n_poly_zero(Q); + return; + } + + if (Q == A || Q == B) + { + n_poly_init2(tQ, A_len - B_len + 1); + q = tQ->coeffs; + } + else + { + n_poly_fit_length(Q, A_len - B_len + 1); + q = Q->coeffs; + } + + _nmod_poly_divexact(q, A->coeffs, A_len, B->coeffs, B_len, ctx); + + if (Q == A || Q == B) + { + n_poly_swap(tQ, Q); + n_poly_clear(tQ); + } + + Q->length = A_len - B_len + 1; +} + void n_poly_mod_rem(n_poly_t R, const n_poly_t A, const n_poly_t B, nmod_t ctx) { const slong lenA = A->length, lenB = B->length; diff --git a/src/n_poly/n_polyu1n_gcd.c b/src/n_poly/n_polyu1n_gcd.c index acde94e4bd..adfaa13a68 100644 --- a/src/n_poly/n_polyu1n_gcd.c +++ b/src/n_poly/n_polyu1n_gcd.c @@ -298,8 +298,8 @@ int n_polyu1n_mod_gcd_brown_smprime( _n_poly_vec_mod_remove_content(cB, B->coeffs, B->length, ctx); n_poly_mod_gcd(cG, cA, cB, ctx); - n_poly_mod_div(cAbar, cA, cG, ctx); - n_poly_mod_div(cBbar, cB, cG, ctx); + n_poly_mod_divexact(cAbar, cA, cG, ctx); + n_poly_mod_divexact(cBbar, cB, cG, ctx); n_poly_mod_gcd(gamma, A->coeffs + 0, B->coeffs + 0, ctx); @@ -377,11 +377,11 @@ int n_polyu1n_mod_gcd_brown_smprime( else { n_poly_mod_gcd(Gevalp, Aevalp, Bevalp, ctx); - n_poly_mod_div(Abarevalp, Aevalp, Gevalp, ctx); - n_poly_mod_div(Bbarevalp, Bevalp, Gevalp, ctx); + n_poly_mod_divexact(Abarevalp, Aevalp, Gevalp, ctx); + n_poly_mod_divexact(Bbarevalp, Bevalp, Gevalp, ctx); n_poly_mod_gcd(Gevalm, Aevalm, Bevalm, ctx); - n_poly_mod_div(Abarevalm, Aevalm, Gevalm, ctx); - n_poly_mod_div(Bbarevalm, Bevalm, Gevalm, ctx); + n_poly_mod_divexact(Abarevalm, Aevalm, Gevalm, ctx); + n_poly_mod_divexact(Bbarevalm, Bevalm, Gevalm, ctx); gstab = astab = bstab = 0; } diff --git a/src/nmod_mat/minpoly.c b/src/nmod_mat/minpoly.c index 19957b8e57..919ded83c2 100644 --- a/src/nmod_mat/minpoly.c +++ b/src/nmod_mat/minpoly.c @@ -164,8 +164,9 @@ void nmod_mat_minpoly_with_gens(nmod_poly_t p, const nmod_mat_t X, ulong * P) _nmod_poly_set_length(b, r1 + 1); nmod_poly_gcd(g, p, b); + /* todo: compute as (p * b) / g or (p / g) * b or p * (g / b) ? */ nmod_poly_mul(p, p, b); - nmod_poly_div(p, p, g); + nmod_poly_divexact(p, p, g); if (first_poly && r2 < n) { diff --git a/src/nmod_mpoly/gcd.c b/src/nmod_mpoly/gcd.c index 1745951998..ef9c832b26 100644 --- a/src/nmod_mpoly/gcd.c +++ b/src/nmod_mpoly/gcd.c @@ -960,14 +960,14 @@ int _do_univar( I->Gmin_exp, I->Gstride, ctx); if (Abar != NULL) { - nmod_poly_div(t, a, g); + nmod_poly_divexact(t, a, g); _nmod_mpoly_from_nmod_poly_inflate(Abar, I->Abarbits, t, v_in_both, I->Abarmin_exp, I->Gstride, ctx); } if (Bbar != NULL) { - nmod_poly_div(t, b, g); + nmod_poly_divexact(t, b, g); _nmod_mpoly_from_nmod_poly_inflate(Bbar, I->Bbarbits, t, v_in_both, I->Bbarmin_exp, I->Gstride, ctx); } diff --git a/src/nmod_mpoly/gcd_brown.c b/src/nmod_mpoly/gcd_brown.c index a4b5a3c90f..622e738f79 100644 --- a/src/nmod_mpoly/gcd_brown.c +++ b/src/nmod_mpoly/gcd_brown.c @@ -155,11 +155,11 @@ static void _splitworker_bivar(void * varg) else { n_poly_mod_gcd(Gevalp, Aevalp, Bevalp, ctx->mod); - n_poly_mod_div(Abarevalp, Aevalp, Gevalp, ctx->mod); - n_poly_mod_div(Bbarevalp, Bevalp, Gevalp, ctx->mod); + n_poly_mod_divexact(Abarevalp, Aevalp, Gevalp, ctx->mod); + n_poly_mod_divexact(Bbarevalp, Bevalp, Gevalp, ctx->mod); n_poly_mod_gcd(Gevalm, Aevalm, Bevalm, ctx->mod); - n_poly_mod_div(Abarevalm, Aevalm, Gevalm, ctx->mod); - n_poly_mod_div(Bbarevalm, Bevalm, Gevalm, ctx->mod); + n_poly_mod_divexact(Abarevalm, Aevalm, Gevalm, ctx->mod); + n_poly_mod_divexact(Bbarevalm, Bevalm, Gevalm, ctx->mod); } FLINT_ASSERT(Gevalp->length > 0); @@ -874,8 +874,8 @@ int nmod_mpolyn_gcd_brown_smprime_threaded_pool( n_poly_init(cAbar); n_poly_init(cBbar); - n_poly_mod_div(cAbar, cA, cG, ctx->mod); - n_poly_mod_div(cBbar, cB, cG, ctx->mod); + n_poly_mod_divexact(cAbar, cA, cG, ctx->mod); + n_poly_mod_divexact(cBbar, cB, cG, ctx->mod); n_poly_init(gamma); n_poly_mod_gcd(gamma, nmod_mpolyn_leadcoeff_poly(A, ctx), diff --git a/src/nmod_mpoly/mpolyn_divides_threaded.c b/src/nmod_mpoly/mpolyn_divides_threaded.c index 76cb554464..5cc58a076d 100644 --- a/src/nmod_mpoly/mpolyn_divides_threaded.c +++ b/src/nmod_mpoly/mpolyn_divides_threaded.c @@ -1817,7 +1817,7 @@ int nmod_mpolyn_divides_threaded_pool( qexps = (ulong *) TMP_ALLOC(N*sizeof(ulong)); mpoly_monomial_sub(qexps + N*0, A->exps + N*0, B->exps + N*0, N); - n_poly_mod_div(qcoeff, A->coeffs + 0, B->coeffs + 0, ctx->mod); /* already checked */ + n_poly_mod_divexact(qcoeff, A->coeffs + 0, B->coeffs + 0, ctx->mod); /* already checked */ nmod_mpolyn_ts_init(H->polyQ, qcoeff, qexps, 1, H->bits, H->N, ctx); diff --git a/src/nmod_mpoly/mpolyn_gcd_brown.c b/src/nmod_mpoly/mpolyn_gcd_brown.c index 2d2320dd84..f67cf14578 100644 --- a/src/nmod_mpoly/mpolyn_gcd_brown.c +++ b/src/nmod_mpoly/mpolyn_gcd_brown.c @@ -95,8 +95,8 @@ int nmod_mpolyn_gcd_brown_smprime_bivar( n_poly_mod_gcd(cG, cA, cB, ctx->mod); - n_poly_mod_div(cAbar, cA, cG, ctx->mod); - n_poly_mod_div(cBbar, cB, cG, ctx->mod); + n_poly_mod_divexact(cAbar, cA, cG, ctx->mod); + n_poly_mod_divexact(cBbar, cB, cG, ctx->mod); n_poly_mod_gcd(gamma, nmod_mpolyn_leadcoeff_poly(A, ctx), nmod_mpolyn_leadcoeff_poly(B, ctx), ctx->mod); @@ -186,11 +186,11 @@ int nmod_mpolyn_gcd_brown_smprime_bivar( else { n_poly_mod_gcd(Gevalp, Aevalp, Bevalp, ctx->mod); - n_poly_mod_div(Abarevalp, Aevalp, Gevalp, ctx->mod); - n_poly_mod_div(Bbarevalp, Bevalp, Gevalp, ctx->mod); + n_poly_mod_divexact(Abarevalp, Aevalp, Gevalp, ctx->mod); + n_poly_mod_divexact(Bbarevalp, Bevalp, Gevalp, ctx->mod); n_poly_mod_gcd(Gevalm, Aevalm, Bevalm, ctx->mod); - n_poly_mod_div(Abarevalm, Aevalm, Gevalm, ctx->mod); - n_poly_mod_div(Bbarevalm, Bevalm, Gevalm, ctx->mod); + n_poly_mod_divexact(Abarevalm, Aevalm, Gevalm, ctx->mod); + n_poly_mod_divexact(Bbarevalm, Bevalm, Gevalm, ctx->mod); gstab = astab = bstab = 0; } @@ -412,8 +412,8 @@ int nmod_mpolyn_gcd_brown_smprime( n_poly_mod_gcd(cG, cA, cB, ctx->mod); - n_poly_mod_div(cAbar, cA, cG, ctx->mod); - n_poly_mod_div(cBbar, cB, cG, ctx->mod); + n_poly_mod_divexact(cAbar, cA, cG, ctx->mod); + n_poly_mod_divexact(cBbar, cB, cG, ctx->mod); n_poly_mod_gcd(gamma, nmod_mpolyn_leadcoeff_poly(A, ctx), nmod_mpolyn_leadcoeff_poly(B, ctx), ctx->mod); @@ -739,8 +739,8 @@ int nmod_mpolyn_gcd_brown_lgprime_bivar( n_poly_init(cAbar); n_poly_init(cBbar); - n_poly_mod_div(cAbar, cA, cG, ctx->mod); - n_poly_mod_div(cBbar, cB, cG, ctx->mod); + n_poly_mod_divexact(cAbar, cA, cG, ctx->mod); + n_poly_mod_divexact(cBbar, cB, cG, ctx->mod); n_poly_init(gamma); n_poly_mod_gcd(gamma, nmod_mpolyn_leadcoeff_poly(A, ctx), @@ -983,8 +983,8 @@ int nmod_mpolyn_gcd_brown_lgprime( n_poly_init(cAbar); n_poly_init(cBbar); - n_poly_mod_div(cAbar, cA, cG, ctx->mod); - n_poly_mod_div(cBbar, cB, cG, ctx->mod); + n_poly_mod_divexact(cAbar, cA, cG, ctx->mod); + n_poly_mod_divexact(cBbar, cB, cG, ctx->mod); n_poly_init(gamma); n_poly_mod_gcd(gamma, nmod_mpolyn_leadcoeff_poly(A, ctx), diff --git a/src/nmod_mpoly/mpolyu_gcdp_zippel.c b/src/nmod_mpoly/mpolyu_gcdp_zippel.c index 4099dbbb48..35aaa91920 100644 --- a/src/nmod_mpoly/mpolyu_gcdp_zippel.c +++ b/src/nmod_mpoly/mpolyu_gcdp_zippel.c @@ -628,9 +628,9 @@ static int nmod_mpolyu_gcdp_zippel_univar( nmod_mpolyu_cvtto_poly(b, B, ctx); nmod_poly_gcd(g, a, b); nmod_mpolyu_cvtfrom_poly(G, g, ctx); - nmod_poly_div(t, a, g); + nmod_poly_divexact(t, a, g); nmod_mpolyu_cvtfrom_poly(Abar, t, ctx); - nmod_poly_div(t, b, g); + nmod_poly_divexact(t, b, g); nmod_mpolyu_cvtfrom_poly(Bbar, t, ctx); nmod_poly_clear(a); nmod_poly_clear(b); diff --git a/src/nmod_mpoly_factor/lcc_wang.c b/src/nmod_mpoly_factor/lcc_wang.c index 429655afb2..ffdb84b64f 100644 --- a/src/nmod_mpoly_factor/lcc_wang.c +++ b/src/nmod_mpoly_factor/lcc_wang.c @@ -88,7 +88,7 @@ int nmod_mpoly_factor_lcc_wang( while (n_poly_degree(R) > 0) { n_poly_mod_gcd(R, R, Q, ctx->mod); - n_poly_mod_div(Q, Q, R, ctx->mod); + n_poly_mod_divexact(Q, Q, R, ctx->mod); if (n_poly_degree(Q) < 1) { success = 0; diff --git a/src/nmod_mpoly_factor/n_bpoly_mod_factor_smprime.c b/src/nmod_mpoly_factor/n_bpoly_mod_factor_smprime.c index 43e52cd973..3b02a10afa 100644 --- a/src/nmod_mpoly_factor/n_bpoly_mod_factor_smprime.c +++ b/src/nmod_mpoly_factor/n_bpoly_mod_factor_smprime.c @@ -437,7 +437,7 @@ static void _n_bpoly_mod_lift_build_steps(n_bpoly_mod_lift_t L, nmod_t ctx) for (k = 0; k < r; k++) { /* s[k] = (prod_{i!=k} B[i].coeffs[0])^-1 (mod B[k].coeffs[0]) */ - n_poly_mod_div(t, A->coeffs + 0, B[k].coeffs + 0, ctx); + n_poly_mod_divexact(t, A->coeffs + 0, B[k].coeffs + 0, ctx); if (!n_poly_mod_invmod(s + k, t, B[k].coeffs + 0, ctx)) flint_throw(FLINT_IMPINV, "n_bpoly_mod_lift: bad inverse"); diff --git a/src/nmod_mpoly_factor/n_bpoly_mod_hlift.c b/src/nmod_mpoly_factor/n_bpoly_mod_hlift.c index b4fc4da71a..31d5846204 100644 --- a/src/nmod_mpoly_factor/n_bpoly_mod_hlift.c +++ b/src/nmod_mpoly_factor/n_bpoly_mod_hlift.c @@ -140,7 +140,7 @@ int n_bpoly_mod_hlift2_cubic( n_poly_mod_rem(u, t, B0->coeffs + 0, ctx); n_poly_mod_mul(t, u, B1->coeffs + 0, ctx); n_poly_mod_sub(c, c, t, ctx); - n_poly_mod_div(v, c, B0->coeffs + 0, ctx); + n_poly_mod_divexact(v, c, B0->coeffs + 0, ctx); if (!n_poly_is_zero(u)) { @@ -275,7 +275,7 @@ int n_bpoly_mod_hlift2( n_poly_mod_rem(u, t, B0->coeffs + 0, ctx); n_poly_mod_mul(t, u, B1->coeffs + 0, ctx); n_poly_mod_sub(c, c, t, ctx); - n_poly_mod_div(v, c, B0->coeffs + 0, ctx); + n_poly_mod_divexact(v, c, B0->coeffs + 0, ctx); if (j < B0->length) n_poly_mod_add(B0->coeffs + j, B0->coeffs + j, u, ctx); @@ -430,7 +430,7 @@ int n_bpoly_mod_hlift_cubic( for (k = 0; k < r; k++) { /* s[k] = (prod_{i!=k} B[i].coeffs[0])^-1 (mod B[k].coeffs[0]) */ - n_poly_mod_div(t, A->coeffs + 0, B[k].coeffs + 0, ctx); + n_poly_mod_divexact(t, A->coeffs + 0, B[k].coeffs + 0, ctx); if (!n_poly_mod_invmod(s[k], t, B[k].coeffs + 0, ctx)) { success = -1; diff --git a/src/nmod_mpoly_factor/n_bpoly_mod_pfrac.c b/src/nmod_mpoly_factor/n_bpoly_mod_pfrac.c index 63ea102fb0..39c488e757 100644 --- a/src/nmod_mpoly_factor/n_bpoly_mod_pfrac.c +++ b/src/nmod_mpoly_factor/n_bpoly_mod_pfrac.c @@ -116,7 +116,7 @@ int n_bpoly_mod_pfrac2( _n_poly_mod_rem(C1evalp, t2, B1evalp, mod); _n_poly_mod_mul(t2, B2evalp, C1evalp, mod); n_poly_mod_sub(Aevalp, Aevalp, t2, mod); - _n_poly_mod_div(C2evalp, Aevalp, B1evalp, mod); + _n_poly_mod_divexact(C2evalp, Aevalp, B1evalp, mod); if (!n_poly_mod_invmod(t1, B2evalm, B1evalm, mod)) goto bad_prime; @@ -124,7 +124,7 @@ int n_bpoly_mod_pfrac2( _n_poly_mod_rem(C1evalm, t2, B1evalm, mod); _n_poly_mod_mul(t2, B2evalm, C1evalm, mod); n_poly_mod_sub(Aevalm, Aevalm, t2, mod); - _n_poly_mod_div(C2evalm, Aevalm, B1evalm, mod); + _n_poly_mod_divexact(C2evalm, Aevalm, B1evalm, mod); /* update interpolants */ if (n_poly_degree(modulus) > 0) diff --git a/src/nmod_poly.h b/src/nmod_poly.h index 13668faa23..dac1d99b70 100644 --- a/src/nmod_poly.h +++ b/src/nmod_poly.h @@ -603,6 +603,13 @@ void _nmod_poly_rem(mp_ptr R, mp_srcptr A, slong lenA, void nmod_poly_rem(nmod_poly_t R, const nmod_poly_t A, const nmod_poly_t B); +void _nmod_poly_divexact(mp_ptr Q, mp_srcptr A, slong lenA, + mp_srcptr B, slong lenB, nmod_t mod); + +void nmod_poly_divexact(nmod_poly_t Q, + const nmod_poly_t A, const nmod_poly_t B); + + void _nmod_poly_inv_series_basecase(mp_ptr Qinv, mp_srcptr Q, slong Qlen, slong n, nmod_t mod); diff --git a/src/nmod_poly/divexact.c b/src/nmod_poly/divexact.c new file mode 100644 index 0000000000..55cdf1e6af --- /dev/null +++ b/src/nmod_poly/divexact.c @@ -0,0 +1,89 @@ +/* + Copyright (C) 2010 Sebastian Pancratz + Copyright (C) 2011 William Hart + Copyright (C) 2023, 2024 Fredrik Johansson + + 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 "nmod.h" +#include "nmod_vec.h" +#include "nmod_poly.h" +#include "gr_poly.h" + +void +_nmod_poly_divexact(mp_ptr Q, mp_srcptr A, slong lenA, mp_srcptr B, slong lenB, nmod_t mod) +{ + if (lenA == lenB) + { + Q[0] = nmod_div(A[lenA - 1], B[lenB - 1], mod); + } + else if (lenB == 1) + { + _nmod_vec_scalar_mul_nmod(Q, A, lenA, nmod_inv(B[0], mod), mod); + } + else + { + gr_ctx_t ctx; + _gr_ctx_init_nmod(ctx, &mod); + GR_MUST_SUCCEED(_gr_poly_divexact(Q, A, lenA, B, lenB, ctx)); + } +} + +void +nmod_poly_divexact(nmod_poly_t Q, + const nmod_poly_t A, const nmod_poly_t B) +{ + nmod_poly_t tQ; + mp_ptr q; + slong A_len, B_len; + + B_len = B->length; + + if (B_len == 0) + { + if (nmod_poly_modulus(B) == 1) + { + nmod_poly_set(Q, A); + return; + } + else + { + flint_throw(FLINT_ERROR, "Exception (nmod_poly_divexact). Division by zero.\n"); + } + } + + A_len = A->length; + + if (A_len < B_len) + { + nmod_poly_zero(Q); + return; + } + + if (Q == A || Q == B) + { + nmod_poly_init2(tQ, A->mod.n, A_len - B_len + 1); + q = tQ->coeffs; + } + else + { + nmod_poly_fit_length(Q, A_len - B_len + 1); + q = Q->coeffs; + } + + _nmod_poly_divexact(q, A->coeffs, A_len, B->coeffs, B_len, A->mod); + + if (Q == A || Q == B) + { + nmod_poly_swap(tQ, Q); + nmod_poly_clear(tQ); + } + + Q->length = A_len - B_len + 1; +} diff --git a/src/nmod_poly/find_distinct_nonzero_roots.c b/src/nmod_poly/find_distinct_nonzero_roots.c index 7ed8a88e77..810c65b8f1 100644 --- a/src/nmod_poly/find_distinct_nonzero_roots.c +++ b/src/nmod_poly/find_distinct_nonzero_roots.c @@ -42,7 +42,7 @@ void _nmod_poly_split_rabin( goto try_again; } - nmod_poly_div(b, f, a); + nmod_poly_divexact(b, f, a); /* deg a >= deg b */ if (nmod_poly_degree(a) < nmod_poly_degree(b)) diff --git a/src/nmod_poly/test/main.c b/src/nmod_poly/test/main.c index 9e9704e519..86a91c45c7 100644 --- a/src/nmod_poly/test/main.c +++ b/src/nmod_poly/test/main.c @@ -40,6 +40,7 @@ #include "t-derivative.c" #include "t-discriminant.c" #include "t-div.c" +#include "t-divexact.c" #include "t-divides.c" #include "t-divides_classical.c" #include "t-div_newton_n_preinv.c" @@ -163,6 +164,7 @@ test_struct tests[] = TEST_FUNCTION(nmod_poly_derivative), TEST_FUNCTION(nmod_poly_discriminant), TEST_FUNCTION(nmod_poly_div), + TEST_FUNCTION(nmod_poly_divexact), TEST_FUNCTION(nmod_poly_divides), TEST_FUNCTION(nmod_poly_divides_classical), TEST_FUNCTION(nmod_poly_div_newton_n_preinv), diff --git a/src/nmod_poly/test/t-divexact.c b/src/nmod_poly/test/t-divexact.c new file mode 100644 index 0000000000..3d99af6b09 --- /dev/null +++ b/src/nmod_poly/test/t-divexact.c @@ -0,0 +1,77 @@ +/* + Copyright (C) 2011 William Hart + Copyright (C) 2024 Fredrik Johansson + + 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 "test_helpers.h" +#include "ulong_extras.h" +#include "nmod_poly.h" + +TEST_FUNCTION_START(nmod_poly_divexact, state) +{ + int i, result; + + for (i = 0; i < 100 * flint_test_multiplier(); i++) + { + nmod_poly_t a, b, ab, q; + int aliasing; + + mp_limb_t n; + do n = n_randtest_not_zero(state); + while (!n_is_probabprime(n)); + + nmod_poly_init(a, n); + nmod_poly_init(b, n); + nmod_poly_init(ab, n); + nmod_poly_init(q, n); + + nmod_poly_randtest(a, state, n_randint(state, 400)); + do nmod_poly_randtest(b, state, n_randint(state, 400)); + while (b->length == 0); + + nmod_poly_mul(ab, a, b); + + aliasing = n_randint(state, 3); + + switch (aliasing) + { + case 0: + nmod_poly_divexact(q, ab, b); + break; + case 1: + nmod_poly_set(q, ab); + nmod_poly_divexact(q, q, b); + break; + default: + nmod_poly_set(q, b); + nmod_poly_divexact(q, ab, q); + break; + } + + result = (nmod_poly_equal(q, a)); + if (!result) + { + flint_printf("FAIL:\n"); + nmod_poly_print(a), flint_printf("\n\n"); + nmod_poly_print(b), flint_printf("\n\n"); + nmod_poly_print(q), flint_printf("\n\n"); + flint_printf("n = %wd\n", n); + fflush(stdout); + flint_abort(); + } + + nmod_poly_clear(a); + nmod_poly_clear(b); + nmod_poly_clear(ab); + nmod_poly_clear(q); + } + + TEST_FUNCTION_END(state); +} diff --git a/src/nmod_poly_factor/factor_berlekamp.c b/src/nmod_poly_factor/factor_berlekamp.c index f4882a5b12..098a80da71 100644 --- a/src/nmod_poly_factor/factor_berlekamp.c +++ b/src/nmod_poly_factor/factor_berlekamp.c @@ -210,7 +210,7 @@ __nmod_poly_factor_berlekamp(nmod_poly_factor_t factors, nmod_poly_init_mod(Q, f->mod); - nmod_poly_div(Q, f, g); + nmod_poly_divexact(Q, f, g); if (!nmod_poly_is_zero(Q)) nmod_poly_make_monic(Q, Q); diff --git a/src/nmod_poly_factor/factor_equal_deg.c b/src/nmod_poly_factor/factor_equal_deg.c index b2e63d3ce4..e6300aa2b4 100644 --- a/src/nmod_poly_factor/factor_equal_deg.c +++ b/src/nmod_poly_factor/factor_equal_deg.c @@ -38,7 +38,7 @@ nmod_poly_factor_equal_deg(nmod_poly_factor_t factors, flint_randclear(state); nmod_poly_init_mod(g, pol->mod); - nmod_poly_div(g, pol, f); + nmod_poly_divexact(g, pol, f); nmod_poly_factor_equal_deg(factors, f, d); nmod_poly_clear(f); diff --git a/src/nmod_poly_factor/factor_squarefree.c b/src/nmod_poly_factor/factor_squarefree.c index 704e799e7c..e5a041bd25 100644 --- a/src/nmod_poly_factor/factor_squarefree.c +++ b/src/nmod_poly_factor/factor_squarefree.c @@ -76,7 +76,7 @@ nmod_poly_factor_squarefree(nmod_poly_factor_t res, const nmod_poly_t f) nmod_poly_t h, z; nmod_poly_gcd(g, f, f_d); - nmod_poly_div(g_1, f, g); + nmod_poly_divexact(g_1, f, g); i = 1; @@ -87,7 +87,7 @@ nmod_poly_factor_squarefree(nmod_poly_factor_t res, const nmod_poly_t f) while (!nmod_poly_is_one(g_1)) { nmod_poly_gcd(h, g_1, g); - nmod_poly_div(z, g_1, h); + nmod_poly_divexact(z, g_1, h); /* out <- out.z */ if (z->length > 1) @@ -101,7 +101,7 @@ nmod_poly_factor_squarefree(nmod_poly_factor_t res, const nmod_poly_t f) i++; nmod_poly_set(g_1, h); - nmod_poly_div(g, g, h); + nmod_poly_divexact(g, g, h); } nmod_poly_clear(h); diff --git a/src/nmod_poly_mat/fflu.c b/src/nmod_poly_mat/fflu.c index b9f29f775e..c81b161235 100644 --- a/src/nmod_poly_mat/fflu.c +++ b/src/nmod_poly_mat/fflu.c @@ -84,7 +84,7 @@ nmod_poly_mat_fflu(nmod_poly_mat_t B, nmod_poly_t den, slong * perm, nmod_poly_mul(t, E(j, pivot_col), E(pivot_row, k)); nmod_poly_sub(E(j, k), E(j, k), t); if (pivot_row > 0) - nmod_poly_div(E(j, k), E(j, k), den); + nmod_poly_divexact(E(j, k), E(j, k), den); } } diff --git a/src/nmod_poly_mat/rref.c b/src/nmod_poly_mat/rref.c index 2bb10ddf2e..811e9b6ab3 100644 --- a/src/nmod_poly_mat/rref.c +++ b/src/nmod_poly_mat/rref.c @@ -70,7 +70,7 @@ nmod_poly_mat_rref(nmod_poly_mat_t R, nmod_poly_t den, const nmod_poly_mat_t A) nmod_poly_sub(tmp, tmp, tmp2); } - nmod_poly_div(nmod_poly_mat_entry(R, i, nonpivots[k]), + nmod_poly_divexact(nmod_poly_mat_entry(R, i, nonpivots[k]), tmp, nmod_poly_mat_entry(R, i, pivots[i])); } } diff --git a/src/nmod_poly_mat/solve_fflu_precomp.c b/src/nmod_poly_mat/solve_fflu_precomp.c index 26bc9630ce..b5689cbc72 100644 --- a/src/nmod_poly_mat/solve_fflu_precomp.c +++ b/src/nmod_poly_mat/solve_fflu_precomp.c @@ -65,7 +65,7 @@ nmod_poly_mat_solve_fflu_precomp(nmod_poly_mat_t X, nmod_poly_mul(T, LU(j, i), XX(i, k)); nmod_poly_sub(XX(j, k), XX(j, k), T); if (i > 0) - nmod_poly_div(XX(j, k), XX(j, k), LU(i-1, i-1)); + nmod_poly_divexact(XX(j, k), XX(j, k), LU(i-1, i-1)); } } @@ -78,7 +78,7 @@ nmod_poly_mat_solve_fflu_precomp(nmod_poly_mat_t X, nmod_poly_mul(T, XX(j, k), LU(i, j)); nmod_poly_sub(XX(i, k), XX(i, k), T); } - nmod_poly_div(XX(i, k), XX(i, k), LU(i, i)); + nmod_poly_divexact(XX(i, k), XX(i, k), LU(i, i)); } }