Skip to main content

Module random

Module random 

Source
Expand description

Safe interface for NumPy’s random BitGenerator.

Using the patterns described in “Extending numpy.random, you can generate random numbers without being attached to the interpreter runtime by:

use pyo3::prelude::*;
use numpy::random::BitGenerator;

let mut bitgen = Python::attach(|py| {
    BitGenerator::new(py, Default::default())
})?;
let random_number = bitgen.next_u64();

If you write a pyo3 extension, you would extract a numpy.random.BitGenerator into a [Bound]<’_, PyBitGenerator>:

use numpy::random::{BitGenerator, PyBitGenerator, PyBitGeneratorMethods as _};

#[pyfunction]
fn make_random_number(bitgen: Bound<PyBitGenerator>) -> PyResult<u64> {
    // spawn an owned child, then use it without being attached to the interpreter runtime
    Ok(bitgen.spawn_one()?.next_u64())
}

Python::attach(|py| -> PyResult<_> {
    let bitgen: Bound<PyBitGenerator> = default_bit_gen(py)?;
    let random_number = make_random_number(bitgen)?;
    println!("{random_number}");
    Ok(())
})?;

With the rand crate installed, you can also use its Rng APIs on any generator, since BitGenerator implements rand_core::RngCore.

use pyo3::prelude::*;
use rand::Rng as _;
use numpy::random::{BitGenerator, BitGeneratorKind::SFC64};

let mut bitgen = Python::attach(|py| BitGenerator::new(py, SFC64))?;
if bitgen.random_ratio(1, 1_000_000) {
    println!("a sure thing");
};

Using spawn, you can create multiple BitGenerators to generate random numbers truly in parallel, all without being attached to the interpreter runtime:

use numpy::{PyArray2, PyArrayMethods as _};

Python::attach(|py| -> PyResult<_> {
    let bitgen: Bound<PyBitGenerator> = default_bit_gen(py)?;
    let children = bitgen.spawn(4)?;
    let mut arr = PyArray2::<u32>::zeros(py, (4, 300), false).readwrite();
    let mut ndarr = arr.as_array_mut();  // ndarray for more convenience
    py.detach(|| std::thread::scope(|s| {
        for (mut chunk, mut child) in ndarr.rows_mut().into_iter().zip(children) {
            s.spawn(move || {
                for x in chunk.iter_mut() {
                    *x = child.random_range(10..200);
                }
            });
        }
    }));
    println!("Now filled: {arr:?}");
    Ok(())
})?;

Structs§

BitGenerator
A numpy BitGenerator usable without being attached to the interpreter runtime, with exclusive access to its state.
PyBitGenerator
Wrapper for np.random.BitGenerator.

Enums§

BitGeneratorKind
Which of numpy’s bit generator algorithms BitGenerator::new should create.

Traits§

PyBitGeneratorMethods
Methods for PyBitGenerator.