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 bygen_specs["user"]["ub"]
andgen_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 bygen_specs["user"]["ub"]
andgen_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"]
andgen_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"]
andgen_specs["user"]["lb"]
but requests eachobj_component
be evaluated separately.See also
- 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 bygen_specs["user"]["ub"]
andgen_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.
See also
- 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.
See also
- 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.
See also
- 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.
See also