From 5b1d05548e5ae311a4ac254a308aa4efce8822b1 Mon Sep 17 00:00:00 2001 From: y0z Date: Fri, 13 Dec 2024 16:35:59 +0900 Subject: [PATCH 1/8] Add tutorial for constrained optimization --- recipes/007_benchmarks_advanced.py | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/recipes/007_benchmarks_advanced.py b/recipes/007_benchmarks_advanced.py index 464cb9b..4ae42b9 100644 --- a/recipes/007_benchmarks_advanced.py +++ b/recipes/007_benchmarks_advanced.py @@ -21,6 +21,7 @@ import optuna from optunahub.benchmarks import BaseProblem +from optunahub.benchmarks import ConstrainedMixIn ################################################################################################### @@ -63,6 +64,36 @@ def evaluate(self, params: dict[str, float]) -> float: study = optuna.create_study(directions=dynamic_problem.directions) study.optimize(dynamic_problem, n_trials=20) + +################################################################################################### +# Implementing a problem with constraints +# ------------------------------------------------- +# Here, let's implement a problem with constraints. +# To implement a problem with constraints, you need to inherit ``ConstrainedMixIn`` class in addition to ``BaseProblem`` and implement the ``evaluate_constraints`` method. +# The ``evaluate_constraints`` method evaluates the constraint functions given a dictionary of input parameters and returns a list of constraint values. +# Then, ``ConstrainedMixIn`` internally defines the ``constraints_func`` method properly for Optuna samplers to handle constraints. +class ConstrainedProblem(ConstrainedMixIn, DynamicProblem): + def evaluate_constraints(self, params: dict[str, float]) -> list[float]: + x = params["x"] + c0 = x - 2 + if "y" not in params: + return [c0] + else: + y = params["y"] + c1 = x + y - 3 + return [c0, c1] + + +################################################################################################### +# Then, you can optimize the problem with Optuna as usual. +# Don't forget to set the `constraints_func` argument of the sampler to the `constraints_func` of the problem. +problem = ConstrainedProblem() +sampler = optuna.samplers.TPESampler( + constraints_func=problem.constraints_func +) # Pass the constraints_func to the sampler. +study = optuna.create_study(sampler=sampler, directions=problem.directions) +study.optimize(problem, n_trials=20) + ################################################################################################### # After implementing your own benchmark problem, you can register it with OptunaHub. # See :doc:`002_registration` for how to register your benchmark problem with OptunaHub. From 8af91233f5a9867a9da4364727c780eb6769d87f Mon Sep 17 00:00:00 2001 From: y0z Date: Mon, 16 Dec 2024 13:05:27 +0900 Subject: [PATCH 2/8] Rename MixIn to Mixin --- recipes/007_benchmarks_advanced.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/recipes/007_benchmarks_advanced.py b/recipes/007_benchmarks_advanced.py index 4ae42b9..0ec1a50 100644 --- a/recipes/007_benchmarks_advanced.py +++ b/recipes/007_benchmarks_advanced.py @@ -21,7 +21,7 @@ import optuna from optunahub.benchmarks import BaseProblem -from optunahub.benchmarks import ConstrainedMixIn +from optunahub.benchmarks import ConstrainedMixin ################################################################################################### @@ -69,10 +69,10 @@ def evaluate(self, params: dict[str, float]) -> float: # Implementing a problem with constraints # ------------------------------------------------- # Here, let's implement a problem with constraints. -# To implement a problem with constraints, you need to inherit ``ConstrainedMixIn`` class in addition to ``BaseProblem`` and implement the ``evaluate_constraints`` method. +# To implement a problem with constraints, you need to inherit ``ConstrainedMixin`` class in addition to ``BaseProblem`` and implement the ``evaluate_constraints`` method. # The ``evaluate_constraints`` method evaluates the constraint functions given a dictionary of input parameters and returns a list of constraint values. -# Then, ``ConstrainedMixIn`` internally defines the ``constraints_func`` method properly for Optuna samplers to handle constraints. -class ConstrainedProblem(ConstrainedMixIn, DynamicProblem): +# Then, ``ConstrainedMixin`` internally defines the ``constraints_func`` method properly for Optuna samplers to handle constraints. +class ConstrainedProblem(ConstrainedMixin, DynamicProblem): def evaluate_constraints(self, params: dict[str, float]) -> list[float]: x = params["x"] c0 = x - 2 From 4c8f3681e388fdfe7a7a0a7ae40c56b153c8ddf8 Mon Sep 17 00:00:00 2001 From: Yoshihiko Ozaki <30489874+y0z@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:03:45 +0900 Subject: [PATCH 3/8] Update recipes/007_benchmarks_advanced.py Co-authored-by: Shuhei Watanabe <47781922+nabenabe0928@users.noreply.github.com> --- recipes/007_benchmarks_advanced.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/007_benchmarks_advanced.py b/recipes/007_benchmarks_advanced.py index 0ec1a50..9cca78b 100644 --- a/recipes/007_benchmarks_advanced.py +++ b/recipes/007_benchmarks_advanced.py @@ -71,7 +71,7 @@ def evaluate(self, params: dict[str, float]) -> float: # Here, let's implement a problem with constraints. # To implement a problem with constraints, you need to inherit ``ConstrainedMixin`` class in addition to ``BaseProblem`` and implement the ``evaluate_constraints`` method. # The ``evaluate_constraints`` method evaluates the constraint functions given a dictionary of input parameters and returns a list of constraint values. -# Then, ``ConstrainedMixin`` internally defines the ``constraints_func`` method properly for Optuna samplers to handle constraints. +# Then, ``ConstrainedMixin`` internally defines the ``constraints_func`` method for Optuna samplers. class ConstrainedProblem(ConstrainedMixin, DynamicProblem): def evaluate_constraints(self, params: dict[str, float]) -> list[float]: x = params["x"] From 2394c0ba7b8d01f4d4e94706fec9006f31d26ec4 Mon Sep 17 00:00:00 2001 From: Yoshihiko Ozaki <30489874+y0z@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:03:52 +0900 Subject: [PATCH 4/8] Update recipes/007_benchmarks_advanced.py Co-authored-by: Shuhei Watanabe <47781922+nabenabe0928@users.noreply.github.com> --- recipes/007_benchmarks_advanced.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/007_benchmarks_advanced.py b/recipes/007_benchmarks_advanced.py index 9cca78b..9374fce 100644 --- a/recipes/007_benchmarks_advanced.py +++ b/recipes/007_benchmarks_advanced.py @@ -73,7 +73,7 @@ def evaluate(self, params: dict[str, float]) -> float: # The ``evaluate_constraints`` method evaluates the constraint functions given a dictionary of input parameters and returns a list of constraint values. # Then, ``ConstrainedMixin`` internally defines the ``constraints_func`` method for Optuna samplers. class ConstrainedProblem(ConstrainedMixin, DynamicProblem): - def evaluate_constraints(self, params: dict[str, float]) -> list[float]: + def evaluate_constraints(self, params: dict[str, float]) -> tuple[float]: x = params["x"] c0 = x - 2 if "y" not in params: From edabb38b8591caee46e2d3129ab7a41f1df4760e Mon Sep 17 00:00:00 2001 From: Yoshihiko Ozaki <30489874+y0z@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:04:02 +0900 Subject: [PATCH 5/8] Update recipes/007_benchmarks_advanced.py Co-authored-by: Shuhei Watanabe <47781922+nabenabe0928@users.noreply.github.com> --- recipes/007_benchmarks_advanced.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/recipes/007_benchmarks_advanced.py b/recipes/007_benchmarks_advanced.py index 9374fce..2eb36a5 100644 --- a/recipes/007_benchmarks_advanced.py +++ b/recipes/007_benchmarks_advanced.py @@ -77,7 +77,8 @@ def evaluate_constraints(self, params: dict[str, float]) -> tuple[float]: x = params["x"] c0 = x - 2 if "y" not in params: - return [c0] + c1 = 0.0 # c1 <= 0, so c1 is satisfied in this case. + return c0, c1 else: y = params["y"] c1 = x + y - 3 From 458d990d9fdc668f12a3363ef80eb0b73ce0d3b4 Mon Sep 17 00:00:00 2001 From: Yoshihiko Ozaki <30489874+y0z@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:05:58 +0900 Subject: [PATCH 6/8] Update recipes/007_benchmarks_advanced.py Co-authored-by: Shuhei Watanabe <47781922+nabenabe0928@users.noreply.github.com> --- recipes/007_benchmarks_advanced.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/007_benchmarks_advanced.py b/recipes/007_benchmarks_advanced.py index 2eb36a5..30d4b46 100644 --- a/recipes/007_benchmarks_advanced.py +++ b/recipes/007_benchmarks_advanced.py @@ -82,7 +82,7 @@ def evaluate_constraints(self, params: dict[str, float]) -> tuple[float]: else: y = params["y"] c1 = x + y - 3 - return [c0, c1] + return c0, c1 ################################################################################################### From 13310468051879ea7ecb5d448447aa76eb415a5f Mon Sep 17 00:00:00 2001 From: Yoshihiko Ozaki <30489874+y0z@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:06:04 +0900 Subject: [PATCH 7/8] Update recipes/007_benchmarks_advanced.py Co-authored-by: Shuhei Watanabe <47781922+nabenabe0928@users.noreply.github.com> --- recipes/007_benchmarks_advanced.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/007_benchmarks_advanced.py b/recipes/007_benchmarks_advanced.py index 30d4b46..0945aa3 100644 --- a/recipes/007_benchmarks_advanced.py +++ b/recipes/007_benchmarks_advanced.py @@ -87,7 +87,7 @@ def evaluate_constraints(self, params: dict[str, float]) -> tuple[float]: ################################################################################################### # Then, you can optimize the problem with Optuna as usual. -# Don't forget to set the `constraints_func` argument of the sampler to the `constraints_func` of the problem. +# Don't forget to set the `constraints_func` argument to the sampler to use. problem = ConstrainedProblem() sampler = optuna.samplers.TPESampler( constraints_func=problem.constraints_func From d620cb2d7e4b90169caf05d68a7e6141b4f2e44a Mon Sep 17 00:00:00 2001 From: y0z Date: Wed, 18 Dec 2024 12:13:19 +0900 Subject: [PATCH 8/8] Fix type hints --- recipes/007_benchmarks_advanced.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/007_benchmarks_advanced.py b/recipes/007_benchmarks_advanced.py index 0945aa3..2e098b9 100644 --- a/recipes/007_benchmarks_advanced.py +++ b/recipes/007_benchmarks_advanced.py @@ -73,7 +73,7 @@ def evaluate(self, params: dict[str, float]) -> float: # The ``evaluate_constraints`` method evaluates the constraint functions given a dictionary of input parameters and returns a list of constraint values. # Then, ``ConstrainedMixin`` internally defines the ``constraints_func`` method for Optuna samplers. class ConstrainedProblem(ConstrainedMixin, DynamicProblem): - def evaluate_constraints(self, params: dict[str, float]) -> tuple[float]: + def evaluate_constraints(self, params: dict[str, float]) -> tuple[float, float]: x = params["x"] c0 = x - 2 if "y" not in params: