Skip to content

Mod poly and mpn_mod random generation - #2448

Open
dlesnoff wants to merge 18 commits into
flintlib:mainfrom
dlesnoff:mod_poly-random-generation
Open

Mod poly and mpn_mod random generation#2448
dlesnoff wants to merge 18 commits into
flintlib:mainfrom
dlesnoff:mod_poly-random-generation

Conversation

@dlesnoff

Copy link
Copy Markdown
Contributor

Follow-up of #2430 .
Adds a rand function:

  • nmod_poly
  • nmod_poly_mat
  • mpn_mod
  • fmpz_mod_poly

It seems that implementations of nmod_mpoly randtest functions generate uniformly random coefficients.
I did not add rand functions for basic types like fmpz_mod nor nmod.
I plan to add a rand function for mpn_mod_poly and mpn_mod_mat.
Please forgive me, I based my branch on my previously non-merged branch and it needs some cleanup.

@fredrik-johansson

Copy link
Copy Markdown
Collaborator

Please forgive me, I based my branch on my previously non-merged branch and it needs some cleanup.

I think you need to rebase on main and force-push to get a clean diff.

@dlesnoff
dlesnoff force-pushed the mod_poly-random-generation branch from c1be23c to ba6af38 Compare October 29, 2025 18:07
Comment thread doc/source/fmpz_poly.rst Outdated
Comment thread src/fmpz/rand.c Outdated
}
}

void fmpz_randm_nonzero(fmpz_t f, flint_rand_t state, const fmpz_t m) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current behaviour does not have uniform distribution (it is more likely to generate 1 than other values). Maybe generate uniformly in [0,m-2] (being careful with m=1 or such corner cases), and then add 1?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does m stands for uniform? For me, it stands for modulus since the element is upper bounded by a modulus and is not just a random element with a set number of bits. Sorry, I did not meant to make something uniform.
The functions fmpz_mod_poly_randtest used randm. I prefered creating a randm_nonzero function than using randtest_nonzero.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I meant is that currently, fmpz_randm generates a uniform integer in [0, m) (all values have equal probability), as can be seen from the code. The fact that the distribution is uniform is not explicitly indicated in the documentation, but that's ok, it is the "canonical distribution" for a finite set.

So if a fmpz_randm_nonzero function is added, it seems to me that it should also have uniform distribution (choosing uniformly in [1, m)), unless this is tricky to make. In this case it is not tricky: apply fmpz_randm with m-1 to get a uniform choice in [0, m-1), and then add 1, this gives you a uniform choice in [1, m).

Comment thread src/fmpz_mod_poly/randtest.c
Comment thread src/fmpz_mod_poly/randtest.c Outdated
fmpz_mod_poly_fit_length(poly, len, ctx);
_fmpz_vec_zero(poly->coeffs, len);
fmpz_randm(poly->coeffs + 0, state, fmpz_mod_ctx_modulus(ctx));
fmpz_randm_nonzero(poly->coeffs + 0, state, fmpz_mod_ctx_modulus(ctx));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change, or why using nonzero almost everywhere?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To have at least a randfull-like functionality. See my comments above.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As suggested in other functions, I think that in these randtest functions we may as well rely on the existing fmpz_randtest_mod.

@vneiger

vneiger commented Oct 29, 2025

Copy link
Copy Markdown
Collaborator

I cancelled the CI workflow because they were still in testing after almost 4 hours. Please review the code carefully to see what changes to existing functions could have led to this, thanks! (I pointed at some modifications in my comments, but there may be others)

@dlesnoff

Copy link
Copy Markdown
Contributor Author

fmpz_randtest does not generate a coefficient with increased sparsity (here, 0 with increased probability) but generates a coefficient using a number of bits. For mod functions, it requires to be reduced after being generated.
fmpz_randm generates directly a coefficient in the range [0, m) where m is a bound, but I am unsure if this function has some pseudo-uniformity guarantee (the algorithm is unspecified).
So randtest has a slight different meaning for fmpz than for structures in mod n source files.

There is probably an infinite loop, I'll do a manual bisect.

The randtest functions are using `randm` which generates positive coefficients in [0, m) range with m the modulus given by the context.
The documentation told that the coefficients are randomly signed, so I
fixed that.
I introduced a `randm_nonzero` function in fmpz to ensure that
coefficients are nonzero and replaced all occurences of `randm` in
`fmpz_mod_poly_randtest` functions by this new function.
Apart from the `rand` function, this introduces a `rand_monic` and
a `rand_irreducible` function.
I added _fmpz_mod_vec_rand with the intent to use it in
_mpn_mod_vec_rand but did not use it in the end.

This reverts commit f98e52c.
@dlesnoff
dlesnoff force-pushed the mod_poly-random-generation branch from 21ee353 to 59f5c7d Compare October 30, 2025 11:17
@dlesnoff

dlesnoff commented Oct 30, 2025

Copy link
Copy Markdown
Contributor Author

The tests halt indefinitely after gr_special_fac. I am unsure if it's related to my PR.
This commit is the culprit: Add fmpz_mod_poly_rand, rand_monic, irred funcs

@dlesnoff

Copy link
Copy Markdown
Contributor Author

Ok, I guess that if a polynomial has nonzero coefficients, it is irreducible with much less probability. This could slow down the tests. I should indeed give up on a "randfull-like" functionality for fmpz_mod_poly_randtest functions but then what would be the point of making another rand function?

Comment thread doc/source/nmod_poly.rst
.. function:: void nmod_poly_randtest(nmod_poly_t poly, flint_rand_t state, slong len)

Generates a random polynomial with length up to ``len``.
Generates a random and sparse with increased probability polynomial with length up to ``len``.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Generates a random and sparse with increased probability polynomial with length up to ``len``.
Generates a random polynomial with length up to ``len``, with for each coefficient the probability of some special values increased (see :func:`n_randtest`). This function is intended for use in test code.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is sparse with increased proba, but also special values are more likely than with a uniform distribution. So maybe,

Suggested change
Generates a random and sparse with increased probability polynomial with length up to ``len``.
Generates a random polynomial with length up to ``len``, sparse with increased probability, and with coefficients generated by :func:`n_randtest` .

Comment thread doc/source/nmod_poly.rst
Comment thread doc/source/nmod_poly_mat.rst
Comment thread src/fmpz/rand.c Outdated
}
}

void fmpz_randm_nonzero(fmpz_t f, flint_rand_t state, const fmpz_t m) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I meant is that currently, fmpz_randm generates a uniform integer in [0, m) (all values have equal probability), as can be seen from the code. The fact that the distribution is uniform is not explicitly indicated in the documentation, but that's ok, it is the "canonical distribution" for a finite set.

So if a fmpz_randm_nonzero function is added, it seems to me that it should also have uniform distribution (choosing uniformly in [1, m)), unless this is tricky to make. In this case it is not tricky: apply fmpz_randm with m-1 to get a uniform choice in [0, m-1), and then add 1, this gives you a uniform choice in [1, m).

{
if (len == 0)
{
flint_throw(FLINT_ERROR, "Exception (fmpz_mod_poly_randtest_irreducible). len == 0.\n");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
flint_throw(FLINT_ERROR, "Exception (fmpz_mod_poly_randtest_irreducible). len == 0.\n");
flint_throw(FLINT_ERROR, "Exception (fmpz_mod_poly_rand_irreducible). len == 0.\n");

@vneiger vneiger Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a mismatch function name / name in exception.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(modified comment after checking the diff more carefully)

Comment thread src/fmpz_mod_poly/randtest.c Outdated
Comment thread src/fmpz_mod_poly/randtest.c Outdated
Comment thread src/fmpz_mod_poly/randtest.c Outdated
fmpz_mod_poly_fit_length(poly, len, ctx);
_fmpz_vec_zero(poly->coeffs, len);
fmpz_randm(poly->coeffs + 0, state, fmpz_mod_ctx_modulus(ctx));
fmpz_randm_nonzero(poly->coeffs + 0, state, fmpz_mod_ctx_modulus(ctx));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As suggested in other functions, I think that in these randtest functions we may as well rely on the existing fmpz_randtest_mod.

Comment thread src/mpn_mod.h Outdated
@vneiger

vneiger commented Oct 30, 2025

Copy link
Copy Markdown
Collaborator

Ok, I guess that if a polynomial has nonzero coefficients, it is irreducible with much less probability. This could slow down the tests. I should indeed give up on a "randfull-like" functionality for fmpz_mod_poly_randtest functions

This is likely indeed. I haven't looked closely at the test files and the one that is failing, but let's suppose that some test includes working modulo 2, then the new randtest using randm_nonzero will only generate coefficients that are 1 ! I don't think randtest should ban 0.

but then what would be the point of making another rand function?

In my last batch of comments, you can see that I suggest using fmpz_randtest_mod instead of fmpz_randm_nonzero. Then the randtest and rand functions for fmpz_mod_poly would become rather different and I think it would make sense to have both. (However, one question that remains, is whether this change will suffice to solve the "infinite test" issue.)

@dlesnoff
dlesnoff force-pushed the mod_poly-random-generation branch from f5b0816 to eafe4cf Compare November 3, 2025 13:46
@dlesnoff

dlesnoff commented Nov 3, 2025

Copy link
Copy Markdown
Contributor Author

I changed randm_non_zero t to randtest calls. I gave one extra bit for the random generation before taking the modulus. If you think it is not necessary, I will remove it.
I have still a few changes to perform.

Comment thread doc/source/fmpz_poly.rst Outdated
@dlesnoff
dlesnoff marked this pull request as draft August 6, 2026 18:51
@dlesnoff

dlesnoff commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Hello, sorry for not making quickly the last modifications needed to close this PR.

As suggested in other functions, I think that in these randtest functions we may as well rely on the existing fmpz_randtest_mod.

Is this still actual? I can't remember if I did this change. I'll look into it tomorrow.

Pay attention to the previous commit. I remove an invocation to fmpz_bits. It apparently fixes a segfault, but I am not sure why it was invocated in the first place. Could you check out for this during review?

Otherwise, I made two changes:

  • fix documentation errors
  • the change so that fmpz_randm_nonzero provides a uniform distribution using the add-one trick suggested by @vneiger

@dlesnoff
dlesnoff marked this pull request as ready for review August 6, 2026 21:18
Comment on lines +223 to +225
Sets `f` to a random polynomial with up to the given length and where
each coefficient has up to the given number of bits. The coefficients
are uniformly generated random numbers in `[0, n)`, where `n` is the modulus given by the context `ctx`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to copy-paste the doc of e.g. nmod_poly:

Suggested change
Sets `f` to a random polynomial with up to the given length and where
each coefficient has up to the given number of bits. The coefficients
are uniformly generated random numbers in `[0, n)`, where `n` is the modulus given by the context `ctx`.
Generates a random polynomial with length up to `len`, with uniformly chosen coefficients.

Comment on lines +229 to +231
Sets `f` to a random monic polynomial with up to the given length and where
each coefficient has up to the given number of bits. The coefficients
are uniformly generated random numbers in `[0, n)`, where `n` is the modulus given by the context `ctx`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to copy-paste the doc of e.g. nmod_poly:

Suggested change
Sets `f` to a random monic polynomial with up to the given length and where
each coefficient has up to the given number of bits. The coefficients
are uniformly generated random numbers in `[0, n)`, where `n` is the modulus given by the context `ctx`.
Generates a random monic polynomial with length `len`, with uniformly chosen coefficients.

Comment on lines +235 to +236
Sets `f` to a random irreducible polynomial with up to the given length and where each coefficient has up to the given number of bits. The coefficients
are uniformly generated random numbers in `[0, n)`, where `n` is the modulus given by the context `ctx`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, I would suggest something more concise (and there is nothing about number of bits here):

Suggested change
Sets `f` to a random irreducible polynomial with up to the given length and where each coefficient has up to the given number of bits. The coefficients
are uniformly generated random numbers in `[0, n)`, where `n` is the modulus given by the context `ctx`.
Generates a random irreducible polynomial with up to the given length and where the coefficients
are generated uniformly.

Comment thread doc/source/fmpz_poly.rst
Sets `f` to a random polynomial with up to the given length and where
each coefficient has up to the given number of bits. The coefficients
are signed randomly.
are random numbers in `[1, n)`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a small mistake here, I don't think this function has been changed, and the previous doc was correct it seems(?).

Comment thread doc/source/nmod_poly.rst

.. function:: void nmod_poly_rand(nmod_poly_t poly, flint_rand_t state, slong len)

Generates a random polynomial with length up to ``len``.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Generates a random polynomial with length up to ``len``.
Generates a random polynomial with length up to ``len`` and coefficients generated uniformly.

Comment thread doc/source/nmod_poly.rst

.. function:: void nmod_poly_rand_monic(nmod_poly_t poly, flint_rand_t state, slong len)

Generates a random monic polynomial with length up to ``len``.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Generates a random monic polynomial with length up to ``len``.
Generates a random monic polynomial of length ``len`` and non-leading coefficients generated uniformly.

Comment thread doc/source/nmod_poly.rst

.. function:: void nmod_poly_rand_irreducible(nmod_poly_t poly, flint_rand_t state, slong len)

Generates a random irreducible polynomial with length up to ``len``.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Generates a random irreducible polynomial with length up to ``len``.
Generates a random irreducible polynomial with length up to ``len`` with coefficients generated uniformly.

Comment thread doc/source/nmod_poly.rst
.. function:: void nmod_poly_randtest(nmod_poly_t poly, flint_rand_t state, slong len)

Generates a random polynomial with length up to ``len``.
Generates a random and sparse with increased probability polynomial with length up to ``len``.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is sparse with increased proba, but also special values are more likely than with a uniform distribution. So maybe,

Suggested change
Generates a random and sparse with increased probability polynomial with length up to ``len``.
Generates a random polynomial with length up to ``len``, sparse with increased probability, and with coefficients generated by :func:`n_randtest` .

Comment thread doc/source/nmod_poly.rst
.. function:: void nmod_poly_randtest_monic(nmod_poly_t poly, flint_rand_t state, slong len)

Generates a random monic polynomial with length ``len``.
Generates a random and sparse with increased probability monic polynomial with length ``len``.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the comment above on a similar function.

@vneiger

vneiger commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Here is a first batch of comments, on the documentation.

Comment thread doc/source/fmpz.rst
.. function:: void fmpz_randm_nonzero(fmpz_t f, flint_rand_t state, const fmpz_t m)

Generates a random integer in the range `1` to `m - 1` inclusive. Requires
`m \geq 2`, otherwise an exception will result.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`m \geq 2`, otherwise an exception will result.
`m \geq 2`, otherwise an exception is thrown.

Comment thread src/fmpz/rand.c
{
if (fmpz_cmp_ui(m, 2) <= 0)
{
flint_throw(FLINT_ERROR, "Exception (fmpz_randm_nonzero). m <= 2.\n");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
flint_throw(FLINT_ERROR, "Exception (fmpz_randm_nonzero). m <= 2.\n");
flint_throw(FLINT_ERROR, "Exception (fmpz_randm_nonzero). m < 2.\n");

Comment thread src/fmpz/rand.c
void
fmpz_randm_nonzero(fmpz_t f, flint_rand_t state, const fmpz_t m)
{
if (fmpz_cmp_ui(m, 2) <= 0)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (fmpz_cmp_ui(m, 2) <= 0)
if (fmpz_cmp_ui(m, 2) < 0)

because the issue is when m is strictly less than 2

Comment thread src/fmpz/rand.c
Comment on lines +93 to +94
fmpz_randm(f, state, mMinusOne); // 0..m-2
fmpz_add_ui(f, f, 1); // 1..m-1

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fmpz_randm(f, state, mMinusOne); // 0..m-2
fmpz_add_ui(f, f, 1); // 1..m-1
fmpz_randm(f, state, mMinusOne); /* 0..m-2 */
fmpz_add_ui(f, f, 1); /* 1..m-1 */

Comment thread src/fmpz/rand.c
}

void
fmpz_randm_nonzero(fmpz_t f, flint_rand_t state, const fmpz_t m)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fmpz_randm_nonzero(fmpz_t f, flint_rand_t state, const fmpz_t m)
fmpz_randm_not_zero(fmpz_t f, flint_rand_t state, const fmpz_t m)

(to follow the naming used elsewhere: fmpq_randtest_not_zero, arf_randtest_not_zero, fq_default_rand_not_zero, etc)

Comment thread doc/source/fmpz.rst

Generates a random integer in the range `0` to `m - 1` inclusive.

.. function:: void fmpz_randm_nonzero(fmpz_t f, flint_rand_t state, const fmpz_t m)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.. function:: void fmpz_randm_nonzero(fmpz_t f, flint_rand_t state, const fmpz_t m)
.. function:: void fmpz_randm_not_zero(fmpz_t f, flint_rand_t state, const fmpz_t m)

Comment on lines +73 to +74
fmpz_randtest_unsigned(f->coeffs + i, state, fmpz_bits(fmpz_mod_ctx_modulus(ctx)));
fmpz_mod(f->coeffs + i, f->coeffs + i, fmpz_mod_ctx_modulus(ctx));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For these two lines (and all the similar ones below in this file), I would suggest to make use of fmpz_randtest_mod

{
if (len == 0)
{
flint_throw(FLINT_ERROR, "Exception (fmpz_mod_poly_randtest_irreducible). len == 0.\n");

@vneiger vneiger Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a mismatch function name / name in exception.

Comment on lines +112 to +113
fmpz_randtest_unsigned(poly->coeffs + random_idx + 1, state, fmpz_bits(fmpz_mod_ctx_modulus(ctx)));
fmpz_mod(poly->coeffs + random_idx + 1, poly->coeffs + random_idx + 1, fmpz_mod_ctx_modulus(ctx));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above, about using fmpz_randtest_mod

Comment thread src/nmod_poly/randtest.c
#include "nmod_poly.h"
#include "nmod_poly_factor.h"

// Rand functions -> random dense polynomials with high probability

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Rand functions -> random dense polynomials with high probability
/* rand functions -> coefficients generated uniformly */

@vneiger

vneiger commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Pay attention to the previous commit. I remove an invocation to fmpz_bits. It apparently fixes a segfault, but I am not sure why it was invocated in the first place. Could you check out for this during review?

Yes, your change is fine, and I agree this was an extraneous invocation that was probably added by mistake.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants