Macaulay2 Engine
Loading...
Searching...
No Matches
random.cpp
Go to the documentation of this file.
1// Copyright 2008 by Michael Stillman
2
3#include "interface/random.h"
5
6#include "exceptions.hpp"
7#include "error.h"
8
9#define INITIALMAXINT 10
10
11#define IA 16807
12#define IM 2147483647
13#define IQ 127773
14#define IR 2836
15#define MASK 123459876
16
17static mpz_t maxHeight;
18static gmp_randstate_t state;
19static int32_t RandomSeed = MASK;
20
22{
24 mpz_init_set_si(maxHeight, INITIALMAXINT);
25 gmp_randinit_default(state);
26}
27
29{
30 gmp_randseed(state, newseed);
31
32 int32_t s = mpz_get_si(newseed);
33 s = s & 0x7fffffff;
34 if (s == MASK) s = 0;
35 RandomSeed = s ^ MASK;
36}
37
38void rawSetRandomMax(gmp_ZZ newHeight) { mpz_set(maxHeight, newHeight); }
39unsigned long rawRandomULong(unsigned long max)
40{
41 return gmp_urandomm_ui(state, max);
42}
43
44int32_t rawRandomInt(int32_t max)
45/* generate a random number in the range 0..max-1 */
46{
47 if (max <= 0) return 0;
48 int32_t k = RandomSeed / IQ;
50 IA * (RandomSeed - k * IQ) - IR * k; /* Schrage algorithm to compute
51 idum = (IA*idum) mod IM */
52 if (RandomSeed < 0) RandomSeed += IM;
53 return RandomSeed % max;
54}
55
57/* if height is the null pointer, use the default height */
58{
59 if (maxN == nullptr) maxN = maxHeight;
60 if (mpz_cmp_si(maxN, 0) <= 0)
61 throw exc::engine_error("expected a positive height");
62
63 mpz_urandomm(result, state, maxN);
64}
65
67/* if height is the null pointer, use the default height */
68{
69 mpz_ptr result = getmemstructtype(mpz_ptr);
70 mpz_init(result);
71
72 try {
74 } catch (const exc::engine_error& e) {
75 ERROR(e.what());
76 return nullptr;
77 }
78
80 return result;
81}
82
84/* sets result = the nearest rational to x w/ denominator <= height */
85/* see https://en.wikipedia.org/wiki/Farey_sequence */
86{
87 int sgn;
88 mpfr_t fracpart, tmp1, tmp2;
89 mpz_t intpart, a, b, c, d, q, p;
90 mpq_t tmp3;
91
92 // get integer and fractional parts of |x|
93 sgn = mpfr_sgn(x);
94 mpfr_init2(fracpart, mpfr_get_prec(x));
95 mpfr_abs(fracpart, x, MPFR_RNDN);
96 mpz_init(intpart);
97 mpfr_get_z(intpart, fracpart, MPFR_RNDD);
98 mpfr_frac(fracpart, fracpart, MPFR_RNDN);
99
100 // goal: find nearest rational number to fracpart
101 // start w/ a/b = 0, p/q = 1/2, c/d = 1
102 mpfr_init2(tmp1, mpfr_get_prec(x));
103 mpfr_init2(tmp2, mpfr_get_prec(x));
104 mpz_init_set_ui(a, 0);
105 mpz_init_set_ui(b, 1);
106 mpz_init_set_ui(c, 1);
107 mpz_init_set_ui(d, 1);
108 mpz_init_set_ui(p, 1);
109 mpz_init_set_ui(q, 2);
110 mpq_init(tmp3);
111
112 // compute mediant p/q = (a+c)/(b+d) until q > height
113 while (mpz_cmp(q, height) <= 0) {
114 mpfr_mul_z(tmp1, fracpart, q, MPFR_RNDN);
115 // check if fracpart is to the left or right of p/q
116 // and update a/b or c/d accordingly
117 if (mpfr_cmp_z(tmp1, p) <= 0) {
118 mpz_set(c, p);
119 mpz_set(d, q);
120 } else {
121 mpz_set(a, p);
122 mpz_set(b, q);
123 }
124 mpz_add(p, a, c);
125 mpz_add(q, b, d);
126 }
127
128 // now check which endpoint is closest
129 // tmp1 = fracpart - a/b
130 mpfr_set_z(tmp1, a, MPFR_RNDN);
131 mpfr_neg(tmp1, tmp1, MPFR_RNDN);
132 mpfr_div_z(tmp1, tmp1, b, MPFR_RNDN);
133 mpfr_add(tmp1, tmp1, fracpart, MPFR_RNDN);
134
135 // tmp2 = c/d - fracpart
136 mpfr_set_z(tmp2, c, MPFR_RNDN);
137 mpfr_div_z(tmp2, tmp2, d, MPFR_RNDN);
138 mpfr_sub(tmp2, tmp2, fracpart, MPFR_RNDN);
139
140 if (mpfr_cmp(tmp1, tmp2) <= 0) {
141 mpq_set_z(result, a);
142 mpq_set_z(tmp3, b);
143 } else {
144 mpq_set_z(result, c);
145 mpq_set_z(tmp3, d);
146 }
147
148 // finally, add back intpart and negate if x < 0
149 mpq_div(result, result, tmp3);
150 mpq_set_z(tmp3, intpart);
151 mpq_add(result, result, tmp3);
152 mpq_set_si(tmp3, sgn, 1);
153 mpq_mul(result, result, tmp3);
154 mpq_canonicalize(result);
155
156 mpz_clears(intpart, a, b, c, d, p, q, nullptr);
157 mpfr_clears(fracpart, tmp1, tmp2, nullptr);
158 mpq_clear(tmp3);
159}
160
162/* returns the nearest rational to x w/ denominator <= height */
163{
164 mpq_ptr result = getmemstructtype(mpq_ptr);
165 mpq_init(result);
167 return moveTo_gmpQQ(result);
168}
169
170void rawSetRandomQQ(mpq_ptr result, gmp_ZZ height)
171/* returns random a/b, where 1 <= b <= height, 1 <= a <= height */
172/* if height is the null pointer, use the default height */
173{
174 mpz_t d;
175
176 mpz_init(d);
177 if (height == nullptr) height = maxHeight;
178 if (mpz_cmp_si(height, 0) <= 0)
179 throw exc::engine_error("expected a positive height");
180
181 while (true) {
182 mpz_urandomm(mpq_numref(result), state, height);
183 mpz_urandomm(mpq_denref(result), state, height);
184 mpz_add_ui(mpq_numref(result), mpq_numref(result), 1);
185 mpz_add_ui(mpq_denref(result), mpq_denref(result), 1);
186 mpz_gcd(d, mpq_numref(result), mpq_denref(result));
187 if (mpz_cmp_ui(d, 1) == 0)
188 break;
189 }
190
191 mpz_clear(d);
192}
193
195/* returns random a/b, where 1 <= b <= height, 1 <= a <= height */
196/* if height is the null pointer, use the default height */
197{
198 mpq_ptr result = getmemstructtype(mpq_ptr);
199 mpq_init(result);
200
201 try {
202 rawSetRandomQQ(result, height);
203 } catch (const exc::engine_error& e) {
204 ERROR(e.what());
205 return nullptr;
206 }
207
208 return moveTo_gmpQQ(result);
209}
210
211gmp_RR rawRandomRRUniform(unsigned long precision)
212/* returns a uniformly distributed random real with the given precision, in
213 * range [0.0,1.0] */
214{
215 mpfr_ptr result = getmemstructtype(mpfr_ptr);
216 mpfr_init2(result, precision);
217 mpfr_urandomb(result, state);
218 return moveTo_gmpRR(result);
219}
220
221gmp_RR rawRandomRRNormal(unsigned long precision)
222/* returns a normally distributed random real with the given precision */
223{
224 mpfr_ptr result = getmemstructtype(mpfr_ptr);
225 mpfr_init2(result, precision);
226 mpfr_nrandom(result, state, MPFR_RNDN);
227 return moveTo_gmpRR(result);
228}
229
230gmp_CC rawRandomCC(unsigned long precision)
231/* returns a uniformly distributed random complex in the box [0.0,0.0],
232 * [1.0,1.0] */
233{
235 result->re = const_cast<gmp_RRmutable>(rawRandomRRUniform(precision));
236 result->im = const_cast<gmp_RRmutable>(rawRandomRRUniform(precision));
237 return reinterpret_cast<gmp_CC>(result);
238}
239
240void randomMpfr(mpfr_t result)
241/* returns a uniformly distributed random real with the given precision, in
242 * range [0.0,1.0]
243 * (result is assumed to be initialized) */
244{
245 mpfr_urandomb(result, state);
246}
247
249{
250 mpfr_t val;
251 mpfr_init2(val, 53);
252 randomMpfr(val);
253 double result = mpfr_get_d(val, MPFR_RNDN);
254 mpfr_clear(val);
255 return result;
256}
257
259{
260 mpfr_t val;
261
262 mpfr_init2(val, mpfi_get_prec(result));
263 randomMpfr(val);
264 mpfi_set_fr(result,val);
265 randomMpfr(val);
266 mpfi_put_fr(result,val);
267 mpfr_clear(val);
268}
269
270gmp_RRi rawRandomRRi(unsigned long precision)
271{
272 mpfi_ptr result;
273
274 result = getmemstructtype(mpfi_ptr);
275 mpfi_init2(result, precision);
277
278 return moveTo_gmpRRi(result);
279}
280
281gmp_CCi rawRandomCCi(unsigned long precision)
282{
284 result->re = const_cast<gmp_RRimutable>(rawRandomRRi(precision));
285 result->im = const_cast<gmp_RRimutable>(rawRandomRRi(precision));
286 return reinterpret_cast<gmp_CCi>(result);
287}
288
289
291{
292#if 0
293 extern long random();
294 return random();
295#elif 0
296 extern long random00();
297 return random00();
298#else
299 return rawRandomInt((int32_t)~0 >> 1);
300#endif
301}
302
303// Local Variables:
304// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
305// indent-tabs-mode: nil
306// End:
Engine error-reporting primitives: ERROR, INTERNAL_ERROR, error, error_message.
namespace exc — internal C++ exception types and the TRY / CATCH macro pair.
mpfr_srcptr moveTo_gmpRR(mpfr_ptr _z)
Definition gmp-util.h:153
gmp_QQ moveTo_gmpQQ(mpq_ptr z)
Definition gmp-util.h:58
mpfi_srcptr moveTo_gmpRRi(mpfi_ptr _z)
Definition gmp-util.h:159
void mpz_reallocate_limbs(mpz_ptr _z)
Definition gmp-util.h:46
Inline helpers that move GMP / MPFR / MPFI limbs from malloc-managed storage into the bdwgc heap.
int p
void size_t s
Definition m2-mem.cpp:271
const int ERROR
Definition m2-mem.cpp:55
VALGRIND_MAKE_MEM_DEFINED & result(result)
#define getmemstructtype(S)
Definition m2-mem.h:143
mpfr_srcptr gmp_RR
Definition m2-types.h:148
struct gmp_CC_struct * gmp_CC
Definition m2-types.h:156
mpfr_ptr gmp_RRmutable
Definition m2-types.h:150
mpfi_ptr gmp_RRimutable
Definition m2-types.h:152
struct gmp_CCmutable_struct * gmp_CCmutable
Definition m2-types.h:159
mpfi_srcptr gmp_RRi
Definition m2-types.h:153
mpz_srcptr gmp_ZZ
Definition m2-types.h:141
mpq_srcptr gmp_QQ
Definition m2-types.h:145
struct gmp_CCi_struct * gmp_CCi
Definition m2-types.h:162
struct gmp_CCimutable_struct * gmp_CCimutable
Definition m2-types.h:165
volatile int x
#define max(a, b)
Definition polyroots.cpp:52
static int32_t RandomSeed
Definition random.cpp:19
static mpz_t maxHeight
Definition random.cpp:17
double randomDouble()
Definition random.cpp:248
#define IM
Definition random.cpp:12
#define INITIALMAXINT
Definition random.cpp:9
void rawSetRandomMax(gmp_ZZ newHeight)
Definition random.cpp:38
unsigned long rawRandomULong(unsigned long max)
Definition random.cpp:39
#define IR
Definition random.cpp:14
void rawSetFareyApproximation(mpq_ptr result, gmp_RR x, gmp_ZZ height)
Definition random.cpp:83
void rawSetRandomSeed(gmp_ZZ newseed)
Definition random.cpp:28
void rawSetRandomRRi(mpfi_ptr result)
Definition random.cpp:258
int32_t rawRandomInt(int32_t max)
Definition random.cpp:44
gmp_CC rawRandomCC(unsigned long precision)
Definition random.cpp:230
void rawSetRandomInteger(mpz_ptr result, gmp_ZZ maxN)
Definition random.cpp:56
static gmp_randstate_t state
Definition random.cpp:18
gmp_RR rawRandomRRNormal(unsigned long precision)
Definition random.cpp:221
void rawSetRandomQQ(mpq_ptr result, gmp_ZZ height)
Definition random.cpp:170
#define IQ
Definition random.cpp:13
void rawRandomInitialize()
Definition random.cpp:21
void randomMpfr(mpfr_t result)
Definition random.cpp:240
gmp_ZZ rawRandomInteger(gmp_ZZ maxN)
Definition random.cpp:66
gmp_QQ rawRandomQQ(gmp_ZZ height)
Definition random.cpp:194
gmp_CCi rawRandomCCi(unsigned long precision)
Definition random.cpp:281
gmp_QQ rawFareyApproximation(gmp_RR x, gmp_ZZ height)
Definition random.cpp:161
gmp_RRi rawRandomRRi(unsigned long precision)
Definition random.cpp:270
#define IA
Definition random.cpp:11
#define MASK
Definition random.cpp:15
int system_randomint()
Definition random.cpp:290
gmp_RR rawRandomRRUniform(unsigned long precision)
Definition random.cpp:211
Engine-boundary C API for the engine's PRNG and rational / real / complex random draws.