Skip to content

Commit

Permalink
Cleaned up comments on basic examples
Browse files Browse the repository at this point in the history
  • Loading branch information
Katrina Petroske committed Aug 14, 2018
1 parent ae9745e commit 32849bf
Show file tree
Hide file tree
Showing 3 changed files with 330 additions and 0 deletions.
228 changes: 228 additions & 0 deletions examples/basic_examples/alloc_funcs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
"""
# Allocation functions
# + persistent_gen_min
# - assign a persistent generator
# - send the 'x' that gave the minimum
# + persistent_gen_like
# - assign a persistent generator
# - send all the likelihoods and subbatch numbers
# + persistent_gen_banana
# - assign a persistent generator
# - send all the logvalues and subbatch numbers
"""
from __future__ import division
from __future__ import absolute_import

from mpi4py import MPI # for libE communicator
import numpy as np

# Import libEnsemble main
from libensemble.libE import libE
from libensemble.message_numbers import UNSET_TAG, STOP_TAG, PERSIS_STOP, EVAL_GEN_TAG, EVAL_SIM_TAG , FINISHED_PERSISTENT_GEN_TAG

# For debugging, set a breakpoint with pdb.set_trace() or ipdb.set_trace()
#import pdb
#import ipdb


def persistent_gen_min(W, H, sim_specs, gen_specs, persis_info):
"""
Decide what should be given to workers. Note that everything put into
the Work dictionary will be given, so we are careful not to put more gen or
sim items into Work than necessary.
This allocation function will
- Start up a persistent generator.
- It will only do this if at least one worker will be left to perform
simulation evaluations.
- Return the 'x' from the batch that has the minimum evaluated value
"""

# Initialize Work as empty
Work = {}
gen_count = sum(W['persis_state'] == EVAL_GEN_TAG)
already_in_Work = np.zeros(len(H),dtype=bool) # To mark points as they are included in Work, but not yet marked as 'given' in H.


###### Persistent Generator ######
# If i is idle, but in persistent mode, and its calculated values have
# returned, give them back to i. Otherwise, give nothing to i
for i in W['worker_id'][np.logical_and(W['active']==0,W['persis_state']!=0)]:
gen_inds = H['gen_worker']==i
if np.all(H['returned'][gen_inds]): # Has sim_f completed everything from this persistent worker?
# Then give back the 'x' that gave the minimum value
last_batch_inds = H['f'][gen_inds]==np.min(H['f'][gen_inds])
inds_to_send_back = np.where(np.logical_and(gen_inds,last_batch_inds))[0]
Work[i] = {'persis_info': persis_info[i],
'H_fields': sim_specs['in'], #specify keys of what you want to send back
'tag':EVAL_GEN_TAG,
'libE_info': {'H_rows': np.atleast_1d(inds_to_send_back), #specify what rows you want to send back
'persistent': True
}
}

###### Workers ######
for i in W['worker_id'][np.logical_and(W['active']==0,W['persis_state']==0)]:
"""perform sim evaluations from existing runs (if they exist)."""
q_inds_logical = np.logical_and.reduce((~H['given'],~H['paused'],~already_in_Work))
if np.any(q_inds_logical):
sim_ids_to_send = np.nonzero(q_inds_logical)[0][0] # oldest point
Work[i] = {'H_fields': sim_specs['in'],
'persis_info': {}, # Our sims don't need information about how points were generated
'tag':EVAL_SIM_TAG,
'libE_info': {'H_rows': np.atleast_1d(sim_ids_to_send),
},
}

already_in_Work[sim_ids_to_send] = True
else:
""" Finally, generate points since there is nothing else to do. """
if gen_count > 0:
continue
gen_count += 1
""" There are no points available, so we call our gen_func (this only gets called once when
persistent generator is assigned """
Work[i] = {'persis_info': persis_info[i],
'H_fields': gen_specs['in'],
'tag':EVAL_GEN_TAG,
'libE_info': {'H_rows': [],
'persistent': True
}
}

return Work, persis_info


def persistent_gen_like(W, H, sim_specs, gen_specs, persis_info):
"""
These persistent generators produce points (x) in batches and subbatches.
The points x are given in subbatches to workers to perform a calculation.
When all subbatches have returned, their output is given back to the
corresponding persistent generator.
The first time called there are no persistent workers so the 1st for loop is not done
"""

Work = {}
gen_count = sum(W['persis_state'] == EVAL_GEN_TAG)
already_in_Work = np.zeros(len(H),dtype=bool) # To mark points as they are included in Work, but not yet marked as 'given' in H.

# If i is idle, but in persistent mode, and generated work has all returned
# give output back to i. Otherwise, give nothing to i
for i in W['worker_id'][np.logical_and(W['active']==0,W['persis_state']!=0)]:
gen_inds = H['gen_worker']==i
if np.all(H['returned'][gen_inds]): # Has sim_f completed everything from this persistent worker?
# Then give back everything in the last batch
last_batch_inds = H['batch'][gen_inds]==np.max(H['batch'][gen_inds])
inds_to_send_back = np.where(np.logical_and(gen_inds,last_batch_inds))[0]
# Assign weights to correct batch (last two batchs weights will need to be done outside of alloc_func)
if H['batch'][-1] > 0:
n = gen_specs['subbatch_size']*gen_specs['num_subbatches']
k = H['batch'][-1]
H['weight'][(n*(k-1)):(n*k)] = H['weight'][(n*k):(n*(k+1))]
Work[i] = {'persis_info': persis_info[i],
'H_fields': ['like'] + ['subbatch'], #specify keys of what you want to send back
'tag':EVAL_GEN_TAG,
'libE_info': {'H_rows': np.atleast_1d(inds_to_send_back), #atleast_1d -> Convert inputs to arrays with at least one dimension.
'persistent': True
}
}


for i in W['worker_id'][np.logical_and(W['active']==0,W['persis_state']==0)]:
# perform sim evaluations (if any point hasn't been given).
q_inds_logical = np.logical_and(~H['given'],~already_in_Work)
if np.any(q_inds_logical):
sim_ids_to_send = np.nonzero(q_inds_logical)[0][H['subbatch'][q_inds_logical]==np.min(H['subbatch'][q_inds_logical])]
Work[i] = {'H_fields': sim_specs['in'], #things to evaluate
'persis_info': {}, # Our sims don't need information about how points were generated
'tag':EVAL_SIM_TAG,
'libE_info': {'H_rows': np.atleast_1d(sim_ids_to_send), #tells me what x's the returned values go with
},
}

already_in_Work[sim_ids_to_send] = True

else:
# Finally, generate points since there is nothing else to do.
if gen_count > 0:
continue # continue with the next loop of the iteration
gen_count += 1
# There are no points available, so we call our gen_func
Work[i] = {'persis_info':persis_info[i],
'H_fields': gen_specs['in'],
'tag':EVAL_GEN_TAG,
'libE_info': {'H_rows': [],
'persistent': True
}
}

return Work, persis_info


def persistent_gen_logval(W, H, sim_specs, gen_specs, persis_info):
"""
Starts up to gen_count number of persistent generators.
These persistent generators produce points (x) in batches and subbatches.
The points x are given in subbatches to workers to perform a calculation.
When all subbatches have returned, their output is given back to the
corresponding persistent generator.
The first time called there are no persistent workers so the 1st for loop is not done
"""

Work = {}
gen_count = sum(W['persis_state'] == EVAL_GEN_TAG)
already_in_Work = np.zeros(len(H),dtype=bool) # To mark points as they are included in Work, but not yet marked as 'given' in H.

# If i is idle, but in persistent mode, and generated work has all returned
# give output back to i. Otherwise, give nothing to i
for i in W['worker_id'][np.logical_and(W['active']==0,W['persis_state']!=0)]:
gen_inds = H['gen_worker']==i #it there is more than 1 persistant generator make sure you assign the correct work to it
if np.all(H['returned'][gen_inds]): # Has sim_f completed everything from this persistent worker?
# Then give back everything in the last batch
last_batch_inds = H['batch'][gen_inds]==np.max(H['batch'][gen_inds])
inds_to_send_back = np.where(np.logical_and(gen_inds,last_batch_inds))[0]
# Assign weights to correct batch (last two batchs weights will need to be done outside of alloc_func)
if H['batch'][-1] > 0:
n = gen_specs['subbatch_size']*gen_specs['num_subbatches']
k = H['batch'][-1]
H['weight'][(n*(k-1)):(n*k)] = H['weight'][(n*k):(n*(k+1))]
Work[i] = {'persis_info': persis_info[i],
'H_fields': ['logVal'] + ['subbatch'], #specify keys of what you want to send back
'tag':EVAL_GEN_TAG,
'libE_info': {'H_rows': np.atleast_1d(inds_to_send_back), #atleast_1d -> Convert inputs to arrays with at least one dimension.
'persistent': True
}
}

for i in W['worker_id'][np.logical_and(W['active']==0,W['persis_state']==0)]:
# perform sim evaluations (if any point hasn't been given).
q_inds_logical = np.logical_and(~H['given'],~already_in_Work)
if np.any(q_inds_logical):
sim_ids_to_send = np.nonzero(q_inds_logical)[0][H['subbatch'][q_inds_logical]==np.min(H['subbatch'][q_inds_logical])]
Work[i] = {'H_fields': sim_specs['in'], #things to evaluate
'persis_info': {}, # Our sims don't need information about how points were generated
'tag':EVAL_SIM_TAG,
'libE_info': {'H_rows': np.atleast_1d(sim_ids_to_send), #tells me what x's the returned values go with
},
}

already_in_Work[sim_ids_to_send] = True

else:
# Finally, generate points since there is nothing else to do.
if gen_count > 0:
continue # continue with the next loop of the iteration
gen_count += 1
# There are no points available, so we call our gen_func
Work[i] = {'persis_info':persis_info[i],
'H_fields': gen_specs['in'],
'tag':EVAL_GEN_TAG,
'libE_info': {'H_rows': [],
'persistent': True
}

}

return Work, persis_info
69 changes: 69 additions & 0 deletions examples/basic_examples/gen_funcs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""
# Generator functions
# + uniform_random_sample_persistent_gen
# - Persisent uniform distribution generator
# - Acts on output of sim_func
#
# NOTE: This is an example of how libEnsemble works, not something to do in practice
"""
from __future__ import division
from __future__ import absolute_import

from mpi4py import MPI # for libE communicator
import numpy as np

# Import libEnsemble main
from libensemble.libE import libE
from libensemble.message_numbers import UNSET_TAG, STOP_TAG, PERSIS_STOP, EVAL_GEN_TAG, EVAL_SIM_TAG , FINISHED_PERSISTENT_GEN_TAG

# For debugging, set a breakpoint with pdb.set_trace() or ipdb.set_trace()
#import pdb
#import ipdb


def uniform_random_sample_persistent_gen(H,persis_info,gen_specs,libE_info):
"""
Generates points uniformly over the domain defined at first by gen_specs['ub'] and
gen_specs['lb'] and subsequently by taking the minimum 'x' of each batch.
"""
n = gen_specs['n']
comm = libE_info['comm']
while 1:
# If you have received data from sim_func evaluation use it
if 'calc_in' in vars():
ub = calc_in['x'] + 1.0*np.ones(n)
lb = calc_in['x'] - 1.0*np.ones(n)
else:
ub = gen_specs['ub']
lb = gen_specs['lb']

b = gen_specs['gen_batch_size']

# Receive information from the manager (or a STOP_TAG)
status = MPI.Status()
O = np.zeros(b, dtype=gen_specs['out'])
# Generate samples
for i in range(0,b):
x = persis_info['rand_stream'].uniform(lb,ub)
O['x'][i] = x.flatten()
D = {'calc_out':O,
'libE_info': {'persistent':True},
'calc_status': UNSET_TAG,
'calc_type': EVAL_GEN_TAG
}
# Send generated samples
comm.send(obj=D,dest=0,tag=EVAL_GEN_TAG)
# Check to see what information (if any) is coming
comm.probe(source=0, tag=MPI.ANY_TAG, status=status)
tag = status.Get_tag()
if tag in [STOP_TAG, PERSIS_STOP]:
break
else:
Work = comm.recv(buf=None, source=0, tag=MPI.ANY_TAG, status=status)

# Receive information
libE_info = Work['libE_info']
calc_in = comm.recv(buf=None, source=0)

return O, persis_info, tag

33 changes: 33 additions & 0 deletions examples/basic_examples/sim_funcs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""
# Simulation functions
# Rosenbrock Function
"""
from __future__ import division
from __future__ import absolute_import

from mpi4py import MPI # for libE communicator
import numpy as np

# Import libEnsemble main
from libensemble.libE import libE
from libensemble.message_numbers import UNSET_TAG, STOP_TAG, PERSIS_STOP, EVAL_GEN_TAG, EVAL_SIM_TAG , FINISHED_PERSISTENT_GEN_TAG

# For debugging, set a breakpoint with pdb.set_trace() or ipdb.set_trace()
#import pdb
#import ipdb


def rosenbrock(H, gen_info, sim_specs, libE_info):
"""
Evaluates Rosenbrock Function
"""
batch = len(H['x'])
O = np.zeros(batch,dtype=sim_specs['out'])

for i,x in enumerate(H['x']):
O['f'][i] = sum(100.0*(x[1:] - x[:-1]**2.0)**2.0 + (1 - x[:-1])**2.0)


return O, gen_info


0 comments on commit 32849bf

Please sign in to comment.