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.latin_hypercube_sample(H, 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(H, 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_cancel(H, persis_info, gen_specs, _)

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

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.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_with_variable_resources(H, 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/regression_tests/test_uniform_sampling_with_variable_resources.py>`_ # noqa

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(H, 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/regression_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(H, 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/regression_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/regression_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(H, 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(H, 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
183    # Generate the intervals and random values
184    intervals = np.linspace(0, 1, k + 1)
185    rand_source = stream.uniform(0, 1, (k, n))
186    rand_pts = np.zeros((k, n))
187    sample = np.zeros((k, n))
188
189    # Add a point uniformly in each interval
190    a = intervals[:k]
191    b = intervals[1:]
192    for j in range(n):
193        rand_pts[:, j] = rand_source[:, j] * (b - a) + a
194
195    # Randomly perturb
196    for j in range(n):
197        sample[:, j] = rand_pts[stream.permutation(k), j]
198
199    return sample

persistent_sampling

persistent_sampling.batched_history_matching(H, 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.

See also

test_persistent_sampling.py # noqa

persistent_sampling.persistent_request_shutdown(H, 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.persistent_uniform(H, 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.uniform_random_sample_with_variable_resources(H, persis_info, gen_specs, libE_info)

Generates 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 the evaluation of the generated points after the initial batch.

persistent_sampling.py

  1import numpy as np
  2
  3from libensemble.message_numbers import STOP_TAG, PERSIS_STOP, FINISHED_PERSISTENT_GEN_TAG, EVAL_GEN_TAG
  4from libensemble.tools.persistent_support import PersistentSupport
  5
  6__all__ = [
  7    "persistent_uniform",
  8    "uniform_random_sample_with_variable_resources",
  9    "persistent_request_shutdown",
 10    "batched_history_matching",
 11]
 12
 13
 14def persistent_uniform(H, persis_info, gen_specs, libE_info):
 15    """
 16    This generation function always enters into persistent mode and returns
 17    ``gen_specs['initial_batch_size']`` uniformly sampled points the first time it
 18    is called. Afterwards, it returns the number of points given. This can be
 19    used in either a batch or asynchronous mode by adjusting the allocation
 20    function.
 21
 22    .. seealso::
 23        `test_persistent_sampling.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_persistent_sampling.py>`_ # noqa
 24        `test_persistent_sampling_async.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_persistent_sampling_async.py>`_ # noqa
 25    """
 26    ub = gen_specs["user"]["ub"]
 27    lb = gen_specs["user"]["lb"]
 28    n = len(lb)
 29    b = gen_specs["user"]["initial_batch_size"]
 30    ps = PersistentSupport(libE_info, EVAL_GEN_TAG)
 31
 32    # Send batches until manager sends stop tag
 33    tag = None
 34    while tag not in [STOP_TAG, PERSIS_STOP]:
 35        H_o = np.zeros(b, dtype=gen_specs["out"])
 36        H_o["x"] = persis_info["rand_stream"].uniform(lb, ub, (b, n))
 37        tag, Work, calc_in = ps.send_recv(H_o)
 38        if hasattr(calc_in, "__len__"):
 39            b = len(calc_in)
 40
 41    H_o = None
 42    if gen_specs["user"].get("replace_final_fields", 0):
 43        # This is only to test libE ability to accept History after a
 44        # PERSIS_STOP. This history is returned in Work.
 45        H_o = Work
 46        H_o["x"] = -1.23
 47
 48    return H_o, persis_info, FINISHED_PERSISTENT_GEN_TAG
 49
 50
 51def uniform_random_sample_with_variable_resources(H, persis_info, gen_specs, libE_info):
 52    """
 53    Generates points uniformly over the domain defined by ``gen_specs['user']['ub']`` and
 54    ``gen_specs['user']['lb']``. Also randomly requests a different number of resource
 55    sets to be used in the evaluation of the generated points after the initial batch.
 56
 57    .. seealso::
 58        `test_uniform_sampling_with_variable_resources.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_uniform_sampling_with_variable_resources.py>`_ # noqa
 59    """
 60    ub = gen_specs["user"]["ub"]
 61    lb = gen_specs["user"]["lb"]
 62    n = len(lb)
 63    b = gen_specs["user"]["initial_batch_size"]
 64    ps = PersistentSupport(libE_info, EVAL_GEN_TAG)
 65
 66    H_o = np.zeros(b, dtype=gen_specs["out"])
 67    for i in range(0, b):
 68        # x= i*np.ones(n)
 69        x = persis_info["rand_stream"].uniform(lb, ub, (1, n))
 70        H_o["x"][i] = x
 71        H_o["resource_sets"][i] = 1
 72        H_o["priority"] = 1
 73
 74    # Send batches until manager sends stop tag
 75    tag, Work, calc_in = ps.send_recv(H_o)
 76    while tag not in [STOP_TAG, PERSIS_STOP]:
 77        H_o = np.zeros(b, dtype=gen_specs["out"])
 78        # H_o['x'] = len(H)*np.ones(n)
 79        H_o["x"] = persis_info["rand_stream"].uniform(lb, ub, (b, n))
 80        H_o["resource_sets"] = persis_info["rand_stream"].integers(1, gen_specs["user"]["max_resource_sets"] + 1, b)
 81        H_o["priority"] = 10 * H_o["resource_sets"]
 82        print("Created {} sims, with worker_teams req. of size(s) {}".format(b, H_o["resource_sets"]), flush=True)
 83        tag, Work, calc_in = ps.send_recv(H_o)
 84
 85        if calc_in is not None:
 86            b = len(calc_in)
 87
 88    return H_o, persis_info, FINISHED_PERSISTENT_GEN_TAG
 89
 90
 91def persistent_request_shutdown(H, persis_info, gen_specs, libE_info):
 92    """
 93    This generation function is similar in structure to persistent_uniform,
 94    but uses a count to test exiting on a threshold value. This principle can
 95    be used with a supporting allocation function (e.g. start_only_persistent)
 96    to shutdown an ensemble when a condition is met.
 97
 98    .. seealso::
 99        `test_persistent_uniform_gen_decides_stop.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_persistent_uniform_gen_decides_stop.py>`_ # noqa
100    """
101    ub = gen_specs["user"]["ub"]
102    lb = gen_specs["user"]["lb"]
103    n = len(lb)
104    b = gen_specs["user"]["initial_batch_size"]
105    shutdown_limit = gen_specs["user"]["shutdown_limit"]
106    f_count = 0
107    ps = PersistentSupport(libE_info, EVAL_GEN_TAG)
108
109    # Send batches until manager sends stop tag
110    tag = None
111    while tag not in [STOP_TAG, PERSIS_STOP]:
112        H_o = np.zeros(b, dtype=gen_specs["out"])
113        H_o["x"] = persis_info["rand_stream"].uniform(lb, ub, (b, n))
114        tag, Work, calc_in = ps.send_recv(H_o)
115        if hasattr(calc_in, "__len__"):
116            b = len(calc_in)
117        f_count += b
118        if f_count >= shutdown_limit:
119            print("Reached threshold.", f_count, flush=True)
120            break  # End the persistent gen
121
122    return H_o, persis_info, FINISHED_PERSISTENT_GEN_TAG
123
124
125def uniform_nonblocking(H, persis_info, gen_specs, libE_info):
126    """
127    This generation function is designed to test non-blocking receives.
128
129    .. seealso::
130        `test_persistent_sampling.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_persistent_sampling.py>`_ # noqa
131
132    """
133    ub = gen_specs["user"]["ub"]
134    lb = gen_specs["user"]["lb"]
135    n = len(lb)
136    b = gen_specs["user"]["initial_batch_size"]
137    ps = PersistentSupport(libE_info, EVAL_GEN_TAG)
138
139    # Send batches until manager sends stop tag
140    tag = None
141    while tag not in [STOP_TAG, PERSIS_STOP]:
142        H_o = np.zeros(b, dtype=gen_specs["out"])
143        H_o["x"] = persis_info["rand_stream"].uniform(lb, ub, (b, n))
144        ps.send(H_o)
145
146        received = False
147        spin_count = 0
148        while not received:
149            tag, Work, calc_in = ps.recv(blocking=False)
150            if tag is not None:
151                received = True
152            else:
153                spin_count += 1
154
155        persis_info["spin_count"] = spin_count
156
157        if hasattr(calc_in, "__len__"):
158            b = len(calc_in)
159
160    return H_o, persis_info, FINISHED_PERSISTENT_GEN_TAG
161
162
163def batched_history_matching(H, persis_info, gen_specs, libE_info):
164    """
165    Given
166    - sim_f with an input of x with len(x)=n
167    - b, the batch size of points to generate
168    - q<b, the number of best samples to use in the following iteration
169
170    Pseudocode:
171    Let (mu, Sigma) denote a mean and covariance matrix initialized to the
172    origin and the identity, respectively.
173
174    While true (batch synchronous for now):
175
176        Draw b samples x_1, ... , x_b from MVN( mu, Sigma)
177        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)
178        Update (mu, Sigma) based on the sample mean and sample covariance of these q x values.
179
180    .. seealso::
181        `test_persistent_sampling.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_persistent_sampling.py>`_ # noqa
182    """
183    lb = gen_specs["user"]["lb"]
184
185    n = len(lb)
186    b = gen_specs["user"]["initial_batch_size"]
187    q = gen_specs["user"]["num_best_vals"]
188    ps = PersistentSupport(libE_info, EVAL_GEN_TAG)
189
190    mu = np.zeros(n)
191    Sigma = np.eye(n)
192    tag = None
193
194    while tag not in [STOP_TAG, PERSIS_STOP]:
195        H_o = np.zeros(b, dtype=gen_specs["out"])
196        H_o["x"] = persis_info["rand_stream"].multivariate_normal(mu, Sigma, b)
197
198        # Send data and get next assignment
199        tag, Work, calc_in = ps.send_recv(H_o)
200        if calc_in is not None:
201            all_inds = np.argsort(calc_in["f"])
202            best_inds = all_inds[:q]
203            mu = np.mean(H_o["x"][best_inds], axis=0)
204            Sigma = np.cov(H_o["x"][best_inds].T)
205
206    return H_o, persis_info, FINISHED_PERSISTENT_GEN_TAG