From d58ee31a78ad8727d34378e192283cddaa22e014 Mon Sep 17 00:00:00 2001 From: Chrysoula Kappatou Date: Mon, 18 Dec 2023 10:15:02 +0100 Subject: [PATCH 01/12] implement batch constraint for doe --- bofire/strategies/doe/utils.py | 16 ++++++++++++++++ tests/bofire/strategies/doe/test_design.py | 22 ++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/bofire/strategies/doe/utils.py b/bofire/strategies/doe/utils.py index ee4391949..16ca235da 100644 --- a/bofire/strategies/doe/utils.py +++ b/bofire/strategies/doe/utils.py @@ -1,3 +1,4 @@ +import math import sys from itertools import combinations from typing import List, Optional, Union @@ -12,6 +13,7 @@ LinearInequalityConstraint, NChooseKConstraint, NonlinearEqualityConstraint, + InterpointEqualityConstraint, ) from bofire.data_models.constraints.nonlinear import NonlinearInequalityConstraint from bofire.data_models.domain.domain import Domain @@ -290,7 +292,21 @@ def constraints_as_scipy_constraints( ) constraints.append(NonlinearConstraint(fun, lb, ub, jac=fun.jacobian)) + elif isinstance(c, InterpointEqualityConstraint): + # similar to linear constraint but with diferent A + # write lower/upper bound as vector + lb = np.zeros(n_experiments) + ub = np.zeros(n_experiments) + A = np.zeros(shape=(n_experiments, D * n_experiments)) + for i in range(math.ceil(n_experiments / c.multiplicity)): + for j, p in enumerate(domain.inputs.get_keys()): + if p in c.feature: + for k in range(i*c.multiplicity+1, min((i+1) * c.multiplicity, n_experiments)): + A[k-1, (k-1)*D+j]=1 + A[k-1, k*D+j] = -A[k-1, (k-1)*D+j] + + constraints.append(LinearConstraint(A, lb, ub)) # type: ignore else: raise NotImplementedError(f"No implementation for this constraint: {c}") diff --git a/tests/bofire/strategies/doe/test_design.py b/tests/bofire/strategies/doe/test_design.py index 2d7ce5849..978e34914 100644 --- a/tests/bofire/strategies/doe/test_design.py +++ b/tests/bofire/strategies/doe/test_design.py @@ -9,6 +9,7 @@ LinearInequalityConstraint, NChooseKConstraint, NonlinearInequalityConstraint, + InterpointEqualityConstraint, ) from bofire.data_models.domain.api import Domain from bofire.data_models.features.api import ( @@ -25,6 +26,27 @@ CYIPOPT_AVAILABLE = importlib.util.find_spec("cyipopt") is not None +def test_interpoint_constraint(): + inputs = [ + ContinuousInput( + key=f"x{i+1}", + bounds=(0, 1), + ) + for i in range(4) + ] + domain = Domain.from_lists( + inputs=inputs, + outputs=[ContinuousOutput(key="y")], + constraints=[ + InterpointEqualityConstraint( + feature="x1", + multiplicity= 2 + ) + ], + ) + find_local_max_ipopt(domain, "linear") + assert True + @pytest.mark.skipif(CYIPOPT_AVAILABLE, reason="requires cyipopt") def test_raise_error_if_cyipopt_not_available(): From d39b91c7e71e21903cc57d6b9292a64bb460d133 Mon Sep 17 00:00:00 2001 From: Chrysoula Kappatou Date: Mon, 18 Dec 2023 13:15:32 +0100 Subject: [PATCH 02/12] minor change --- bofire/strategies/doe/utils.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/bofire/strategies/doe/utils.py b/bofire/strategies/doe/utils.py index 16ca235da..c41c1e68d 100644 --- a/bofire/strategies/doe/utils.py +++ b/bofire/strategies/doe/utils.py @@ -9,11 +9,11 @@ from scipy.optimize import LinearConstraint, NonlinearConstraint from bofire.data_models.constraints.api import ( + InterpointEqualityConstraint, LinearEqualityConstraint, LinearInequalityConstraint, NChooseKConstraint, NonlinearEqualityConstraint, - InterpointEqualityConstraint, ) from bofire.data_models.constraints.nonlinear import NonlinearInequalityConstraint from bofire.data_models.domain.domain import Domain @@ -184,7 +184,7 @@ def n_zero_eigvals( return len(eigvals) - len(eigvals[eigvals > epsilon]) -def constraints_as_scipy_constraints( +def constraints_as_scipy_constraints( # noqa: C901 domain: Domain, n_experiments: int, ignore_nchoosek: bool = True, @@ -301,11 +301,13 @@ def constraints_as_scipy_constraints( A = np.zeros(shape=(n_experiments, D * n_experiments)) for i in range(math.ceil(n_experiments / c.multiplicity)): for j, p in enumerate(domain.inputs.get_keys()): - if p in c.feature: - for k in range(i*c.multiplicity+1, min((i+1) * c.multiplicity, n_experiments)): - A[k-1, (k-1)*D+j]=1 - A[k-1, k*D+j] = -A[k-1, (k-1)*D+j] - + if p in c.feature: + for k in range( + i * c.multiplicity + 1, + min((i + 1) * c.multiplicity, n_experiments), + ): + A[k - 1, (k - 1) * D + j] = 1 + A[k - 1, k * D + j] = -A[k - 1, (k - 1) * D + j] constraints.append(LinearConstraint(A, lb, ub)) # type: ignore else: raise NotImplementedError(f"No implementation for this constraint: {c}") From 25d87d16d7b8a9542ccdea16f9a4c9cbe88eaaa4 Mon Sep 17 00:00:00 2001 From: Chrysoula Kappatou Date: Mon, 18 Dec 2023 13:22:18 +0100 Subject: [PATCH 03/12] minor formating --- bofire/strategies/doe/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bofire/strategies/doe/utils.py b/bofire/strategies/doe/utils.py index c41c1e68d..3a7450a4f 100644 --- a/bofire/strategies/doe/utils.py +++ b/bofire/strategies/doe/utils.py @@ -308,6 +308,7 @@ def constraints_as_scipy_constraints( # noqa: C901 ): A[k - 1, (k - 1) * D + j] = 1 A[k - 1, k * D + j] = -A[k - 1, (k - 1) * D + j] + constraints.append(LinearConstraint(A, lb, ub)) # type: ignore else: raise NotImplementedError(f"No implementation for this constraint: {c}") From b560f0093cbc543c0b0f135be2b8e3bf694724d6 Mon Sep 17 00:00:00 2001 From: Chrysoula Kappatou Date: Mon, 18 Dec 2023 13:48:44 +0100 Subject: [PATCH 04/12] more formating --- bofire/strategies/doe/utils.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bofire/strategies/doe/utils.py b/bofire/strategies/doe/utils.py index 3a7450a4f..6e627dcf1 100644 --- a/bofire/strategies/doe/utils.py +++ b/bofire/strategies/doe/utils.py @@ -299,12 +299,15 @@ def constraints_as_scipy_constraints( # noqa: C901 ub = np.zeros(n_experiments) A = np.zeros(shape=(n_experiments, D * n_experiments)) - for i in range(math.ceil(n_experiments / c.multiplicity)): + n_int_repetitions = int(math.ceil(n_experiments / c.multiplicity)) + for i in range(n_int_repetitions): for j, p in enumerate(domain.inputs.get_keys()): if p in c.feature: + temp_lb = i * c.multiplicity + 1 + temp_ub = min((i + 1) * c.multiplicity, n_experiments) for k in range( - i * c.multiplicity + 1, - min((i + 1) * c.multiplicity, n_experiments), + temp_lb, + temp_ub, ): A[k - 1, (k - 1) * D + j] = 1 A[k - 1, k * D + j] = -A[k - 1, (k - 1) * D + j] From 8033b7241c0d860da5ba3848f188731591cbf039 Mon Sep 17 00:00:00 2001 From: Chrysoula Kappatou Date: Mon, 18 Dec 2023 14:05:16 +0100 Subject: [PATCH 05/12] and some more formating --- bofire/strategies/doe/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bofire/strategies/doe/utils.py b/bofire/strategies/doe/utils.py index 6e627dcf1..e9b816266 100644 --- a/bofire/strategies/doe/utils.py +++ b/bofire/strategies/doe/utils.py @@ -303,8 +303,8 @@ def constraints_as_scipy_constraints( # noqa: C901 for i in range(n_int_repetitions): for j, p in enumerate(domain.inputs.get_keys()): if p in c.feature: - temp_lb = i * c.multiplicity + 1 - temp_ub = min((i + 1) * c.multiplicity, n_experiments) + temp_lb = int(i * c.multiplicity + 1) + temp_ub = int(min((i + 1) * c.multiplicity, n_experiments)) for k in range( temp_lb, temp_ub, From 67f23be8b4eb08bac154a49e61758f66057059a4 Mon Sep 17 00:00:00 2001 From: Chrysoula Kappatou Date: Mon, 18 Dec 2023 14:07:35 +0100 Subject: [PATCH 06/12] and some more formating --- tests/bofire/strategies/doe/test_design.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/bofire/strategies/doe/test_design.py b/tests/bofire/strategies/doe/test_design.py index 978e34914..03a692a54 100644 --- a/tests/bofire/strategies/doe/test_design.py +++ b/tests/bofire/strategies/doe/test_design.py @@ -5,11 +5,11 @@ import pytest from bofire.data_models.constraints.api import ( + InterpointEqualityConstraint, LinearEqualityConstraint, LinearInequalityConstraint, NChooseKConstraint, NonlinearInequalityConstraint, - InterpointEqualityConstraint, ) from bofire.data_models.domain.api import Domain from bofire.data_models.features.api import ( @@ -26,23 +26,19 @@ CYIPOPT_AVAILABLE = importlib.util.find_spec("cyipopt") is not None + def test_interpoint_constraint(): inputs = [ - ContinuousInput( - key=f"x{i+1}", - bounds=(0, 1), - ) - for i in range(4) + ContinuousInput( + key=f"x{i+1}", + bounds=(0, 1), + ) + for i in range(4) ] domain = Domain.from_lists( inputs=inputs, outputs=[ContinuousOutput(key="y")], - constraints=[ - InterpointEqualityConstraint( - feature="x1", - multiplicity= 2 - ) - ], + constraints=[InterpointEqualityConstraint(feature="x1", multiplicity=2)], ) find_local_max_ipopt(domain, "linear") assert True From d30a63e0dc7aa194d16b67fb677b9cf6f3199d9e Mon Sep 17 00:00:00 2001 From: Chrysoula Kappatou Date: Mon, 18 Dec 2023 14:32:25 +0100 Subject: [PATCH 07/12] more formating --- bofire/strategies/doe/utils.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/bofire/strategies/doe/utils.py b/bofire/strategies/doe/utils.py index e9b816266..8b01fa073 100644 --- a/bofire/strategies/doe/utils.py +++ b/bofire/strategies/doe/utils.py @@ -299,12 +299,15 @@ def constraints_as_scipy_constraints( # noqa: C901 ub = np.zeros(n_experiments) A = np.zeros(shape=(n_experiments, D * n_experiments)) - n_int_repetitions = int(math.ceil(n_experiments / c.multiplicity)) - for i in range(n_int_repetitions): + temp = math.ceil(n_experiments / c.multiplicity) + n_max_batch_reps = int(temp) + for i in range(n_max_batch_reps): for j, p in enumerate(domain.inputs.get_keys()): if p in c.feature: - temp_lb = int(i * c.multiplicity + 1) - temp_ub = int(min((i + 1) * c.multiplicity, n_experiments)) + dummy = i * c.multiplicity + 1 + temp_lb = int(dummy) + dummy2 = min((i + 1) * c.multiplicity, n_experiments) + temp_ub = int(dummy2) for k in range( temp_lb, temp_ub, From 710dbc4bef83d18ddb8cf4b9be1ea37a8d069182 Mon Sep 17 00:00:00 2001 From: Chrysoula Kappatou Date: Mon, 18 Dec 2023 14:50:23 +0100 Subject: [PATCH 08/12] more is less --- bofire/strategies/doe/utils.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bofire/strategies/doe/utils.py b/bofire/strategies/doe/utils.py index 8b01fa073..e20d3753d 100644 --- a/bofire/strategies/doe/utils.py +++ b/bofire/strategies/doe/utils.py @@ -1,4 +1,3 @@ -import math import sys from itertools import combinations from typing import List, Optional, Union @@ -299,15 +298,16 @@ def constraints_as_scipy_constraints( # noqa: C901 ub = np.zeros(n_experiments) A = np.zeros(shape=(n_experiments, D * n_experiments)) - temp = math.ceil(n_experiments / c.multiplicity) + temp = np.ceil(n_experiments / c.multiplicity) n_max_batch_reps = int(temp) for i in range(n_max_batch_reps): + dummy = i * c.multiplicity for j, p in enumerate(domain.inputs.get_keys()): if p in c.feature: - dummy = i * c.multiplicity + 1 - temp_lb = int(dummy) - dummy2 = min((i + 1) * c.multiplicity, n_experiments) - temp_ub = int(dummy2) + # dummy = i * c.multiplicity + 1 + # dummy2 = min((i + 1) * c.multiplicity, n_experiments) + temp_lb = int(dummy + 1) + temp_ub = int(min(dummy + c.multiplicity, n_experiments)) for k in range( temp_lb, temp_ub, From 4d0970dd86cc0f2df11fcf4c8b94c7c741813c37 Mon Sep 17 00:00:00 2001 From: Chrysoula Kappatou Date: Mon, 18 Dec 2023 14:59:13 +0100 Subject: [PATCH 09/12] less is more --- bofire/strategies/doe/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bofire/strategies/doe/utils.py b/bofire/strategies/doe/utils.py index e20d3753d..4e75d2a26 100644 --- a/bofire/strategies/doe/utils.py +++ b/bofire/strategies/doe/utils.py @@ -298,10 +298,10 @@ def constraints_as_scipy_constraints( # noqa: C901 ub = np.zeros(n_experiments) A = np.zeros(shape=(n_experiments, D * n_experiments)) - temp = np.ceil(n_experiments / c.multiplicity) - n_max_batch_reps = int(temp) + multiplicity = int(c.multiplicity) + n_max_batch_reps = int(np.ceil(n_experiments / multiplicity)) for i in range(n_max_batch_reps): - dummy = i * c.multiplicity + dummy = i * multiplicity for j, p in enumerate(domain.inputs.get_keys()): if p in c.feature: # dummy = i * c.multiplicity + 1 From bd042ff92c82df3de2968b33418b6357b38751a7 Mon Sep 17 00:00:00 2001 From: Chrysoula Kappatou Date: Mon, 18 Dec 2023 15:07:53 +0100 Subject: [PATCH 10/12] less is more 2 --- bofire/strategies/doe/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bofire/strategies/doe/utils.py b/bofire/strategies/doe/utils.py index 4e75d2a26..6ed1e69f3 100644 --- a/bofire/strategies/doe/utils.py +++ b/bofire/strategies/doe/utils.py @@ -298,7 +298,7 @@ def constraints_as_scipy_constraints( # noqa: C901 ub = np.zeros(n_experiments) A = np.zeros(shape=(n_experiments, D * n_experiments)) - multiplicity = int(c.multiplicity) + multiplicity = c.multiplicity n_max_batch_reps = int(np.ceil(n_experiments / multiplicity)) for i in range(n_max_batch_reps): dummy = i * multiplicity @@ -307,7 +307,7 @@ def constraints_as_scipy_constraints( # noqa: C901 # dummy = i * c.multiplicity + 1 # dummy2 = min((i + 1) * c.multiplicity, n_experiments) temp_lb = int(dummy + 1) - temp_ub = int(min(dummy + c.multiplicity, n_experiments)) + temp_ub = int(min(dummy + multiplicity, n_experiments)) for k in range( temp_lb, temp_ub, From c6aafb9b3cf53c2e272b8c5e5f70f15b318c0bf0 Mon Sep 17 00:00:00 2001 From: Chrysoula Kappatou Date: Mon, 18 Dec 2023 15:14:43 +0100 Subject: [PATCH 11/12] eureka maybe --- bofire/strategies/doe/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bofire/strategies/doe/utils.py b/bofire/strategies/doe/utils.py index 6ed1e69f3..169a29b43 100644 --- a/bofire/strategies/doe/utils.py +++ b/bofire/strategies/doe/utils.py @@ -298,7 +298,7 @@ def constraints_as_scipy_constraints( # noqa: C901 ub = np.zeros(n_experiments) A = np.zeros(shape=(n_experiments, D * n_experiments)) - multiplicity = c.multiplicity + multiplicity = c.multiplicity or len(n_experiments) n_max_batch_reps = int(np.ceil(n_experiments / multiplicity)) for i in range(n_max_batch_reps): dummy = i * multiplicity From c40b81da4be71b0d8dda17a46368a7a7b7df6f6a Mon Sep 17 00:00:00 2001 From: Chrysoula Kappatou Date: Mon, 18 Dec 2023 15:19:27 +0100 Subject: [PATCH 12/12] eureka maybe2 --- bofire/strategies/doe/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bofire/strategies/doe/utils.py b/bofire/strategies/doe/utils.py index 169a29b43..0028adb53 100644 --- a/bofire/strategies/doe/utils.py +++ b/bofire/strategies/doe/utils.py @@ -298,14 +298,14 @@ def constraints_as_scipy_constraints( # noqa: C901 ub = np.zeros(n_experiments) A = np.zeros(shape=(n_experiments, D * n_experiments)) - multiplicity = c.multiplicity or len(n_experiments) + multiplicity = c.multiplicity or n_experiments n_max_batch_reps = int(np.ceil(n_experiments / multiplicity)) for i in range(n_max_batch_reps): dummy = i * multiplicity for j, p in enumerate(domain.inputs.get_keys()): if p in c.feature: - # dummy = i * c.multiplicity + 1 - # dummy2 = min((i + 1) * c.multiplicity, n_experiments) + # temp_lb = i * multiplicity + 1 + # temp_ub = min((i + 1) * multiplicity, n_experiments) temp_lb = int(dummy + 1) temp_ub = int(min(dummy + multiplicity, n_experiments)) for k in range(