Skip to content

Commit 4c78014

Browse files
Merge pull request #2702 from fredrik-johansson/divlowsmodp
Base fmpz_poly_div[low/high]_smodp on _fmpz_mod_poly_div_series
2 parents c5d8cf0 + 7b72a57 commit 4c78014

6 files changed

Lines changed: 120 additions & 87 deletions

File tree

doc/source/fmpz_mod_vec.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ Conversions
1111
Set the `fmpz_mod_vec` `(A, len)` to the `fmpz_vec` `(B, len)` after
1212
reduction of each entry modulo the modulus..
1313

14+
.. function:: void _fmpz_mod_vec_get_fmpz_vec_smod(fmpz * res, const fmpz * vec, slong len, const fmpz_mod_ctx_t ctx)
15+
16+
Given `(vec, len)` of residues in `[0, n)`, set `(res, len)` to the symmetric
17+
residues in `(-n/2, n/2]`. This is equivalent to applying
18+
:func:`_fmpz_vec_scalar_smod_fmpz` but optimized for the case where
19+
the input vector is known to be reduced mod `n` ahead of time.
20+
1421
Arithmetic
1522
--------------------------------------------------------------------------------
1623

src/fmpz_mod_vec.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ extern "C" {
2828
void _fmpz_mod_vec_set_fmpz_vec(fmpz * A, const fmpz * B, slong len,
2929
const fmpz_mod_ctx_t ctx);
3030

31+
void _fmpz_mod_vec_get_fmpz_vec_smod(fmpz * res, const fmpz * vec, slong len,
32+
const fmpz_mod_ctx_t ctx);
33+
3134
void _fmpz_mod_vec_neg(fmpz * A, const fmpz * B, slong len,
3235
const fmpz_mod_ctx_t ctx);
3336

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
Copyright (C) 2026 Fredrik Johansson
3+
4+
This file is part of FLINT.
5+
6+
FLINT is free software: you can redistribute it and/or modify it under
7+
the terms of the GNU Lesser General Public License (LGPL) as published
8+
by the Free Software Foundation; either version 3 of the License, or
9+
(at your option) any later version. See <https://www.gnu.org/licenses/>.
10+
*/
11+
#include "fmpz.h"
12+
#include "fmpz_mod.h"
13+
#include "fmpz_mod_vec.h"
14+
15+
void _fmpz_mod_vec_get_fmpz_vec_smod(fmpz * res, const fmpz * vec, slong len, const fmpz_mod_ctx_t ctx)
16+
{
17+
const fmpz * p = fmpz_mod_ctx_modulus(ctx);
18+
fmpz_t phalf;
19+
slong i;
20+
21+
fmpz_init(phalf);
22+
fmpz_fdiv_q_2exp(phalf, p, 1);
23+
24+
for (i = 0; i < len; i++)
25+
{
26+
if (fmpz_cmp(vec + i, phalf) > 0)
27+
fmpz_sub(res + i, vec + i, p);
28+
else
29+
fmpz_set(res + i, vec + i);
30+
}
31+
32+
fmpz_clear(phalf);
33+
}

src/fmpz_poly/divhigh_smodp.c

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
Copyright (C) 2016 William Hart
3+
Copyright (C) 2026 Fredrik Johansson
34
45
This file is part of FLINT.
56
@@ -12,43 +13,43 @@
1213
#include "fmpz.h"
1314
#include "fmpz_vec.h"
1415
#include "fmpz_poly.h"
16+
#include "fmpz_mod.h"
17+
#include "fmpz_mod_vec.h"
18+
#include "fmpz_mod_poly.h"
1519

1620
void fmpz_poly_divhigh_smodp(fmpz * res, const fmpz_poly_t f,
17-
const fmpz_poly_t g, const fmpz_t p, slong n)
21+
const fmpz_poly_t g, const fmpz_t p, slong n)
1822
{
19-
fmpz_t d, cinv;
20-
slong i = 0, k, start = 0, len_g = g->length;
21-
fmpz_poly_t tf;
22-
23-
fmpz_init(d);
24-
fmpz_init(cinv);
25-
26-
fmpz_poly_init2(tf, f->length);
27-
28-
fmpz_poly_set(tf, f);
29-
30-
fmpz_gcdinv(d, cinv, g->coeffs + len_g - 1, p);
31-
if (!fmpz_is_one(d))
32-
{
33-
flint_throw(FLINT_ERROR, "Exception (fmpz_poly_divhigh_smodp). Impossible inverse.\n");
34-
}
35-
36-
for (k = n - 1, i = f->length - len_g; k >= 0; i--, k--)
37-
{
38-
if (i < f->length - n)
39-
start++;
40-
41-
fmpz_mul(res + k, tf->coeffs + i + len_g - 1, cinv);
42-
43-
fmpz_smod(res + k, res + k, p);
44-
45-
_fmpz_vec_scalar_submul_fmpz(tf->coeffs + i + start,
46-
g->coeffs + start, len_g - start, res + k);
47-
_fmpz_vec_scalar_smod_fmpz(tf->coeffs + i + start,
48-
tf->coeffs + i + start, len_g - start, p);
49-
}
50-
51-
fmpz_poly_clear(tf);
52-
fmpz_clear(cinv);
53-
fmpz_clear(d);
23+
fmpz_mod_ctx_t ctx;
24+
fmpz *tA, *tB;
25+
slong glen, flen, Alen, Blen;
26+
27+
glen = g->length;
28+
flen = f->length;
29+
Blen = FLINT_MIN(glen, n);
30+
Alen = FLINT_MIN(flen, n);
31+
32+
if (Alen == 0)
33+
{
34+
_fmpz_vec_zero(res, n);
35+
return;
36+
}
37+
38+
fmpz_mod_ctx_init(ctx, p);
39+
tA = _fmpz_vec_init(Alen);
40+
tB = _fmpz_vec_init(Blen);
41+
42+
_fmpz_mod_vec_set_fmpz_vec(tA, f->coeffs + (flen - Alen), Alen, ctx);
43+
_fmpz_poly_reverse(tA, tA, Alen, Alen);
44+
_fmpz_mod_vec_set_fmpz_vec(tB, g->coeffs + (glen - Blen), Blen, ctx);
45+
_fmpz_poly_reverse(tB, tB, Blen, Blen);
46+
47+
_fmpz_mod_poly_div_series(res, tA, Alen, tB, Blen, n, ctx);
48+
_fmpz_poly_reverse(res, res, n, n);
49+
_fmpz_mod_vec_get_fmpz_vec_smod(res, res, n, ctx);
50+
51+
_fmpz_vec_clear(tA, Alen);
52+
_fmpz_vec_clear(tB, Blen);
53+
fmpz_mod_ctx_clear(ctx);
5454
}
55+

src/fmpz_poly/divlow_smodp.c

Lines changed: 37 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
Copyright (C) 2016 William Hart
3+
Copyright (C) 2026 Fredrik Johansson
34
45
This file is part of FLINT.
56
@@ -12,58 +13,43 @@
1213
#include "fmpz.h"
1314
#include "fmpz_vec.h"
1415
#include "fmpz_poly.h"
16+
#include "fmpz_mod.h"
17+
#include "fmpz_mod_vec.h"
18+
#include "fmpz_mod_poly.h"
1519

1620
void fmpz_poly_divlow_smodp(fmpz * res, const fmpz_poly_t f,
17-
const fmpz_poly_t g, const fmpz_t p, slong n)
21+
const fmpz_poly_t g, const fmpz_t p, slong n)
1822
{
19-
fmpz_t d, cinv;
20-
slong i = 0, k, zeroes;
21-
fmpz_poly_t tf;
22-
23-
fmpz_init(d);
24-
fmpz_init(cinv);
25-
26-
while (fmpz_is_zero(g->coeffs + i))
27-
i++;
28-
29-
zeroes = i;
30-
31-
fmpz_poly_init2(tf, n + zeroes);
32-
33-
fmpz_poly_set(tf, f);
34-
35-
if (fmpz_sgn(g->coeffs + zeroes) >= 0)
36-
fmpz_gcdinv(d, cinv, g->coeffs + zeroes, p);
37-
else
38-
{
39-
fmpz_t temp;
40-
41-
fmpz_init(temp);
42-
43-
fmpz_add(temp, g->coeffs + zeroes, p);
44-
fmpz_gcdinv(d, cinv, temp, p);
45-
46-
fmpz_clear(temp);
47-
}
48-
49-
if (!fmpz_is_one(d))
50-
{
51-
flint_throw(FLINT_ERROR, "Exception (fmpz_poly_divlow_smodp). Impossible inverse.\n");
52-
}
53-
54-
for (k = 0; k < n; i++, k++)
55-
{
56-
fmpz_mul(res + k, tf->coeffs + i, cinv);
57-
58-
fmpz_smod(res + k, res + k, p);
59-
60-
_fmpz_vec_scalar_submul_fmpz(tf->coeffs + i, g->coeffs + zeroes,
61-
FLINT_MIN(g->length - zeroes, n - k), res + k);
62-
_fmpz_vec_scalar_smod_fmpz(tf->coeffs + i, tf->coeffs + i,
63-
FLINT_MIN(g->length - zeroes, n - k), p);
64-
}
65-
66-
fmpz_poly_clear(tf);
67-
fmpz_clear(cinv);
68-
fmpz_clear(d);
23+
fmpz_mod_ctx_t ctx;
24+
fmpz *tA, *tB;
25+
slong zeroes, glen, flen, Alen, Blen;
26+
27+
zeroes = 0;
28+
while (fmpz_is_zero(g->coeffs + zeroes))
29+
zeroes++;
30+
31+
flen = f->length - zeroes;
32+
glen = g->length - zeroes;
33+
Alen = FLINT_MAX(0, FLINT_MIN(flen, n));
34+
Blen = FLINT_MIN(glen, n);
35+
36+
if (Alen == 0)
37+
{
38+
_fmpz_vec_zero(res, n);
39+
return;
40+
}
41+
42+
fmpz_mod_ctx_init(ctx, p);
43+
tA = _fmpz_vec_init(Alen);
44+
tB = _fmpz_vec_init(Blen);
45+
46+
_fmpz_mod_vec_set_fmpz_vec(tA, f->coeffs + zeroes, Alen, ctx);
47+
_fmpz_mod_vec_set_fmpz_vec(tB, g->coeffs + zeroes, Blen, ctx);
48+
_fmpz_mod_poly_div_series(res, tA, Alen, tB, Blen, n, ctx);
49+
_fmpz_mod_vec_get_fmpz_vec_smod(res, res, n, ctx);
50+
51+
_fmpz_vec_clear(tA, Alen);
52+
_fmpz_vec_clear(tB, Blen);
53+
fmpz_mod_ctx_clear(ctx);
6954
}
55+

src/fmpz_poly/test/t-divlow_smodp.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ TEST_FUNCTION_START(fmpz_poly_divlow_smodp, state)
6363
}
6464
} while (b->length < 2 || !fmpz_is_one(d1) || !fmpz_is_one(d2));
6565

66+
/* Test with some leading zeros */
67+
fmpz_poly_shift_left(b, b, n_randint(state, 3));
68+
6669
fmpz_poly_mul(c, a, b);
6770

6871
fmpz_poly_scalar_mod_fmpz(d, b, P);

0 commit comments

Comments
 (0)