Source code for deephyper.skopt.sampler.grid

"""
Inspired by https://github.com/jonathf/chaospy/blob/master/chaospy/
distributions/sampler/sequences/grid.py
"""
import numpy as np
from .base import InitialPointGenerator
from ..space import Space
from sklearn.utils import check_random_state


def _quadrature_combine(args):
    args = [np.asarray(arg).reshape(len(arg), -1) for arg in args]
    shapes = [arg.shape for arg in args]

    size = np.prod(shapes, 0)[0] * np.sum(shapes, 0)[1]
    if size > 10**9:
        raise MemoryError("Too large sets")

    out = args[0]
    for arg in args[1:]:
        out = np.hstack(
            [
                np.tile(out, len(arg)).reshape(-1, out.shape[1]),
                np.tile(arg.T, len(out)).reshape(arg.shape[1], -1).T,
            ]
        )
    return out


def _create_uniform_grid_exclude_border(n_dim, order):
    assert order > 0
    assert n_dim > 0
    x_data = np.arange(1, order + 1) / (order + 1.0)
    x_data = _quadrature_combine([x_data] * n_dim)
    return x_data


def _create_uniform_grid_include_border(n_dim, order):
    assert order > 1
    assert n_dim > 0
    x_data = np.arange(0, order) / (order - 1.0)
    x_data = _quadrature_combine([x_data] * n_dim)
    return x_data


def _create_uniform_grid_only_border(n_dim, order):
    assert n_dim > 0
    assert order > 1
    x = [[0.0, 1.0]] * (n_dim - 1)
    x.append(list(np.arange(0, order) / (order - 1.0)))
    x_data = _quadrature_combine(x)
    return x_data


[docs]class Grid(InitialPointGenerator): """Generate samples from a regular grid. Parameters ---------- border : str, default='exclude' defines how the samples are generated: - 'include' : Includes the border into the grid layout - 'exclude' : Excludes the border from the grid layout - 'only' : Selects only points at the border of the dimension use_full_layout : boolean, default=True When True, a full factorial design is generated and missing points are taken from the next larger full factorial design, depending on `append_border` When False, the next larger full factorial design is generated and points are randomly selected from it. append_border : str, default="only" When use_full_layout is True, this parameter defines how the missing points will be generated from the next larger grid layout: - 'include' : Includes the border into the grid layout - 'exclude' : Excludes the border from the grid layout - 'only' : Selects only points at the border of the dimension """ def __init__(self, border="exclude", use_full_layout=True, append_border="only"): self.border = border self.use_full_layout = use_full_layout self.append_border = append_border
[docs] def generate(self, dimensions, n_samples, random_state=None): """Creates samples from a regular grid. Parameters ---------- dimensions : list, shape (n_dims,) List of search space dimensions. Each search dimension can be defined either as - a `(lower_bound, upper_bound)` tuple (for `Real` or `Integer` dimensions), - a `(lower_bound, upper_bound, "prior")` tuple (for `Real` dimensions), - as a list of categories (for `Categorical` dimensions), or - an instance of a `Dimension` object (`Real`, `Integer` or `Categorical`). n_samples : int The order of the Halton sequence. Defines the number of samples. random_state : int, RandomState instance, or None (default) Set random state to something other than None for reproducible results. Returns ------- np.array, shape=(n_dim, n_samples) grid set """ rng = check_random_state(random_state) space = Space(dimensions) n_dim = space.n_dims transformer = space.get_transformer() space.set_transformer("normalize") if self.border == "include": if self.use_full_layout: order = int(np.floor(np.sqrt(n_samples))) else: order = int(np.ceil(np.sqrt(n_samples))) if order < 2: order = 2 h = _create_uniform_grid_include_border(n_dim, order) elif self.border == "exclude": if self.use_full_layout: order = int(np.floor(np.sqrt(n_samples))) else: order = int(np.ceil(np.sqrt(n_samples))) if order < 1: order = 1 h = _create_uniform_grid_exclude_border(n_dim, order) elif self.border == "only": if self.use_full_layout: order = int(np.floor(n_samples / 2.0)) else: order = int(np.ceil(n_samples / 2.0)) if order < 2: order = 2 h = _create_uniform_grid_exclude_border(n_dim, order) else: raise ValueError("Wrong value for border") if np.size(h, 0) > n_samples: rng.shuffle(h) h = h[:n_samples, :] elif np.size(h, 0) < n_samples: if self.append_border == "only": order = int(np.ceil((n_samples - np.size(h, 0)) / 2.0)) if order < 2: order = 2 h2 = _create_uniform_grid_only_border(n_dim, order) elif self.append_border == "include": order = int(np.ceil(np.sqrt(n_samples - np.size(h, 0)))) if order < 2: order = 2 h2 = _create_uniform_grid_include_border(n_dim, order) elif self.append_border == "exclude": order = int(np.ceil(np.sqrt(n_samples - np.size(h, 0)))) if order < 1: order = 1 h2 = _create_uniform_grid_exclude_border(n_dim, order) else: raise ValueError("Wrong value for append_border") h = np.vstack((h, h2[: (n_samples - np.size(h, 0))])) rng.shuffle(h) else: rng.shuffle(h) h = space.inverse_transform(h) space.set_transformer(transformer) return h