Skip to content

Commit

Permalink
Update documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelgondu committed Aug 2, 2024
1 parent be8daab commit 39bb89a
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 240 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -743,12 +743,9 @@ <h1>poli.core.util.abstract_observer.AbstractObserver<a class="headerlink" href=
</dd></dl>

<dl class="py method">
<dt class="sig sig-object py">
<span class="sig-name descname"><span class="pre">initialize_observer(problem_setup_info:</span> <span class="pre">ProblemSetupInformation,</span> <span class="pre">caller_info:</span> <span class="pre">object,</span></span></dt>
<dd><blockquote>
<div><p>x0: np.ndarray, y0: np.ndarray, seed: int) -&gt; object:</p>
</div></blockquote>
<p>Initializes the observer with the necessary information to monitor
<dt class="sig sig-object py" id="poli.core.util.abstract_observer.AbstractObserver.initialize_observer">
<span class="sig-name descname"><span class="pre">initialize_observer</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">problem_setup_info</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="poli.core.problem_setup_information.ProblemSetupInformation.html#poli.core.problem_setup_information.ProblemSetupInformation" title="poli.core.problem_setup_information.ProblemSetupInformation"><span class="pre">ProblemSetupInformation</span></a></span></em>, <em class="sig-param"><span class="n"><span class="pre">caller_info</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">object</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">seed</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">object:</span></span></span><a class="headerlink" href="#poli.core.util.abstract_observer.AbstractObserver.initialize_observer" title="Permalink to this definition">#</a></dt>
<dd><p>Initializes the observer with the necessary information to monitor
the optimization process.</p>
</dd></dl>

Expand Down Expand Up @@ -777,7 +774,7 @@ <h1>poli.core.util.abstract_observer.AbstractObserver<a class="headerlink" href=
<tr class="row-even"><td><p><a class="reference internal" href="#poli.core.util.abstract_observer.AbstractObserver.finish" title="poli.core.util.abstract_observer.AbstractObserver.finish"><code class="xref py py-obj docutils literal notranslate"><span class="pre">finish</span></code></a>()</p></td>
<td><p>Finish the observer.</p></td>
</tr>
<tr class="row-odd"><td><p><code class="xref py py-obj docutils literal notranslate"><span class="pre">initialize_observer</span></code>(problem_setup_info, ...)</p></td>
<tr class="row-odd"><td><p><a class="reference internal" href="#poli.core.util.abstract_observer.AbstractObserver.initialize_observer" title="poli.core.util.abstract_observer.AbstractObserver.initialize_observer"><code class="xref py py-obj docutils literal notranslate"><span class="pre">initialize_observer</span></code></a>(problem_setup_info, ...)</p></td>
<td><p>Initialize the observer.</p></td>
</tr>
<tr class="row-even"><td><p><a class="reference internal" href="#poli.core.util.abstract_observer.AbstractObserver.observe" title="poli.core.util.abstract_observer.AbstractObserver.observe"><code class="xref py py-obj docutils literal notranslate"><span class="pre">observe</span></code></a>(x, y[, context])</p></td>
Expand Down
62 changes: 24 additions & 38 deletions _sources/contributing/a_new_problem.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This tutorial covers how black boxes and problems are structured in the repository, and what it takes to add a new one.

If you want to implement your own black box and problem, we recommend copy-pasting an existing folder (e.g. `sa_tdc`), and modifying it to suit your needs. We provide a checklist at the end of this tutorial for the things you need to pay attention to.
If you want to implement your own black box and problem, we recommend copy-pasting an existing folder (e.g. `dockstring`), and modifying it to suit your needs. We provide a checklist at the end of this tutorial for the things you need to pay attention to.

## The structure of a problem

Expand All @@ -15,7 +15,7 @@ poli/objective_repository
│   ├── information.py # A BlackBoxInformation containing a desc. of the black box
│   ├── isolated_function.py # The logic of your black box, as complex as you want.
│   ├── environment.yml # The conda env where isolated_function.py runs
│   └── register.py # Boilerplate for registration and importing.
│   └── register.py # Boilerplate. the problem factory and black box interface.
```

You can also have as many other files as you want. Think of the folder `.../problem_name` as a small project as of itself: you can use any internal code you write here, since it'll be carried with `poli` at installation time.
Expand Down Expand Up @@ -68,7 +68,7 @@ my_problem_information = BlackBoxInformation(

Think of `isolated_function.py` as the entry-route to all the complex, dependency-heavy logic of your black box.

We expect you to implement a subclass of an `AbstractIsolatedFunction`. These are dynamically instanced in isolated environments, such as the one you provide in `environment.yml.
We expect you to implement a subclass of an `AbstractIsolatedFunction`. These are dynamically instanced in isolated environments, such as the one you provide in `environment.yml`.

The average structure of this file would be as follows:

Expand Down Expand Up @@ -118,7 +118,7 @@ The average `register.py` has the following structure

```python
# my_problem_name/register.py
# This one needs to run on a conda env. with minimal dependencies (numpy)
# This one NEEDS TO run on a conda env. with minimal dependencies (numpy)
from typing import Tuple, List

import numpy as np
Expand All @@ -142,33 +142,38 @@ class MyBlackBox(AbstractBlackBox):
batch_size: int = None,
parallelize: bool = False,
num_workers: int = None,
evaluation_budget: int = float("inf")
evaluation_budget: int = float("inf"),
force_isolation: bool = False,
):
super().__init__(
batch_size=batch_size,
parallelize=parallelize,
num_workers=num_workers,
evaluation_budget=evaluation_budget,
force_isolation=force_isolation,
)

#... your manipulation of args and kwargs.

# Importing the isolated logic if we can:
try:
from poli.objective_repository.my_problem.isolated_function import
MyIsolatedLogic

self.inner_function = MyIsolatedLogic(...)
except ImportError:
# If we weren't able to import it, we can still
# create it in an isolated process:
self.inner_function = instance_function_as_isolated_process(
name="problem_name__isolated" # The same name in `isolated_function.py`.
)
_ = get_inner_function(
isolated_function_name="your_problem__isolated", # <-- modify this
class_name="MyIsolatedLogic", # <-- modify this
module_to_import="poli.objective_repository.your_problem.isolated_function", # <-- modify this
force_isolation=force_isolation,
**other_kwargs_that_go_into_MyIsolatedLogic # <-- modify this
)

# Boilerplate for the black box call:
def _black_box(self, x: np.ndarray, context: dict = None) -> np.ndarray:
return self.inner_function(x, context)
inner_function = get_inner_function(
isolated_function_name="your_problem__isolated", # <-- modify this
class_name="MyIsolatedLogic", # <-- modify this
module_to_import="poli.objective_repository.your_problem.isolated_function", # <-- modify this
force_isolation=force_isolation,
**other_kwargs_that_go_into_MyIsolatedLogic # <-- modify this
)
return inner_function(x, context)

# A static method that gives you access to the information.
@staticmethod
Expand Down Expand Up @@ -209,24 +214,9 @@ class MyProblemFactory(AbstractProblemFactory):
x0 = ...

return Problem(f, x0)


if __name__ == "__main__":
from poli.core.registry import register_problem

# Once we have created a simple conda enviroment
# (see the environment.yml file in this folder),
# we can register our problem s.t. it uses
# said conda environment.
my_problem_factory = MyProblemFactory()
register_problem(
my_problem_factory,
conda_environment_name="your_env", # This is the env specified
# by your environment.yml
)
```

That is, **the script creates and registers** your problem factory.
That is, **the script provides an access to your isolated logic**. Now users can create a new problem factory or black box without having to worry about having the right dependencies.

:::{warning}
It is important that name of your problem should be the name of the folder it's contained in, **exactly**. (We advice using `camel_case`).
Expand Down Expand Up @@ -319,7 +309,7 @@ If you
1. have put your new problem is inside `poli/objective_repository`,
2. have an `information.py` that describes your black box,
3. have an `isolated_function.py` that implements the complex logic of your black box and registers it,
4. have a `register.py` that creates and register your problem factory,
4. have a `register.py` that creates your problem factory and black box,
5. have an `environment.yml` that describes the environment you use,
6. have imported your black box and factory in `objective_repository/__init__.py`,

Expand All @@ -335,10 +325,6 @@ problem = objective_factory.create(
...,
your_arg_1=..., # <-- Keywords you (maybe) needed
your_arg_2=..., # <-- at your_factory.create(...)
your_kwarg=..., # <--
# For now, only certain types are
# supported: str, int, bool, float,
# None, and lists thereof.
)
```

Expand Down
56 changes: 23 additions & 33 deletions _sources/using_poli/the_basics/defining_an_observer.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"metadata": {},
"source": [
"All observers inherit from an `AbstractObserver` (which you can find on `poli/core/util/abstract_observer.py`). The abstract methods you need to overwrite are:\n",
"- `initialize_observer(problem_info: ProblemSetupInformation, caller_info: object, x0: np.ndarray, y0: np.ndarray, seed: int) -> object`, which gets called as part of the set-up of the objective function (when `objective_factory.create` is called).\n",
"- `initialize_observer(problem_setup_info: BlackBoxInformation, caller_info: object, seed: int) -> object`, which gets called as part of the set-up of the objective function (when `objective_factory.create` is called).\n",
"- `observe(x: np.ndarray, y: np.ndarray, context: object) -> None`, which gets called every time your optimization algorithms query the objective function.\n",
"- `finish()`, which gets called either by the user, or by the object deletion at the end of the script."
]
Expand Down Expand Up @@ -72,8 +72,6 @@
" self,\n",
" problem_setup_info: ProblemSetupInformation,\n",
" caller_info: object,\n",
" x0: np.ndarray,\n",
" y0: np.ndarray,\n",
" seed: int\n",
" ) -> object:\n",
" ...\n",
Expand Down Expand Up @@ -101,7 +99,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -111,7 +109,7 @@
"\n",
"import numpy as np\n",
"\n",
"from poli.core.problem_setup_information import ProblemSetupInformation\n",
"from poli.core.black_box_information import BlackBoxInformation\n",
"from poli.core.util.abstract_observer import AbstractObserver\n",
"\n",
"THIS_DIR = Path().resolve()\n",
Expand All @@ -131,10 +129,8 @@
" \n",
" def initialize_observer(\n",
" self,\n",
" problem_setup_info: ProblemSetupInformation,\n",
" problem_setup_info: BlackBoxInformation,\n",
" caller_info: object,\n",
" x0: np.ndarray,\n",
" y0: np.ndarray,\n",
" seed: int\n",
" ) -> object:\n",
"\n",
Expand All @@ -147,8 +143,6 @@
" metadata[\"caller_info\"] = caller_info\n",
"\n",
" # Saving the initial evaluations and seed\n",
" metadata[\"x0\"] = x0.tolist()\n",
" metadata[\"y0\"] = y0.tolist()\n",
" metadata[\"seed\"] = seed\n",
"\n",
" # Saving the metadata\n",
Expand Down Expand Up @@ -183,7 +177,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
Expand Down Expand Up @@ -224,7 +218,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 6,
"metadata": {
"tags": [
"hide-cell"
Expand Down Expand Up @@ -260,8 +254,6 @@
" self,\n",
" problem_setup_info: ProblemSetupInformation,\n",
" caller_info: object,\n",
" x0: np.ndarray,\n",
" y0: np.ndarray,\n",
" seed: int\n",
" ) -> object:\n",
"\n",
Expand All @@ -274,8 +266,6 @@
" metadata[\"caller_info\"] = caller_info\n",
"\n",
" # Saving the initial evaluations and seed\n",
" metadata[\"x0\"] = x0.tolist()\n",
" metadata[\"y0\"] = y0.tolist()\n",
" metadata[\"seed\"] = seed\n",
"\n",
" # Saving the metadata\n",
Expand Down Expand Up @@ -304,22 +294,13 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 13,
"metadata": {
"tags": [
"hide-output"
]
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"poli 🧪: Creating the objective aloha from the repository.\n",
"poli 🧪: initializing the observer.\n"
]
}
],
"outputs": [],
"source": [
"from poli import objective_factory\n",
"\n",
Expand All @@ -331,7 +312,17 @@
" name=\"aloha\",\n",
" observer=observer,\n",
")\n",
"f, x0 = problem.black_box, problem.x0"
"f, x0 = problem.black_box, problem.x0\n",
"\n",
"# We initialize the observer\n",
"observer.initialize_observer(\n",
" problem_setup_info=f.info,\n",
" caller_info={},\n",
" seed=None,\n",
")\n",
"\n",
"# We set the observer to track f.\n",
"f.set_observer(observer)"
]
},
{
Expand All @@ -343,14 +334,14 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'name': 'aloha', 'max_sequence_length': 5, 'aligned': True, 'fixed_length': True, 'deterministic': True, 'discrete': True, 'fidelity': None, 'alphabet': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'], 'log_transform_recommended': False, 'padding_token': '', 'caller_info': None, 'x0': [['A', 'L', 'O', 'O', 'F']], 'y0': [[3]], 'seed': None}\n"
"{'name': 'aloha', 'max_sequence_length': 5, 'aligned': True, 'fixed_length': True, 'deterministic': True, 'discrete': True, 'fidelity': None, 'alphabet': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'], 'log_transform_recommended': False, 'padding_token': '', 'caller_info': {}, 'seed': None}\n"
]
}
],
Expand All @@ -368,7 +359,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 15,
"metadata": {},
"outputs": [
{
Expand Down Expand Up @@ -396,14 +387,13 @@
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[['A', 'L', 'O', 'O', 'F']]\t[[3]]\n",
"[['M', 'I', 'G', 'U', 'E']]\t[[0]]\n",
"[['F', 'L', 'E', 'A', 'S']]\t[[1]]\n",
"[['A', 'L', 'O', 'H', 'A']]\t[[5]]\n",
Expand Down
Loading

0 comments on commit 39bb89a

Please sign in to comment.