Allocation Functions
Below are example allocation functions available in libEnsemble.
Important
See the API for allocation functions here.
Note
The default alloc_func is give_sim_work_first.
give_sim_work_first
- give_sim_work_first.give_sim_work_first(W, H, sim_specs, gen_specs, alloc_specs, persis_info, libE_info)
Decide what should be given to workers. This allocation function gives any available simulation work first, and only when all simulations are completed or running does it start (at most
alloc_specs['user']['num_active_gens']
) generator instances.Allows for a
alloc_specs['user']['batch_mode']
where no generation work is given out unless all entries inH
are returned.Can give points in highest priority, if
'priority'
is a field inH
. If alloc_specs[‘user’][‘give_all_with_same_priority’] is set to True, then all points with the same priority value are given as a batch to the sim.Workers performing sims will be assigned resources given in H[‘resource_sets’] this field exists, else defaulting to one. Workers performing gens are assigned resource_sets given by persis_info[‘gen_resources’] or zero.
This is the default allocation function if one is not defined.
tags: alloc, default, batch, priority
See also
test_uniform_sampling.py # noqa
give_sim_work_first.py
1import numpy as np
2import time
3from libensemble.tools.alloc_support import AllocSupport, InsufficientFreeResources
4
5
6def give_sim_work_first(W, H, sim_specs, gen_specs, alloc_specs, persis_info, libE_info):
7 """
8 Decide what should be given to workers. This allocation function gives any
9 available simulation work first, and only when all simulations are
10 completed or running does it start (at most ``alloc_specs['user']['num_active_gens']``)
11 generator instances.
12
13 Allows for a ``alloc_specs['user']['batch_mode']`` where no generation
14 work is given out unless all entries in ``H`` are returned.
15
16 Can give points in highest priority, if ``'priority'`` is a field in ``H``.
17 If alloc_specs['user']['give_all_with_same_priority'] is set to True, then
18 all points with the same priority value are given as a batch to the sim.
19
20 Workers performing sims will be assigned resources given in H['resource_sets']
21 this field exists, else defaulting to one. Workers performing gens are
22 assigned resource_sets given by persis_info['gen_resources'] or zero.
23
24 This is the default allocation function if one is not defined.
25
26 tags: alloc, default, batch, priority
27
28 .. seealso::
29 `test_uniform_sampling.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_uniform_sampling.py>`_ # noqa
30 """
31
32 user = alloc_specs.get("user", {})
33
34 if "cancel_sims_time" in user:
35 # Cancel simulations that are taking too long
36 rows = np.where(np.logical_and.reduce((H["sim_started"], ~H["sim_ended"], ~H["cancel_requested"])))[0]
37 inds = time.time() - H["sim_started_time"][rows] > user["cancel_sims_time"]
38 to_request_cancel = rows[inds]
39 for row in to_request_cancel:
40 H[row]["cancel_requested"] = True
41
42 if libE_info["sim_max_given"] or not libE_info["any_idle_workers"]:
43 return {}, persis_info
44
45 # Initialize alloc_specs['user'] as user.
46 batch_give = user.get("give_all_with_same_priority", False)
47 gen_in = gen_specs.get("in", [])
48
49 manage_resources = "resource_sets" in H.dtype.names or libE_info["use_resource_sets"]
50 support = AllocSupport(W, manage_resources, persis_info, libE_info)
51 gen_count = support.count_gens()
52 Work = {}
53
54 points_to_evaluate = ~H["sim_started"] & ~H["cancel_requested"]
55 for wid in support.avail_worker_ids():
56
57 if np.any(points_to_evaluate):
58 sim_ids_to_send = support.points_by_priority(H, points_avail=points_to_evaluate, batch=batch_give)
59 try:
60 Work[wid] = support.sim_work(wid, H, sim_specs["in"], sim_ids_to_send, persis_info.get(wid))
61 except InsufficientFreeResources:
62 break
63 points_to_evaluate[sim_ids_to_send] = False
64 else:
65
66 # Allow at most num_active_gens active generator instances
67 if gen_count >= user.get("num_active_gens", gen_count + 1):
68 break
69
70 # Do not start gen instances in batch mode if workers still working
71 if user.get("batch_mode") and not support.all_sim_ended(H):
72 break
73
74 # Give gen work
75 return_rows = range(len(H)) if gen_in else []
76 try:
77 Work[wid] = support.gen_work(wid, gen_in, return_rows, persis_info.get(wid))
78 except InsufficientFreeResources:
79 break
80 gen_count += 1
81
82 return Work, persis_info
fast_alloc
- fast_alloc.give_sim_work_first(W, H, sim_specs, gen_specs, alloc_specs, persis_info, libE_info)
This allocation function gives (in order) entries in
H
to idle workers to evaluate in the simulation function. The fields insim_specs['in']
are given. If all entries in H have been given a be evaluated, a worker is told to call the generator function, provided this wouldn’t result in more thanalloc_specs['user']['num_active_gen']
active generators.This fast_alloc variation of give_sim_work_first is useful for cases that simply iterate through H, issuing evaluations in order and, in particular, is likely to be faster if there will be many short simulation evaluations, given that this function contains fewer column length operations.
tags: alloc, simple, fast
See also
test_fast_alloc.py # noqa
fast_alloc.py
1from libensemble.tools.alloc_support import AllocSupport, InsufficientFreeResources
2
3
4def give_sim_work_first(W, H, sim_specs, gen_specs, alloc_specs, persis_info, libE_info):
5 """
6 This allocation function gives (in order) entries in ``H`` to idle workers
7 to evaluate in the simulation function. The fields in ``sim_specs['in']``
8 are given. If all entries in `H` have been given a be evaluated, a worker
9 is told to call the generator function, provided this wouldn't result in
10 more than ``alloc_specs['user']['num_active_gen']`` active generators.
11
12 This fast_alloc variation of give_sim_work_first is useful for cases that
13 simply iterate through H, issuing evaluations in order and, in particular,
14 is likely to be faster if there will be many short simulation evaluations,
15 given that this function contains fewer column length operations.
16
17 tags: alloc, simple, fast
18
19 .. seealso::
20 `test_fast_alloc.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_fast_alloc.py>`_ # noqa
21 """
22
23 if libE_info["sim_max_given"] or not libE_info["any_idle_workers"]:
24 return {}, persis_info
25
26 user = alloc_specs.get("user", {})
27 manage_resources = "resource_sets" in H.dtype.names or libE_info["use_resource_sets"]
28
29 support = AllocSupport(W, manage_resources, persis_info, libE_info)
30
31 gen_count = support.count_gens()
32 Work = {}
33 gen_in = gen_specs.get("in", [])
34
35 for wid in support.avail_worker_ids():
36 # Skip any cancelled points
37 while persis_info["next_to_give"] < len(H) and H[persis_info["next_to_give"]]["cancel_requested"]:
38 persis_info["next_to_give"] += 1
39
40 # Give sim work if possible
41 if persis_info["next_to_give"] < len(H):
42 try:
43 Work[wid] = support.sim_work(wid, H, sim_specs["in"], [persis_info["next_to_give"]], [])
44 except InsufficientFreeResources:
45 break
46 persis_info["next_to_give"] += 1
47
48 elif gen_count < user.get("num_active_gens", gen_count + 1):
49
50 # Give gen work
51 return_rows = range(len(H)) if gen_in else []
52 try:
53 Work[wid] = support.gen_work(wid, gen_in, return_rows, persis_info.get(wid))
54 except InsufficientFreeResources:
55 break
56 gen_count += 1
57 persis_info["total_gen_calls"] += 1
58
59 return Work, persis_info
fast_alloc_to_aposmm
- fast_alloc_to_aposmm.give_sim_work_first(W, H, sim_specs, gen_specs, alloc_specs, persis_info, libE_info)
This allocation function gives (in order) entries in
H
to idle workers to evaluate in the simulation function. The fields insim_specs['in']
are given. If all entries in H have been given to be evaluated, a worker is told to call the generator function, provided this wouldn’t result in more thanalloc_specs['user']['num_active_gen']
active generators. Also allows for a'batch_mode'
.tags: alloc, simple, fast, batch, aposmm
See also
start_only_persistent
- start_only_persistent.only_persistent_gens(W, H, sim_specs, gen_specs, alloc_specs, persis_info, libE_info)
This allocation function will give simulation work if possible, but otherwise start up to
alloc_specs['user']['num_active_gens']
persistent generators (defaulting to one).By default, evaluation results are given back to the generator once all generated points have been returned from the simulation evaluation. If
alloc_specs['user']['async_return']
is set to True, then any returned points are given back to the generator.If any workers are marked as zero_resource_workers, then these will only be used for generators.
If any of the persistent generators has exited, then ensemble shutdown is triggered.
User options:
To be provided in calling script: E.g.,
alloc_specs['user']['async_return'] = True
- init_sample_size: int, optional
Initial sample size - always return in batch. Default: 0
- num_active_gens: int, optional
Maximum number of persistent generators to start. Default: 1
- async_return: boolean, optional
Return results to gen as they come in (after sample). Default: False (batch return).
- active_recv_gen: boolean, optional
Create gen in active receive mode. If True, the manager does not need to wait for a return from the generator before sending further returned points. Default: False
tags: alloc, batch, async, persistent, priority
See also
test_persistent_sampling.py # noqa test_persistent_sampling_async.py # noqa test_persistent_surmise_calib.py # noqa test_persistent_uniform_gen_decides_stop.py # noqa
- start_only_persistent.only_persistent_workers(W, H, sim_specs, gen_specs, alloc_specs, persis_info, libE_info)
This allocation function will give simulation work if possible to any worker not listed as a zero_resource_worker. On the first call, the worker will be placed into a persistent state that will be maintained until libE is exited.
Otherwise, zero resource workers will be given up to a maximum of
alloc_specs['user']['num_active_gens']
persistent generators (defaulting to one).By default, evaluation results are given back to the generator once all generated points have been returned from the simulation evaluation. If
alloc_specs['user']['async_return']
is set to True, then any returned points are given back to the generator.If any of the persistent generators has exited, then ensemble shutdown is triggered.
Note, that an alternative to using zero resource workers would be to set a fixed number of simulation workers in persistent state at the start, allowing at least one worker for the generator - a minor alteration.
User options:
To be provided in calling script: E.g.,
alloc_specs['user']['async_return'] = True
- init_sample_size: int, optional
Initial sample size - always return in batch. Default: 0
- num_active_gens: int, optional
Maximum number of persistent generators to start. Default: 1
- async_return: boolean, optional
Return results to gen as they come in (after sample). Default: False (batch return).
- active_recv_gen: boolean, optional
Create gen in active receive mode. If True, the manager does not need to wait for a return from the generator before sending further returned points. Default: False
See also
start_only_persistent.py
1import numpy as np
2from libensemble.message_numbers import EVAL_SIM_TAG, EVAL_GEN_TAG
3from libensemble.tools.alloc_support import AllocSupport, InsufficientFreeResources
4
5
6def only_persistent_gens(W, H, sim_specs, gen_specs, alloc_specs, persis_info, libE_info):
7 """
8 This allocation function will give simulation work if possible, but
9 otherwise start up to ``alloc_specs['user']['num_active_gens']``
10 persistent generators (defaulting to one).
11
12 By default, evaluation results are given back to the generator once
13 all generated points have been returned from the simulation evaluation.
14 If ``alloc_specs['user']['async_return']`` is set to True, then any
15 returned points are given back to the generator.
16
17 If any workers are marked as zero_resource_workers, then these will only
18 be used for generators.
19
20 If any of the persistent generators has exited, then ensemble shutdown
21 is triggered.
22
23 **User options**:
24
25 To be provided in calling script: E.g., ``alloc_specs['user']['async_return'] = True``
26
27 init_sample_size: int, optional
28 Initial sample size - always return in batch. Default: 0
29
30 num_active_gens: int, optional
31 Maximum number of persistent generators to start. Default: 1
32
33 async_return: boolean, optional
34 Return results to gen as they come in (after sample). Default: False (batch return).
35
36 active_recv_gen: boolean, optional
37 Create gen in active receive mode. If True, the manager does not need to wait
38 for a return from the generator before sending further returned points.
39 Default: False
40
41 tags: alloc, batch, async, persistent, priority
42
43 .. seealso::
44 `test_persistent_sampling.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_persistent_sampling.py>`_ # noqa
45 `test_persistent_sampling_async.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_persistent_sampling_async.py>`_ # noqa
46 `test_persistent_surmise_calib.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_persistent_surmise_calib.py>`_ # noqa
47 `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
48 """
49
50 if libE_info["sim_max_given"] or not libE_info["any_idle_workers"]:
51 return {}, persis_info
52
53 # Initialize alloc_specs['user'] as user.
54 user = alloc_specs.get("user", {})
55 manage_resources = "resource_sets" in H.dtype.names or libE_info["use_resource_sets"]
56 active_recv_gen = user.get("active_recv_gen", False) # Persistent gen can handle irregular communications
57 init_sample_size = user.get("init_sample_size", 0) # Always batch return until this many evals complete
58 batch_give = user.get("give_all_with_same_priority", False)
59
60 support = AllocSupport(W, manage_resources, persis_info, libE_info)
61 gen_count = support.count_persis_gens()
62 Work = {}
63
64 # Asynchronous return to generator
65 async_return = user.get("async_return", False) and sum(H["sim_ended"]) >= init_sample_size
66
67 if gen_count < persis_info.get("num_gens_started", 0):
68 # When a persistent worker is done, trigger a shutdown (returning exit condition of 1)
69 return Work, persis_info, 1
70
71 # Give evaluated results back to a running persistent gen
72 for wid in support.avail_worker_ids(persistent=EVAL_GEN_TAG, active_recv=active_recv_gen):
73 gen_inds = H["gen_worker"] == wid
74 returned_but_not_given = np.logical_and.reduce((H["sim_ended"], ~H["gen_informed"], gen_inds))
75 if np.any(returned_but_not_given):
76 if async_return or support.all_sim_ended(H, gen_inds):
77 point_ids = np.where(returned_but_not_given)[0]
78 Work[wid] = support.gen_work(
79 wid,
80 gen_specs["persis_in"],
81 point_ids,
82 persis_info.get(wid),
83 persistent=True,
84 active_recv=active_recv_gen,
85 )
86 returned_but_not_given[point_ids] = False
87
88 # Now the give_sim_work_first part
89 points_to_evaluate = ~H["sim_started"] & ~H["cancel_requested"]
90 avail_workers = support.avail_worker_ids(persistent=False, zero_resource_workers=False)
91 for wid in avail_workers:
92
93 if not np.any(points_to_evaluate):
94 break
95
96 sim_ids_to_send = support.points_by_priority(H, points_avail=points_to_evaluate, batch=batch_give)
97 try:
98 Work[wid] = support.sim_work(wid, H, sim_specs["in"], sim_ids_to_send, persis_info.get(wid))
99 except InsufficientFreeResources:
100 break
101
102 points_to_evaluate[sim_ids_to_send] = False
103
104 # Start persistent gens if no worker to give out. Uses zero_resource_workers if defined.
105 if not np.any(points_to_evaluate):
106 avail_workers = support.avail_worker_ids(persistent=False, zero_resource_workers=True)
107
108 for wid in avail_workers:
109 if gen_count < user.get("num_active_gens", 1):
110 # Finally, start a persistent generator as there is nothing else to do.
111 try:
112 Work[wid] = support.gen_work(
113 wid,
114 gen_specs.get("in", []),
115 range(len(H)),
116 persis_info.get(wid),
117 persistent=True,
118 active_recv=active_recv_gen,
119 )
120 except InsufficientFreeResources:
121 break
122 persis_info["num_gens_started"] = persis_info.get("num_gens_started", 0) + 1
123 gen_count += 1
124
125 return Work, persis_info, 0
126
127
128def only_persistent_workers(W, H, sim_specs, gen_specs, alloc_specs, persis_info, libE_info):
129 """
130 This allocation function will give simulation work if possible to any worker
131 not listed as a zero_resource_worker. On the first call, the worker will be
132 placed into a persistent state that will be maintained until libE is exited.
133
134 Otherwise, zero resource workers will be given up to a maximum of
135 ``alloc_specs['user']['num_active_gens']`` persistent generators (defaulting to one).
136
137 By default, evaluation results are given back to the generator once
138 all generated points have been returned from the simulation evaluation.
139 If ``alloc_specs['user']['async_return']`` is set to True, then any
140 returned points are given back to the generator.
141
142 If any of the persistent generators has exited, then ensemble shutdown
143 is triggered.
144
145 Note, that an alternative to using zero resource workers would be to set
146 a fixed number of simulation workers in persistent state at the start, allowing
147 at least one worker for the generator - a minor alteration.
148
149 **User options**:
150
151 To be provided in calling script: E.g., ``alloc_specs['user']['async_return'] = True``
152
153 init_sample_size: int, optional
154 Initial sample size - always return in batch. Default: 0
155
156 num_active_gens: int, optional
157 Maximum number of persistent generators to start. Default: 1
158
159 async_return: boolean, optional
160 Return results to gen as they come in (after sample). Default: False (batch return).
161
162 active_recv_gen: boolean, optional
163 Create gen in active receive mode. If True, the manager does not need to wait
164 for a return from the generator before sending further returned points.
165 Default: False
166
167
168 .. seealso::
169 `test_persistent_gensim_uniform_sampling.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_persistent_gensim_uniform_sampling.py>`_ # noqa
170 """
171
172 if libE_info["sim_max_given"] or not libE_info["any_idle_workers"]:
173 return {}, persis_info
174
175 # Initialize alloc_specs['user'] as user.
176 user = alloc_specs.get("user", {})
177 manage_resources = "resource_sets" in H.dtype.names or libE_info["use_resource_sets"]
178 active_recv_gen = user.get("active_recv_gen", False) # Persistent gen can handle irregular communications
179 init_sample_size = user.get("init_sample_size", 0) # Always batch return until this many evals complete
180 batch_give = user.get("give_all_with_same_priority", False)
181
182 support = AllocSupport(W, manage_resources, persis_info, libE_info)
183 gen_count = support.count_persis_gens()
184 Work = {}
185
186 # Asynchronous return to generator
187 async_return = user.get("async_return", False) and sum(H["sim_ended"]) >= init_sample_size
188
189 if gen_count < persis_info.get("num_gens_started", 0):
190 # When a persistent gen worker is done, trigger a shutdown (returning exit condition of 1)
191 return Work, persis_info, 1
192
193 # Give evaluated results back to a running persistent gen
194 for wid in support.avail_worker_ids(persistent=EVAL_GEN_TAG, active_recv=active_recv_gen):
195 gen_inds = H["gen_worker"] == wid
196 returned_but_not_given = np.logical_and.reduce((H["sim_ended"], ~H["gen_informed"], gen_inds))
197 if np.any(returned_but_not_given):
198 if async_return or support.all_sim_ended(H, gen_inds):
199 point_ids = np.where(returned_but_not_given)[0]
200 Work[wid] = support.gen_work(
201 wid,
202 gen_specs["persis_in"],
203 point_ids,
204 persis_info.get(wid),
205 persistent=True,
206 active_recv=active_recv_gen,
207 )
208 returned_but_not_given[point_ids] = False
209
210 # Now the give_sim_work_first part
211 points_to_evaluate = ~H["sim_started"] & ~H["cancel_requested"]
212 avail_workers = list(
213 set(support.avail_worker_ids(persistent=False, zero_resource_workers=False))
214 | set(support.avail_worker_ids(persistent=EVAL_SIM_TAG, zero_resource_workers=False))
215 )
216 for wid in avail_workers:
217
218 if not np.any(points_to_evaluate):
219 break
220
221 sim_ids_to_send = support.points_by_priority(H, points_avail=points_to_evaluate, batch=batch_give)
222 try:
223 # Note that resources will not change if worker is already persistent.
224 Work[wid] = support.sim_work(
225 wid, H, sim_specs["in"], sim_ids_to_send, persis_info.get(wid), persistent=True
226 )
227 except InsufficientFreeResources:
228 break
229
230 points_to_evaluate[sim_ids_to_send] = False
231
232 # Start persistent gens if no sim work to give out. Uses zero_resource_workers if defined.
233 if not np.any(points_to_evaluate):
234 avail_workers = support.avail_worker_ids(persistent=False, zero_resource_workers=True)
235
236 for wid in avail_workers:
237 if gen_count < user.get("num_active_gens", 1):
238 # Finally, start a persistent generator as there is nothing else to do.
239 try:
240 Work[wid] = support.gen_work(
241 wid,
242 gen_specs.get("in", []),
243 range(len(H)),
244 persis_info.get(wid),
245 persistent=True,
246 active_recv=active_recv_gen,
247 )
248 except InsufficientFreeResources:
249 break
250 persis_info["num_gens_started"] = persis_info.get("num_gens_started", 0) + 1
251 gen_count += 1
252 del support
253 return Work, persis_info, 0
start_persistent_local_opt_gens
- start_persistent_local_opt_gens.start_persistent_local_opt_gens(W, H, sim_specs, gen_specs, alloc_specs, persis_info, libE_info)
This allocation function will do the following:
Start up a persistent generator that is a local opt run at the first point identified by APOSMM’s decide_where_to_start_localopt. Note, it will do this only if at least one worker will be left to perform simulation evaluations.
If multiple starting points are available, the one with smallest function value is chosen.
If no candidate starting points exist, points from existing runs will be evaluated (oldest first).
If no points are left, call the generation function.
tags: alloc, persistent, aposmm
See also
test_uniform_sampling_then_persistent_localopt_runs.py # noqa