/ src / gmpy2_random.c
gmpy2_random.c
  1  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2   * gmpy_random.c                                                           *
  3   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  4   * Python interface to the GMP or MPIR, MPFR, and MPC multiple precision   *
  5   * libraries.                                                              *
  6   *                                                                         *
  7   * Copyright 2000 - 2009 Alex Martelli                                     *
  8   *                                                                         *
  9   * Copyright 2008 - 2021 Case Van Horsen                                   *
 10   *                                                                         *
 11   * This file is part of GMPY2.                                             *
 12   *                                                                         *
 13   * GMPY2 is free software: you can redistribute it and/or modify it under  *
 14   * the terms of the GNU Lesser General Public License as published by the  *
 15   * Free Software Foundation, either version 3 of the License, or (at your  *
 16   * option) any later version.                                              *
 17   *                                                                         *
 18   * GMPY2 is distributed in the hope that it will be useful, but WITHOUT    *
 19   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or   *
 20   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public    *
 21   * License for more details.                                               *
 22   *                                                                         *
 23   * You should have received a copy of the GNU Lesser General Public        *
 24   * License along with GMPY2; if not, see <http://www.gnu.org/licenses/>    *
 25   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 26  
 27  static RandomState_Object *
 28  GMPy_RandomState_New(void)
 29  {
 30      RandomState_Object *result;
 31  
 32      if ((result = PyObject_New(RandomState_Object, &RandomState_Type))) {
 33          gmp_randinit_default(result->state);
 34      }
 35      return result;
 36  };
 37  
 38  static void
 39  GMPy_RandomState_Dealloc(RandomState_Object *self)
 40  {
 41      gmp_randclear(self->state);
 42      PyObject_Del(self);
 43  };
 44  
 45  static PyObject *
 46  GMPy_RandomState_Repr(RandomState_Object *self)
 47  {
 48      return Py_BuildValue("s", "<gmpy2.RandomState>");
 49  };
 50  
 51  PyDoc_STRVAR(GMPy_doc_random_state_factory,
 52  "random_state([seed]) -> object\n\n"
 53  "Return new object containing state information for the random number\n"
 54  "generator. An optional integer can be specified as the seed value.");
 55  
 56  static PyObject *
 57  GMPy_RandomState_Factory(PyObject *self, PyObject *args)
 58  {
 59      RandomState_Object *result;
 60      MPZ_Object *temp;
 61  
 62      if (!(result = GMPy_RandomState_New())) {
 63          return NULL;
 64      }
 65  
 66      if (PyTuple_GET_SIZE(args) == 0) {
 67          gmp_randseed_ui(result->state, 0);
 68      }
 69      else if (PyTuple_GET_SIZE(args) == 1) {
 70          if (!(temp = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args,0), NULL))) {
 71              Py_DECREF((PyObject*)result);
 72              TYPE_ERROR("seed must be an integer");
 73              return NULL;
 74          }
 75          gmp_randseed(result->state, temp->z);
 76          Py_DECREF((PyObject*)temp);
 77      }
 78      else {
 79          Py_DECREF((PyObject*)result);
 80          TYPE_ERROR("random_state() requires 0 or 1 integer arguments");
 81          return NULL;
 82      }
 83      return (PyObject*)result;
 84  }
 85  
 86  PyDoc_STRVAR(GMPy_doc_mpz_urandomb_function,
 87  "mpz_urandomb(random_state, bit_count) -> mpz\n\n"
 88  "Return uniformly distributed random integer between 0 and\n"
 89  "2**bit_count-1.");
 90  
 91  static PyObject *
 92  GMPy_MPZ_urandomb_Function(PyObject *self, PyObject *args)
 93  {
 94      MPZ_Object *result;
 95      mp_bitcnt_t len;
 96  
 97      if (PyTuple_GET_SIZE(args) != 2) {
 98          TYPE_ERROR("mpz_urandomb() requires 2 arguments");
 99          return NULL;
100      }
101  
102      if (!RandomState_Check(PyTuple_GET_ITEM(args, 0))) {
103          TYPE_ERROR("mpz_urandomb() requires 'random_state' and 'bit_count' arguments");
104          return NULL;
105      }
106  
107      len = mp_bitcnt_t_From_Integer(PyTuple_GET_ITEM(args, 1));
108      if (len == (mp_bitcnt_t)(-1) && PyErr_Occurred()) {
109          TYPE_ERROR("mpz_urandomb() requires 'random_state' and 'bit_count' arguments");
110          return NULL;
111      }
112  
113      if ((result = GMPy_MPZ_New(NULL))) {
114          mpz_urandomb(result->z, RANDOM_STATE(PyTuple_GET_ITEM(args, 0)), len);
115      }
116  
117      return (PyObject*)result;
118  }
119  
120  PyDoc_STRVAR(GMPy_doc_mpz_rrandomb_function,
121  "mpz_rrandomb(random_state, bit_count) -> mpz\n\n"
122  "Return a random integer between 0 and 2**bit_count-1 with long\n"
123  "sequences of zeros and one in its binary representation.");
124  
125  static PyObject *
126  GMPy_MPZ_rrandomb_Function(PyObject *self, PyObject *args)
127  {
128      MPZ_Object *result;
129      mp_bitcnt_t len;
130  
131      if (PyTuple_GET_SIZE(args) != 2) {
132          TYPE_ERROR("mpz_rrandomb() requires 2 arguments");
133          return NULL;
134      }
135  
136      if (!RandomState_Check(PyTuple_GET_ITEM(args, 0))) {
137          TYPE_ERROR("mpz_rrandomb() requires 'random_state' and 'bit_count' arguments");
138          return NULL;
139      }
140  
141      len = mp_bitcnt_t_From_Integer(PyTuple_GET_ITEM(args, 1));
142      if (len == (mp_bitcnt_t)(-1) && PyErr_Occurred()) {
143          TYPE_ERROR("mpz_rrandomb() requires 'random_state' and 'bit_count' arguments");
144          return NULL;
145      }
146  
147      if ((result = GMPy_MPZ_New(NULL))) {
148          mpz_rrandomb(result->z, RANDOM_STATE(PyTuple_GET_ITEM(args, 0)), len);
149      }
150  
151      return (PyObject*)result;
152  }
153  
154  PyDoc_STRVAR(GMPy_doc_mpz_random_function,
155  "mpz_random(random_state, int) -> mpz\n\n"
156  "Return uniformly distributed random integer between 0 and n-1.");
157  
158  static PyObject *
159  GMPy_MPZ_random_Function(PyObject *self, PyObject *args)
160  {
161      MPZ_Object *result, *temp;
162  
163      if (PyTuple_GET_SIZE(args) != 2) {
164          TYPE_ERROR("mpz_random() requires 2 arguments");
165          return NULL;
166      }
167  
168      if (!RandomState_Check(PyTuple_GET_ITEM(args, 0))) {
169          TYPE_ERROR("mpz_random() requires 'random_state' and 'int' arguments");
170          return NULL;
171      }
172  
173      if (!(temp = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL))) {
174          TYPE_ERROR("mpz_random() requires 'random_state' and 'int' arguments");
175          return NULL;
176      }
177  
178      if ((result = GMPy_MPZ_New(NULL))) {
179          mpz_urandomm(result->z, RANDOM_STATE(PyTuple_GET_ITEM(args, 0)), temp->z);
180      }
181  
182      Py_DECREF((PyObject*)temp);
183      return (PyObject*)result;
184  }
185  
186  PyDoc_STRVAR(GMPy_doc_mpfr_random_function,
187  "mpfr_random(random_state) -> mpfr\n\n"
188  "Return uniformly distributed number between [0,1].");
189  
190  static PyObject *
191  GMPy_MPFR_random_Function(PyObject *self, PyObject *args)
192  {
193      MPFR_Object *result;
194      CTXT_Object *context = NULL;
195  
196      CHECK_CONTEXT(context);
197  
198      if (PyTuple_GET_SIZE(args) != 1) {
199          TYPE_ERROR("mpfr_random() requires 1 argument");
200          return NULL;
201      }
202  
203      if (!RandomState_Check(PyTuple_GET_ITEM(args, 0))) {
204          TYPE_ERROR("mpfr_random() requires 'random_state' argument");
205          return NULL;
206      }
207  
208      if ((result = GMPy_MPFR_New(0, context))) {
209          mpfr_urandom(result->f, RANDOM_STATE(PyTuple_GET_ITEM(args, 0)), GET_MPFR_ROUND(context));
210      }
211  
212      return (PyObject*)result;
213  }
214  
215  #if MPFR_VERSION_MAJOR > 3
216  
217  PyDoc_STRVAR(GMPy_doc_mpfr_nrandom_function,
218  "mpfr_nrandom(random_state) -> (mpfr)\n\n"
219  "Return a random number with gaussian distribution.");
220  
221  static PyObject *
222  GMPy_MPFR_nrandom_Function(PyObject *self, PyObject *args)
223  {
224      MPFR_Object *result;
225      CTXT_Object *context = NULL;
226  
227      CHECK_CONTEXT(context);
228  
229      if (PyTuple_GET_SIZE(args) != 1) {
230          TYPE_ERROR("mpfr_nrandom() requires 1 argument");
231          return NULL;
232      }
233  
234      if (!RandomState_Check(PyTuple_GET_ITEM(args, 0))) {
235          TYPE_ERROR("mpfr_nrandom() requires 'random_state' argument");
236          return NULL;
237      }
238  
239      if ((result = GMPy_MPFR_New(0, context))) {
240          mpfr_nrandom(result->f,
241                      RANDOM_STATE(PyTuple_GET_ITEM(args, 0)),
242                      GET_MPFR_ROUND(context));
243      }
244      return (PyObject*)result;
245  }
246  
247  PyDoc_STRVAR(GMPy_doc_mpfr_grandom_function,
248  "mpfr_grandom(random_state) -> (mpfr, mpfr)\n\n"
249  "Return two random numbers with gaussian distribution.");
250  
251  static PyObject *
252  GMPy_MPFR_grandom_Function(PyObject *self, PyObject *args)
253  {
254      MPFR_Object *result1, *result2;
255      PyObject *result;
256      CTXT_Object *context = NULL;
257  
258      CHECK_CONTEXT(context);
259  
260      if (PyTuple_GET_SIZE(args) != 1) {
261          TYPE_ERROR("mpfr_grandom() requires 1 argument");
262          return NULL;
263      }
264  
265      if (!RandomState_Check(PyTuple_GET_ITEM(args, 0))) {
266          TYPE_ERROR("mpfr_grandom() requires 'random_state' argument");
267          return NULL;
268      }
269  
270      result1 = GMPy_MPFR_New(0, context);
271      result2 = GMPy_MPFR_New(0, context);
272      if (!result1 || !result2) {
273          Py_XDECREF((PyObject*)result1);
274          Py_XDECREF((PyObject*)result2);
275          return NULL;
276      }
277  
278      mpfr_nrandom(result1->f,
279                   RANDOM_STATE(PyTuple_GET_ITEM(args, 0)),
280                   GET_MPFR_ROUND(context));
281  
282      mpfr_nrandom(result2->f,
283                   RANDOM_STATE(PyTuple_GET_ITEM(args, 0)),
284                   GET_MPFR_ROUND(context));
285  
286      result = Py_BuildValue("(NN)", (PyObject*)result1, (PyObject*)result2);
287      if (!result) {
288          Py_DECREF((PyObject*)result1);
289          Py_DECREF((PyObject*)result2);
290      }
291      return result;
292  }
293  #else
294  PyDoc_STRVAR(GMPy_doc_mpfr_grandom_function,
295  "mpfr_grandom(random_state) -> (mpfr, mpfr)\n\n"
296  "Return two random numbers with gaussian distribution.");
297  
298  static PyObject *
299  GMPy_MPFR_grandom_Function(PyObject *self, PyObject *args)
300  {
301      MPFR_Object *result1, *result2;
302      PyObject *result;
303      CTXT_Object *context = NULL;
304  
305      CHECK_CONTEXT(context);
306  
307      if (PyTuple_GET_SIZE(args) != 1) {
308          TYPE_ERROR("mpfr_grandom() requires 1 argument");
309          return NULL;
310      }
311  
312      if (!RandomState_Check(PyTuple_GET_ITEM(args, 0))) {
313          TYPE_ERROR("mpfr_grandom() requires 'random_state' argument");
314          return NULL;
315      }
316  
317      result1 = GMPy_MPFR_New(0, context);
318      result2 = GMPy_MPFR_New(0, context);
319      if (!result1 || !result2) {
320          Py_XDECREF((PyObject*)result1);
321          Py_XDECREF((PyObject*)result2);
322          return NULL;
323      }
324  
325      mpfr_grandom(result1->f, result2->f,
326                   RANDOM_STATE(PyTuple_GET_ITEM(args, 0)),
327                   GET_MPFR_ROUND(context));
328  
329      result = Py_BuildValue("(NN)", (PyObject*)result1, (PyObject*)result2);
330      if (!result) {
331          Py_DECREF((PyObject*)result1);
332          Py_DECREF((PyObject*)result2);
333      }
334      return result;
335  }
336  #endif
337  
338  
339  PyDoc_STRVAR(GMPy_doc_mpc_random_function,
340  "mpc_random(random_state) -> mpc\n\n"
341  "Return uniformly distributed number in the unit square [0,1]x[0,1].");
342  
343  static PyObject *
344  GMPy_MPC_random_Function(PyObject *self, PyObject *args)
345  {
346      MPC_Object *result;
347      CTXT_Object *context = NULL;
348  
349      CHECK_CONTEXT(context);
350  
351      if (PyTuple_GET_SIZE(args) != 1) {
352          TYPE_ERROR("mpfc_random() requires 1 argument");
353          return NULL;
354      }
355  
356      if (!RandomState_Check(PyTuple_GET_ITEM(args, 0))) {
357          TYPE_ERROR("mpc_random() requires 'random_state' argument");
358          return NULL;
359      }
360  
361      if ((result = GMPy_MPC_New(0, 0, context))) {
362          mpc_urandom(result->c, RANDOM_STATE(PyTuple_GET_ITEM(args, 0)));
363      }
364  
365      return (PyObject*)result;
366  }
367  
368  static PyTypeObject RandomState_Type =
369  {
370  #ifdef PY3
371      PyVarObject_HEAD_INIT(0, 0)
372  #else
373      PyObject_HEAD_INIT(0)
374          0,                                  /* ob_size          */
375  #endif
376      "gmpy2 random state",                   /* tp_name          */
377      sizeof(RandomState_Object),             /* tp_basicsize     */
378          0,                                  /* tp_itemsize      */
379      (destructor) GMPy_RandomState_Dealloc,  /* tp_dealloc       */
380          0,                                  /* tp_print         */
381          0,                                  /* tp_getattr       */
382          0,                                  /* tp_setattr       */
383          0,                                  /* tp_reserved      */
384      (reprfunc) GMPy_RandomState_Repr,       /* tp_repr          */
385          0,                                  /* tp_as_number     */
386          0,                                  /* tp_as_sequence   */
387          0,                                  /* tp_as_mapping    */
388          0,                                  /* tp_hash          */
389          0,                                  /* tp_call          */
390          0,                                  /* tp_str           */
391          0,                                  /* tp_getattro      */
392          0,                                  /* tp_setattro      */
393          0,                                  /* tp_as_buffer     */
394      Py_TPFLAGS_DEFAULT,                     /* tp_flags         */
395      "GMPY2 Random number generator state",  /* tp_doc           */
396          0,                                  /* tp_traverse      */
397          0,                                  /* tp_clear         */
398          0,                                  /* tp_richcompare   */
399          0,                                  /* tp_weaklistoffset*/
400          0,                                  /* tp_iter          */
401          0,                                  /* tp_iternext      */
402          0,                                  /* tp_methods       */
403          0,                                  /* tp_members       */
404          0,                                  /* tp_getset        */
405  };