libEnsemble Tutorial
The following libe_basic_ex.py code is an example of basic ParMOO + libEnsemble usage from the Extras and Plugins section of the User Guide.
import numpy as np
from parmoo.extras.libe import libE_MOOP
from parmoo.searches import LatinHypercube
from parmoo.surrogates import GaussRBF
from parmoo.acquisitions import UniformWeights
from parmoo.optimizers import LocalGPS
# When running with MPI, we need to keep track of which thread is the manager
# using libensemble.tools.parse_args()
from libensemble.tools import parse_args
_, is_manager, _, _ = parse_args()
# All functions are defined below.
def sim_func(x):
if x["x2"] == 0:
return np.array([(x["x1"] - 0.2) ** 2, (x["x1"] - 0.8) ** 2])
else:
return np.array([99.9, 99.9])
def obj_f1(x, s):
return s["MySim"][0]
def obj_f2(x, s):
return s["MySim"][1]
def const_c1(x, s):
return 0.1 - x["x1"]
# When using libEnsemble with Python MP, the "solve" command must be enclosed
# in an "if __name__ == '__main__':" block, as shown below
if __name__ == "__main__":
# Fix the random seed for reproducibility
np.random.seed(0)
# Create a libE_MOOP
my_moop = libE_MOOP(LocalGPS)
# Add 2 design variables (one continuous and one categorical)
my_moop.addDesign({'name': "x1",
'des_type': "continuous",
'lb': 0.0, 'ub': 1.0})
my_moop.addDesign({'name': "x2", 'des_type': "categorical",
'levels': 3})
# Add the simulation (note the budget of 20 sim evals during search phase)
my_moop.addSimulation({'name': "MySim",
'm': 2,
'sim_func': sim_func,
'search': LatinHypercube,
'surrogate': GaussRBF,
'hyperparams': {'search_budget': 20}})
# Add the objectives
my_moop.addObjective({'name': "f1", 'obj_func': obj_f1})
my_moop.addObjective({'name': "f2", 'obj_func': obj_f2})
# Add the constraint
my_moop.addConstraint({'name': "c1", 'constraint': const_c1})
# Add 3 acquisition functions
for i in range(3):
my_moop.addAcquisition({'acquisition': UniformWeights,
'hyperparams': {}})
# Turn on checkpointing -- creates files parmoo.moop & parmoo.surrogate.1
my_moop.setCheckpoint(True, checkpoint_data=False, filename="parmoo")
# Use sim_max = 30 to perform just 30 simulations
my_moop.solve(sim_max=30)
# Display the solution -- this "if" clause is needed when running with MPI
if is_manager:
results = my_moop.getPF(format="pandas")
print(results)
You can run the above script with MPI
mpirun -np N python3 libe_basic_ex.py
or with Python’s built-in multiprocessing module.
python3 libe_basic_ex.py --comms local --nworkers N
The resulting output is shown below.
x1 x2 f1 f2 c1
0 0.742825 0 0.294659 0.003269 -0.642825
1 0.680283 0 0.230672 0.014332 -0.580283
2 0.616501 0 0.173473 0.033672 -0.516501
3 0.580369 0 0.144680 0.048238 -0.480369
4 0.555222 0 0.126183 0.059916 -0.455222
5 0.518980 0 0.101749 0.078972 -0.418980
6 0.475477 0 0.075888 0.105315 -0.375477
7 0.302503 0 0.010507 0.247503 -0.202503
8 0.201285 0 0.000002 0.358460 -0.101285