Skip to content

array_sampler


Overview

The array sampler will generate samples by taking the Cartesian product of the provided discrete values for each parameter. The samples are directly specified in 'bounds' in the config file.


ArraySampler

ArraySampler(bounds, parameters, **kwargs)

Bases: Sampler

Configuration

To use the ArraySampler, specify it in the configuration file as in following example:

sampler:
    type: Array
    bounds: [[5, 7, 77, 199], [0.02, 0.2]]
    num_samples: [4, 2]
    parameters: ['a', 'b']

This configuration would create the following sample space:

[[5, 0.02], [5, 0.2], [7, 0.02], [7, 0.2], [77, 0.02], [77, 0.2], [199, 0.02], [199, 0.2]].

Attributes:

Name Type Description
bounds list of list of float or int

The bounds of each parameter.

num_samples list of int

The number of samples for each parameter.

parameters list of str

The names of the parameters.

budget int

The total number of parameter combinations.

num_initial_points int

The number of initial points in the sample space.

samples list of list of float or int

The generated parameter combinations.

current_index int

The index of the current parameter combination.


Assumption and notes

- This throws errors if you are asking for something insane, e.g., 10 parameters  for 10 samples each -> 10 billion so hard limit at 100.000

Initializes the ArraySampler.

Parameters:

Name Type Description Default
bounds list of list of float or int

The bounds of each parameter.

required
num_samples list of int

The number of samples for each parameter.

required
parameters list of str

The names of the parameters.

required
Source code in src/enchanted_surrogates/samplers/array_sampler.py
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
def __init__(self, bounds, parameters, **kwargs):
    """
    Initializes the ArraySampler.

    Args:
        bounds (list of list of float or int): The bounds of each parameter.
        num_samples (list of int): The number of samples for each parameter.
        parameters (list of str): The names of the parameters.
    """

    self.parameters = parameters
    self.bounds = bounds
    self.budget = np.prod(np.array([len(b) for b in bounds]))
    if self.budget > 100000:
        raise Exception(
            (
                "Can not do array sampling on more than 10000 samples, ",
                f"you requested {self.budget}",
            )
        )
    self.batch_size = kwargs.get("batch_size", self.budget)
    self.samples = list(self.generate_parameters())
    self.current_index = 0

generate_parameters

generate_parameters()

Generates the parameter combinations.

Yields:

Type Description

list of float or int: The next parameter combination.

Source code in src/enchanted_surrogates/samplers/array_sampler.py
79
80
81
82
83
84
85
86
87
88
89
90
91
def generate_parameters(self):
    """
    Generates the parameter combinations.

    Yields:
        list of float or int: The next parameter combination.
    """
    samples = self.bounds
    # Use itertools.product to create a Cartesian product of sample
    # points, representing the hypercube
    for params_tuple in product(*samples):
        # Convert tuples to list to ensure serializability
        yield list(params_tuple)

get_next_samples

get_next_samples()

Gets the next batch of parameter combinations.

Returns:

Type Description
list[dict]

list[dict]: List of parameter dicts for the batch, or empty list if no samples remain.

Source code in src/enchanted_surrogates/samplers/array_sampler.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
def get_next_samples(self) -> list[dict]:
    """
    Gets the next batch of parameter combinations.

    Returns:
        list[dict]: List of parameter dicts for the batch,
                    or empty list if no samples remain.
    """
    list_param_dicts = []

    for _ in range(self.batch_size):
        if self.current_index >= len(self.samples):
            break
        params = self.samples[self.current_index]
        self.current_index += 1
        param_dict = {key: value for key, value in zip(self.parameters, params)}
        list_param_dicts.append(param_dict)
    self.submitted += len(list_param_dicts)

    return list_param_dicts

register_future

register_future(future)

Doesn't matter for random sampler TODO: Probably?

Source code in src/enchanted_surrogates/samplers/array_sampler.py
114
115
116
def register_future(self, future):
    """ Doesn't matter for random sampler TODO: Probably? """
    return None