Skip to content

Commit f058a95

Browse files
Merge pull request #2649 from edgarcosta/fix/gr-randtest-arg-eval-order
fix(gr): arg-eval-order divergence in randtest helpers (closes #2646)
2 parents 4a2ed06 + 9c4d6d9 commit f058a95

8 files changed

Lines changed: 127 additions & 24 deletions

File tree

doc/source/history.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,17 @@ FLINT 3.6.0 (in development)
1212

1313
Bug fixes
1414

15+
* Fix architecture-dependent test behaviour caused by undefined argument
16+
evaluation order in several ``gr_ctx_init_random_*`` and ``_gr_*_randtest``
17+
functions, which produced different RNG sequences on 32-bit ARM, i386, and
18+
x86_64. Also gate the ``log(a*b) = log(a) + log(b)`` check in
19+
``gr_poly_log_series`` on commutativity of the coefficient ring
20+
[EC, `#2649 <https://github.com/flintlib/flint/pull/2649>`_].
1521
* Fix ``flint_sprintf`` producing truncated output (e.g. ``"x"`` instead of
1622
``"x1"``) on 32-bit glibc, which broke ``mpoly_test_irreducible`` and the
1723
``compose_mpoly`` tests on i386/armhf
1824
[EC, `#2648 <https://github.com/flintlib/flint/pull/2648>`_].
1925

20-
2126
2026-04-24 -- FLINT 3.5.0
2227
-------------------------------------------------------------------------------
2328

src/gr/fmpq_mpoly.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,21 +140,30 @@ _gr_fmpq_mpoly_set_shallow(fmpq_mpoly_t res, const fmpq_mpoly_t poly, gr_ctx_t c
140140
static int
141141
_gr_fmpq_mpoly_randtest(fmpq_mpoly_t res, flint_rand_t state, gr_ctx_t ctx)
142142
{
143-
slong bits;
143+
slong bits, length;
144+
flint_bitcnt_t exp_bits;
144145

145146
if (n_randint(state, 10) != 0)
146147
bits = 10;
147148
else
148149
bits = 100;
149150

150-
fmpq_mpoly_randtest_bits(res, state, n_randint(state, 5), bits, 1 + n_randint(state, 3), MPOLYNOMIAL_MCTX(ctx));
151+
/* Split state-mutating calls so consumption order is architecture-independent. */
152+
length = n_randint(state, 5);
153+
exp_bits = 1 + n_randint(state, 3);
154+
fmpq_mpoly_randtest_bits(res, state, length, bits, exp_bits, MPOLYNOMIAL_MCTX(ctx));
151155
return GR_SUCCESS;
152156
}
153157

154158
static int
155159
_gr_fmpq_mpoly_randtest_small(fmpq_mpoly_t res, flint_rand_t state, gr_ctx_t ctx)
156160
{
157-
fmpq_mpoly_randtest_bits(res, state, n_randint(state, 3), 3, 1 + n_randint(state, 3), MPOLYNOMIAL_MCTX(ctx));
161+
slong length;
162+
flint_bitcnt_t exp_bits;
163+
164+
length = n_randint(state, 3);
165+
exp_bits = 1 + n_randint(state, 3);
166+
fmpq_mpoly_randtest_bits(res, state, length, 3, exp_bits, MPOLYNOMIAL_MCTX(ctx));
158167
return GR_SUCCESS;
159168
}
160169

src/gr/fmpz_mod_mpoly_q.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,14 +139,25 @@ _gr_fmpz_mod_mpoly_q_set_shallow(fmpz_mod_mpoly_q_t res, const fmpz_mod_mpoly_q_
139139
static int
140140
_gr_fmpz_mod_mpoly_q_randtest(fmpz_mod_mpoly_q_t res, flint_rand_t state, gr_ctx_t ctx)
141141
{
142-
fmpz_mod_mpoly_q_randtest(res, state, n_randint(state, 5), 1 + n_randint(state, 3), MPOLYNOMIAL_MCTX(ctx));
142+
slong length;
143+
flint_bitcnt_t exp_bits;
144+
145+
/* Split state-mutating calls so consumption order is architecture-independent. */
146+
length = n_randint(state, 5);
147+
exp_bits = 1 + n_randint(state, 3);
148+
fmpz_mod_mpoly_q_randtest(res, state, length, exp_bits, MPOLYNOMIAL_MCTX(ctx));
143149
return GR_SUCCESS;
144150
}
145151

146152
static int
147153
_gr_fmpz_mod_mpoly_q_randtest_small(fmpz_mod_mpoly_q_t res, flint_rand_t state, gr_ctx_t ctx)
148154
{
149-
fmpz_mod_mpoly_q_randtest(res, state, n_randint(state, 3), 1 + n_randint(state, 3), MPOLYNOMIAL_MCTX(ctx));
155+
slong length;
156+
flint_bitcnt_t exp_bits;
157+
158+
length = n_randint(state, 3);
159+
exp_bits = 1 + n_randint(state, 3);
160+
fmpz_mod_mpoly_q_randtest(res, state, length, exp_bits, MPOLYNOMIAL_MCTX(ctx));
150161
return GR_SUCCESS;
151162
}
152163

src/gr/fmpz_mpoly.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,21 +140,32 @@ _gr_fmpz_mpoly_set_shallow(fmpz_mpoly_t res, const fmpz_mpoly_t poly, gr_ctx_t c
140140
static int
141141
_gr_fmpz_mpoly_randtest(fmpz_mpoly_t res, flint_rand_t state, gr_ctx_t ctx)
142142
{
143-
slong bits;
143+
slong bits, length;
144+
flint_bitcnt_t exp_bits;
144145

145146
if (n_randint(state, 10) != 0)
146147
bits = 10;
147148
else
148149
bits = 100;
149150

150-
fmpz_mpoly_randtest_bits(res, state, n_randint(state, 5), bits, 1 + n_randint(state, 3), MPOLYNOMIAL_MCTX(ctx));
151+
/* The two n_randint calls have side effects on `state`; split them so
152+
the consumption order is the same on every architecture (C does not
153+
specify the order in which function arguments are evaluated). */
154+
length = n_randint(state, 5);
155+
exp_bits = 1 + n_randint(state, 3);
156+
fmpz_mpoly_randtest_bits(res, state, length, bits, exp_bits, MPOLYNOMIAL_MCTX(ctx));
151157
return GR_SUCCESS;
152158
}
153159

154160
static int
155161
_gr_fmpz_mpoly_randtest_small(fmpz_mpoly_t res, flint_rand_t state, gr_ctx_t ctx)
156162
{
157-
fmpz_mpoly_randtest_bits(res, state, n_randint(state, 3), 3, 1 + n_randint(state, 3), MPOLYNOMIAL_MCTX(ctx));
163+
slong length;
164+
flint_bitcnt_t exp_bits;
165+
166+
length = n_randint(state, 3);
167+
exp_bits = 1 + n_randint(state, 3);
168+
fmpz_mpoly_randtest_bits(res, state, length, 3, exp_bits, MPOLYNOMIAL_MCTX(ctx));
158169
return GR_SUCCESS;
159170
}
160171

src/gr/fmpz_mpoly_q.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,21 +74,30 @@ _gr_fmpz_mpoly_q_set_shallow(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t poly, gr_c
7474
static int
7575
_gr_fmpz_mpoly_q_randtest(fmpz_mpoly_q_t res, flint_rand_t state, gr_ctx_t ctx)
7676
{
77-
slong bits;
77+
slong bits, length;
78+
flint_bitcnt_t exp_bits;
7879

7980
if (n_randint(state, 10) != 0)
8081
bits = 10;
8182
else
8283
bits = 100;
8384

84-
fmpz_mpoly_q_randtest(res, state, n_randint(state, 5), bits, 1 + n_randint(state, 3), MPOLYNOMIAL_MCTX(ctx));
85+
/* Split state-mutating calls so consumption order is architecture-independent. */
86+
length = n_randint(state, 5);
87+
exp_bits = 1 + n_randint(state, 3);
88+
fmpz_mpoly_q_randtest(res, state, length, bits, exp_bits, MPOLYNOMIAL_MCTX(ctx));
8589
return GR_SUCCESS;
8690
}
8791

8892
static int
8993
_gr_fmpz_mpoly_q_randtest_small(fmpz_mpoly_q_t res, flint_rand_t state, gr_ctx_t ctx)
9094
{
91-
fmpz_mpoly_q_randtest(res, state, n_randint(state, 3), 3, 1 + n_randint(state, 3), MPOLYNOMIAL_MCTX(ctx));
95+
slong length;
96+
flint_bitcnt_t exp_bits;
97+
98+
length = n_randint(state, 3);
99+
exp_bits = 1 + n_randint(state, 3);
100+
fmpz_mpoly_q_randtest(res, state, length, 3, exp_bits, MPOLYNOMIAL_MCTX(ctx));
92101
return GR_SUCCESS;
93102
}
94103

src/gr/init_random.c

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,12 @@ gr_ctx_init_random_ring_composite(gr_ctx_t ctx, flint_rand_t state)
5454
gr_ctx_init_gr_poly(ctx, base_ring);
5555
break;
5656
case 1:
57-
gr_ctx_init_gr_mpoly(ctx, base_ring, n_randint(state, 3), mpoly_ordering_randtest(state));
57+
{
58+
/* Split state-mutating calls so consumption order is architecture-independent. */
59+
slong nvars = n_randint(state, 3);
60+
ordering_t ord = mpoly_ordering_randtest(state);
61+
gr_ctx_init_gr_mpoly(ctx, base_ring, nvars, ord);
62+
}
5863
break;
5964
case 2:
6065
gr_series_ctx_init(ctx, base_ring, n_randint(state, 6));
@@ -127,16 +132,30 @@ gr_ctx_init_random_ring_finite_field(gr_ctx_t ctx, flint_rand_t state)
127132
switch (n_randint(state, 3))
128133
{
129134
case 0:
130-
gr_ctx_init_fq_nmod(ctx, n_randtest_prime(state, 0), 1 + n_randint(state, 4), NULL);
135+
{
136+
/* Split state-mutating calls so consumption order is architecture-independent. */
137+
ulong p = n_randtest_prime(state, 0);
138+
slong d = 1 + n_randint(state, 4);
139+
gr_ctx_init_fq_nmod(ctx, p, d, NULL);
140+
}
131141
break;
132142

133143
case 1:
134-
gr_ctx_init_fq_zech(ctx, n_randprime(state, 4, 0), 1 + n_randint(state, 3), NULL);
144+
{
145+
ulong p = n_randprime(state, 4, 0);
146+
slong d = 1 + n_randint(state, 3);
147+
gr_ctx_init_fq_zech(ctx, p, d, NULL);
148+
}
135149
break;
136150

137151
case 2:
138-
fmpz_randprime(t, state, 2 + n_randint(state, 100), 0);
139-
gr_ctx_init_fq(ctx, t, 1 + n_randint(state, 4), NULL);
152+
{
153+
flint_bitcnt_t bits = 2 + n_randint(state, 100);
154+
slong d;
155+
fmpz_randprime(t, state, bits, 0);
156+
d = 1 + n_randint(state, 4);
157+
gr_ctx_init_fq(ctx, t, d, NULL);
158+
}
140159
break;
141160
}
142161

@@ -154,7 +173,16 @@ gr_ctx_init_random_ring_number_field(gr_ctx_t ctx, flint_rand_t state)
154173

155174
do
156175
{
157-
fmpz_poly_randtest_irreducible(g, state, 2 + n_randint(state, 5), 1 + n_randint(state, 10));
176+
slong len;
177+
flint_bitcnt_t bits;
178+
179+
/* The two n_randint calls below have side effects on `state`; we
180+
split them into separate statements so the order of consumption
181+
is the same on every architecture (C does not specify the order
182+
in which function arguments are evaluated). */
183+
len = 2 + n_randint(state, 5);
184+
bits = 1 + n_randint(state, 10);
185+
fmpz_poly_randtest_irreducible(g, state, len, bits);
158186
} while (g->length < 2);
159187

160188
fmpq_poly_set_fmpz_poly(f, g);
@@ -217,10 +245,19 @@ gr_ctx_init_random_ring_builtin_poly(gr_ctx_t ctx, flint_rand_t state)
217245
gr_ctx_init_fmpq_poly(ctx);
218246
break;
219247
case 2:
220-
gr_ctx_init_fmpz_mpoly(ctx, n_randint(state, 3), mpoly_ordering_randtest(state));
248+
{
249+
/* Split state-mutating calls so consumption order is architecture-independent. */
250+
slong nvars = n_randint(state, 3);
251+
ordering_t ord = mpoly_ordering_randtest(state);
252+
gr_ctx_init_fmpz_mpoly(ctx, nvars, ord);
253+
}
221254
break;
222255
case 3:
223-
gr_ctx_init_fmpz_mpoly_q(ctx, n_randint(state, 2), mpoly_ordering_randtest(state));
256+
{
257+
slong nvars = n_randint(state, 2);
258+
ordering_t ord = mpoly_ordering_randtest(state);
259+
gr_ctx_init_fmpz_mpoly_q(ctx, nvars, ord);
260+
}
224261
break;
225262
}
226263
}
@@ -323,10 +360,19 @@ gr_ctx_init_random_mpoly(gr_ctx_t ctx, flint_rand_t state)
323360
switch (n_randint(state, 2))
324361
{
325362
case 0:
326-
gr_ctx_init_gr_mpoly(ctx, _gr_random_base_ring(state), n_randint(state, 3), ordering);
363+
{
364+
/* Split state-mutating calls so consumption order is architecture-independent. */
365+
gr_ctx_struct * base = _gr_random_base_ring(state);
366+
slong nvars = n_randint(state, 3);
367+
gr_ctx_init_gr_mpoly(ctx, base, nvars, ordering);
368+
}
327369
break;
328370
case 1:
329-
gr_ctx_init_fmpz_mpoly(ctx, n_randint(state, 3), mpoly_ordering_randtest(state));
371+
{
372+
slong nvars = n_randint(state, 3);
373+
ordering_t ord = mpoly_ordering_randtest(state);
374+
gr_ctx_init_fmpz_mpoly(ctx, nvars, ord);
375+
}
330376
break;
331377
}
332378
}

src/gr/matrix.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,12 @@ static int
198198
matrix_randtest(gr_mat_t res, flint_rand_t state, gr_ctx_t ctx)
199199
{
200200
if (MATRIX_CTX(ctx)->all_sizes)
201-
_gr_mat_resize(res, n_randint(state, 7), n_randint(state, 7), MATRIX_CTX(ctx)->base_ring);
201+
{
202+
/* Split state-mutating calls so consumption order is architecture-independent. */
203+
slong r = n_randint(state, 7);
204+
slong c = n_randint(state, 7);
205+
_gr_mat_resize(res, r, c, MATRIX_CTX(ctx)->base_ring);
206+
}
202207

203208
return gr_mat_randtest(res, state, MATRIX_CTX(ctx)->base_ring);
204209
}

src/gr_poly/test/t-log_series.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,14 @@ test_log_series(flint_rand_t state)
5858
status |= gr_poly_set_coeff_si(fab, 0, 0, ctx);
5959
status |= gr_poly_set_coeff_si(fafb, 0, 0, ctx);
6060

61-
if (status == GR_SUCCESS && gr_poly_equal(fab, fafb, ctx) == T_FALSE)
61+
/* The identity log(a*b) = log(a) + log(b) only holds when a and b
62+
commute as polynomials, i.e. when the coefficient ring is
63+
commutative. Skip the check for non-commutative rings (e.g.
64+
matrix rings) where the BCH commutator terms make the two sides
65+
differ in general. */
66+
if (status == GR_SUCCESS
67+
&& gr_ctx_is_commutative_ring(ctx) == T_TRUE
68+
&& gr_poly_equal(fab, fafb, ctx) == T_FALSE)
6269
{
6370
flint_printf("FAIL\n\n");
6471
gr_ctx_println(ctx);

0 commit comments

Comments
 (0)