Source code for prefsampling.point.gaussian

from __future__ import annotations

from collections.abc import Iterable

import numpy as np

from prefsampling.inputvalidators import validate_int
from prefsampling.point.utils import validate_center_point, validate_width


[docs] def gaussian( num_points: int, num_dimensions: int, center_point: Iterable[float] = None, sigmas: float | Iterable[float] = 1, widths: Iterable[float] = None, seed: int = None, ) -> np.ndarray: """ Samples points uniformly at random in a gaussian space. Parameters ---------- num_points: int The number of points to sample. num_dimensions: int The number of dimensions for the Gaussian space. center_point: Iterable[float] The coordinates of the center point of the gaussian distribution. It needs to have one coordinate per dimension. sigmas: float | Iterable[float], default: :code:`1` The standard deviation of the gaussian distribution. If a single value is given, the width is applied to all dimensions. In case multiple values are given, they are applied to each dimension independently. widths: Iterable[float], default: :code:`None` Maximal widths for the Gaussian distributions. One width per dimension needs to be provided. When sampling points, if the distance between the point and the center point is larger than half the width of a dimension, the point is resampled. seed : int, default: :code:`None` Seed for numpy random number generator. Returns ------- np.ndarray The coordinates of the :code:`num_points` points that have been sampled. Validation ---------- .. image:: ../validation_plots/point/gaussian.png :width: 800 :alt: Observed frequencies for a Gaussian model """ validate_int(num_points, "num_points", 0) validate_int(num_dimensions, "num_dimensions", 1) if widths is not None: if isinstance(widths, Iterable): widths = np.array(widths, dtype=float) if len(widths) != num_dimensions: raise ValueError( f"The number of widths needs to be equal to the number of dimensions " f"({len(widths)} given for {num_dimensions} dimensions)." ) else: raise TypeError( "The 'widths' parameter needs to be an iterable with one value per dimension." ) center_point = validate_center_point(center_point, num_dimensions) sigmas = validate_width(sigmas, num_dimensions) rng = np.random.default_rng(seed) if widths is None: return rng.normal( loc=center_point, scale=sigmas, size=(num_points, num_dimensions) ) else: points = [] for _ in range(num_points): point = rng.normal(loc=center_point, scale=sigmas, size=num_dimensions) while not (np.abs(point - center_point) <= (widths / 2)).all(): point = rng.normal(loc=center_point, scale=sigmas, size=num_dimensions) points.append(point) return np.array(points, dtype=float)