From 165cc97525171ce2ef8271f7bc4880aa93113b46 Mon Sep 17 00:00:00 2001 From: y0z Date: Mon, 16 Dec 2024 15:48:13 +0900 Subject: [PATCH 1/3] Add bbob-constrained --- package/benchmarks/bbob_constrained/LICENSE | 21 +++++ package/benchmarks/bbob_constrained/README.md | 85 ++++++++++++++++++ .../benchmarks/bbob_constrained/__init__.py | 4 + .../bbob_constrained/_bbob_constrained.py | 87 +++++++++++++++++++ .../bbob_constrained/requirements.txt | 1 + 5 files changed, 198 insertions(+) create mode 100644 package/benchmarks/bbob_constrained/LICENSE create mode 100644 package/benchmarks/bbob_constrained/README.md create mode 100644 package/benchmarks/bbob_constrained/__init__.py create mode 100644 package/benchmarks/bbob_constrained/_bbob_constrained.py create mode 100644 package/benchmarks/bbob_constrained/requirements.txt diff --git a/package/benchmarks/bbob_constrained/LICENSE b/package/benchmarks/bbob_constrained/LICENSE new file mode 100644 index 00000000..380b0c20 --- /dev/null +++ b/package/benchmarks/bbob_constrained/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Preferred Networks, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/package/benchmarks/bbob_constrained/README.md b/package/benchmarks/bbob_constrained/README.md new file mode 100644 index 00000000..7ddde4a4 --- /dev/null +++ b/package/benchmarks/bbob_constrained/README.md @@ -0,0 +1,85 @@ +--- +author: Optuna team +title: The blackbox optimization benchmarking-constrained (bbob-constrained) test suite +description: The bbob-constrained test suite is a suite of 54 non-linearly constrained test functions with varying number of (active and inactive) constraints. This package is a wrapper of the COCO (COmparing Continuous Optimizers) experiments library. +tags: [benchmarks, continuous optimization, constrained optimization, BBOB, COCO] +optuna_versions: [4.1.0] +license: MIT License +--- + +## Abstract + +This package provides a wrapper of the COCO experiments libarary's bbob-constrained test suite. + +## APIs + +### class `Problem(function_id: int, dimension: int, instance_id: int = 1)` + +- `function_id`: [ID of the bbob-constrained benchmark function](https://numbbo.github.io/coco/testsuites/bbob-constrained) to use. It must be in the range of `[1, 54]`. +- `dimension`: Dimension of the benchmark function. It must be in `[2, 3, 5, 10, 20, 40]`. +- `instance_id`: ID of the instance of the benchmark function. It must be in the range of `[1, 15]`. + +#### Methods and Properties + +- `search_space`: Return the search space. + - Returns: `dict[str, optuna.distributions.BaseDistribution]` +- `directions`: Return the optimization directions. + - Returns: `list[optuna.study.StudyDirection]` +- `__call__(trial: optuna.Trial)`: Evaluate the objective function and return the objective value. + - Args: + - `trial`: Optuna trial object. + - Returns: `float` +- `evaluate(params: dict[str, float])`: Evaluate the objective function and return the objective value. + - Args: + - `params`: Decision variable like `{"x0": x1_value, "x1": x1_value, ..., "xn": xn_value}`. The number of parameters must be equal to `dimension`. + - Returns: `float` +- `constraints_func(trial: optuna.Trial.FrozenTrial)`: Evaluate the constraint functions and return the list of constraint functions values. + - Args: + - `trial`: Optuna trial object. + - Returns: `list[float]` +- `evaluate_constraints(params: dict[str, float])`: Evaluate the constraint functions and return the list of constraint functions values. + - Args: + - `params`: Decision variable like `{"x0": x1_value, "x1": x1_value, ..., "xn": xn_value}`. The number of parameters must be equal to `dimension`. + - Returns: `list[float]` + +It is also available that properties defiend in [cocoex.Problem](https://numbbo.github.io/coco-doc/apidocs/cocoex/cocoex.Problem.html) such as `number_of_objectives`. + +## Installation + +Please install the [coco-experiment](https://github.com/numbbo/coco-experiment/tree/main/build/python) package. + +```shell +pip install -U coco-experiment +``` + +## Example + +```python +import optuna +import optunahub + + +bbob_constrained = optunahub.load_module("benchmarks/bbob_constrained") +constrained_sphere2d = bbob_constrained.Problem(function_id=1, dimension=2, instance_id=1) + +study = optuna.create_study( + sampler=optuna.samplers.TPESampler( + constraints_func=constrained_sphere2d.constraints_func + ), + directions=constrained_sphere2d.directions +) +study.optimize(constrained_sphere2d, n_trials=20) + +try: + print(study.best_trial.params, study.best_trial.value) +except Exception as e: + print(e) +``` + +## Details of Benchmark Functions + +Please refer to [the paper](https://numbbo.github.io/coco-doc/bbob-constrained/functions.pdf) for details about each benchmark function. + +## Reference + +Paul Dufossé, Nikolaus Hansen, Dimo Brockhoff, Phillipe R. Sampaio, Asma Atamna, and Anne Auger. [Building scalable test problems for benchmarking constrained optimizers. 2022. To be submitted to the SIAM Journal of Optimization](https://numbbo.github.io/coco-doc/bbob-constrained/functions.pdf). diff --git a/package/benchmarks/bbob_constrained/__init__.py b/package/benchmarks/bbob_constrained/__init__.py new file mode 100644 index 00000000..efbf752e --- /dev/null +++ b/package/benchmarks/bbob_constrained/__init__.py @@ -0,0 +1,4 @@ +from ._bbob_constrained import Problem + + +__all__ = ["Problem"] diff --git a/package/benchmarks/bbob_constrained/_bbob_constrained.py b/package/benchmarks/bbob_constrained/_bbob_constrained.py new file mode 100644 index 00000000..cee5429f --- /dev/null +++ b/package/benchmarks/bbob_constrained/_bbob_constrained.py @@ -0,0 +1,87 @@ +from __future__ import annotations + +from typing import Any +from typing import Sequence + +import cocoex as ex +import optuna +import optunahub + + +class Problem(optunahub.benchmarks.ConstrainedMixin, optunahub.benchmarks.BaseProblem): + """Wrapper class for COCO bbob-constrained test suite. + https://coco-platform.org/ + + The detail is described in the following paper. + Paul Dufossé, Nikolaus Hansen, Dimo Brockhoff, Phillipe R. Sampaio, Asma Atamna, and Anne Auger. + Building scalable test problems for benchmarking constrained optimizers. 2022. To be submitted to the SIAM Journal of Optimization. + https://numbbo.github.io/coco-doc/bbob-constrained/functions.pdf + """ + + def __init__(self, function_id: int, dimension: int, instance_id: int = 1): + """Initialize the problem. + Args: + function_id: Function index in [1, 54]. + dimension: Dimension of the problem in [2, 3, 5, 10, 20, 40]. + instance_id: Instance index in [1, 15]. + + Please refer to the COCO documentation for the details of the available properties. + https://numbbo.github.io/coco-doc/apidocs/cocoex/cocoex.Problem.html + """ + + assert 1 <= function_id <= 54, "function_id must be in [1, 54]" + assert dimension in [2, 3, 5, 10, 20, 40], "dimension must be in [2, 3, 5, 10, 20, 40]" + assert 1 <= instance_id <= 15, "instance_id must be in [1, 15]" + + self._problem = ex.Suite( + "bbob-constrained", "", "" + ).get_problem_by_function_dimension_instance( + function=function_id, dimension=dimension, instance=instance_id + ) + self._search_space = { + f"x{i}": optuna.distributions.FloatDistribution( + low=self._problem.lower_bounds[i], + high=self._problem.upper_bounds[i], + ) + for i in range(self._problem.dimension) + } + + @property + def search_space(self) -> dict[str, optuna.distributions.BaseDistribution]: + """Return the search space.""" + return self._search_space + + @property + def directions(self) -> Sequence[optuna.study.StudyDirection]: + """Return the optimization directions.""" + return [optuna.study.StudyDirection.MINIMIZE] + + def evaluate(self, params: dict[str, float]) -> float: + """Evaluate the objective function. + Args: + params: + Decision variable, e.g., evaluate({"x0": 1.0, "x1": 2.0}). + The number of parameters must be equal to the dimension of the problem. + Returns: + The objective value. + + """ + return self._problem(list(params.values())) + + def evaluate_constraints(self, params: dict[str, float]) -> Sequence[float]: + """Evaluate the constraint functions. + Args: + params: + Decision variable, e.g., evaluate_constraints({"x0": 1.0, "x1": 2.0}). + The number of parameters must be equal to the dimension of the problem. + Returns: + The constraint functions values. + + """ + return self._problem.constraint(list(params.values())).tolist() + + def __getattr__(self, name: str) -> Any: + return getattr(self._problem, name) + + def __del__(self) -> None: + self._problem.free() diff --git a/package/benchmarks/bbob_constrained/requirements.txt b/package/benchmarks/bbob_constrained/requirements.txt new file mode 100644 index 00000000..8213f255 --- /dev/null +++ b/package/benchmarks/bbob_constrained/requirements.txt @@ -0,0 +1 @@ +coco-experiment \ No newline at end of file From 3eee04ecbd8bde4fa0c42c5f942452f950311598 Mon Sep 17 00:00:00 2001 From: y0z Date: Mon, 16 Dec 2024 20:24:00 +0900 Subject: [PATCH 2/3] Update --- .../benchmarks/bbob_constrained/_bbob_constrained.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/package/benchmarks/bbob_constrained/_bbob_constrained.py b/package/benchmarks/bbob_constrained/_bbob_constrained.py index cee5429f..e29c10a9 100644 --- a/package/benchmarks/bbob_constrained/_bbob_constrained.py +++ b/package/benchmarks/bbob_constrained/_bbob_constrained.py @@ -1,7 +1,6 @@ from __future__ import annotations from typing import Any -from typing import Sequence import cocoex as ex import optuna @@ -49,10 +48,10 @@ def __init__(self, function_id: int, dimension: int, instance_id: int = 1): @property def search_space(self) -> dict[str, optuna.distributions.BaseDistribution]: """Return the search space.""" - return self._search_space + return self._search_space.copy() @property - def directions(self) -> Sequence[optuna.study.StudyDirection]: + def directions(self) -> list[optuna.study.StudyDirection]: """Return the optimization directions.""" return [optuna.study.StudyDirection.MINIMIZE] @@ -66,9 +65,9 @@ def evaluate(self, params: dict[str, float]) -> float: The objective value. """ - return self._problem(list(params.values())) + return self._problem([params[name] for name in self._search_space]) - def evaluate_constraints(self, params: dict[str, float]) -> Sequence[float]: + def evaluate_constraints(self, params: dict[str, float]) -> list[float]: """Evaluate the constraint functions. Args: params: @@ -78,7 +77,7 @@ def evaluate_constraints(self, params: dict[str, float]) -> Sequence[float]: The constraint functions values. """ - return self._problem.constraint(list(params.values())).tolist() + return self._problem.constraint([params[name] for name in self._search_space]) def __getattr__(self, name: str) -> Any: return getattr(self._problem, name) From 32d05f97280484ca81879c37a9cd2d9a2b995fe8 Mon Sep 17 00:00:00 2001 From: Shuhei Watanabe <47781922+nabenabe0928@users.noreply.github.com> Date: Tue, 17 Dec 2024 11:04:54 +0100 Subject: [PATCH 3/3] Update package/benchmarks/bbob_constrained/README.md --- package/benchmarks/bbob_constrained/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/benchmarks/bbob_constrained/README.md b/package/benchmarks/bbob_constrained/README.md index 7ddde4a4..39af3a31 100644 --- a/package/benchmarks/bbob_constrained/README.md +++ b/package/benchmarks/bbob_constrained/README.md @@ -42,7 +42,7 @@ This package provides a wrapper of the COCO experiments libarary's bbob-constrai - `params`: Decision variable like `{"x0": x1_value, "x1": x1_value, ..., "xn": xn_value}`. The number of parameters must be equal to `dimension`. - Returns: `list[float]` -It is also available that properties defiend in [cocoex.Problem](https://numbbo.github.io/coco-doc/apidocs/cocoex/cocoex.Problem.html) such as `number_of_objectives`. +The properties defined by [cocoex.Problem](https://numbbo.github.io/coco-doc/apidocs/cocoex/cocoex.Problem.html) are also available such as `number_of_objectives`. ## Installation