Source code for gemseo.algos.opt.mnbi.settings.mnbi_settings
# Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License version 3 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""Settings for the mNBI algorithm."""
from __future__ import annotations
from collections.abc import Sequence # noqa: TC003
from pathlib import Path # noqa: TC003
from typing import TYPE_CHECKING
from pydantic import Field
from pydantic import NonNegativeInt
from pydantic import PositiveInt
from pydantic import field_validator
from pydantic import model_validator
from gemseo.algos.opt.base_optimizer_settings import BaseOptimizerSettings
from gemseo.typing import StrKeyMapping # noqa: TC001
from gemseo.utils.pydantic_ndarray import NDArrayPydantic # noqa: TC001
if TYPE_CHECKING:
from typing_extensions import Self
[docs]
class MNBI_Settings(BaseOptimizerSettings): # noqa: N801
"""The mNBI algorithm settings."""
_TARGET_CLASS_NAME = "MNBI"
normalize_design_space: bool = Field(
default=False,
description="""Whether to normalize the design space variables between 0 and 1.
The mNBI algorithm does not allow to normalize the design space at the top
level, only the sub-optimizations accept design space normalization. To do
this, pass the setting ``normalize_design_space`` to
``sub_optim_algo_settings``.""",
)
sub_optim_algo: str = Field(
description=(
"The optimization algorithm used to solve the sub-optimization problems."
)
)
n_sub_optim: PositiveInt = Field(
default=1,
description="""The number of sub-optimizations points.
mNBI generates ``n_sub_optim`` points on the Pareto front between the
`n-objective` individual minima. This value must be strictly greater than
the number of objectives of the problem.""",
)
sub_optim_algo_settings: StrKeyMapping = Field(
default_factory=dict,
description="""The settings for the sub optimization algorithm.""",
)
sub_optim_max_iter: NonNegativeInt = Field(
default=0,
description="""The maximum number of iterations of the sub-optimization algorithms.
If 0, the ``max_iter`` value is used.""", # noqa: E501
)
doe_algo: str = Field(
default="PYDOE_FULLFACT",
description="""
The design of experiments algo for the target points on the Pareto front.
A ``fullfactorial`` DOE is used default as these tend to be low dimensions,
usually not more than 3 objectives for a given problem.
This setting is relevant only for problems with more than 2 objectives.""", # noqa: E501
)
doe_algo_settings: StrKeyMapping = Field(
default_factory=dict,
description="""The settings for the DOE algorithm.""",
)
debug: bool = Field(
default=False,
description=(
"""Whether to output the sub-optimization optima in a database hdf file."""
),
)
debug_file_path: str | Path = Field(
default="debug_history.h5",
description="""The path to the debug file if debug mode is active.""",
)
skip_betas: bool = Field(
default=True,
description="""Whether to skip the sub-optimizations of relevant.
The sub-optimizations are skipped if they correspond to values of beta for
which the theoretical result has already been found.""",
)
custom_anchor_points: Sequence[NDArrayPydantic] = Field(
default=(),
description=(
"""The bounding points of the custom phi simplex for the optimization."""
),
)
custom_phi_betas: Sequence[NDArrayPydantic] = Field(
default=(),
description=(
r"The custom values of :math:`\\Phi \beta` to be used in the optimization."
),
)
n_processes: PositiveInt = Field(
default=1,
description=(
"The maximum number of processes used to parallelize the sub-optimizations."
),
)
@field_validator("normalize_design_space")
@classmethod
def __validate_normalize(cls, normalize_design_space: bool) -> bool:
"""Check that the normalization is disabled for the top-level problem."""
if normalize_design_space:
message = (
"The mNBI algo does not allow to normalize the design space at "
"the top level, only the sub optimizations accept design space "
"normalization. To do this, pass the setting "
"``normalize_design_space`` to ``sub_optim_algo_settings``."
)
raise ValueError(message)
return normalize_design_space
@model_validator(mode="after")
def __validate_sub_optim_max_iter(self) -> Self:
"""Check if a sub_optim_max_iter was passed, otherwise use max_iter."""
if self.sub_optim_max_iter == 0:
self.sub_optim_max_iter = self.max_iter
return self