Source code for nubo.utils.latin_hypercube
import torch
from torch import Tensor
from torch.nn.functional import pdist
from typing import Optional
[docs]
class LatinHypercubeSampling:
r"""
Latin hypercube sampling.
Generates a space-filling design. Two options are possible: sampling from a
random or a maximin Latin hypercube. To sample :math:`n` points, the random
Latin hypercube divides each dimension into :math:`n` equal parts and
places :math:`n` points such that for every dimension each equal part
contains exactly one point. The maximin Latin hypercube takes a simple
approach and draws a large number of random Latin hypercube samples and
returns the one with the largest minimal distance between points.
Attributes
----------
dims : ``int``
Number of dimensions
"""
def __init__(self, dims: int) -> None:
"""
Parameters
----------
dims : ``int``
Number of dimensions.
"""
self.dims = dims
[docs]
def random(self, points: int) -> Tensor:
r"""
Draw a random Latin hypercube sample.
To sample :math:`n` points, the random Latin hypercube divides each
dimension into :math:`n` equal parts and places :math:`n` points such
that for every dimension each equal part contains exactly one point.
Parameters
----------
points : ``int``
Number of points.
Returns
-------
``torch.Tensor``
(size `points` x `dims`) Random Latin hypercube sample.
"""
hypercube = torch.empty((points, self.dims), dtype=torch.float64)
# pick random permutation of (1, ..., points) for each dimension
for dim in range(self.dims):
hypercube[:, dim] = torch.randperm(points)
# translate each dimension to [0, 1] range
increment = 1/points
hypercube = hypercube * increment
# pick random value within increment
jitter = torch.rand(size=hypercube.size(), dtype=torch.float64) * increment
hypercube = hypercube + jitter
return hypercube
[docs]
def maximin(self,
points: int,
samples: Optional[int]=1000) -> Tensor:
r"""
Draw a maximin Latin hypercube sample.
Draws a large number of random Latin hypercube samples and selects the
one with the largest minimal distance between points.
Parameters
----------
points : ``int``
Number of points.
samples : ``int``
Number of random Latin hypercube samples.
Returns
-------
``torch.Tensor``
(size `points` x `dims`) Maximin Latin hypercube sample.
"""
hypercubes = torch.empty((samples, points, self.dims), dtype=torch.float64)
min_dist = torch.empty(samples, dtype=torch.float64)
for sample in range(samples):
# sample random Latin hypercubes
hypercubes[sample, :, :] = self.random(points)
# compute minimal distance of all samples
min_dist[sample] = torch.min(pdist(hypercubes[sample, :, :]))
# pick hypercube with maximal minimal distance
maximin_index = torch.argmax(min_dist)
maximin_hypercube = hypercubes[maximin_index]
return maximin_hypercube