Skip to content

Commit 56accbc

Browse files
Middle products for fmpz_mod_poly, mpn_mod_poly
1 parent d88503f commit 56accbc

21 files changed

+519
-54
lines changed

doc/source/fmpz_mod_poly.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,20 @@ Multiplication
495495
Sets ``res`` to the lowest `n` coefficients of the product of
496496
``poly1`` and ``poly2``.
497497

498+
.. function:: void _fmpz_mod_poly_mulmid(fmpz * res, const fmpz * poly1, slong len1, const fmpz * poly2, slong len2, slong nlo, slong nhi, const fmpz_mod_ctx_t ctx)
499+
500+
Sets ``(res, nhi - nlo)`` to the coefficients at indices `[nlo, nhi)`
501+
in the full product of ``(poly1, len1)`` and ``(poly2, len2)``.
502+
Assumes that ``len1`` and ``len2`` are positive and that
503+
`0 \le nlo < nhi \le len1 + len2 - 1`.
504+
Does not support aliasing between the inputs and the output.
505+
506+
.. function:: void fmpz_mod_poly_mulmid(fmpz_mod_poly_t res, const fmpz_mod_poly_t poly1, const fmpz_mod_poly_t poly2, slong nlo, slong nhi, const fmpz_mod_ctx_t ctx)
507+
508+
Sets ``res`` to the polynomial formed by the coefficients at indices `[nlo, nhi)`
509+
in the product of ``poly1`` and ``poly2``. Equivalently, compute
510+
`[(poly1 \cdot poly2) \bmod x^{nhi}] / x^{nlo}`.
511+
498512
.. function:: void _fmpz_mod_poly_sqr(fmpz * res, const fmpz * poly, slong len, const fmpz_mod_ctx_t ctx)
499513

500514
Sets ``res`` to the square of ``poly``.

doc/source/mpn_mod.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,34 +227,40 @@ Multiplication
227227
All multiplication algorithms optimize for squaring.
228228

229229
.. function:: int _mpn_mod_poly_mullow_classical(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong len, gr_ctx_t ctx)
230+
int _mpn_mod_poly_mulmid_classical(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong nlo, slong nhi, gr_ctx_t ctx)
230231

231232
Polynomial multiplication using the schoolbook algorithm.
232233

233234
.. function:: int _mpn_mod_poly_mullow_KS(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong len, gr_ctx_t ctx)
235+
int _mpn_mod_poly_mulmid_KS(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong nlo, slong nhi, gr_ctx_t ctx)
234236

235237
Polynomial multiplication using Kronecker substitution (bit packing).
236238

237239
.. function:: int _mpn_mod_poly_mullow_karatsuba(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong len, slong cutoff, gr_ctx_t ctx)
240+
int _mpn_mod_poly_mulmid_karatsuba(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong nlo, slong nhi, slong cutoff, gr_ctx_t ctx)
238241

239242
Polynomial multiplication using the Karatsuba algorithm,
240243
implemented without intermediate modular reductions.
241244
This algorithm calls itself recursively, switching to
242245
basecase multiplication (also without intermediate reductions)
243246
when either *len1* or *len2* is smaller than *cutoff*.
244247

245-
Currently a full product is computed internally regardless of *len*;
246-
truncation only skips the modular reductions.
248+
Currently a full product is computed internally regardless of the
249+
output length; truncation only skips the modular reductions.
247250

248251
.. function:: int _mpn_mod_poly_mullow_fft_small(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong len, gr_ctx_t ctx)
252+
int _mpn_mod_poly_mulmid_fft_small(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong nlo, slong nhi, gr_ctx_t ctx)
249253

250254
Polynomial multiplication using the small-prime FFT.
251255
Returns ``GR_UNABLE`` if the small-prime FFT is not available
252256
or if the coefficients are too large to use this implementation.
253257

254258
.. function:: int _mpn_mod_poly_mullow(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong len, gr_ctx_t ctx)
259+
int _mpn_mod_poly_mulmid(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong nlo, slong nhi, gr_ctx_t ctx)
255260

256261
Polynomial multiplication with automatic algorithm selection.
257262

263+
258264
Division
259265
..............
260266

src/fmpz_mod_poly.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ void fmpz_mod_poly_mul(fmpz_mod_poly_t res, const fmpz_mod_poly_t poly1, const f
310310
void _fmpz_mod_poly_mullow(fmpz *res, const fmpz *poly1, slong len1, const fmpz *poly2, slong len2, slong n, const fmpz_mod_ctx_t ctx);
311311
void fmpz_mod_poly_mullow(fmpz_mod_poly_t res, const fmpz_mod_poly_t poly1, const fmpz_mod_poly_t poly2, slong n, const fmpz_mod_ctx_t ctx);
312312

313+
void _fmpz_mod_poly_mulmid(fmpz *res, const fmpz *poly1, slong len1, const fmpz *poly2, slong len2, slong nlo, slong nhi, const fmpz_mod_ctx_t ctx);
314+
void fmpz_mod_poly_mulmid(fmpz_mod_poly_t res, const fmpz_mod_poly_t poly1, const fmpz_mod_poly_t poly2, slong nlo, slong nhi, const fmpz_mod_ctx_t ctx);
315+
313316
void _fmpz_mod_poly_sqr(fmpz *res, const fmpz *poly, slong len, const fmpz_mod_ctx_t ctx);
314317

315318
void fmpz_mod_poly_mulhigh(fmpz_mod_poly_t res, const fmpz_mod_poly_t poly1, const fmpz_mod_poly_t poly2, slong start, const fmpz_mod_ctx_t ctx);

src/fmpz_mod_poly/mulmid.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
Copyright (C) 2011 Sebastian Pancratz
3+
Copyright (C) 2010 William Hart
4+
Copyright (C) 2026 Fredrik Johansson
5+
6+
This file is part of FLINT.
7+
8+
FLINT is free software: you can redistribute it and/or modify it under
9+
the terms of the GNU Lesser General Public License (LGPL) as published
10+
by the Free Software Foundation; either version 3 of the License, or
11+
(at your option) any later version. See <https://www.gnu.org/licenses/>.
12+
*/
13+
14+
#include "fmpz_vec.h"
15+
#include "fmpz_poly.h"
16+
#include "fmpz_mod.h"
17+
#include "fmpz_mod_vec.h"
18+
#include "fmpz_mod_poly.h"
19+
20+
void _fmpz_mod_poly_mulmid(fmpz *res, const fmpz *poly1, slong len1,
21+
const fmpz *poly2, slong len2,
22+
slong nlo, slong nhi, const fmpz_mod_ctx_t ctx)
23+
{
24+
_fmpz_poly_mulmid(res, poly1, len1, poly2, len2, nlo, nhi);
25+
_fmpz_mod_vec_set_fmpz_vec(res, res, nhi - nlo, ctx);
26+
}
27+
28+
void fmpz_mod_poly_mulmid(fmpz_mod_poly_t res, const fmpz_mod_poly_t poly1,
29+
const fmpz_mod_poly_t poly2, slong nlo, slong nhi, const fmpz_mod_ctx_t ctx)
30+
{
31+
slong len1 = poly1->length;
32+
slong len2 = poly2->length;
33+
slong len;
34+
35+
FLINT_ASSERT(nlo >= 0);
36+
FLINT_ASSERT(nhi >= 0);
37+
38+
if (len1 == 0 || len2 == 0 || nlo >= FLINT_MIN(nhi, len1 + len2 - 1))
39+
{
40+
fmpz_mod_poly_zero(res, ctx);
41+
return;
42+
}
43+
44+
nhi = FLINT_MIN(nhi, len1 + len2 - 1);
45+
len = nhi - nlo;
46+
47+
if ((res == poly1) || (res == poly2))
48+
{
49+
fmpz *t = _fmpz_vec_init(len);
50+
_fmpz_mod_poly_mulmid(t, poly1->coeffs, len1, poly2->coeffs, len2, nlo, nhi, ctx);
51+
_fmpz_vec_clear(res->coeffs, res->alloc);
52+
res->coeffs = t;
53+
res->alloc = len;
54+
res->length = len;
55+
_fmpz_mod_poly_normalise(res);
56+
}
57+
else
58+
{
59+
fmpz_mod_poly_fit_length(res, len, ctx);
60+
_fmpz_mod_poly_mulmid(res->coeffs, poly1->coeffs, len1, poly2->coeffs, len2, nlo, nhi, ctx);
61+
_fmpz_mod_poly_set_length(res, len);
62+
_fmpz_mod_poly_normalise(res);
63+
}
64+
}

src/fmpz_mod_poly/test/main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
#include "t-mul.c"
6464
#include "t-mulhigh.c"
6565
#include "t-mullow.c"
66+
#include "t-mulmid.c"
6667
#include "t-mulmod.c"
6768
#include "t-mulmod_preinv.c"
6869
#include "t-neg.c"
@@ -139,6 +140,7 @@ test_struct tests[] =
139140
TEST_FUNCTION(fmpz_mod_poly_mul),
140141
TEST_FUNCTION(fmpz_mod_poly_mulhigh),
141142
TEST_FUNCTION(fmpz_mod_poly_mullow),
143+
TEST_FUNCTION(fmpz_mod_poly_mulmid),
142144
TEST_FUNCTION(fmpz_mod_poly_mulmod),
143145
TEST_FUNCTION(fmpz_mod_poly_mulmod_preinv),
144146
TEST_FUNCTION(fmpz_mod_poly_neg),

src/fmpz_mod_poly/test/t-mulmid.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
Copyright (C) 2009 William Hart
3+
Copyright (C) 2011 Sebastian Pancratz
4+
5+
This file is part of FLINT.
6+
7+
FLINT is free software: you can redistribute it and/or modify it under
8+
the terms of the GNU Lesser General Public License (LGPL) as published
9+
by the Free Software Foundation; either version 3 of the License, or
10+
(at your option) any later version. See <https://www.gnu.org/licenses/>.
11+
*/
12+
13+
#include "test_helpers.h"
14+
#include "fmpz.h"
15+
#include "fmpz_mod.h"
16+
#include "fmpz_mod_poly.h"
17+
18+
TEST_FUNCTION_START(fmpz_mod_poly_mulmid, state)
19+
{
20+
int i, result;
21+
fmpz_mod_ctx_t ctx;
22+
23+
fmpz_mod_ctx_init_ui(ctx, 2);
24+
25+
/* Compare with mullow */
26+
for (i = 0; i < 200 * flint_test_multiplier(); i++)
27+
{
28+
fmpz_t p;
29+
fmpz_mod_poly_t a, b, c;
30+
slong nlo, nhi;
31+
32+
fmpz_init(p);
33+
fmpz_randtest_unsigned(p, state, 2 * FLINT_BITS);
34+
fmpz_add_ui(p, p, 2);
35+
fmpz_mod_ctx_set_modulus(ctx, p);
36+
37+
fmpz_mod_poly_init(a, ctx);
38+
fmpz_mod_poly_init(b, ctx);
39+
fmpz_mod_poly_init(c, ctx);
40+
nlo = n_randint(state, 50);
41+
nhi = n_randint(state, 50);
42+
fmpz_mod_poly_randtest(b, state, 1 + n_randint(state, 50), ctx);
43+
fmpz_mod_poly_randtest(c, state, 1 + n_randint(state, 50), ctx);
44+
45+
if (n_randint(state, 2))
46+
{
47+
fmpz_mod_poly_set(a, b, ctx);
48+
fmpz_mod_poly_mulmid(a, a, c, nlo, nhi, ctx);
49+
}
50+
else if (n_randint(state, 2))
51+
{
52+
fmpz_mod_poly_set(a, c, ctx);
53+
fmpz_mod_poly_mulmid(a, b, a, nlo, nhi, ctx);
54+
}
55+
else
56+
{
57+
fmpz_mod_poly_mulmid(a, b, c, nlo, nhi, ctx);
58+
}
59+
60+
fmpz_mod_poly_mullow(b, b, c, nhi, ctx);
61+
fmpz_mod_poly_shift_right(b, b, nlo, ctx);
62+
63+
result = (fmpz_mod_poly_equal(a, b, ctx));
64+
if (!result)
65+
{
66+
flint_printf("FAIL:\n");
67+
fmpz_mod_poly_print(a, ctx), flint_printf("\n\n");
68+
fmpz_mod_poly_print(b, ctx), flint_printf("\n\n");
69+
fflush(stdout);
70+
flint_abort();
71+
}
72+
73+
fmpz_mod_poly_clear(a, ctx);
74+
fmpz_mod_poly_clear(b, ctx);
75+
fmpz_mod_poly_clear(c, ctx);
76+
fmpz_clear(p);
77+
}
78+
79+
fmpz_mod_ctx_clear(ctx);
80+
81+
TEST_FUNCTION_END(state);
82+
}

src/gr/fmpz_mod.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,20 @@ _gr_fmpz_mod_poly_mullow(fmpz * res,
554554
return GR_SUCCESS;
555555
}
556556

557+
static int
558+
_gr_fmpz_mod_poly_mulmid(fmpz * res,
559+
const fmpz * poly1, slong len1,
560+
const fmpz * poly2, slong len2, slong nlo, slong nhi, gr_ctx_t ctx)
561+
{
562+
if (len1 >= len2)
563+
_fmpz_mod_poly_mulmid(res, poly1, len1, poly2, len2, nlo, nhi, FMPZ_MOD_CTX(ctx));
564+
else
565+
_fmpz_mod_poly_mulmid(res, poly2, len2, poly1, len1, nlo, nhi, FMPZ_MOD_CTX(ctx));
566+
567+
return GR_SUCCESS;
568+
}
569+
570+
557571
/* fixme: duplicate _fmpz_mod_poly methods for error handling */
558572
static int
559573
_gr_fmpz_mod_poly_divrem(fmpz * Q, fmpz * R, const fmpz * A, slong lenA,
@@ -852,6 +866,7 @@ gr_method_tab_input _fmpz_mod_methods_input[] =
852866
{GR_METHOD_VEC_DOT, (gr_funcptr) _gr_fmpz_mod_vec_dot},
853867
{GR_METHOD_VEC_DOT_REV, (gr_funcptr) _gr_fmpz_mod_vec_dot_rev},
854868
{GR_METHOD_POLY_MULLOW, (gr_funcptr) _gr_fmpz_mod_poly_mullow},
869+
{GR_METHOD_POLY_MULMID, (gr_funcptr) _gr_fmpz_mod_poly_mulmid},
855870
{GR_METHOD_POLY_INV_SERIES, (gr_funcptr) _gr_fmpz_mod_poly_inv_series},
856871
{GR_METHOD_POLY_DIV_SERIES, (gr_funcptr) _gr_fmpz_mod_poly_div_series},
857872
{GR_METHOD_POLY_DIVREM, (gr_funcptr) _gr_fmpz_mod_poly_divrem},

src/gr_poly.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ WARN_UNUSED_RESULT int gr_poly_compose_mod_brent_kung_precomp_preinv(gr_poly_t r
615615
/* Test functions */
616616

617617
void _gr_poly_test_mullow(gr_method_poly_binary_trunc_op mullow_impl, gr_method_poly_binary_trunc_op mullow_ref, flint_rand_t state, slong iters, slong maxn, gr_ctx_t ctx);
618+
void _gr_poly_test_mulmid(gr_method_poly_binary_trunc2_op mulmid_impl, gr_method_poly_binary_trunc2_op mulmid_ref, flint_rand_t state, slong iters, slong maxn, gr_ctx_t ctx);
618619
void _gr_poly_test_divrem(gr_method_poly_binary_binary_op divrem_impl, flint_rand_t state, slong iters, slong maxn, gr_ctx_t ctx);
619620
void _gr_poly_test_div(gr_method_poly_binary_op div_impl, flint_rand_t state, slong iters, slong maxn, gr_ctx_t ctx);
620621
void _gr_poly_test_inv_series(gr_method_poly_unary_trunc_op inv_series_impl, flint_rand_t state, slong iters, slong maxn, gr_ctx_t ctx);

src/gr_poly/test_mulmid.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
Copyright (C) 2024, 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+
12+
#include "gr_vec.h"
13+
#include "gr_poly.h"
14+
15+
PUSH_OPTIONS
16+
OPTIMIZE_OSIZE
17+
18+
void _gr_poly_test_mulmid(gr_method_poly_binary_trunc2_op mulmid_impl, gr_method_poly_binary_trunc2_op mulmid_ref,
19+
flint_rand_t state, slong iters, slong maxn, gr_ctx_t ctx)
20+
{
21+
slong iter;
22+
gr_ctx_ptr given_ctx = ctx;
23+
24+
if (mulmid_ref == NULL)
25+
mulmid_ref = (gr_method_poly_binary_trunc2_op) _gr_poly_mulmid_generic;
26+
27+
for (iter = 0; iter < iters; iter++)
28+
{
29+
gr_ptr A, B, C, D;
30+
slong n1, n2, nhi, nlo;
31+
int status = GR_SUCCESS;
32+
gr_ctx_t my_ctx;
33+
gr_ctx_struct * ctx;
34+
int squaring;
35+
36+
if (given_ctx == NULL)
37+
{
38+
gr_ctx_init_random(my_ctx, state);
39+
ctx = my_ctx;
40+
}
41+
else
42+
ctx = given_ctx;
43+
44+
squaring = n_randint(state, 2);
45+
46+
n1 = 1 + n_randint(state, 1 + maxn);
47+
n2 = squaring ? n1 : 1 + n_randint(state, 1 + maxn);
48+
nhi = 1 + n_randint(state, 1 + maxn);
49+
nhi = FLINT_MIN(nhi, n1 + n2 - 1);
50+
nlo = n_randint(state, nhi);
51+
52+
A = gr_heap_init_vec(n1, ctx);
53+
B = squaring ? A : gr_heap_init_vec(n2, ctx);
54+
C = gr_heap_init_vec(nhi - nlo, ctx);
55+
D = gr_heap_init_vec(nhi - nlo, ctx);
56+
57+
GR_MUST_SUCCEED(_gr_vec_randtest(A, state, n1, ctx));
58+
if (!squaring)
59+
GR_MUST_SUCCEED(_gr_vec_randtest(B, state, n2, ctx));
60+
GR_MUST_SUCCEED(_gr_vec_randtest(C, state, nhi - nlo, ctx));
61+
62+
#if 0
63+
/* Useful for debugging */
64+
slong i;
65+
for (i = 0; i < n1; i++)
66+
GR_IGNORE(gr_set_ui(GR_ENTRY(A, i, ctx->sizeof_elem), i + 1, ctx));
67+
for (i = 0; i < n2; i++)
68+
GR_IGNORE(gr_set_ui(GR_ENTRY(B, i, ctx->sizeof_elem), i + 1, ctx));
69+
#endif
70+
71+
status |= mulmid_impl(C, A, n1, B, n2, nlo, nhi, ctx);
72+
73+
if (status == GR_SUCCESS)
74+
status |= mulmid_ref(D, A, n1, B, n2, nlo, nhi, ctx);
75+
76+
if (status == GR_SUCCESS && _gr_vec_equal(C, D, nhi - nlo, ctx) == T_FALSE)
77+
{
78+
flint_printf("FAIL: mulmid\n");
79+
gr_ctx_println(ctx);
80+
flint_printf("len1 = %wd, len2 = %wd, nlo = %wd, ni = %wd, squaring = %d\n\n", n1, n2, nlo, nhi, squaring);
81+
flint_printf("A:\n"); _gr_vec_print(A, n1, ctx); flint_printf("\n\n");
82+
flint_printf("B:\n"); _gr_vec_print(B, n2, ctx); flint_printf("\n\n");
83+
flint_printf("C:\n"); _gr_vec_print(C, nhi - nlo, ctx); flint_printf("\n\n");
84+
flint_printf("D:\n"); _gr_vec_print(D, nhi - nlo, ctx); flint_printf("\n\n");
85+
flint_abort();
86+
}
87+
88+
gr_heap_clear_vec(A, n1, ctx);
89+
if (!squaring)
90+
gr_heap_clear_vec(B, n2, ctx);
91+
gr_heap_clear_vec(C, nhi - nlo, ctx);
92+
gr_heap_clear_vec(D, nhi - nlo, ctx);
93+
94+
if (given_ctx == NULL)
95+
gr_ctx_clear(ctx);
96+
}
97+
}
98+
99+
POP_OPTIONS

src/mpn_mod.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,12 @@ int mpn_mod_mat_reduce_row(slong * column, gr_mat_t A, slong * P, slong * L, slo
219219

220220
/* Polynomial algorithms */
221221

222+
int _mpn_mod_poly_mulmid_classical(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong nlo, slong nhi, gr_ctx_t ctx);
223+
int _mpn_mod_poly_mulmid_karatsuba(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong nlo, slong nhi, slong cutoff, gr_ctx_t ctx);
224+
int _mpn_mod_poly_mulmid_KS(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong nlo, slong nhi, gr_ctx_t ctx);
225+
int _mpn_mod_poly_mulmid_fft_small(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong nlo, slong nhi, gr_ctx_t ctx);
226+
int _mpn_mod_poly_mulmid(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong nlo, slong nhi, gr_ctx_t ctx);
227+
222228
int _mpn_mod_poly_mullow_classical(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong len, gr_ctx_t ctx);
223229
int _mpn_mod_poly_mullow_karatsuba(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong len, slong cutoff, gr_ctx_t ctx);
224230
int _mpn_mod_poly_mullow_KS(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong len, gr_ctx_t ctx);

0 commit comments

Comments
 (0)