sampling

This module contains multiple generation functions for sampling a domain. All use (and return) a random stream in persis_info, given by the allocation function.

sampling.uniform_random_sample(_, persis_info, gen_specs)

Generates gen_specs["user"]["gen_batch_size"] points uniformly over the domain defined by gen_specs["user"]["ub"] and gen_specs["user"]["lb"].

See also

test_uniform_sampling.py # noqa

sampling.uniform_random_sample_with_variable_resources(_, persis_info, gen_specs)

Generates gen_specs["user"]["gen_batch_size"] points uniformly over the domain defined by gen_specs["user"]["ub"] and gen_specs["user"]["lb"].

Also randomly requests a different number of resource sets to be used in each evaluation.

This generator is used to test/demonstrate setting of resource sets.

#.. seealso::

#`test_uniform_sampling_with_variable_resources.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/functionality_tests/test_uniform_sampling_with_variable_resources.py>`_ # noqa

sampling.uniform_random_sample_with_var_priorities_and_resources(H, persis_info, gen_specs)

Generates points uniformly over the domain defined by gen_specs["user"]["ub"] and gen_specs["user"]["lb"]. Also, randomly requests a different priority and number of resource sets to be used in the evaluation of the generated points, after the initial batch.

This generator is used to test/demonstrate setting of priorities and resource sets.

sampling.uniform_random_sample_obj_components(H, persis_info, gen_specs)

Generates points uniformly over the domain defined by gen_specs["user"]["ub"] and gen_specs["user"]["lb"] but requests each obj_component be evaluated separately.

sampling.latin_hypercube_sample(_, persis_info, gen_specs)

Generates gen_specs["user"]["gen_batch_size"] points in a Latin hypercube sample over the domain defined by gen_specs["user"]["ub"] and gen_specs["user"]["lb"].

See also

test_1d_sampling.py # noqa

sampling.uniform_random_sample_cancel(_, persis_info, gen_specs)

Similar to uniform_random_sample but with immediate cancellation of selected points for testing.

sampling.py
  1"""
  2This module contains multiple generation functions for sampling a domain. All
  3use (and return) a random stream in ``persis_info``, given by the allocation
  4function.
  5"""
  6import numpy as np
  7
  8__all__ = [
  9    "uniform_random_sample",
 10    "uniform_random_sample_with_variable_resources",
 11    "uniform_random_sample_with_var_priorities_and_resources",
 12    "uniform_random_sample_obj_components",
 13    "latin_hypercube_sample",
 14    "uniform_random_sample_cancel",
 15]
 16
 17
 18def uniform_random_sample(_, persis_info, gen_specs):
 19    """
 20    Generates ``gen_specs["user"]["gen_batch_size"]`` points uniformly over the domain
 21    defined by ``gen_specs["user"]["ub"]`` and ``gen_specs["user"]["lb"]``.
 22
 23    .. seealso::
 24        `test_uniform_sampling.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/functionality_tests/test_uniform_sampling.py>`_ # noqa
 25    """
 26    ub = gen_specs["user"]["ub"]
 27    lb = gen_specs["user"]["lb"]
 28
 29    n = len(lb)
 30    b = gen_specs["user"]["gen_batch_size"]
 31
 32    H_o = np.zeros(b, dtype=gen_specs["out"])
 33
 34    H_o["x"] = persis_info["rand_stream"].uniform(lb, ub, (b, n))
 35
 36    return H_o, persis_info
 37
 38
 39def uniform_random_sample_with_variable_resources(_, persis_info, gen_specs):
 40    """
 41    Generates ``gen_specs["user"]["gen_batch_size"]`` points uniformly over the domain
 42    defined by ``gen_specs["user"]["ub"]`` and ``gen_specs["user"]["lb"]``.
 43
 44    Also randomly requests a different number of resource sets to be used in each evaluation.
 45
 46    This generator is used to test/demonstrate setting of resource sets.
 47
 48    #.. seealso::
 49        #`test_uniform_sampling_with_variable_resources.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/functionality_tests/test_uniform_sampling_with_variable_resources.py>`_ # noqa
 50    """
 51
 52    ub = gen_specs["user"]["ub"]
 53    lb = gen_specs["user"]["lb"]
 54    max_rsets = gen_specs["user"]["max_resource_sets"]
 55
 56    n = len(lb)
 57    b = gen_specs["user"]["gen_batch_size"]
 58
 59    H_o = np.zeros(b, dtype=gen_specs["out"])
 60
 61    H_o["x"] = persis_info["rand_stream"].uniform(lb, ub, (b, n))
 62    H_o["resource_sets"] = persis_info["rand_stream"].integers(1, max_rsets + 1, b)
 63
 64    print(f'GEN: H rsets requested: {H_o["resource_sets"]}')
 65
 66    return H_o, persis_info
 67
 68
 69def uniform_random_sample_with_var_priorities_and_resources(H, persis_info, gen_specs):
 70    """
 71    Generates points uniformly over the domain defined by ``gen_specs["user"]["ub"]`` and
 72    ``gen_specs["user"]["lb"]``. Also, randomly requests a different priority and number of
 73    resource sets to be used in the evaluation of the generated points, after the initial batch.
 74
 75    This generator is used to test/demonstrate setting of priorities and resource sets.
 76
 77    """
 78    ub = gen_specs["user"]["ub"]
 79    lb = gen_specs["user"]["lb"]
 80    max_rsets = gen_specs["user"]["max_resource_sets"]
 81
 82    n = len(lb)
 83
 84    if len(H) == 0:
 85        b = gen_specs["user"]["initial_batch_size"]
 86
 87        H_o = np.zeros(b, dtype=gen_specs["out"])
 88        for i in range(0, b):
 89            # x= i*np.ones(n)
 90            x = persis_info["rand_stream"].uniform(lb, ub, (1, n))
 91            H_o["x"][i] = x
 92            H_o["resource_sets"][i] = 1
 93            H_o["priority"] = 1
 94
 95    else:
 96        H_o = np.zeros(1, dtype=gen_specs["out"])
 97        # H_o["x"] = len(H)*np.ones(n)  # Can use a simple count for testing.
 98        H_o["x"] = persis_info["rand_stream"].uniform(lb, ub)
 99        H_o["resource_sets"] = persis_info["rand_stream"].integers(1, max_rsets + 1)
100        H_o["priority"] = 10 * H_o["resource_sets"]
101        # print("Created sim for {} resource sets".format(H_o["resource_sets"]), flush=True)
102
103    return H_o, persis_info
104
105
106def uniform_random_sample_obj_components(H, persis_info, gen_specs):
107    """
108    Generates points uniformly over the domain defined by ``gen_specs["user"]["ub"]``
109    and ``gen_specs["user"]["lb"]`` but requests each ``obj_component`` be evaluated
110    separately.
111
112    .. seealso::
113        `test_uniform_sampling_one_residual_at_a_time.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/functionality_tests/test_uniform_sampling_one_residual_at_a_time.py>`_ # noqa
114    """
115    ub = gen_specs["user"]["ub"]
116    lb = gen_specs["user"]["lb"]
117
118    n = len(lb)
119    m = gen_specs["user"]["components"]
120    b = gen_specs["user"]["gen_batch_size"]
121
122    H_o = np.zeros(b * m, dtype=gen_specs["out"])
123    for i in range(0, b):
124        x = persis_info["rand_stream"].uniform(lb, ub, (1, n))
125        H_o["x"][i * m : (i + 1) * m, :] = np.tile(x, (m, 1))
126        H_o["priority"][i * m : (i + 1) * m] = persis_info["rand_stream"].uniform(0, 1, m)
127        H_o["obj_component"][i * m : (i + 1) * m] = np.arange(0, m)
128
129        H_o["pt_id"][i * m : (i + 1) * m] = len(H) // m + i
130
131    return H_o, persis_info
132
133
134def uniform_random_sample_cancel(_, persis_info, gen_specs):
135    """
136    Similar to uniform_random_sample but with immediate cancellation of
137    selected points for testing.
138
139    """
140    ub = gen_specs["user"]["ub"]
141    lb = gen_specs["user"]["lb"]
142
143    n = len(lb)
144    b = gen_specs["user"]["gen_batch_size"]
145
146    H_o = np.zeros(b, dtype=gen_specs["out"])
147    for i in range(b):
148        if i % 10 == 0:
149            H_o[i]["cancel_requested"] = True
150
151    H_o["x"] = persis_info["rand_stream"].uniform(lb, ub, (b, n))
152
153    return H_o, persis_info
154
155
156def latin_hypercube_sample(_, persis_info, gen_specs):
157    """
158    Generates ``gen_specs["user"]["gen_batch_size"]`` points in a Latin
159    hypercube sample over the domain defined by ``gen_specs["user"]["ub"]`` and
160    ``gen_specs["user"]["lb"]``.
161
162    .. seealso::
163        `test_1d_sampling.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_1d_sampling.py>`_ # noqa
164    """
165
166    ub = gen_specs["user"]["ub"]
167    lb = gen_specs["user"]["lb"]
168
169    n = len(lb)
170    b = gen_specs["user"]["gen_batch_size"]
171
172    H_o = np.zeros(b, dtype=gen_specs["out"])
173
174    A = lhs_sample(n, b, persis_info["rand_stream"])
175
176    H_o["x"] = A * (ub - lb) + lb
177
178    return H_o, persis_info
179
180
181def lhs_sample(n, k, stream):
182    # Generate the intervals and random values
183    intervals = np.linspace(0, 1, k + 1)
184    rand_source = stream.uniform(0, 1, (k, n))
185    rand_pts = np.zeros((k, n))
186    sample = np.zeros((k, n))
187
188    # Add a point uniformly in each interval
189    a = intervals[:k]
190    b = intervals[1:]
191    for j in range(n):
192        rand_pts[:, j] = rand_source[:, j] * (b - a) + a
193
194    # Randomly perturb
195    for j in range(n):
196        sample[:, j] = rand_pts[stream.permutation(k), j]
197
198    return sample

persistent_sampling

Persistent generator providing points using sampling

persistent_sampling.persistent_uniform(_, persis_info, gen_specs, libE_info)

This generation function always enters into persistent mode and returns gen_specs["initial_batch_size"] uniformly sampled points the first time it is called. Afterwards, it returns the number of points given. This can be used in either a batch or asynchronous mode by adjusting the allocation function.

persistent_sampling.persistent_uniform_final_update(_, persis_info, gen_specs, libE_info)

Assuming the value "f" returned from sim_f is stochastic, this generation is updating an estimated mean "f_est" of the sim_f output at each of the corners of the domain.

persistent_sampling.persistent_request_shutdown(_, persis_info, gen_specs, libE_info)

This generation function is similar in structure to persistent_uniform, but uses a count to test exiting on a threshold value. This principle can be used with a supporting allocation function (e.g. start_only_persistent) to shutdown an ensemble when a condition is met.

persistent_sampling.uniform_nonblocking(_, persis_info, gen_specs, libE_info)

This generation function is designed to test non-blocking receives.

persistent_sampling.batched_history_matching(_, persis_info, gen_specs, libE_info)

Given - sim_f with an input of x with len(x)=n - b, the batch size of points to generate - q<b, the number of best samples to use in the following iteration

Pseudocode: Let (mu, Sigma) denote a mean and covariance matrix initialized to the origin and the identity, respectively.

While true (batch synchronous for now):

Draw b samples x_1, … , x_b from MVN( mu, Sigma) Evaluate f(x_1), … , f(x_b) and determine the set of q x_i whose f(x_i) values are smallest (breaking ties lexicographically) Update (mu, Sigma) based on the sample mean and sample covariance of these q x values.

persistent_sampling.persistent_uniform_with_cancellations(_, persis_info, gen_specs, libE_info)
persistent_sampling.py
  1"""Persistent generator providing points using sampling"""
  2
  3import numpy as np
  4
  5from libensemble.message_numbers import EVAL_GEN_TAG, FINISHED_PERSISTENT_GEN_TAG, PERSIS_STOP, STOP_TAG
  6from libensemble.tools.persistent_support import PersistentSupport
  7
  8__all__ = [
  9    "persistent_uniform",
 10    "persistent_uniform_final_update",
 11    "persistent_request_shutdown",
 12    "uniform_nonblocking",
 13    "batched_history_matching",
 14    "persistent_uniform_with_cancellations",
 15]
 16
 17
 18def _get_user_params(user_specs):
 19    """Extract user params"""
 20    b = user_specs["initial_batch_size"]
 21    ub = user_specs["ub"]
 22    lb = user_specs["lb"]
 23    n = len(lb)  # dimension
 24    assert isinstance(b, int), "Batch size must be an integer"
 25    assert isinstance(n, int), "Dimension must be an integer"
 26    assert isinstance(lb, np.ndarray), "lb must be a numpy array"
 27    assert isinstance(ub, np.ndarray), "ub must be a numpy array"
 28    return b, n, lb, ub
 29
 30
 31def persistent_uniform(_, persis_info, gen_specs, libE_info):
 32    """
 33    This generation function always enters into persistent mode and returns
 34    ``gen_specs["initial_batch_size"]`` uniformly sampled points the first time it
 35    is called. Afterwards, it returns the number of points given. This can be
 36    used in either a batch or asynchronous mode by adjusting the allocation
 37    function.
 38
 39    .. seealso::
 40        `test_persistent_uniform_sampling.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/functionality_tests/test_persistent_uniform_sampling.py>`_
 41        `test_persistent_uniform_sampling_async.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/functionality_tests/test_persistent_uniform_sampling_async.py>`_
 42    """  # noqa
 43
 44    b, n, lb, ub = _get_user_params(gen_specs["user"])
 45    ps = PersistentSupport(libE_info, EVAL_GEN_TAG)
 46
 47    # Send batches until manager sends stop tag
 48    tag = None
 49    while tag not in [STOP_TAG, PERSIS_STOP]:
 50        H_o = np.zeros(b, dtype=gen_specs["out"])
 51        H_o["x"] = persis_info["rand_stream"].uniform(lb, ub, (b, n))
 52        if "obj_component" in H_o.dtype.fields:
 53            H_o["obj_component"] = persis_info["rand_stream"].integers(
 54                low=0, high=gen_specs["user"]["num_components"], size=b
 55            )
 56        tag, Work, calc_in = ps.send_recv(H_o)
 57        if hasattr(calc_in, "__len__"):
 58            b = len(calc_in)
 59
 60    return H_o, persis_info, FINISHED_PERSISTENT_GEN_TAG
 61
 62
 63def persistent_uniform_final_update(_, persis_info, gen_specs, libE_info):
 64    """
 65    Assuming the value ``"f"`` returned from sim_f is stochastic, this
 66    generation is updating an estimated mean ``"f_est"`` of the sim_f output at
 67    each of the corners of the domain.
 68
 69    .. seealso::
 70        `test_persistent_uniform_sampling_running_mean.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/functionality_tests/test_persistent_uniform_sampling_running_mean.py>`_
 71    """  # noqa
 72
 73    b, n, lb, ub = _get_user_params(gen_specs["user"])
 74    ps = PersistentSupport(libE_info, EVAL_GEN_TAG)
 75
 76    def generate_corners(x, y):
 77        n = len(x)
 78        corner_indices = np.arange(2**n)
 79        corners = []
 80        for index in corner_indices:
 81            corner = [x[i] if index & (1 << i) else y[i] for i in range(n)]
 82            corners.append(corner)
 83        return corners
 84
 85    def sample_corners_with_probability(corners, p, b):
 86        selected_corners = np.random.choice(len(corners), size=b, p=p)
 87        sampled_corners = [corners[i] for i in selected_corners]
 88        return sampled_corners, selected_corners
 89
 90    corners = generate_corners(lb, ub)
 91
 92    # Start with equal probabilies
 93    p = np.ones(2**n) / 2**n
 94
 95    running_total = np.nan * np.ones(2**n)
 96    number_of_samples = np.zeros(2**n)
 97    sent = np.array([], dtype=int)
 98
 99    # Send batches of `b` points until manager sends stop tag
100    tag = None
101    next_id = 0
102    while tag not in [STOP_TAG, PERSIS_STOP]:
103        H_o = np.zeros(b, dtype=gen_specs["out"])
104        H_o["sim_id"] = range(next_id, next_id + b)
105        next_id += b
106
107        sampled_corners, corner_ids = sample_corners_with_probability(corners, p, b)
108
109        H_o["corner_id"] = corner_ids
110        H_o["x"] = sampled_corners
111        sent = np.append(sent, corner_ids)
112
113        tag, Work, calc_in = ps.send_recv(H_o)
114        if hasattr(calc_in, "__len__"):
115            b = len(calc_in)
116            for row in calc_in:
117                number_of_samples[row["corner_id"]] += 1
118                if np.isnan(running_total[row["corner_id"]]):
119                    running_total[row["corner_id"]] = row["f"]
120                else:
121                    running_total[row["corner_id"]] += row["f"]
122
123    # Having received a PERSIS_STOP, update f_est field for all points and return
124    # For manager to honor final H_o return, must have set libE_specs["use_persis_return_gen"] = True
125    f_est = running_total / number_of_samples
126    H_o = np.zeros(len(sent), dtype=[("sim_id", int), ("corner_id", int), ("f_est", float)])
127    for count, i in enumerate(sent):
128        H_o["sim_id"][count] = count
129        H_o["corner_id"][count] = i
130        H_o["f_est"][count] = f_est[i]
131
132    return H_o, persis_info, FINISHED_PERSISTENT_GEN_TAG
133
134
135def persistent_request_shutdown(_, persis_info, gen_specs, libE_info):
136    """
137    This generation function is similar in structure to persistent_uniform,
138    but uses a count to test exiting on a threshold value. This principle can
139    be used with a supporting allocation function (e.g. start_only_persistent)
140    to shutdown an ensemble when a condition is met.
141
142    .. seealso::
143        `test_persistent_uniform_gen_decides_stop.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/functionality_tests/test_persistent_uniform_gen_decides_stop.py>`_
144    """  # noqa
145    b, n, lb, ub = _get_user_params(gen_specs["user"])
146    shutdown_limit = gen_specs["user"]["shutdown_limit"]
147    f_count = 0
148    ps = PersistentSupport(libE_info, EVAL_GEN_TAG)
149
150    # Send batches until manager sends stop tag
151    tag = None
152    while tag not in [STOP_TAG, PERSIS_STOP]:
153        H_o = np.zeros(b, dtype=gen_specs["out"])
154        H_o["x"] = persis_info["rand_stream"].uniform(lb, ub, (b, n))
155        tag, Work, calc_in = ps.send_recv(H_o)
156        if hasattr(calc_in, "__len__"):
157            b = len(calc_in)
158        f_count += b
159        if f_count >= shutdown_limit:
160            print("Reached threshold.", f_count, flush=True)
161            break  # End the persistent gen
162
163    return H_o, persis_info, FINISHED_PERSISTENT_GEN_TAG
164
165
166def uniform_nonblocking(_, persis_info, gen_specs, libE_info):
167    """
168    This generation function is designed to test non-blocking receives.
169
170    .. seealso::
171        `test_persistent_uniform_sampling.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/functionality_tests/test_persistent_uniform_sampling.py>`_
172    """  # noqa
173    b, n, lb, ub = _get_user_params(gen_specs["user"])
174    ps = PersistentSupport(libE_info, EVAL_GEN_TAG)
175
176    # Send batches until manager sends stop tag
177    tag = None
178    while tag not in [STOP_TAG, PERSIS_STOP]:
179        H_o = np.zeros(b, dtype=gen_specs["out"])
180        H_o["x"] = persis_info["rand_stream"].uniform(lb, ub, (b, n))
181        ps.send(H_o)
182
183        received = False
184        spin_count = 0
185        while not received:
186            tag, Work, calc_in = ps.recv(blocking=False)
187            if tag is not None:
188                received = True
189            else:
190                spin_count += 1
191
192        persis_info["spin_count"] = spin_count
193
194        if hasattr(calc_in, "__len__"):
195            b = len(calc_in)
196
197    return H_o, persis_info, FINISHED_PERSISTENT_GEN_TAG
198
199
200def batched_history_matching(_, persis_info, gen_specs, libE_info):
201    """
202    Given
203    - sim_f with an input of x with len(x)=n
204    - b, the batch size of points to generate
205    - q<b, the number of best samples to use in the following iteration
206
207    Pseudocode:
208    Let (mu, Sigma) denote a mean and covariance matrix initialized to the
209    origin and the identity, respectively.
210
211    While true (batch synchronous for now):
212
213        Draw b samples x_1, ... , x_b from MVN( mu, Sigma)
214        Evaluate f(x_1), ... , f(x_b) and determine the set of q x_i whose f(x_i) values are smallest (breaking ties lexicographically)
215        Update (mu, Sigma) based on the sample mean and sample covariance of these q x values.
216
217    .. seealso::
218        `test_persistent_uniform_sampling.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/functionality_tests/test_persistent_uniform_sampling.py>`_
219    """  # noqa
220    lb = gen_specs["user"]["lb"]
221
222    n = len(lb)
223    b = gen_specs["user"]["initial_batch_size"]
224    q = gen_specs["user"]["num_best_vals"]
225    ps = PersistentSupport(libE_info, EVAL_GEN_TAG)
226
227    mu = np.zeros(n)
228    Sigma = np.eye(n)
229    tag = None
230
231    while tag not in [STOP_TAG, PERSIS_STOP]:
232        H_o = np.zeros(b, dtype=gen_specs["out"])
233        H_o["x"] = persis_info["rand_stream"].multivariate_normal(mu, Sigma, b)
234
235        # Send data and get next assignment
236        tag, Work, calc_in = ps.send_recv(H_o)
237        if calc_in is not None:
238            all_inds = np.argsort(calc_in["f"])
239            best_inds = all_inds[:q]
240            mu = np.mean(H_o["x"][best_inds], axis=0)
241            Sigma = np.cov(H_o["x"][best_inds].T)
242
243    return H_o, persis_info, FINISHED_PERSISTENT_GEN_TAG
244
245
246def persistent_uniform_with_cancellations(_, persis_info, gen_specs, libE_info):
247    ub = gen_specs["user"]["ub"]
248    lb = gen_specs["user"]["lb"]
249    n = len(lb)
250    b = gen_specs["user"]["initial_batch_size"]
251
252    # Start cancelling points from half initial batch onward
253    cancel_from = b // 2  # Should get at least this many points back
254
255    ps = PersistentSupport(libE_info, EVAL_GEN_TAG)
256
257    # Send batches until manager sends stop tag
258    tag = None
259    while tag not in [STOP_TAG, PERSIS_STOP]:
260        H_o = np.zeros(b, dtype=gen_specs["out"])
261        H_o["x"] = persis_info["rand_stream"].uniform(lb, ub, (b, n))
262        tag, Work, calc_in = ps.send_recv(H_o)
263
264        if hasattr(calc_in, "__len__"):
265            b = len(calc_in)
266
267            # Cancel as many points as got back
268            cancel_ids = list(range(cancel_from, cancel_from + b))
269            cancel_from += b
270            ps.request_cancel_sim_ids(cancel_ids)
271
272    return H_o, persis_info, FINISHED_PERSISTENT_GEN_TAG

persistent_sampling_var_resources

Persistent random sampling using various methods of dynamic resource assignment

Each function generates points uniformly over the domain defined by gen_specs["user"]["ub"] and gen_specs["user"]["lb"].

Most functions use a random request of resources over a range, setting num_procs, num_gpus, or resource sets. The function uniform_sample_with_var_gpus uses the x value to determine the number of GPUs requested.

persistent_sampling_var_resources.uniform_sample(_, persis_info, gen_specs, libE_info)

Randomly requests a different number of resource sets to be used in the evaluation of the generated points.

persistent_sampling_var_resources.uniform_sample_with_procs_gpus(_, persis_info, gen_specs, libE_info)

Randomly requests a different number of processors and gpus to be used in the evaluation of the generated points.

persistent_sampling_var_resources.uniform_sample_with_var_priorities(_, persis_info, gen_specs, libE_info)

Initial batch has matching priorities, after which a different number of resource sets and priorities are requested for each point.

persistent_sampling_var_resources.uniform_sample_diff_simulations(_, persis_info, gen_specs, libE_info)

Randomly requests a different number of processors for each simulation. One simulation type also uses GPUs.

persistent_sampling_var_resources.uniform_sample_with_sim_gen_resources(_, persis_info, gen_specs, libE_info)

Randomly requests a different number of processors and gpus to be used in the evaluation of the generated points.