Skip to content

Commit

Permalink
Merge ffa6ad8 into e530f0c
Browse files Browse the repository at this point in the history
  • Loading branch information
jmlarson1 committed Nov 14, 2018
2 parents e530f0c + ffa6ad8 commit 667f98b
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 24 deletions.
50 changes: 35 additions & 15 deletions libensemble/gen_funcs/aposmm.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@

def aposmm_logic(H,persis_info,gen_specs,_):
"""
APOSMM as a libEnsemble generation function. Coordinates multiple local
optimization runs, starting from points which do not have a better point
nearby them. This generation function produces/requires the following
fields in ``H``:
APOSMM coordinates multiple local optimization runs, starting from points
which do not have a better point nearby (within a distance ``r_k``). This
generation function produces/requires the following fields in ``H``:
- ``'x' [n floats]``: Parameters being optimized over
- ``'x_on_cube' [n floats]``: Parameters scaled to the unit cube
Expand All @@ -43,18 +42,19 @@ def aposmm_logic(H,persis_info,gen_specs,_):
- ``'started_run' [bool]``: True if point has started a local optimization run
- ``'num_active_runs' [int]``: Counts number of non-terminated local runs the point is in
- ``'local_min' [float]``: True if point has been ruled a local minima
- ``'sim_id' [int]``: Row number of entry in history
and optionally
- ``'priority' [float]``: Value quantifying a point's desirability
- ``'f_i' [float]``: Value of ith objective component (if calculated one at a time)
- ``'fvec' [m floats]``: All objective components (if calculated together)
- ``'obj_component' [int]``: Index corresponding to value in ``'f_i``'
- ``'pt_id' [int]``: Identify the point
- ``'pt_id' [int]``: Identify the point (useful when evaluating different objective components for a given ``'x'``)
When using libEnsemble to do individual objective component evaluations,
APOSMM will return ``gen_specs['components']`` copies of each point, but
each component=0 version of the point will only be considered when
the component=0 entry of each point will only be considered when
- deciding where to start a run,
- best nearby point,
Expand All @@ -81,9 +81,10 @@ def aposmm_logic(H,persis_info,gen_specs,_):
- ``'mu' [float]``: Distance from the boundary that all localopt starting points must satisfy
- ``'nu' [float]``: Distance from identified minima that all starting points must satisfy
- ``'single_component_at_a_time' [bool]``: True if single objective components will be evaluated at a time
- ``'rk_const' [float]``:
- ``'rk_const' [float]``: Multiplier in front of the r_k value
- ``'max_active_runs' [int]``: Upper bound on the number of runs APOSMM is advancing
And ``gen_specs`` convergence tolerances for NLopt and PETSc/TAO:
And ``gen_specs`` convergence tolerances for NLopt and PETSc/TAO localopt_methods:
- ``'fatol' [float]``:
- ``'ftol_abs' [float]``:
Expand All @@ -93,6 +94,20 @@ def aposmm_logic(H,persis_info,gen_specs,_):
- ``'xtol_abs' [float]``:
- ``'xtol_rel' [float]``:
As a default, APOSMM starts a local optimization runs from a point that:
- is not in an active local optimization run,
- is more than ``mu`` from the boundary (in the unit-cube domain),
- is more than ``nu`` from identified minima (in the unit-cube domain),
- does not have a better point within a distance ``r_k`` of it.
If the above results in more than ``'max_active_runs'`` being advanced, the
best point in each run is determined and the dist_to_better is computed
(with inf being the value for the best run). Then those
``'max_active_runs'`` runs with largest dist_to_better are advanced
(breaking ties arbitrarily).
:Note:
``gen_specs['combine_component_func']`` must be defined when there are
multiple objective components.
Expand Down Expand Up @@ -132,6 +147,13 @@ def aposmm_logic(H,persis_info,gen_specs,_):
exit_code: 0 if a new localopt point has been found, otherwise it's the NLopt/POUNDERS code
samples_needed: counts the number of additional uniformly drawn samples needed
Description of persistent variables used to maintain the state of APOSMM
persis_info['total_runs']: Running count of started and completed localopt runs
persis_info['run_order']: Sequence of indices of points in each unfinished run
persis_info['old_runs']: Sequence of indices of points in each finished run
"""

n, n_s, c_flag, O, r_k, mu, nu = initialize_APOSMM(H, gen_specs)
Expand All @@ -156,17 +178,16 @@ def aposmm_logic(H,persis_info,gen_specs,_):
H['num_active_runs'][ind] += 1

persis_info['run_order'][new_run_num] = [ind]
persis_info['active_runs'].update([new_run_num])
persis_info['total_runs'] +=1

num_runs = len(persis_info['run_order'])
if 'max_active_runs' in gen_specs and gen_specs['max_active_runs'] < num_runs:
run_vals = np.zeros((num_runs,2),dtype=int)
run_vals = np.zeros((num_runs,2),dtype=int) # Stores run number and sim_id (i.e., the row in H) of the best point in each run
for i,run in enumerate(persis_info['run_order'].keys()):
run_vals[i,0] = run
run_vals[i,1] = persis_info['run_order'][run][np.nanargmin(H['f'][persis_info['run_order'][run]])]

P = squareform(pdist(H['x_on_cube'][run_vals[:,1]], 'euclidean'))
P = squareform(pdist(H['x_on_cube'][run_vals[:,1]], 'euclidean')) # Pairwise distance between the best points in each run
dist_to_better = np.inf*np.ones(num_runs)

for i in range(num_runs):
Expand All @@ -176,14 +197,14 @@ def aposmm_logic(H,persis_info,gen_specs,_):

k_sorted = np.argpartition(-dist_to_better,kth=gen_specs['max_active_runs']-1) # Take max_active_runs largest

persis_info['active_runs'] = set(run_vals[k_sorted[:gen_specs['max_active_runs']],0].astype(int))
active_runs = set(run_vals[k_sorted[:gen_specs['max_active_runs']],0].astype(int))
else:
persis_info['active_runs'] = set(persis_info['run_order'].keys())
active_runs = set(persis_info['run_order'].keys())

inactive_runs = set()

# Find next point in any uncompleted runs using information stored in persis_info
for run in persis_info['active_runs']:
for run in active_runs:
if not np.all(H['returned'][persis_info['run_order'][run]]):
continue # Can't advance this run since all of it's points haven't been returned.

Expand All @@ -205,7 +226,6 @@ def aposmm_logic(H,persis_info,gen_specs,_):
persis_info['run_order'][run].append(O['sim_id'][matching_ind[0]])

for i in inactive_runs:
persis_info['active_runs'].remove(i)
old_run = persis_info['run_order'].pop(i) # Deletes any information about this run
persis_info['old_runs'][i] = old_run

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@
persis_info = {'next_to_give':0}
persis_info['total_gen_calls'] = 0
persis_info['last_worker'] = 0
persis_info[0] = {'active_runs': set(),
'run_order': {},
persis_info[0] = {'run_order': {},
'old_runs': {},
'total_runs': 0,
'rand_stream': np.random.RandomState(1)}
Expand Down
1 change: 0 additions & 1 deletion libensemble/tests/regression_tests/test_branin_aposmm.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@
persis_info[i] = {'rand_stream': np.random.RandomState(i)}

persis_info[1]['total_runs'] = 0
persis_info[1]['active_runs'] = set()
persis_info[1]['run_order'] = {}
persis_info[1]['old_runs'] = {}
persis_info[1]['total_runs'] = 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@
persis_info[i] = {'rand_stream': np.random.RandomState(i)}

persis_info['last_worker'] = 0
persis_info[0] = {'active_runs': set(),
'run_order': {},
persis_info[0] = {'run_order': {},
'old_runs': {},
'total_runs': 0,
'rand_stream': np.random.RandomState(1)}
Expand Down
3 changes: 1 addition & 2 deletions libensemble/tests/regression_tests/test_chwirut_pounders.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@
for i in range(MPI.COMM_WORLD.Get_size()):
persis_info[i] = {'rand_stream': np.random.RandomState(i)}

persis_info[1] = {'active_runs': set(),
'run_order': {},
persis_info[1] = {'run_order': {},
'old_runs': {},
'total_runs': 0,
'rand_stream': np.random.RandomState(1)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@
persis_info[i] = {'rand_stream': np.random.RandomState(i)}

persis_info['last_worker'] = 0
persis_info[0] = {'active_runs': set(),
'run_order': {},
persis_info[0] = {'run_order': {},
'old_runs': {},
'total_runs': 0,
'rand_stream': np.random.RandomState(1)}
Expand Down

0 comments on commit 667f98b

Please sign in to comment.