Conversation
Replace the calls to rand() in the library by a pseudo-random number generator that produces the same sequence on all platforms for a given seed: rand() is implementation-defined (e.g. RAND_MAX is only 32767 on Windows), so the random choices of msolve, such as primes and random linear forms, differed between operating systems. The generator is MT19937, taken from GSL 1.9 (src/neogb/mt.c), the last GSL release licensed under GPL version 2 or later. The imported file keeps GSL's license and copyright notices; the modifications (the GSL framework and the 1998/1999 seeding variants were removed, the code uses fixed-width types) are listed at the top of the file. The sequence coincides with GSL's gsl_rng_mt19937, which is checked by a new test. Each thread owns its own generator, the one of the main thread is seeded via --random-seed. Random numbers drawn inside OpenMP parallel loops (the random multipliers of the probabilistic linear algebra and the computations over several primes) now come from generators seeded from a base seed and the loop index, so that they do not depend on the thread scheduling: for a given seed and number of threads, the random choices are reproducible. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
wegank
marked this pull request as ready for review
October 1, 2026 19:56
Member
Author
|
This should be rebased once #370 is merged. |
wegank
marked this pull request as draft
October 1, 2026 23:49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
msolve used
rand()/srand()for all its random choices: the primes of the multi-modular algorithms, random linear forms, the multipliers of the probabilistic linear algebra, and the start vectors and verification values of FGLM.rand()is implementation-defined. Its sequence differs between C libraries, andRAND_MAXis only 32767 on Windows. So the same--random-seedled to different computations on different operating systems. In addition,rand()was called concurrently from OpenMP threads in the probabilistic linear algebra and in the loop over primes, so multi-threaded runs were not reproducible even on a single platform.Changes
src/neogb/mt.c,src/neogb/mt.h: the Mersenne Twister MT19937 from GSL 1.9 (rng/mt.c), the last GSL release licensed under GPL-2.0-or-later. GSL's license and copyright notices are kept, and the (dated) modifications are listed at the top ofmt.c:gsl_rngframework and the 1998/1999 seeding variants were removed;mt_set/mt_getare declared inmt.h, so they are no longerstatic;uint32_tinstead ofunsigned long.The generated sequence is identical to GSL's
gsl_rng_mt19937.src/neogb/rng.c,src/neogb/rng.h: msolve's interface to the generator.msolve_srand()/msolve_rand()replacesrand()/rand().msolve_rand()returns values in[0, 2^31 - 1], the same range as glibc'srand().msolve_rng_tprovides local generators.Parallel loops: random numbers no longer depend on the thread scheduling.
la_ff_{8,16,32}.c): each block draws its multipliers from a local generator seeded with a base seed plus the block index. The base seed is drawn before the parallel loop.secondary_modular_steps): each prime reseeds the generator of the executing thread with the base seed plus its index. The generator of the calling thread is saved before the loop and restored after it.--random-seed(ortime(0)by default) seeds the main thread's generator.New test
neogb_rng(test/neogb/rng/mt19937.c).Behaviour
libneogbinstalls two new headers (rng.h,mt.h) and exports the newmsolve_rng_*/msolve_rand*functions as well asmt_set/mt_get.Testing
make checkpasses (69 tests, including the new one).neogb_rngchecks:std::mt19937(seed 5489: the 10000th output is 4123659995);std::mt19937for 7 seeds × 10,000 draws.mt.candrng.cbuild without warnings (-Wall -Wextra -pedantic) under gnu99, c11, gnu17 and gnu23.nonradical-radicalshape-31.ms -P 1 -l 42,mastergave different outputs between runs with 4 and 8 threads. With this branch, every seed gives a single output across 1, 4 and 8 threads (40 seeds, 6 runs each).eco10-31,eco11-31,kat7-qq,henrion5-qqandcyclic5-qqwith-l 42/-l 44.unsigned long) was emulated and gives identical outputs; it has not been tested natively.Not addressed
nbdoitheuristic inmsolve.c). So the number of primes used may vary between runs, even with one thread. Outputs are not affected.Use of generative AI
This PR was prepared with the assistance of generative AI (Claude Code): parts of the code, the tests and this description were written with its help. The commit carries a corresponding
Co-Authored-Bytrailer.🤖 Generated with Claude Code