Source code for pymead.optimization.sampling
import typing
from abc import abstractmethod
from copy import deepcopy
from random import randint, random
import numpy as np
from pymoo.core.problem import Problem
from pymoo.operators.sampling.lhs import LatinHypercubeSampling
[docs]
class Sampling:
[docs]
def __init__(self, n_samples: int, norm_param_list: list):
"""
High-level generic class for any sampling method.
Parameters
----------
n_samples: int
Number of samples
norm_param_list: list
List of normalized parameter values (usually from ``extract_parameters`` in ``MEA``).
"""
self.n_samples = n_samples
self.norm_param_list = deepcopy(norm_param_list)
@abstractmethod
def sample(self) -> list or np.ndarray:
pass
[docs]
class ConstrictedRandomSampling(Sampling):
[docs]
def __init__(self, n_samples: int, norm_param_list: list, max_sampling_width: float):
"""
A custom sampling method where the probability distribution for the new parameter value is uniform with a
specified width on either side of the original parameter value. The probability of falling above or below the
original parameter value is 0.5 and 0.5, respectively. The sampling width is truncated by the parameter bounds
if necessary, retaining a probability of 0.5 on both sides of the original parameter value.
Parameters
==========
n_samples: int
Number of samples
norm_param_list: list
List of normalized parameter values (usually from ``extract_parameters`` in ``MEA``).
max_sampling_width: float
Maximum distance of the new parameter value from the original parameter value. The actual new parameter
value falls randomly in between the original parameter value and this maximum distance in either direction.
"""
self.max_sampling_width = max_sampling_width
super().__init__(n_samples, norm_param_list)
[docs]
def sample(self) -> typing.List[typing.List[float]]:
"""
Randomly samples the design space.
Returns
-------
typing.List[typing.List[float]]
A new nested list of normalized parameter values to be used to update the airfoil system. Each row
of the 2-D list represents a set of genes to apply to each Chromosome, and each value in the row
represents an individual gene. These individual genes are bounds-normalized values representing a new value
for a particular design variable in the geometry collection.
"""
X_list = [self.norm_param_list]
for i in range(self.n_samples - 1):
individual = []
norm_list_copy = deepcopy(self.norm_param_list)
for p in norm_list_copy:
sign_bool = randint(0, 1)
perturbation = random()
if sign_bool:
distance_to_upper_bound = 1 - p
if self.max_sampling_width < distance_to_upper_bound:
new_p = p + self.max_sampling_width * perturbation
else:
new_p = p + distance_to_upper_bound * perturbation
else:
distance_to_lower_bound = p
if self.max_sampling_width < distance_to_lower_bound:
new_p = p - self.max_sampling_width * perturbation
else:
new_p = p - distance_to_lower_bound * perturbation
individual.append(new_p)
X_list.append(individual)
return X_list
[docs]
class PymooLHS(Sampling):
[docs]
def __init__(self, n_samples, norm_param_list):
"""
Latin-Hypercube sampling method from the ``pymoo`` package.
Parameters
----------
n_samples: int
Number of samples
norm_param_list: list
List of normalized parameter values (usually from ``extract_parameters`` in ``MEA``).
"""
super().__init__(n_samples, norm_param_list)
[docs]
def sample(self):
"""
Randomly samples the design space.
Returns
-------
norm_param_list: np.ndarray
1-D array of normalized parameter values (usually from ``extract_parameters`` in ``MEA``).
"""
problem = Problem(n_var=len(self.norm_param_list), l=0.0, xu=1.0)
sampling = LatinHypercubeSampling()
return sampling._do(problem, self.n_samples)