Skip to content

Samplers

ropt.sampler

Public API for sampler implementations.

Samplers generate perturbation values for optimization variables during gradient estimation. In ensemble-based workflows, these perturbations are used to evaluate objective and constraint functions under variable perturbations.

Core Interface

All sampler implementations inherit from the Sampler base class, which defines the sampler lifecycle (__init__, init) and the required sample generation method (generate_samples).

Integration with Optimization

Samplers are accessed via an EnOptContext object through its samplers field, a tuple of sampler instances. Samplers are instantiated either directly as objects or via SamplerConfig objects, which are used by the plugin system to create instances based on the configured method string (e.g., "default" or "sobol").

Built-in and Custom Samplers

The SciPySampler class provides sampling methods backed by scipy.stats and scipy.stats.qmc.

Users can implement custom samplers by subclassing Sampler. Those subclasses can be instantiated directly and passed into an EnOptContext object through its samplers field. Registering a custom sampler with the plugin system is optional and only required when the sampler should be selected and configured via SamplerConfig objects instead of being instantiated explicitly by the user.

Sampler

Bases: ABC

Abstract base class for sampler implementations.

All concrete sampler implementations must inherit from this class and implement the required lifecycle and sample-generation methods. Samplers are responsible for generating perturbation values that are applied to optimization variables when estimating gradients.

Lifecycle

  1. Instantiation via __init__: Called by the plugin system with a configuration object.
  2. Setup via init: Called once per optimization workflow with the EnOptContext, a variable mask, and a random number generator.
  3. Sampling via generate_samples: Called repeatedly during optimization whenever perturbed variable vectors are needed.

Subclasses must implement:

  • __init__: Stores sampler configuration and performs lightweight setup.
  • init: Receives context-dependent inputs for workflow-specific setup.
  • generate_samples: Returns perturbation samples with the expected shape and masking semantics.

__init__ abstractmethod

__init__(sampler_config: SamplerConfig) -> None

Create a new sampler instance.

Called during instantiation. Subclasses should store the configuration and perform any lightweight initialization. Validation and context-dependent setup should usually be deferred to init.

Parameters:

Name Type Description Default
sampler_config SamplerConfig

Configuration object specifying the sampler method and any method-specific options.

required

init abstractmethod

init(
    context: EnOptContext,
    mask: NDArray[bool_] | None,
    rng: Generator,
) -> None

Finalize initialization after the optimization context is known.

Called once at the start of each optimization workflow, after all configuration is finalized. Use this method to store the active context, receive the variable subset handled by this sampler, and initialize random-state dependent internals.

Parameters:

Name Type Description Default
context EnOptContext

The main EnOpt context object.

required
mask NDArray[bool_] | None

Optional boolean mask selecting the variables handled by this sampler. If None, the sampler is responsible for all variables.

required
rng Generator

NumPy random number generator instance for stochastic sampling methods.

required

generate_samples abstractmethod

generate_samples() -> NDArray[np.float64]

Generate perturbation samples for optimization variables.

Returns a three-dimensional NumPy array with shape (n_realizations, n_perturbations, n_variables), where:

  • n_realizations is the number of realizations in the ensemble.
  • n_perturbations is the number of perturbations requested.
  • n_variables is the total number of optimization variables.

If the shared flag is True in the associated SamplerConfig, the first dimension still has size n_realizations. Implementations may internally generate a single realization of samples and broadcast that internally before returning.

If a boolean mask was provided during initialization, this sampler instance is responsible only for a subset of variables (where the mask is True). The returned array must still have the full n_variables size along the last axis. However, values corresponding to variables not handled by this sampler (where the mask is False) must be zero.

Sample Scaling and Perturbation Magnitudes

The generated samples represent unscaled perturbations. During the gradient estimation process, these samples are multiplied element-wise by the perturbation_magnitudes defined in the GradientConfig.

Therefore, it is generally recommended that sampler implementations produce samples with a characteristic scale of approximately one (e.g., drawn from a distribution with a standard deviation of 1, or uniformly distributed within [-1, 1]). This allows the perturbation_magnitudes to directly control the effective size of the perturbations applied to the variables.

Returns:

Type Description
NDArray[float64]

A 3D NumPy array of perturbation values.

ropt.sampler.Sampler

Bases: ABC

Abstract base class for sampler implementations.

All concrete sampler implementations must inherit from this class and implement the required lifecycle and sample-generation methods. Samplers are responsible for generating perturbation values that are applied to optimization variables when estimating gradients.

Lifecycle

  1. Instantiation via __init__: Called by the plugin system with a configuration object.
  2. Setup via init: Called once per optimization workflow with the EnOptContext, a variable mask, and a random number generator.
  3. Sampling via generate_samples: Called repeatedly during optimization whenever perturbed variable vectors are needed.

Subclasses must implement:

  • __init__: Stores sampler configuration and performs lightweight setup.
  • init: Receives context-dependent inputs for workflow-specific setup.
  • generate_samples: Returns perturbation samples with the expected shape and masking semantics.

__init__ abstractmethod

__init__(sampler_config: SamplerConfig) -> None

Create a new sampler instance.

Called during instantiation. Subclasses should store the configuration and perform any lightweight initialization. Validation and context-dependent setup should usually be deferred to init.

Parameters:

Name Type Description Default
sampler_config SamplerConfig

Configuration object specifying the sampler method and any method-specific options.

required

init abstractmethod

init(
    context: EnOptContext,
    mask: NDArray[bool_] | None,
    rng: Generator,
) -> None

Finalize initialization after the optimization context is known.

Called once at the start of each optimization workflow, after all configuration is finalized. Use this method to store the active context, receive the variable subset handled by this sampler, and initialize random-state dependent internals.

Parameters:

Name Type Description Default
context EnOptContext

The main EnOpt context object.

required
mask NDArray[bool_] | None

Optional boolean mask selecting the variables handled by this sampler. If None, the sampler is responsible for all variables.

required
rng Generator

NumPy random number generator instance for stochastic sampling methods.

required

generate_samples abstractmethod

generate_samples() -> NDArray[np.float64]

Generate perturbation samples for optimization variables.

Returns a three-dimensional NumPy array with shape (n_realizations, n_perturbations, n_variables), where:

  • n_realizations is the number of realizations in the ensemble.
  • n_perturbations is the number of perturbations requested.
  • n_variables is the total number of optimization variables.

If the shared flag is True in the associated SamplerConfig, the first dimension still has size n_realizations. Implementations may internally generate a single realization of samples and broadcast that internally before returning.

If a boolean mask was provided during initialization, this sampler instance is responsible only for a subset of variables (where the mask is True). The returned array must still have the full n_variables size along the last axis. However, values corresponding to variables not handled by this sampler (where the mask is False) must be zero.

Sample Scaling and Perturbation Magnitudes

The generated samples represent unscaled perturbations. During the gradient estimation process, these samples are multiplied element-wise by the perturbation_magnitudes defined in the GradientConfig.

Therefore, it is generally recommended that sampler implementations produce samples with a characteristic scale of approximately one (e.g., drawn from a distribution with a standard deviation of 1, or uniformly distributed within [-1, 1]). This allows the perturbation_magnitudes to directly control the effective size of the perturbations applied to the variables.

Returns:

Type Description
NDArray[float64]

A 3D NumPy array of perturbation values.

ropt.sampler.scipy.SciPySampler

Bases: Sampler

A sampler implementation utilizing SciPy's statistical functions.

This sampler leverages functions from the scipy.stats and scipy.stats.qmc modules to generate perturbation samples for optimization.

Supported Sampling Methods:

  • From Probability Distributions (scipy.stats):

    • norm: Samples from a standard normal distribution (mean 0, standard deviation 1). This is the default method if none is specified or if "default" is requested.
    • truncnorm: Samples from a truncated normal distribution (mean 0, std dev 1), truncated to the range [-1, 1] by default.
    • uniform: Samples from a uniform distribution. Defaults to the range [-1, 1].
  • From Quasi-Monte Carlo Sequences (scipy.stats.qmc):

    • sobol: Uses Sobol' sequences.
    • halton: Uses Halton sequences.
    • lhs: Uses Latin Hypercube Sampling. (Note: QMC samples are generated in the unit hypercube [0, 1]^d and then scaled to the hypercube [-1, 1]^d)

Configuration:

The specific sampling method is chosen via the method field in the SamplerConfig. Additional method-specific parameters (e.g., distribution parameters like loc, scale, a, b for stats methods, or engine parameters for qmc methods) can be passed through the options dictionary within the SamplerConfig. Refer to the scipy.stats and documentation for available options.