Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/api/generators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ Generators
AxMultiFidelityGenerator
AxMultitaskGenerator
AxClientGenerator
ExternalGenerator
53 changes: 53 additions & 0 deletions doc/source/user_guide/basic_usage/basic_setup.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,59 @@ Bayesian optimization loop is started (see
)


Using an external generator
^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you have a generator from a third-party library that follows the
`gest-api <https://github.com/campa-consortium/gest-api>`_ generator standard,
you can integrate it with Optimas using
:class:`~optimas.generators.ExternalGenerator`. The external generator must be
instantiated and configured first, then passed to ``ExternalGenerator`` as a
wrapper. The external library itself must be installed separately (see
:ref:`dependencies`).

Known libraries containing generators compatible with this interface include
`Xopt <https://github.com/xopt-org/Xopt>`_ and `libEnsemble
<https://github.com/Libensemble/libensemble>`_.

Using a generic ``gest-api``-compatible generator:

.. code-block:: python

from optimas.generators import ExternalGenerator
from gest_api.vocs import VOCS
from some_library import SomeGenerator

vocs = VOCS(
variables={"x0": [0.0, 15.0], "x1": [-5.0, 5.0]},
objectives={"f": "MINIMIZE"},
)

ext_gen = SomeGenerator(vocs=vocs)
gen = ExternalGenerator(ext_gen=ext_gen, vocs=vocs)

Using an `Xopt <https://github.com/xopt-org/Xopt>`_ generator specifically:

.. code-block:: python

from optimas.generators import ExternalGenerator
from gest_api.vocs import VOCS
from xopt.generators.bayesian.expected_improvement import (
ExpectedImprovementGenerator,
)

vocs = VOCS(
variables={"x0": [0.0, 15.0], "x1": [-5.0, 5.0]},
objectives={"f": "MINIMIZE"},
)

# Create and (optionally) pre-seed the external generator.
ext_gen = ExpectedImprovementGenerator(vocs=vocs)
ext_gen.ingest([{"x0": 1.0, "x1": 0.5, "f": 3.2}])

# Wrap it for use with optimas.
gen = ExternalGenerator(ext_gen=ext_gen, vocs=vocs)


Evaluator
~~~~~~~~~
The evaluator is in charge of getting the trials suggested by the generator and
Expand Down
9 changes: 9 additions & 0 deletions doc/source/user_guide/dependencies.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,12 @@ See table below for a summary.
* - :class:`~optimas.generators.AxClientGenerator`
- :math:`\times`
- :math:`\checkmark`
* - :class:`~optimas.generators.ExternalGenerator` [#external]_
- :math:`\checkmark`
- :math:`\checkmark`

.. [#external] :class:`~optimas.generators.ExternalGenerator` itself has no
additional Optimas dependency beyond ``gest-api`` (already a core
requirement). However, the external generator library being wrapped
(e.g., `Xopt generators <https://github.com/xopt-org/Xopt>`_, or libEnsemble's
`APOSMM <https://libensemble.readthedocs.io/en/main/examples/gest_api/aposmm.html>`_.
87 changes: 83 additions & 4 deletions optimas/generators/external.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,83 @@
"""Contains the definition of an external generator."""
"""Contains the definition of ExternalGenerator.

This module provides a wrapper that integrates third-party generators
implementing the ``gest-api`` generator standard
(https://github.com/campa-consortium/gest-api) into Optimas.
"""

from .base import Generator


class ExternalGenerator(Generator):
"""Supports a generator in the CAMPA generator standard."""
"""Wrap a third-party generator that follows the ``gest-api`` standard:

https://github.com/campa-consortium/gest-api

Any external generator that implements this interface can be used inside
optimas by wrapping it in ``ExternalGenerator``.

Known libraries containing generators compatible with this interface include
`Xopt <https://github.com/xopt-org/Xopt>`_ and `libEnsemble
<https://github.com/Libensemble/libensemble>`_.

Parameters
----------
ext_gen : object
An object implementing/sub-classing the ``gest-api`` generator interface. The
external generator should be fully configured (including any initial
data ingested) before being passed here. The external library itself
must be installed separately.
**kwargs
Additional keyword arguments forwarded to the base
:class:`~optimas.generators.Generator` (e.g., ``vocs``,
``save_model``).

Examples
--------
Using a generic ``gest-api``-compatible generator:

.. code-block:: python

from optimas.generators import ExternalGenerator
from gest_api.vocs import VOCS
from some_library import SomeGenerator

vocs = VOCS(
variables={"x1": [0.0, 1.0], "x2": [0.0, 10.0]},
objectives={"y1": "MINIMIZE"},
)

ext_gen = SomeGenerator(vocs=vocs)
gen = ExternalGenerator(ext_gen=ext_gen, vocs=vocs)

Using an `Xopt <https://github.com/xopt-org/Xopt>`_ generator:

.. code-block:: python

from optimas.generators import ExternalGenerator
from optimas.evaluators import FunctionEvaluator
from optimas.explorations import Exploration
from gest_api.vocs import VOCS
from xopt.generators.bayesian.expected_improvement import (
ExpectedImprovementGenerator,
)

vocs = VOCS(
variables={"x1": [0.0, 1.0], "x2": [0.0, 10.0]},
objectives={"y1": "MINIMIZE"},
)

# Create and (optionally) pre-seed the external generator.
ext_gen = ExpectedImprovementGenerator(vocs=vocs)
ext_gen.ingest([{"x1": 0.5, "x2": 5.0, "y1": 5.0}])

# Wrap it for use with optimas.
gen = ExternalGenerator(ext_gen=ext_gen, vocs=vocs)

ev = FunctionEvaluator(function=my_function)
exp = Exploration(generator=gen, evaluator=ev, max_evals=20, sim_workers=4)
exp.run()
"""

def __init__(
self,
Expand All @@ -17,9 +90,15 @@ def __init__(
self.gen = ext_gen

def suggest(self, n_trials):
"""Request the next set of points to evaluate."""
"""Request the next set of points to evaluate.

Delegates to the wrapped generator's ``suggest`` method.
"""
return self.gen.suggest(n_trials)

def ingest(self, trials):
"""Send the results of evaluations to the generator."""
"""Send the results of evaluations to the generator.

Delegates to the wrapped generator's ``ingest`` method.
"""
self.gen.ingest(trials)
Loading