embodichain.lab.sim.motion.workspace.samplers#

Workspace sampling strategies deriving from BaseSampler.

The package exports uniform, random, Halton, Sobol, and Latin-hypercube samplers. SamplerFactory and create_sampler additionally construct the Gaussian and importance strategies.

Classes:

BaseSampler

Abstract base class for all samplers.

HaltonSampler

Halton sequence sampler using quasi-random low-discrepancy sequences.

ISampler

Interface for all samplers.

LatinHypercubeSampler

Latin Hypercube Sampler (LHS) for stratified sampling.

RandomSampler

Random sampler using uniform distribution.

SamplerFactory

Factory class for creating samplers (Singleton pattern).

SobolSampler

Sobol sequence sampler using quasi-random low-discrepancy sequences.

UniformSampler

Uniform grid sampler.

Functions:

create_sampler([strategy])

Convenience function to create a sampler.

class embodichain.lab.sim.motion.workspace.samplers.BaseSampler[source]#

Bases: ABC

Abstract base class for all samplers.

This class provides common functionality and enforces the implementation of the sampling method in all derived classes.

seed#

Random seed for reproducibility.

rng#

NumPy random number generator.

device#

PyTorch device for tensor operations.

Methods:

__init__([seed, device])

Initialize the base sampler.

get_strategy_name()

Get the name of the sampling strategy.

sample(num_samples[, bounds])

Generate samples within the given bounds.

__init__(seed=42, device=None)[source]#

Initialize the base sampler.

Parameters:
  • seed (int) – Random seed for reproducibility. Defaults to 42.

  • device (device | None) – PyTorch device (cpu/cuda). Defaults to cpu.

abstract get_strategy_name()[source]#

Get the name of the sampling strategy.

Return type:

str

Returns:

String identifier for the sampling strategy.

sample(num_samples, bounds=None)[source]#

Generate samples within the given bounds.

Parameters:
  • num_samples (int) – Number of samples to generate.

  • bounds (Tensor | ndarray | None) – Tensor/Array of shape (n_dims, 2) containing [lower, upper] bounds for each dimension.

Return type:

Tensor

Returns:

Tensor of shape (num_samples, n_dims) containing the sampled points.

Raises:
  • ValueError – If bounds are not provided.

  • NotImplementedError – If the method is not implemented in the derived class.

class embodichain.lab.sim.motion.workspace.samplers.HaltonSampler[source]#

Bases: BaseSampler

Halton sequence sampler using quasi-random low-discrepancy sequences.

The Halton sequence is a deterministic low-discrepancy sequence that provides better coverage than random sampling. It uses coprime bases (primes) for each dimension to generate well-distributed points.

Advantages:
  • Better uniformity than random sampling

  • Deterministic (reproducible)

  • Fast convergence for Monte Carlo integration

  • Works well in low to medium dimensions (2-10)

Disadvantages:
  • Performance degrades in high dimensions (>10)

  • Correlation between dimensions can appear

  • Sequential generation (not easily parallelizable)

bases#

Prime bases for each dimension. If None, uses first n primes.

skip#

Number of initial samples to skip (helps reduce correlation).

Methods:

__init__([seed, device, bases, skip])

Initialize the Halton sampler.

get_strategy_name()

Get the name of the sampling strategy.

__init__(seed=42, device=None, bases=None, skip=0)[source]#

Initialize the Halton sampler.

Parameters:
  • seed (int) – Random seed (used for consistency, but Halton is deterministic).

  • device (device | None) – PyTorch device (cpu/cuda). Defaults to cpu.

  • bases (Optional[List[int]]) – List of prime bases for each dimension. If None, uses first n primes.

  • skip (int) – Number of initial samples to skip. Defaults to 0. Higher values (e.g., 100-1000) can improve distribution quality.

get_strategy_name()[source]#

Get the name of the sampling strategy.

Return type:

str

Returns:

String identifier for the sampling strategy.

class embodichain.lab.sim.motion.workspace.samplers.ISampler[source]#

Bases: Protocol

Interface for all samplers.

This protocol defines the contract that all samplers must follow.

Methods:

__init__(*args, **kwargs)

get_strategy_name()

Get the name of the sampling strategy.

sample(bounds, num_samples)

Generate samples within the given bounds.

__init__(*args, **kwargs)#
get_strategy_name()[source]#

Get the name of the sampling strategy.

Return type:

str

Returns:

String identifier for the sampling strategy.

sample(bounds, num_samples)[source]#

Generate samples within the given bounds.

Parameters:
  • bounds (Tensor | ndarray) – Tensor/Array of shape (n_dims, 2) containing [lower, upper] bounds for each dimension.

  • num_samples (int) – Number of samples to generate.

Return type:

Tensor

Returns:

Tensor of shape (num_samples, n_dims) containing the sampled points.

class embodichain.lab.sim.motion.workspace.samplers.LatinHypercubeSampler[source]#

Bases: BaseSampler

Latin Hypercube Sampler (LHS) for stratified sampling.

Latin Hypercube Sampling ensures that each dimension is divided into equally probable intervals, with exactly one sample in each interval. This provides better coverage with fewer samples compared to random sampling.

Advantages:
  • Excellent coverage with small sample sizes

  • Each dimension is uniformly sampled

  • No sample clustering in any dimension

  • Works well in high dimensions

  • Popular in experimental design and sensitivity analysis

Disadvantages:
  • Samples may align in projections (can be mitigated with optimization)

  • Not deterministic across different sample sizes

  • May have correlation between dimensions (unless optimized)

strength#

Strength of the LHS (1 or 2). Higher strength reduces correlation.

optimization#

Optimization method (‘random-cd’, ‘lloyd’, None). ‘random-cd’: Random coordinate descent (fast, good quality) ‘lloyd’: Lloyd’s algorithm (slower, better quality) None: No optimization (fastest, may have correlation)

Methods:

__init__([seed, device, strength, optimization])

Initialize the Latin Hypercube sampler.

get_strategy_name()

Get the name of the sampling strategy.

sample(bounds, num_samples)

Generate Latin Hypercube samples within the given bounds.

__init__(seed=42, device=None, strength=1, optimization='random-cd')[source]#

Initialize the Latin Hypercube sampler.

Parameters:
  • seed (int) – Random seed for reproducibility. Defaults to 42.

  • device (device | None) – PyTorch device (cpu/cuda). Defaults to cpu.

  • strength (int) – Strength of the LHS (1 or 2). Defaults to 1. Strength 1: Standard LHS Strength 2: Improved spacing (requires more samples)

  • optimization (str | None) – Optimization method to reduce correlation. ‘random-cd’: Fast, good quality (recommended) ‘lloyd’: Better quality, slower None: No optimization (fastest) Defaults to ‘random-cd’.

  • constraint – Optional geometric constraint for sampling (e.g., SphereConstraint).

get_strategy_name()[source]#

Get the name of the sampling strategy.

Return type:

str

Returns:

String identifier for the sampling strategy.

sample(bounds, num_samples)[source]#

Generate Latin Hypercube samples within the given bounds.

Parameters:
  • bounds (Tensor | ndarray) – Tensor/Array of shape (n_dims, 2) containing [lower, upper] bounds.

  • num_samples (int) – Number of samples to generate.

Return type:

Tensor

Returns:

Tensor of shape (num_samples, n_dims) containing the sampled points.

Raises:

ValueError – If bounds are invalid or num_samples is non-positive.

Examples

>>> sampler = LatinHypercubeSampler(seed=42, optimization='random-cd')
>>> bounds = torch.tensor([[-1.0, 1.0], [-1.0, 1.0]], dtype=torch.float32)
>>> samples = sampler.sample(bounds, num_samples=50)
>>> samples.shape
torch.Size([50, 2])
class embodichain.lab.sim.motion.workspace.samplers.RandomSampler[source]#

Bases: BaseSampler

Random sampler using uniform distribution.

This sampler generates samples uniformly at random within the specified bounds. It’s simple and fast, but doesn’t guarantee uniform coverage. Samples may cluster in some regions while leaving other regions sparse.

Advantages:
  • Fast and simple

  • No assumptions about the space

  • Works well for any number of dimensions

Disadvantages:
  • Uneven coverage (clusters and gaps)

  • Slower convergence than quasi-random methods

  • May miss important regions

Methods:

__init__([seed, device])

Initialize the random sampler.

get_strategy_name()

Get the name of the sampling strategy.

__init__(seed=42, device=None)[source]#

Initialize the random sampler.

Parameters:
  • seed (int) – Random seed for reproducibility. Defaults to 42.

  • device (device | None) – PyTorch device for tensor operations.

get_strategy_name()[source]#

Get the name of the sampling strategy.

Return type:

str

Returns:

String identifier for the sampling strategy.

class embodichain.lab.sim.motion.workspace.samplers.SamplerFactory[source]#

Bases: object

Factory class for creating samplers (Singleton pattern).

This factory allows registration and creation of samplers based on the sampling strategy. It uses the singleton pattern to ensure only one instance exists throughout the application.

The factory comes pre-registered with the strategies defined by SamplingStrategy.

Additional samplers can be registered using register_sampler().

Examples

>>> factory = SamplerFactory()
>>> sampler = factory.create_sampler(SamplingStrategy.UNIFORM, seed=42)
>>> isinstance(sampler, UniformSampler)
True
>>> # Register custom sampler
>>> factory.register_sampler("custom", CustomSampler)
>>> custom_sampler = factory.create_sampler("custom", seed=42)

Methods:

__init__()

Initialize the factory with built-in samplers.

__new__(cls)

Create or return the singleton instance.

create_sampler([strategy])

Create a sampler instance based on the strategy.

is_registered(strategy)

Check if a strategy is registered.

list_available_strategies()

List all registered sampling strategies.

register_sampler(name, sampler_class)

Register a new sampler class.

reset_instance()

Reset the singleton instance (mainly for testing).

__init__()[source]#

Initialize the factory with built-in samplers.

This method only runs once due to the singleton pattern.

static __new__(cls)[source]#

Create or return the singleton instance.

Returns:

The singleton SamplerFactory instance.

create_sampler(strategy=None, **kwargs)[source]#

Create a sampler instance based on the strategy.

Parameters:
  • strategy (SamplingStrategy | str | None) – The sampling strategy to use. Can be a SamplingStrategy enum or a string identifier. If None, defaults to RANDOM.

  • **kwargs (Any) – Additional keyword arguments to pass to the sampler constructor. Common options include seed, device, and samples_per_dim for UniformSampler.

Return type:

BaseSampler

Returns:

An instance of the requested sampler.

Raises:

ValueError – If the strategy is not registered.

Examples

>>> factory = SamplerFactory()
>>> # Bounds-based usage
>>> sampler = factory.create_sampler(SamplingStrategy.UNIFORM, seed=42)
>>> sampler = factory.create_sampler("random", seed=123)

Note

Constraint-based sampling is temporarily disabled.

is_registered(strategy)[source]#

Check if a strategy is registered.

Parameters:

strategy (SamplingStrategy | str) – The sampling strategy to check.

Return type:

bool

Returns:

True if the strategy is registered, False otherwise.

list_available_strategies()[source]#

List all registered sampling strategies.

Return type:

list[str]

Returns:

List of registered strategy names.

register_sampler(name, sampler_class)[source]#

Register a new sampler class.

Parameters:
  • name (str) – String identifier for the sampler strategy.

  • sampler_class (Type[BaseSampler]) – The sampler class to register. Must inherit from BaseSampler.

Raises:
  • TypeError – If sampler_class is not a subclass of BaseSampler.

  • ValueError – If name already exists and overwrite=False.

Return type:

None

Examples

>>> factory = SamplerFactory()
>>> factory.register_sampler("my_sampler", MySamplerClass)
classmethod reset_instance()[source]#

Reset the singleton instance (mainly for testing). :rtype: None

Warning

This should only be used in testing scenarios.

class embodichain.lab.sim.motion.workspace.samplers.SobolSampler[source]#

Bases: BaseSampler

Sobol sequence sampler using quasi-random low-discrepancy sequences.

The Sobol sequence is a low-discrepancy sequence that provides excellent uniformity in high-dimensional spaces. It’s widely used in finance, engineering, and scientific computing for Monte Carlo simulations.

Advantages:
  • Excellent uniformity in high dimensions (up to ~40 dimensions)

  • Industry standard for quasi-Monte Carlo methods

  • Better convergence than random sampling (O(1/n) vs O(1/√n))

  • Well-suited for integration and optimization

Disadvantages:
  • Requires scipy library

  • Sequential generation (but can be scrambled for randomization)

  • Initial points may not be well-distributed (use skip parameter)

scramble#

Whether to scramble the sequence for better randomization.

skip#

Number of initial samples to skip.

Notes

This implementation uses scipy.stats.qmc.Sobol for efficient generation. Falls back to a basic implementation if scipy is not available.

Methods:

__init__([seed, device, scramble, skip])

Initialize the Sobol sampler.

get_strategy_name()

Get the name of the sampling strategy.

sample(bounds, num_samples)

Generate Sobol sequence samples within the given bounds.

__init__(seed=42, device=None, scramble=True, skip=0)[source]#

Initialize the Sobol sampler.

Parameters:
  • seed (int) – Random seed for scrambling. Defaults to 42.

  • device (device | None) – PyTorch device (cpu/cuda). Defaults to cpu.

  • scramble (bool) – Whether to scramble the sequence. Defaults to True. Scrambling improves randomization while maintaining low discrepancy.

  • skip (int) – Number of initial samples to skip. Defaults to 0. Recommended: 0 for scrambled, >0 (e.g., 100) for unscrambled.

  • constraint – Optional geometric constraint for sampling (e.g., SphereConstraint).

get_strategy_name()[source]#

Get the name of the sampling strategy.

Return type:

str

Returns:

String identifier for the sampling strategy.

sample(bounds, num_samples)[source]#

Generate Sobol sequence samples within the given bounds.

Parameters:
  • bounds (Tensor | ndarray) – Tensor/Array of shape (n_dims, 2) containing [lower, upper] bounds.

  • num_samples (int) – Number of samples to generate.

Return type:

Tensor

Returns:

Tensor of shape (num_samples, n_dims) containing the sampled points.

Raises:

ValueError – If bounds are invalid or num_samples is non-positive.

Examples

>>> sampler = SobolSampler(scramble=True, seed=42)
>>> bounds = torch.tensor([[-1.0, 1.0], [-1.0, 1.0]], dtype=torch.float32)
>>> samples = sampler.sample(bounds, num_samples=100)
>>> samples.shape
torch.Size([100, 2])
class embodichain.lab.sim.motion.workspace.samplers.UniformSampler[source]#

Bases: BaseSampler

Uniform grid sampler.

This sampler generates samples on a regular grid within the specified bounds. It ensures even coverage of the entire space, but suffers from the curse of dimensionality - the number of samples grows exponentially with the number of dimensions.

Note: Geometric constraint sampling is temporarily disabled.

samples_per_dim#

Number of samples to generate per dimension. When specified, this controls the grid density and takes precedence over num_samples. Total grid points = samples_per_dim^n_dims.

Methods:

__init__([seed, samples_per_dim, device])

Initialize the uniform sampler.

get_strategy_name()

Get the name of the sampling strategy.

__init__(seed=42, samples_per_dim=None, device=None)[source]#

Initialize the uniform sampler.

Parameters:
  • seed (int) – Random seed for reproducibility. Defaults to 42.

  • samples_per_dim (int | None) – Fixed number of samples per dimension. If None, will be calculated automatically from num_samples. Defaults to None.

  • device (device | None) – PyTorch device for tensor operations.

get_strategy_name()[source]#

Get the name of the sampling strategy.

Return type:

str

Returns:

String identifier for the sampling strategy.

embodichain.lab.sim.motion.workspace.samplers.create_sampler(strategy=None, **kwargs)[source]#

Convenience function to create a sampler.

This is a shorthand for SamplerFactory().create_sampler().

Parameters:
  • strategy (SamplingStrategy | str | None) – The sampling strategy to use.

  • **kwargs (Any) – Additional keyword arguments to pass to the sampler constructor.

Return type:

BaseSampler

Returns:

An instance of the requested sampler.

Examples

>>> sampler = create_sampler(SamplingStrategy.UNIFORM, seed=42)
>>> sampler = create_sampler("random", seed=123)

Note

Constraint-based sampling is temporarily disabled.