Random Number Generator Management¶
This page describes the
coola.random package, which provides a unified interface for
managing random number generator (RNG) state across different libraries.
Prerequisites: You'll need to know a bit of Python. For a refresher, see the Python tutorial.
Overview¶
The coola.random package provides a unified interface for controlling random number generators
(RNGs) from multiple libraries:
- Python's built-in
randommodule (always available) - NumPy's random module (if NumPy is installed)
- PyTorch's random module (if PyTorch is installed)
This allows you to set seeds, get and restore RNG states, and manage randomness consistently across different libraries in a single call.
Basic Usage¶
Setting a Random Seed¶
Use manual_seed() to set the seed for all available random number generators:
>>> from coola.random import manual_seed
>>> manual_seed(42)
>>> # Now all RNGs (random, numpy, torch) are seeded with 42
This sets the seed for:
- Python's
randommodule - NumPy's random generator (if NumPy is available)
- PyTorch's random generator (if PyTorch is available)
Using a Random Seed Context¶
Use the random_seed context manager to temporarily set a seed and automatically restore the
previous RNG state afterward:
>>> import numpy
>>> from coola.random import random_seed
>>> with random_seed(42):
... print(numpy.random.randn(2, 4))
...
[[...]]
>>> with random_seed(42):
... print(numpy.random.randn(2, 4))
...
[[...]]
The context manager ensures that:
- The RNG state is saved before setting the seed
- The specified seed is applied
- The original RNG state is restored after the context exits
This is useful for reproducible code blocks without affecting the global RNG state.
Getting and Setting RNG State¶
You can manually save and restore the entire RNG state:
>>> from coola.random import get_rng_state, set_rng_state
>>> # Save current state
>>> state = get_rng_state()
>>> # ... do some random operations ...
>>> # Restore previous state
>>> set_rng_state(state)
The state is a dictionary containing the state of all registered random managers:
>>> from coola.random import get_rng_state
>>> state = get_rng_state()
>>> state.keys()
dict_keys(['random', 'numpy', 'torch'])
Library-Specific Seeds¶
Python's Random Module¶
Set the seed only for Python's random module:
>>> import random
>>> from coola.random.random import RandomRandomManager
>>> manager = RandomRandomManager()
>>> manager.manual_seed(42)
>>> val = random.randint(1, 100)
NumPy¶
Set the seed only for NumPy's random module:
>>> import numpy as np
>>> from coola.random import numpy_seed
>>> with numpy_seed(42):
... np.random.rand(3)
...
array([...])
Or use the NumPy random manager directly:
>>> import numpy as np
>>> from coola.random.numpy import NumpyRandomManager
>>> manager = NumpyRandomManager()
>>> manager.manual_seed(42)
>>> np.random.rand(3)
array([...])
PyTorch¶
Set the seed only for PyTorch's random module:
>>> import torch
>>> from coola.random import torch_seed
>>> with torch_seed(42):
... torch.rand(3)
...
tensor([...])
Or use the PyTorch random manager directly:
>>> import torch
>>> from coola.random.torch import TorchRandomManager
>>> manager = TorchRandomManager()
>>> manager.manual_seed(42)
>>> torch.rand(3)
tensor([...])
Advanced Usage¶
Working with the Registry¶
The default registry manages all available random managers:
>>> from coola.random import get_default_registry
>>> registry = get_default_registry()
>>> registry
RandomManagerRegistry(
(state): Registry(
(random): RandomRandomManager()
(numpy): NumpyRandomManager()
(torch): TorchRandomManager()
)
)
Registering Custom Managers¶
You can register custom random managers to support additional libraries:
>>> from coola.random import register_managers, RandomRandomManager
>>> # Register a custom manager
>>> register_managers({"custom": RandomRandomManager()}) # doctest: +SKIP
To create a custom manager, extend BaseRandomManager:
>>> from coola.random import BaseRandomManager
>>> class MyRandomManager(BaseRandomManager):
... def get_rng_state(self):
... # Return current RNG state
... return {}
... def set_rng_state(self, state):
... # Restore RNG state
... pass
... def manual_seed(self, seed):
... # Set seed
... pass
...
Using Custom Registry¶
You can create and use a custom registry:
>>> from coola.random import RandomManagerRegistry, RandomRandomManager
>>> registry = RandomManagerRegistry()
>>> registry.register("random", RandomRandomManager())
>>> registry.manual_seed(42)
Common Use Cases¶
Reproducible Experiments¶
Ensure reproducibility in scientific experiments:
>>> import numpy as np
>>> import torch
>>> from coola.random import manual_seed
>>> manual_seed(42)
>>> # All random operations are now reproducible
>>> np.random.rand(3)
array([...])
>>> torch.rand(3)
tensor([...])
Reproducible Code Blocks¶
Make a specific code block reproducible without affecting the global state:
>>> import numpy as np
>>> from coola.random import random_seed
>>> # Generate some random data
>>> data1 = np.random.rand(5)
>>> # This block is reproducible
>>> with random_seed(123):
... reproducible_data = np.random.rand(5)
...
>>> # Continue with original RNG state
>>> data2 = np.random.rand(5)
Internally, the context manager saves and restores RNG state before and after the block. It is equivalent to this code.
>>> from coola.random import get_rng_state, set_rng_state, manual_seed
>>> # Save initial state
>>> initial_state = get_rng_state()
>>> # Run test with specific seed
>>> manual_seed(42)
>>> # ... make code reproducible. ...
>>> # Restore initial state
>>> set_rng_state(initial_state)
Cross-Library Seeding¶
Seed all libraries at once for consistent results:
>>> import random
>>> import numpy as np
>>> import torch
>>> from coola.random import manual_seed
>>> # Seed all libraries with one call
>>> manual_seed(42)
>>> # All libraries use the same seed
>>> val1 = random.random()
>>> val2 = np.random.rand()
>>> val3 = torch.rand(1).item()
Temporary Seed Changes¶
Temporarily change seed for a specific operation:
>>> import numpy as np
>>> from coola.random import random_seed
>>> # Normal operations
>>> normal_data = np.random.rand(3)
>>> # Use specific seed for initialization
>>> with random_seed(999):
... initialization = np.random.randn(10, 10)
...
>>> # Continue with normal operations
>>> more_data = np.random.rand(3)
Available Random Managers¶
The coola.random package provides the following random managers:
RandomRandomManager: For Python's built-inrandommodule (always registered)NumpyRandomManager: For NumPy's random module (registered if NumPy is available)TorchRandomManager: For PyTorch's random module (registered if PyTorch is available)
Each manager implements the BaseRandomManager interface with three methods:
manual_seed(seed): Set the random seedget_rng_state(): Get the current RNG stateset_rng_state(state): Restore a previous RNG state
Design Principles¶
The coola.random package design provides:
- Unified interface: Control multiple RNG libraries with a single API
- Automatic detection: Automatically registers managers for available libraries
- State management: Save and restore complete RNG state across all libraries
- Context managers: Temporarily set seeds without affecting global state
- Extensibility: Easy to add support for new random number generators
Best Practices¶
Always Use Context Managers When Possible¶
Prefer random_seed() context manager over manual_seed() for localized reproducibility:
>>> from coola.random import random_seed
>>> # Good: State is automatically restored
>>> with random_seed(42):
... # reproducible code
... pass
...
Instead of:
>>> from coola.random import manual_seed, get_rng_state, set_rng_state
>>> # Not ideal: Manual state management
>>> state = get_rng_state()
>>> manual_seed(42)
>>> # reproducible code
>>> set_rng_state(state)
Set Seeds at the Beginning¶
Set seeds at the beginning of your script for full reproducibility:
>>> from coola.random import manual_seed
>>> manual_seed(42)
>>> # Rest of your code...
Document Seed Usage¶
Always document when and why you're setting seeds:
>>> from coola.random import manual_seed
>>> # Set seed for reproducible results in experiments
>>> manual_seed(42)
See Also¶
- Python's
randommodule - NumPy's Random sampling
- PyTorch's Reproducibility
coola.registry: For understanding the registry pattern used internally