Bertini 2 d882924 (2026-10-06 19:56 UTC)
Numerical algebraic geometry library (C++ core)
Loading...
Searching...
No Matches
random.hpp
Go to the documentation of this file.
1//This file is part of Bertini 2.
2//
3// bertini2/random.hpp is free software: you can redistribute it and/or modify
4//it under the terms of the GNU General Public License as published by
5//the Free Software Foundation, either version 3 of the License, or
6//(at your option) any later version.
7//
8// bertini2/random.hpp is distributed in the hope that it will be useful,
9//but WITHOUT ANY WARRANTY; without even the implied warranty of
10//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11//GNU General Public License for more details.
12//
13//You should have received a copy of the GNU General Public License
14//along with bertini2/random.hpp. If not, see <http://www.gnu.org/licenses/>.
15//
16// Copyright(C) Bertini2 Development Team
17//
18// See <http://www.gnu.org/licenses/> for a copy of the license,
19// as well as COPYING. Bertini2 is provided with permitted
20// additional terms in the b2/licenses/ directory.
21
27
28#ifndef BERTINI_RANDOM_HPP
29#define BERTINI_RANDOM_HPP
30
31
32
33
36#include <boost/random.hpp>
37#include <random>
38#include <cstdint>
39
40
41namespace bertini
42{
43
50 std::mt19937& ThreadEngine();
51
60 // 0 is a seed here and entropy in the classic format: each follows its users' convention (ADR-0072)
61 void SetGlobalSeed(unsigned long seed);
62
67 unsigned long SetGlobalSeedFromEntropy();
68
77 unsigned long ApplyClassicRandomSeed(unsigned long randomseed);
78
83 unsigned long GetGlobalSeed();
84
91 void ReseedThisThread(uint64_t stream_key);
92
99 unsigned long DerivedWorkerSeed(uint64_t worker_index);
100
122 unsigned long DeriveSolveSeed();
123
124
128 template <unsigned long digits = 50>
129 inline
131 {
132 // pinned draw (b2rand/1, ADR-0044): uniform on [-2^(digits/log10(2)), +same]
133 return records::ThreadDrawStream().IntSymmetric(mpz_int(1) << digits*1000L/301L);
134 }
135
136
140 template <unsigned long digits = 50>
142 {
143 // pinned draws (b2rand/1, ADR-0044). A zero denominator is redrawn (deterministically):
144 // the legacy draw could in principle hand mpq a denominator of 0.
145 mpz_int const bound = mpz_int(1) << digits*1000L/301L;
146 auto& stream = records::ThreadDrawStream();
147 mpz_int const num = stream.IntSymmetric(bound);
148 mpz_int den = stream.IntSymmetric(bound);
149 while (den == 0)
150 den = stream.IntSymmetric(bound);
151 return mpq_rational(num, den);
152 }
153
154
160 template <unsigned int length_in_digits>
162 {
163 // Pinned draw (b2rand/1, ADR-0044) from the single per-thread stream shared by
164 // every random type, so SetGlobalSeed()/ReseedThisThread() control them all
165 // uniformly. Uniform on [0,1) at length_in_digits digits, bit-identical on
166 // every platform.
167 real_mp a{records::ThreadDrawStream().UnitRealMp(length_in_digits)};
168 return a;
169 }
170
177 template <unsigned int length_in_digits>
179 {
181 }
182
191 template <unsigned int length_in_digits>
192 real_mp RandomMp(const real_mp & left, const real_mp & right)
193 {
194 return (right-left)*RandomMp<length_in_digits>()+left;
195 }
196
197
198
203
209 real_mp RandomMp(unsigned num_digits);
210
214 real_mp RandomMp(const real_mp & a, const real_mp & b);
215
219 real_mp RandomMp(const real_mp & a, const real_mp & b, unsigned num_digits);
220
226 void RandomMpAssign(real_mp & a, unsigned num_digits);
227
228
229
230
231} // re: namespace bertini
232
233
234
235
236namespace bertini{
237
239
240
243
244
245
249 inline
250 void RandomRealAssign(complex & a, unsigned num_digits)
251 {
252 auto cached = ThreadPrecision();
253 SetThreadPrecision(num_digits);
254 complex temp(RandomMp(real_mp(-1),real_mp(1),num_digits)); // ,0
255 a.swap(temp);
256 SetThreadPrecision(cached);
257 }
258
263 {
264 return complex(RandomMp(real_mp(-1),real_mp(1))); // ,0
265 }
266
270 inline complex RandomReal(unsigned num_digits)
271 {
272 auto cached = ThreadPrecision();
273 SetThreadPrecision(num_digits);
274 auto result = complex(RandomMp(real_mp(-1),real_mp(1),num_digits));// ,0
275 SetThreadPrecision(cached);
276 return result;
277 }
278
279
280
281
282
283
284
288 inline complex rand()
289 {
290 // DRAW ORDER IS A CONTRACT (cross-platform reproducibility, 2026-07-03): the two
291 // component draws are sequenced EXPLICITLY -- real first, then imaginary. Never
292 // put two draws in one full-expression: C++ argument evaluation order is
293 // unspecified, and gcc really does order them differently on x86_64 vs aarch64
294 // (found as an architecture-split seeded-homotopy digest: every (re, im) pair of
295 // every seeded coefficient was transposed between the two).
296 real_mp const re = RandomMp(real_mp(-1),real_mp(1));
297 real_mp const im = RandomMp(real_mp(-1),real_mp(1));
298 return complex( re, im );
299 }
300
301
306 {
307 // draw order is a contract: real first, then imaginary (see rand())
308 real_mp const re = RandomMp(real_mp(-1),real_mp(1));
309 real_mp const im = RandomMp(real_mp(-1),real_mp(1));
310 complex returnme( re, im );
311 return returnme / abs(returnme); // normalize to modulus 1 (NOT sqrt(abs), which left modulus sqrt|z|)
312 }
313
316 {
317 return rand_unit();
318 }
319
320
331 {
332 // draw order is a contract: real first, then imaginary (see rand())
333 real_mp re = RandomMp(real_mp(-1),real_mp(1));
334 real_mp im = RandomMp(real_mp(-1),real_mp(1));
335 complex z( re, im );
336 auto m = abs(z);
337 while (m == 0) // measure-zero, but a zero coefficient is degenerate -- redraw
338 {
339 re = RandomMp(real_mp(-1),real_mp(1));
340 im = RandomMp(real_mp(-1),real_mp(1));
341 z = complex( re, im );
342 m = abs(z);
343 }
344 return z / sqrt(m);
345 }
346
349 {
350 return rand_bounded_modulus();
351 }
352
354 inline
355 void RandomComplexBoundedModulusAssign(complex & a, unsigned num_digits)
356 {
357 auto cached = ThreadPrecision();
358 SetThreadPrecision(num_digits);
359 a.precision(num_digits);
360
361 // draw order is a contract: real first, then imaginary (see rand())
362 real_mp re = RandomMp(real_mp(-1),real_mp(1),num_digits);
363 real_mp im = RandomMp(real_mp(-1),real_mp(1),num_digits);
364 complex z( re, im );
365 auto m = abs(z);
366 while (m == 0)
367 {
368 re = RandomMp(real_mp(-1),real_mp(1),num_digits);
369 im = RandomMp(real_mp(-1),real_mp(1),num_digits);
370 z = complex( re, im );
371 m = abs(z);
372 }
373 a = std::move(z / sqrt(m));
374 SetThreadPrecision(cached);
375 }
376
378 inline
380 {
381 complex a;
383 return a;
384 }
385
386
396 {
397 complex z( RandomMp(real_mp(-1),real_mp(1)) ); // imaginary part 0
398 auto m = abs(z);
399 while (m == 0) // measure-zero, but a zero coefficient is degenerate -- redraw
400 {
401 z = complex( RandomMp(real_mp(-1),real_mp(1)) );
402 m = abs(z);
403 }
404 return z / sqrt(m); // stays real (imag 0 / real = 0)
405 }
406
412
414 inline
415 void RandomRealBoundedModulusAssign(complex & a, unsigned num_digits)
416 {
417 auto cached = ThreadPrecision();
418 SetThreadPrecision(num_digits);
419 a.precision(num_digits);
420
421 complex z( RandomMp(real_mp(-1),real_mp(1),num_digits) ); // imaginary part 0
422 auto m = abs(z);
423 while (m == 0)
424 {
425 z = complex( RandomMp(real_mp(-1),real_mp(1),num_digits) );
426 m = abs(z);
427 }
428 a = std::move(z / sqrt(m)); // stays real
429 SetThreadPrecision(cached);
430 }
431
433 inline
435 {
436 complex a;
437 RandomRealBoundedModulusAssign(a, num_digits);
438 return a;
439 }
440
442 inline
443 void rand_assign(complex & a, unsigned num_digits)
444 {
445 auto cached = ThreadPrecision();
446 SetThreadPrecision(num_digits);
447
448 // draw order is a contract: real first, then imaginary (see rand())
449 real_mp const re = RandomMp(num_digits);
450 real_mp const im = RandomMp(num_digits);
451 complex_mp temp( re, im );
452 a = std::move(temp);
453 SetThreadPrecision(cached);
454 }
455
457 inline
458 void RandomComplexAssign(complex & a, unsigned num_digits)
459 {
460 rand_assign(a,num_digits);
461 }
462
464 inline
465 complex RandomComplex(unsigned num_digits)
466 {
467 complex z;
468 RandomComplexAssign(z, num_digits);
469 return z;
470 }
471
473 inline
474 void RandomUnitAssign(complex & a, unsigned num_digits)
475 {
476 auto cached = ThreadPrecision();
477 SetThreadPrecision(num_digits);
478 a.precision(num_digits);
479
480 // draw order is a contract: real first, then imaginary (see rand())
481 real_mp const re = RandomMp(num_digits);
482 real_mp const im = RandomMp(num_digits);
483 complex temp(re, im);
484 a = std::move(temp/abs(temp)); // normalize to modulus 1 (NOT sqrt(abs))
485 SetThreadPrecision(cached);
486 }
487
489 inline
490 complex RandomUnit(unsigned num_digits)
491 {
492 complex a;
493 RandomUnitAssign(a,num_digits);
494 return a;
495 }
496
497} // namespace multiprecision
498
499
500} // namespaces
501// }
502
503
504
505#endif
real_mp UnitRealMp(unsigned digits)
Uniform on [0,1) at digits decimal digits: ldexp(Bits(k), -k) with k = ceil(digits*log2(10)) + 1,...
mpz_int IntSymmetric(mpz_int const &bound)
Uniform integer on [-bound, bound], by rejection over Bits(bitlen(2*bound)).
Seed-rooted, fully-specified random derivation (b2rand/1; ADR-0044; the structured-output-directory a...
The main multiprecision complex number type.
Definition random.hpp:238
complex rand_bounded_modulus()
Produce a random complex number whose modulus is pulled toward 1, to default precision.
Definition random.hpp:330
complex RandomComplex(unsigned num_digits)
Produce a random complex number, at the given precision.
Definition random.hpp:465
void RandomComplexBoundedModulusAssign(complex &a, unsigned num_digits)
Assign to a a random complex number whose modulus is pulled toward 1, at the given precision.
Definition random.hpp:355
void RandomUnitAssign(complex &a, unsigned num_digits)
Assign a random unit-modulus complex number to a, at the given precision.
Definition random.hpp:474
void rand_assign(complex &a, unsigned num_digits)
Assign a random complex number to a, at the given precision.
Definition random.hpp:443
complex RandomRealBoundedModulus()
Produce a random REAL number (imaginary part 0) whose modulus is pulled toward 1, at default precisio...
Definition random.hpp:408
bertini::complex_mp complex
Shorthand for the multiprecision complex type within this namespace.
Definition random.hpp:241
complex rand_unit()
Produce a random unit complex number, to default precision.
Definition random.hpp:305
void RandomRealBoundedModulusAssign(complex &a, unsigned num_digits)
Assign to a a random REAL number (imaginary part 0) whose modulus is pulled toward 1,...
Definition random.hpp:415
complex RandomReal()
Produce a random real number , to current default precision.
Definition random.hpp:262
complex rand_real_bounded_modulus()
Produce a random REAL number whose modulus is pulled toward 1, to default precision.
Definition random.hpp:395
void RandomRealAssign(complex &a, unsigned num_digits)
Assign to a random real number , to current default precision.
Definition random.hpp:250
complex rand()
Produce a random complex number, to default precision.
Definition random.hpp:288
complex RandomComplexBoundedModulus()
Produce a random complex number whose modulus is pulled toward 1 (away from 0 and infinity),...
Definition random.hpp:348
complex RandomUnit()
Produce a random unit-modulus complex number, to default precision.
Definition random.hpp:315
void RandomComplexAssign(complex &a, unsigned num_digits)
Assign a random complex number to a, at the given precision.
Definition random.hpp:458
real_mp RandomMp()
Produce a random number with at length_in_digits non-zero digits.
Definition random.hpp:161
DrawStream & ThreadDrawStream()
This thread's pinned draw stream — the source of every identity-relevant random draw in bertini2.
Definition algorithm_builder.hpp:36
unsigned long ApplyClassicRandomSeed(unsigned long randomseed)
Apply a classic input file's randomseed, as Bertini 1 does: 0, the default, draws a seed from entropy...
boost::multiprecision::number< boost::multiprecision::backends::gmp_int, boost::multiprecision::et_on > mpz_int
The arbitrary-precision integer type.
Definition mpfr_extensions.hpp:54
void SetGlobalSeed(unsigned long seed)
Set the global RNG seed.
std::mt19937 & ThreadEngine()
Returns this thread's canonical mt19937 engine.
unsigned long GetGlobalSeed()
Returns the effective global seed.
mpz_int RandomInt()
Generate a random integer number between -10^digits and 10^digits.
Definition random.hpp:130
void ReseedThisThread(uint64_t stream_key)
Reseed this thread's engine deterministically from the global seed mixed with stream_key.
void SetThreadPrecision(unsigned prec)
Set the precision (digits) for the current thread only (does not touch the global default).
Definition mpfr_complex.hpp:176
unsigned long DeriveSolveSeed()
Derive an EFFECTIVE PER-SOLVE SEED from the current master.
unsigned long DerivedWorkerSeed(uint64_t worker_index)
Derive a distinct, deterministic child seed for a worker rank from the global (master) seed.
unsigned long SetGlobalSeedFromEntropy()
Set the global RNG seed to one drawn from std::random_device, and return it, so the run can be reprod...
bmp::number< mpc_complex_backend< 0 >, bmp::et_on > complex_mp
The arbitrary-precision complex number type.
Definition mpfr_complex.hpp:58
boost::multiprecision::number< boost::multiprecision::mpfr_float_backend< 0 >, boost::multiprecision::et_on > real_mp
The arbitrary-precision real number type.
Definition mpfr_extensions.hpp:53
void RandomMpAssign(real_mp &a)
a templated function for producing random numbers in the unit interval, of a given number of digits.
Definition random.hpp:178
unsigned ThreadPrecision()
Get the current thread's precision (digits).
Definition mpfr_complex.hpp:183
mpq_rational RandomRat()
Generate a random rational number with numerator and denomenator between -10^digits and 10^digits.
Definition random.hpp:141
boost::multiprecision::number< boost::multiprecision::backends::gmp_rational, boost::multiprecision::et_on > mpq_rational
The exact rational number type.
Definition mpfr_extensions.hpp:55
real_mp RandomMp()
Produce a random number with at length_in_digits non-zero digits.
Definition random.hpp:161