Skip to content

Commit 8aa5eaa

Browse files
Merge pull request #2441 from fredrik-johansson/bivar3
Kronecker substitution multiplication for ``gr_poly``
2 parents 4799931 + e66522d commit 8aa5eaa

File tree

8 files changed

+498
-0
lines changed

8 files changed

+498
-0
lines changed

doc/source/gr_poly.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,14 @@ Multiplication algorithms
192192
Multiply using the classical (schoolbook) algorithm, performing
193193
a sequence of dot products.
194194

195+
.. function:: int _gr_poly_mullow_bivariate_KS(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, slong n, gr_ctx_t ctx)
196+
int gr_poly_mullow_bivariate_KS(gr_poly_t res, const gr_poly_t poly1, const gr_poly_t poly2, slong n, gr_ctx_t ctx)
197+
198+
Assuming that the coefficients are polynomials of type ``gr_poly``,
199+
reduce the bivariate product to a single univariate product using
200+
Kronecker substitution. Returns ``GR_UNABLE`` if the elements are not
201+
of type ``gr_poly``.
202+
195203
.. function:: int _gr_poly_mullow_complex_reorder(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, slong n, int karatsuba, gr_ctx_t ctx, gr_ctx_t real_ctx)
196204
int gr_poly_mullow_complex_reorder(gr_poly_t res, const gr_poly_t poly1, const gr_poly_t poly2, slong n, int karatsuba, gr_ctx_t ctx, gr_ctx_t real_ctx)
197205

src/gr/fmpz_poly.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,18 @@ _gr_fmpz_poly_factor(fmpz_poly_t c, gr_vec_t factors, gr_vec_t exponents, gr_src
801801
return GR_SUCCESS;
802802
}
803803

804+
#define MUL_KS_CUTOFF 5
805+
806+
int
807+
_gr_fmpz_poly_gr_poly_mullow(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, slong n, gr_ctx_t ctx)
808+
{
809+
if (len1 < MUL_KS_CUTOFF || len2 < MUL_KS_CUTOFF || n < MUL_KS_CUTOFF)
810+
return _gr_poly_mullow_classical(res, poly1, len1, poly2, len2, n, ctx);
811+
else
812+
return _gr_poly_mullow_bivariate_KS(res, poly1, len1, poly2, len2, n, ctx);
813+
}
814+
815+
804816
int _fmpz_poly_methods_initialized = 0;
805817

806818
gr_static_method_table _fmpz_poly_methods;
@@ -892,6 +904,7 @@ gr_method_tab_input _fmpz_poly_methods_input[] =
892904
{GR_METHOD_RSQRT, (gr_funcptr) _gr_fmpz_poly_rsqrt},
893905
{GR_METHOD_CANONICAL_ASSOCIATE, (gr_funcptr) _gr_fmpz_poly_canonical_associate},
894906
{GR_METHOD_FACTOR, (gr_funcptr) _gr_fmpz_poly_factor},
907+
{GR_METHOD_POLY_MULLOW, (gr_funcptr) _gr_fmpz_poly_gr_poly_mullow},
895908
{0, (gr_funcptr) NULL},
896909
};
897910

src/gr/polynomial.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,47 @@ polynomial_factor(gr_ptr c, gr_vec_t fac, gr_vec_t mult, const gr_poly_t pol, in
673673
return GR_FACTOR_OP(cctx, POLY_FACTOR)(c, fac, mult, pol, flags, cctx);
674674
}
675675

676+
/* TODO: account for sparsity */
677+
#define MUL_KS_CUTOFF 5
678+
679+
/* Don't do extremely deep recursive KS; the polynomials will
680+
typically be too sparse, and we risk blowing up memory too. */
681+
#define MUL_KS_DEPTH_LIMIT 3
682+
683+
/* Assume that the underlying polynomial ring has asymptotically
684+
fast univariate multiplication if it overrides the default
685+
multiplication routine. */
686+
687+
static int
688+
want_KS(gr_ctx_t cctx, slong depth)
689+
{
690+
if (cctx->methods[GR_METHOD_POLY_MULLOW] == (gr_funcptr) _gr_poly_mullow_generic)
691+
return 0;
692+
693+
/* If the coefficients are polynomials, check the ground ring. */
694+
if (depth > MUL_KS_DEPTH_LIMIT)
695+
return 0;
696+
697+
if (cctx->which_ring == GR_CTX_GR_POLY)
698+
return want_KS(POLYNOMIAL_ELEM_CTX(cctx), depth + 1);
699+
700+
return 1;
701+
}
702+
703+
int
704+
_polynomial_gr_poly_mullow(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, slong n, gr_ctx_t ctx)
705+
{
706+
gr_ctx_struct * cctx = POLYNOMIAL_ELEM_CTX(ctx);
707+
708+
if (len1 < MUL_KS_CUTOFF || len2 < MUL_KS_CUTOFF || n < MUL_KS_CUTOFF)
709+
return _gr_poly_mullow_classical(res, poly1, len1, poly2, len2, n, ctx);
710+
711+
if (!want_KS(cctx, 0))
712+
return _gr_poly_mullow_classical(res, poly1, len1, poly2, len2, n, ctx);
713+
714+
return _gr_poly_mullow_bivariate_KS(res, poly1, len1, poly2, len2, n, ctx);
715+
}
716+
676717

677718
int _gr_poly_methods_initialized = 0;
678719

@@ -760,6 +801,7 @@ gr_method_tab_input _gr_poly_methods_input[] =
760801
{GR_METHOD_GCD, (gr_funcptr) polynomial_gcd},
761802

762803
{GR_METHOD_FACTOR, (gr_funcptr) polynomial_factor},
804+
{GR_METHOD_POLY_MULLOW, (gr_funcptr) _polynomial_gr_poly_mullow},
763805

764806
{0, (gr_funcptr) NULL},
765807
};

src/gr_poly.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ WARN_UNUSED_RESULT int gr_poly_mullow_classical(gr_poly_t res, const gr_poly_t p
144144
WARN_UNUSED_RESULT int _gr_poly_mullow_complex_reorder(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, slong n, int karatsuba, gr_ctx_t ctx, gr_ctx_t real_ctx);
145145
WARN_UNUSED_RESULT int gr_poly_mullow_complex_reorder(gr_poly_t res, const gr_poly_t poly1, const gr_poly_t poly2, slong n, int karatsuba, gr_ctx_t ctx, gr_ctx_t real_ctx);
146146

147+
WARN_UNUSED_RESULT int _gr_poly_mullow_bivariate_KS(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, slong n, gr_ctx_t ctx);
148+
WARN_UNUSED_RESULT int gr_poly_mullow_bivariate_KS(gr_poly_t res, const gr_poly_t poly1, const gr_poly_t poly2, slong n, gr_ctx_t ctx);
149+
147150
WARN_UNUSED_RESULT int _gr_poly_mul_karatsuba(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, gr_ctx_t ctx);
148151
WARN_UNUSED_RESULT int gr_poly_mul_karatsuba(gr_poly_t res, const gr_poly_t poly1, const gr_poly_t poly2, gr_ctx_t ctx);
149152
WARN_UNUSED_RESULT int _gr_poly_mul_toom33(gr_ptr res, gr_srcptr poly1, slong len1, gr_srcptr poly2, slong len2, gr_ctx_t ctx);

src/gr_poly/mullow_bivariate_KS.c

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/*
2+
Copyright (C) 2025 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 <string.h>
13+
#include "gr.h"
14+
#include "gr_vec.h"
15+
#include "gr_poly.h"
16+
17+
int
18+
_gr_poly_mullow_bivariate_KS(gr_ptr res,
19+
gr_srcptr poly1, slong len1,
20+
gr_srcptr poly2, slong len2, slong n, gr_ctx_t ctx)
21+
{
22+
slong i, l, max_len1, max_len2, inner_len;
23+
gr_ctx_struct * cctx;
24+
gr_ctx_t tmp_ctx;
25+
const gr_poly_struct * ppoly1, * ppoly2;
26+
gr_poly_struct * pres;
27+
gr_ptr R, P1, P2, pp, tmp_zero;
28+
slong csz;
29+
int status = GR_SUCCESS;
30+
int squaring;
31+
32+
/* Todo: other base types */
33+
if (ctx->which_ring == GR_CTX_GR_POLY)
34+
{
35+
cctx = POLYNOMIAL_ELEM_CTX(ctx);
36+
}
37+
else if (ctx->which_ring == GR_CTX_FMPZ_POLY)
38+
{
39+
gr_ctx_init_fmpz(tmp_ctx);
40+
cctx = tmp_ctx;
41+
}
42+
else
43+
return GR_UNABLE;
44+
45+
csz = cctx->sizeof_elem;
46+
47+
len1 = FLINT_MIN(len1, n);
48+
len2 = FLINT_MIN(len2, n);
49+
50+
squaring = (poly1 == poly2) && (len1 == len2);
51+
ppoly1 = poly1;
52+
ppoly2 = poly2;
53+
pres = res;
54+
55+
max_len1 = 0;
56+
max_len2 = 0;
57+
58+
for (i = 0; i < len1; i++)
59+
{
60+
l = ppoly1[i].length;
61+
max_len1 = FLINT_MAX(l, max_len1);
62+
}
63+
64+
if (squaring)
65+
{
66+
max_len2 = max_len1;
67+
}
68+
else
69+
{
70+
for (i = 0; i < len2; i++)
71+
{
72+
l = ppoly2[i].length;
73+
max_len2 = FLINT_MAX(l, max_len2);
74+
}
75+
}
76+
77+
if (max_len1 == 0 || max_len2 == 0)
78+
return _gr_vec_zero(res, n, ctx);
79+
80+
inner_len = max_len1 + max_len2 - 1;
81+
82+
GR_TMP_INIT_VEC(R, n * inner_len, cctx);
83+
GR_TMP_INIT_VEC(tmp_zero, inner_len, cctx);
84+
P1 = GR_TMP_ALLOC(len1 * inner_len * cctx->sizeof_elem);
85+
86+
if (squaring)
87+
P2 = P1;
88+
else
89+
P2 = GR_TMP_ALLOC(len2 * inner_len * cctx->sizeof_elem);
90+
91+
for (i = 0; i < len1; i++)
92+
{
93+
l = ppoly1[i].length;
94+
memcpy(GR_ENTRY(P1, i * inner_len, csz), ppoly1[i].coeffs, l * csz);
95+
memcpy(GR_ENTRY(P1, i * inner_len + l, csz), tmp_zero, (inner_len - l) * csz);
96+
}
97+
98+
if (!squaring)
99+
{
100+
for (i = 0; i < len2; i++)
101+
{
102+
l = ppoly2[i].length;
103+
memcpy(GR_ENTRY(P2, i * inner_len, csz), ppoly2[i].coeffs, l * csz);
104+
memcpy(GR_ENTRY(P2, i * inner_len + l, csz), tmp_zero, (inner_len - l) * csz);
105+
}
106+
}
107+
108+
status = _gr_poly_mullow(R, P1, len1 * inner_len, P2, len2 * inner_len, n * inner_len, cctx);
109+
110+
for (i = 0; i < n; i++)
111+
{
112+
l = inner_len;
113+
pp = GR_ENTRY(R, i * inner_len, csz);
114+
while (l > 0 && gr_is_zero(GR_ENTRY(pp, l - 1, csz), cctx) == T_TRUE)
115+
l--;
116+
gr_poly_fit_length(pres + i, l, cctx);
117+
_gr_poly_set_length(pres + i, l, cctx);
118+
_gr_vec_swap(pres[i].coeffs, pp, l, cctx);
119+
}
120+
121+
GR_TMP_CLEAR_VEC(R, n * inner_len, cctx);
122+
GR_TMP_CLEAR_VEC(tmp_zero, inner_len, cctx);
123+
GR_TMP_FREE(P1, len1 * inner_len * cctx->sizeof_elem);
124+
if (!squaring)
125+
GR_TMP_FREE(P2, len2 * inner_len * cctx->sizeof_elem);
126+
127+
return status;
128+
}
129+
130+
int
131+
gr_poly_mullow_bivariate_KS(gr_poly_t res, const gr_poly_t poly1,
132+
const gr_poly_t poly2,
133+
slong n, gr_ctx_t ctx)
134+
{
135+
slong len_out;
136+
int status;
137+
138+
if (poly1->length == 0 || poly2->length == 0 || n == 0)
139+
return gr_poly_zero(res, ctx);
140+
141+
len_out = poly1->length + poly2->length - 1;
142+
n = FLINT_MIN(n, len_out);
143+
144+
if (res == poly1 || res == poly2)
145+
{
146+
gr_poly_t t;
147+
gr_poly_init2(t, n, ctx);
148+
status = _gr_poly_mullow_bivariate_KS(t->coeffs, poly1->coeffs, poly1->length, poly2->coeffs, poly2->length, n, ctx);
149+
gr_poly_swap(res, t, ctx);
150+
gr_poly_clear(t, ctx);
151+
}
152+
else
153+
{
154+
gr_poly_fit_length(res, n, ctx);
155+
status = _gr_poly_mullow_bivariate_KS(res->coeffs, poly1->coeffs, poly1->length, poly2->coeffs, poly2->length, n, ctx);
156+
}
157+
158+
_gr_poly_set_length(res, n, ctx);
159+
_gr_poly_normalise(res, ctx);
160+
return status;
161+
}
162+

0 commit comments

Comments
 (0)