Source code for pysatl_core.distributions.sampling

"""
Sampling Interfaces

This module defines protocols and implementations for sample containers
used in distribution sampling.
"""

from __future__ import annotations

__author__ = "Leonid Elkin, Mikhail Mikhailov"
__copyright__ = "Copyright (c) 2025 PySATL project"
__license__ = "SPDX-License-Identifier: MIT"

from typing import TYPE_CHECKING, Protocol

import numpy as np

if TYPE_CHECKING:
    from collections.abc import Iterator
    from typing import Any

    import numpy.typing as npt


# TODO: This is probably a stillborn idea, it's better to just use NumPy arrays.
[docs] class Sample(Protocol): """ Protocol for sample containers. Attributes ---------- array : numpy.ndarray Array representation of the samples. shape : tuple[int, ...] Shape of the sample array. """ def __len__(self) -> int: ... @property def array(self) -> npt.NDArray[np.floating[Any]]: ... @property def shape(self) -> tuple[int, ...]: ...
# TODO: This is probably a stillborn idea, it's better to just use NumPy arrays.
[docs] class ArraySample: """ Array-backed sample container. This implementation stores samples as a 2D floating-point array of shape (n_samples, n_dimensions). Parameters ---------- data : numpy.ndarray 2D floating-point array of shape (n, d). Attributes ---------- data : numpy.ndarray Backing array containing the samples. dimension : int Dimensionality of the samples (d). Raises ------ ValueError If data is not 2D. """ dimension: int data: npt.NDArray[np.floating[Any]]
[docs] def __init__(self, data: npt.NDArray[np.floating[Any]]) -> None: if data.ndim != 2: raise ValueError("ArraySample expects 2D array of shape (n, d).") self.data = data self.dimension = int(data.shape[1])
[docs] def __len__(self) -> int: """Return the number of samples (n).""" return int(self.data.shape[0])
@property def dim(self) -> int: """Alias for dimension attribute.""" return self.dimension
[docs] def __iter__(self) -> Iterator[npt.NDArray[np.floating[Any]]]: """Iterate over samples (rows of the array).""" yield from self.data
@property def array(self) -> npt.NDArray[np.floating[Any]]: """Return the backing array.""" return self.data @property def shape(self) -> tuple[int, ...]: """Return the shape of the sample array (n, d).""" n, d = self.data.shape return int(n), int(d)