Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/alex-ber/AlexBerUtils/llms.txt

Use this file to discover all available pages before exploring further.

The randoms module provides the Sampler class for drawing samples from continuous statistical distributions with optional lower/upper bounds. When NumPy is installed samples are drawn via numpy.random.RandomState; otherwise the standard library random module is used transparently.

Installation

# Core — uses the standard library random module
pip install alex-ber-utils

# With NumPy acceleration (recommended)
pip install alex-ber-utils[numpy]
If NumPy is not installed, an OptionalNumpyWarning is issued at import time and the pure-Python fallback is activated automatically. No code changes are required.

Quick start

from alexber.utils.randoms import Sampler

sampler = Sampler(
    distribution="lognormvariate",
    shape=0.5,    # sigma of the underlying normal
    scale=1.0,    # exp(mu) — median of the log-normal
    lower_bound=0.1,
    upper_bound=10.0,
    random_seed=42,
)

value = sampler.get_sample()
print(value)  # e.g. 1.3842...

Sampler class

Sampler extends BaseSampler and is the class you should instantiate directly. The concrete implementation chosen at import time depends on whether NumPy is available:
  • NumPy available — uses numpy.random.RandomState methods.
  • NumPy absent — uses the standard random.Random methods.
Both implementations expose the same constructor signature and get_sample() method.

Constructor parameters

distribution
str
required
Name of the distribution to sample from. Must be one of the nine supported values listed in the Supported distributions section below.
shape
float
required
Shape parameter. Its meaning depends on the distribution — for log-normal it is sigma of the underlying normal; for gamma it is the shape (k) parameter; for beta it is the first shape parameter alpha.
scale
float
required
Scale parameter. For log-normal, exp(mu) (the median). For normal and Gaussian distributions, the mean (mu). For exponential, the mean of the distribution directly.
lower_bound
float
default:"-inf"
Minimum acceptable value. Samples below this bound are discarded and re-drawn. None is treated as unbounded (i.e. -math.inf).
upper_bound
float
default:"inf"
Maximum acceptable value. Samples above this bound are discarded and re-drawn. None is treated as unbounded (i.e. math.inf).
max_retries
int
default:"1000"
Maximum number of draw-and-test attempts before raising SamplingError.
random_seed
int | None
default:"None"
Integer seed for the internal random generator. Mutually exclusive with random_state / random_instance.
random_state
numpy.random.RandomState | None
default:"None"
(NumPy build only.) An existing RandomState object to use. Mutually exclusive with random_seed.
random_instance
random.Random | None
default:"None"
(Pure-Python build only.) An existing random.Random instance to use. Mutually exclusive with random_seed.
You must specify either random_seed or random_state/random_instance — never both. Providing both raises ValueError.

get_sample()

Draws and returns a single sample within [lower_bound, upper_bound].
value: float = sampler.get_sample()
The method retries up to max_retries times. If no in-bounds sample is produced within that limit, SamplingError is raised.

Supported distributions

NameParameters usedNotes
lognormvariateshape = sigma, scale = exp(mu)Log-normal; always positive.
normalvariateshape = std dev, scale = meanNormal (Gaussian) via the random module.
gaussshape = std dev, scale = meanGaussian; faster than normalvariate in some implementations.
expovariatescale = meanExponential; always positive. NumPy uses scale directly; pure-Python uses 1/scale internally.
vonmisesvariateshape = kappa, scale = muCircular distribution for angles.
gammavariateshape = k (alpha), scale = thetaGamma distribution.
betavariateshape = alpha, scale = betaBeta distribution; values in (0, 1).
paretovariateshape = alphaPareto distribution; scale is unused.
weibullvariateshape = k, scale = lambdaWeibull distribution.

Examples

Normal distribution with bounds

from alexber.utils.randoms import Sampler

sampler = Sampler(
    distribution="normalvariate",
    shape=1.0,       # standard deviation
    scale=0.0,       # mean
    lower_bound=-3.0,
    upper_bound=3.0,
    random_seed=0,
)

samples = [sampler.get_sample() for _ in range(5)]
print(samples)

Reusing an existing random state (NumPy)

import numpy as np
from alexber.utils.randoms import Sampler

rng = np.random.RandomState(seed=99)

sampler = Sampler(
    distribution="gammavariate",
    shape=2.0,
    scale=1.5,
    random_state=rng,   # share the RNG across multiple samplers
)

value = sampler.get_sample()

Reusing a random.Random instance (pure Python)

import random
from alexber.utils.randoms import Sampler

rng = random.Random(42)

sampler = Sampler(
    distribution="betavariate",
    shape=2.0,   # alpha
    scale=5.0,   # beta
    random_instance=rng,
)

value = sampler.get_sample()
print(value)  # e.g. 0.2791...

Error handling

SamplingError

Raised when get_sample() cannot produce an in-bounds value within max_retries attempts.
from alexber.utils.randoms import Sampler, SamplingError

sampler = Sampler(
    distribution="normalvariate",
    shape=1.0,
    scale=0.0,
    lower_bound=100.0,   # impossible to satisfy with mean=0 and std=1
    upper_bound=200.0,
    max_retries=10,
    random_seed=1,
)

try:
    sampler.get_sample()
except SamplingError as e:
    print(e)
    # Failed to sample a valid value within the specified bounds after max retries.
    # (Distribution: normalvariate, Retries: 10, Lower bound: 100.0, Upper bound: 200.0)
    print(e.distribution)   # 'normalvariate'
    print(e.retries)        # 10
    print(e.lower_bound)    # 100.0
    print(e.upper_bound)    # 200.0
SamplingError attributes:
AttributeTypeDescription
distributionstrThe distribution that was attempted.
retriesintNumber of attempts made.
lower_boundfloat | NoneThe configured lower bound (None if unbounded).
upper_boundfloat | NoneThe configured upper bound (None if unbounded).

OptionalNumpyWarning

Issued at import time when NumPy is not installed. The warning class is defined in alexber.utils.warning. To suppress it:
import warnings
from alexber.utils.warning import OptionalNumpyWarning

warnings.filterwarnings("ignore", category=OptionalNumpyWarning)
import alexber.utils.randoms  # noqa
Increase max_retries if your bounds are tight relative to the distribution’s natural support (e.g. a narrow window on a heavy-tailed distribution). As a rule of thumb, tighter bounds require exponentially more retries.

BaseSampler

BaseSampler contains the validation logic shared by both the NumPy and pure-Python Sampler implementations. You will not instantiate it directly, but you can subclass it to create custom samplers:
from alexber.utils.randoms import BaseSampler

class MySampler(BaseSampler):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def get_sample(self):
        # Custom sampling logic
        ...
Validation performed by BaseSampler.__init__:
  • distribution must be in BaseSampler.supported_distributions.
  • lower_bound must be strictly less than upper_bound.
  • At most one of random_seed / random_state / random_instance may be set.

Build docs developers (and LLMs) love