Domain transforms
ropt.transforms
Domain Transformation Framework.
This module provides a flexible framework for transforming optimization variables, objectives, and constraints between user-defined domains and the domains used internally by the optimizer. These transformations are essential for:
- Improving Optimizer Performance: Scaling, shifting, and other transformations can significantly enhance the efficiency, stability, and convergence of optimization algorithms.
- Implementing Custom Mappings: Beyond simple scaling, this framework supports complex, user-defined mappings between domains, allowing for tailored problem representations.
- Handling Diverse Units and Scales: Transformations enable the optimizer to work with variables and functions that may have vastly different units or scales, improving numerical stability.
Key Components:
- Abstract Base Classes: Transform classes derive from abstract base classes
that define the specific mapping logic between domains.
VariableTransform
: Defines the interface for transforming variables between user and optimizer domains.ObjectiveTransform
: Defines the interface for transforming objective values between user and optimizer domains.NonLinearConstraintTransform
: Defines the interface for transforming non-linear constraint values between user and optimizer domains.
OptModelTransforms
: A container class for conveniently grouping and passing multiple transformation objects (variable, objective, and nonlinear constraint).
Workflow and Integration:
- Configuration: Transformation objects are passed to the
EnOptConfig
during configuration validation, using anOptModelTransforms
instance. This ensures that the entire optimization process is aware of and configured for the transformed space. The trnsformation objects are stored in the configuration object. - Optimization Plan: The same transformation objects are passed to the
relevant optimization steps within the
Plan
via the configuraiton object. (See, for example, the default implementation of an optimizer step inDefaultOptimizerStep.run
). - Evaluation: When the optimizer requests an evaluation of a variable
vector, the following occurs:
- Transformation to the User Domain: The variable vector is
transformed from the optimizer
domain back to the user domain using the
from_optimizer
method of theVariableTransform
. - Function Evaluation: Objective and constraint values are calculated in the user domain.
- Transformation to the Optimizer Domain: The resulting objective and
constraint values are
transformed to the optimizer domain using the
to_optimizer
methods of theObjectiveTransform
andNonLinearConstraintTransform
.
- Transformation to the User Domain: The variable vector is
transformed from the optimizer
domain back to the user domain using the
- Optimization: The optimizer proceeds using the transformed values.
- Results: The
Results
objects produced during optimization hold values in the optimizer domain. To obtain results in the user domain, thetransform_from_optimizer
method is used to create newResults
objects with the transformed values. For example,DefaultOptimizerStep.run
emits events that include a dictionary with a"results"
key That containsResults
objects in the optimizer domain. To obtain results in the user domain they must be converted using thetransform_from_optimizer
method.
Classes:
Name | Description |
---|---|
OptModelTransforms |
A data class for conveniently grouping and passing multiple transformation objects. |
VariableScaler |
A concrete implementation of |
ropt.transforms.OptModelTransforms
dataclass
A container for optimization model transformers.
variables
class-attribute
instance-attribute
A VariableTransform
object that defines the transformation for
variables.
If None
, no transformation is applied to variables.
objectives
class-attribute
instance-attribute
An ObjectiveTransform
object that defines the transformation for
objectives.
If None
, no transformation is applied to objectives.
ropt.transforms.base.VariableTransform
Bases: ABC
Abstract base class for variable transformations.
This class defines the interface for transforming variables between the user-defined domain and the optimizer's internal domain. Concrete implementations of this class handle the specific logic for each type of transformation.
When implementing a variable transformation, the following aspects must be considered:
- Variable Value Transformation: Mapping variable values between the
user and optimizer domains. This is achieved by overriding the
to_optimizer
andfrom_optimizer
methods. - Perturbation Magnitude Transformation: Stochastic gradient-based
algorithms use perturbations with specified magnitudes (see
perturbation_magnitudes
). These magnitudes are typically defined in the user domain and must be transformed to the optimizer domain using themagnitudes_to_optimizer
method. - Bound Constraint Difference Transformation: To report violations of
variable bounds, the differences between variable values and their
lower/upper bounds must be transformed from the optimizer domain back
to the user domain. This is done using the
bound_constraint_diffs_from_optimizer
method. - Linear Constraint Transformation: Linear constraints are generally
defined by coefficients and right-hand-side values in the user domain.
These must be transformed to the optimizer domain using the
linear_constraints_to_optimizer
method. - Linear Constraint Difference Transformation: To report violations of
linear constraints, the differences between the linear constraint
values and their right-hand-side values must be transformed back to the
user domain. This is done using the
linear_constraints_diffs_from_optimizer
method.
to_optimizer
abstractmethod
Transform values from the user domain to the optimizer domain.
This method maps variable values from the user-defined domain to the optimizer's internal domain. This transformation might involve scaling, shifting, or other operations to improve the optimizer's performance.
The input values
may be a multi-dimensional array. It is assumed that
the last axis of the array represents the variable values. If this is
not the case, you must adjust the order of the axes before and after
calling this method.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
values
|
NDArray[float64]
|
The variable values in the user domain to be transformed. |
required |
Returns:
Type | Description |
---|---|
NDArray[float64]
|
The transformed variable values in the optimizer domain. |
from_optimizer
abstractmethod
Transform values from the optimizer domain to the user domain.
This method maps variable values from the optimizer's internal domain back to the user-defined domain. This transformation reverses any scaling, shifting, or other operations that were applied to improve the optimizer's performance.
The input values
may be a multi-dimensional array. It is assumed that
the last axis of the array represents the variable values. If this is
not the case, you must adjust the order of the axes before and after
calling this method.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
values
|
NDArray[float64]
|
The variable values in the optimizer domain to be transformed. |
required |
Returns:
Type | Description |
---|---|
NDArray[float64]
|
The transformed variable values in the user domain. |
magnitudes_to_optimizer
abstractmethod
Transform perturbation magnitudes to the optimizer domain.
This method transforms perturbation magnitudes, typically used in stochastic gradient-based algorithms, from the user-defined domain to the optimizer's internal domain. The transformation ensures that the perturbations are applied correctly in the optimizer's space, which may have different scaling or units than the user domain.
For example, if variables are scaled down in the optimizer domain, the perturbation magnitudes should also be scaled down proportionally.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
values
|
NDArray[float64]
|
The perturbation magnitudes in the user domain to be transformed. |
required |
Returns:
Type | Description |
---|---|
NDArray[float64]
|
The transformed perturbation magnitudes in the optimizer domain. |
bound_constraint_diffs_from_optimizer
abstractmethod
bound_constraint_diffs_from_optimizer(
lower_diffs: NDArray[float64],
upper_diffs: NDArray[float64],
) -> tuple[NDArray[np.float64], NDArray[np.float64]]
Transform bound constraint differences to the user domain.
This method transforms the differences between variable values and their lower/upper bounds from the optimizer's internal domain back to the user-defined domain. These differences are used to report constraint violations.
For example, if variables are scaled in the optimizer domain, the differences between the variables and their bounds must be scaled back to the user domain to accurately reflect the constraint violations in the user's original units.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
lower_diffs
|
NDArray[float64]
|
The differences between the variable values and their lower bounds in the optimizer domain. |
required |
upper_diffs
|
NDArray[float64]
|
The differences between the variable values and their upper bounds in the optimizer domain. |
required |
Returns:
Type | Description |
---|---|
tuple[NDArray[float64], NDArray[float64]]
|
A tuple containing the transformed differences. |
linear_constraints_to_optimizer
linear_constraints_to_optimizer(
coefficients: NDArray[float64],
lower_bounds: NDArray[float64],
upper_bounds: NDArray[float64],
) -> tuple[
NDArray[np.float64],
NDArray[np.float64],
NDArray[np.float64],
]
Transform linear constraints from the user domain to the optimizer domain.
This method transforms linear constraints, defined by their coefficients and right-hand-side bounds, from the user-defined domain to the optimizer's internal domain. This is essential to maintain the validity of the constraints after variable transformations.
For instance, if variables are scaled or shifted in the optimizer domain, the coefficients and bounds of the linear constraints must be adjusted accordingly to ensure the constraints remain consistent.
The linear constraints are defined by the equation A * x = b
, where A
is the coefficient matrix, x
is the variable vector, and b
represents
the right-hand-side bounds.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
coefficients
|
NDArray[float64]
|
The coefficient matrix. |
required |
lower_bounds
|
NDArray[float64]
|
The lower bounds on the right-hand-side values. |
required |
upper_bounds
|
NDArray[float64]
|
The upper bounds on the right-hand-side values. |
required |
Returns:
Type | Description |
---|---|
tuple[NDArray[float64], NDArray[float64], NDArray[float64]]
|
A tuple containing the transformed coefficient matrix and bounds. |
linear_constraints_diffs_from_optimizer
linear_constraints_diffs_from_optimizer(
lower_diffs: NDArray[float64],
upper_diffs: NDArray[float64],
) -> tuple[NDArray[np.float64], NDArray[np.float64]]
Transform linear constraint differences to the user domain.
This method transforms the differences between linear constraint values and their lower/upper bounds from the optimizer's internal domain back to the user-defined domain. These differences are used to report constraint violations.
For example, if linear constraints are scaled in the optimizer domain, the differences between the constraint values and their bounds must be scaled back to the user domain to accurately reflect the constraint violations in the user's original units.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
lower_diffs
|
NDArray[float64]
|
The differences between the linear constraint values and their lower bounds. |
required |
upper_diffs
|
NDArray[float64]
|
The differences between the linear constraint values and their upper bounds. |
required |
Returns:
Type | Description |
---|---|
tuple[NDArray[float64], NDArray[float64]]
|
A tuple containing the transformed lower and upper differences. |
ropt.transforms.base.ObjectiveTransform
Bases: ABC
Abstract base class for objective transformations.
This class defines the interface for transforming objective values between the user-defined domain and the optimizer's internal domain. Concrete implementations of this class handle the specific logic for each type of objective transformation.
When implementing an objective transformation, the following aspects must be considered:
- Objective Value Transformation: Mapping objective values between the
user and optimizer domains. This is achieved by overriding the
to_optimizer
andfrom_optimizer
methods. - Weighted Objective Transformation: The optimizer works with a
single, weighted objective value. If the transformation affects the
weighted objective, the
weighted_objective_from_optimizer
method should be overridden to handle this.
to_optimizer
abstractmethod
Transform objective values to the optimizer domain.
This method maps objective values from the user-defined domain to the optimizer's internal domain. This transformation might involve scaling, shifting, or other operations to improve the optimizer's performance.
The input objectives
may be a multi-dimensional array. It is assumed
that the last axis of the array represents the objective values. If
this is not the case, you must adjust the order of the axes before and
after calling this method.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
objectives
|
NDArray[float64]
|
The objective values in the user domain to be transformed. |
required |
Returns:
Type | Description |
---|---|
NDArray[float64]
|
The transformed objective values in the optimizer domain. |
from_optimizer
abstractmethod
Transform objective values to the user domain.
This method maps objective values from the optimizer's internal domain back to the user-defined domain. This transformation reverses any scaling, shifting, or other operations that were applied to improve the optimizer's performance.
The input objectives
may be a multi-dimensional array. It is assumed
that the last axis of the array represents the objective values. If
this is not the case, you must adjust the order of the axes before and
after calling this method.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
objectives
|
NDArray[float64]
|
The objective values in the optimizer domain to be transformed. |
required |
Returns:
Type | Description |
---|---|
NDArray[float64]
|
The transformed objective values in the user domain. |
weighted_objective_from_optimizer
Transform the weighted objective to the user domain.
The optimizer uses a single, weighted objective value evaluated in the optimizer domain. This method reverses that transformation, mapping the weighted objective back to the user domain.
For example, if the transformation to the optimizer domain involved a sign change to convert a maximization problem into a minimization problem, this method would change the sign back.
Note
This method may be applied to the weighted objective itself or to its gradient. Therefore, the input may be a scalar or a vector of values.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
weighted_objective
|
NDArray[float64]
|
The weighted objective value(s) to transform. |
required |
Returns:
Type | Description |
---|---|
NDArray[float64]
|
The transformed weighted objective value(s). |
ropt.transforms.base.NonLinearConstraintTransform
Bases: ABC
Abstract base class for nonlinear constraint transformations.
This class defines the interface for transforming nonlinear constraint values between the user-defined domain and the optimizer's internal domain. Concrete implementations of this class handle the specific logic for each type of nonlinear constraint transformation.
When implementing a nonlinear constraint transformation, the following aspects must be considered:
- Constraint Value Transformation: Mapping constraint values between the
user and optimizer domains. This is achieved by overriding the
to_optimizer
andfrom_optimizer
methods. - Right-Hand-Side Bound Transformation: Mapping the right-hand-side
bounds of the constraints between the user and optimizer domains. This is
achieved by overriding the
bounds_to_optimizer
method. - Constraint Difference Transformation: To report violations of
nonlinear constraints, the differences between constraint values and their
lower/upper bounds must be transformed from the optimizer domain back to
the user domain. This is done using the
nonlinear_constraint_diffs_from_optimizer
method.
to_optimizer
abstractmethod
Transform constraint values to the optimizer domain.
This method maps nonlinear constraint values from the user-defined domain to the optimizer's internal domain. This transformation might involve scaling, shifting, or other operations to improve the optimizer's performance.
The input constraints
may be a multi-dimensional array. It is assumed
that the last axis of the array represents the constraint values. If
this is not the case, you must adjust the order of the axes before and
after calling this method.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
constraints
|
NDArray[float64]
|
The nonlinear constraint values in the user domain to be transformed. |
required |
Returns:
Type | Description |
---|---|
NDArray[float64]
|
The transformed nonlinear constraint values in the optimizer domain. |
from_optimizer
abstractmethod
Transform constraint values to the user domain.
This method maps nonlinear constraint values from the optimizer's internal domain back to the user-defined domain. This transformation reverses any scaling, shifting, or other operations that were applied to improve the optimizer's performance.
The input constraints
may be a multi-dimensional array. It is assumed
that the last axis of the array represents the constraint values. If
this is not the case, you must adjust the order of the axes before and
after calling this method.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
constraints
|
NDArray[float64]
|
The nonlinear constraint values in the optimizer domain to be transformed. |
required |
Returns:
Type | Description |
---|---|
NDArray[float64]
|
The transformed nonlinear constraint values in the user domain. |
bounds_to_optimizer
abstractmethod
bounds_to_optimizer(
lower_bounds: NDArray[float64],
upper_bounds: NDArray[float64],
) -> tuple[NDArray[np.float64], NDArray[np.float64]]
Transform the right-hand-side bounds to the optimizer domain.
This method transforms the lower and upper bounds of the nonlinear constraints from the user-defined domain to the optimizer's internal domain. This transformation is necessary to ensure that the constraints remain valid after the variables have been transformed.
For example, if constraint values are scaled or shifted in the optimizer domain, the bounds must be adjusted accordingly.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
lower_bounds
|
NDArray[float64]
|
The lower bounds on the right-hand-side values in the user domain. |
required |
upper_bounds
|
NDArray[float64]
|
The upper bounds on the right-hand-side values in the user domain. |
required |
Returns:
Type | Description |
---|---|
tuple[NDArray[float64], NDArray[float64]]
|
A tuple containing the transformed bounds. |
nonlinear_constraint_diffs_from_optimizer
abstractmethod
nonlinear_constraint_diffs_from_optimizer(
lower_diffs: NDArray[float64],
upper_diffs: NDArray[float64],
) -> tuple[NDArray[np.float64], NDArray[np.float64]]
Transform nonlinear constraint differences to the user domain.
This method transforms the differences between nonlinear constraint values and their lower/upper bounds from the optimizer's internal domain back to the user-defined domain. These differences are used to report constraint violations.
For example, if constraint values are scaled in the optimizer domain, the differences between the constraint values and their bounds must be scaled back to the user domain to accurately reflect the constraint violations in the user's original units.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
lower_diffs
|
NDArray[float64]
|
The differences between the nonlinear constraint values and their lower bounds. |
required |
upper_diffs
|
NDArray[float64]
|
The differences between the nonlinear constraint values and their upper bounds. |
required |
Returns:
Type | Description |
---|---|
tuple[NDArray[float64], NDArray[float64]]
|
A tuple containing the transformed lower and upper differences. |
ropt.transforms.VariableScaler
Bases: VariableTransform
Linearly scales and shifts variables between domains.
This class implements a linear transformation for variables, allowing for scaling and shifting between the user-defined domain and the optimizer's internal domain. The transformation is defined by a scaling factor and an offset for each variable.
The transformation from the user domain to the optimizer domain is given by:
The transformation from the optimizer domain back to the user domain is:
This transformation can be used to improve the performance of the optimizer by working with variables that are scaled to a more suitable range or centered around a specific value.
__init__
Initialize the variable scaler.
This scaler applies a linear transformation to variables, defined by scaling factors and offset values.
If both scales
and offsets
are provided, they are broadcasted to
ensure they have the same length.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
scales
|
NDArray[float64] | None
|
The scaling factors for each variable. |
required |
offsets
|
NDArray[float64] | None
|
The offset values for each variable. |
required |
to_optimizer
Transform variable values to the optimizer domain.
This method applies the linear scaling and offset transformation to variable values, mapping them from the user-defined domain to the optimizer's internal domain.
The transformation is defined as: x_opt = (x_user - offset) / scale
.
The input values
may be a multi-dimensional array. It is assumed that
the last axis of the array represents the variable values. If this is
not the case, you must adjust the order of the axes before and after
calling this method.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
values
|
NDArray[float64]
|
The variable values in the user domain to be transformed. |
required |
Returns:
Type | Description |
---|---|
NDArray[float64]
|
The transformed variable values in the optimizer domain. |
from_optimizer
Transform variable values to the user domain.
This method applies the inverse linear scaling and offset transformation to variable values, mapping them from the optimizer's internal domain back to the user-defined domain.
The transformation is defined as: x_user = x_opt * scale + offset
.
The input values
may be a multi-dimensional array. It is assumed that
the last axis of the array represents the variable values. If this is
not the case, you must adjust the order of the axes before and after
calling this method.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
values
|
NDArray[float64]
|
The variable values in the optimizer domain to be transformed. |
required |
Returns:
Type | Description |
---|---|
NDArray[float64]
|
The transformed variable values in the user domain. |
magnitudes_to_optimizer
Transform perturbation magnitudes to the optimizer domain.
This method transforms perturbation magnitudes, typically used in stochastic gradient-based algorithms, from the user-defined domain to the optimizer's internal domain. The transformation ensures that the perturbations are applied correctly in the optimizer's space, which may have different scaling or units than the user domain.
The transformation is defined as: x_opt = x_user / scale
.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
values
|
NDArray[float64]
|
The perturbation magnitudes in the user domain. |
required |
Returns:
Type | Description |
---|---|
NDArray[float64]
|
The transformed perturbation magnitudes in the optimizer domain. |
linear_constraints_to_optimizer
linear_constraints_to_optimizer(
coefficients: NDArray[float64],
lower_bounds: NDArray[float64],
upper_bounds: NDArray[float64],
) -> tuple[
NDArray[np.float64],
NDArray[np.float64],
NDArray[np.float64],
]
Transform linear constraints to the optimizer domain.
This method transforms linear constraints, defined by their coefficients and right-hand-side bounds, from the user-defined domain to the optimizer's internal domain. This transformation accounts for the scaling and shifting applied to the variables and ensures that the constraints remain valid in the optimizer's space.
The set of linear constraints can be represented by a matrix equation: \(\mathbf{A} \mathbf{x} = \mathbf{b}\).
When linearly transforming variables to the optimizer domain, the coefficients (\(\mathbf{A}\)) and right-hand-side values (\(\mathbf{b}\)) must be converted to remain valid (see also the configuration for linear constraints). If the linear transformation of the variables to the optimizer domain is given by:
then the coefficients and right-hand-side values must be transformed as follows:
where \(S\) is a diagonal matrix with scaling factors on the diagonal and \(o\) are the offsets.
The resulting equations are further scaled by dividing them by maximum of the absolute values of the coefficients in each equation.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
coefficients
|
NDArray[float64]
|
The coefficient matrix of the linear constraints. |
required |
lower_bounds
|
NDArray[float64]
|
The lower bounds on the right-hand-side values. |
required |
upper_bounds
|
NDArray[float64]
|
The upper bounds on the right-hand-side values. |
required |
Returns:
Type | Description |
---|---|
tuple[NDArray[float64], NDArray[float64], NDArray[float64]]
|
A tuple containing the transformed coefficient matrix and bounds. |
bound_constraint_diffs_from_optimizer
bound_constraint_diffs_from_optimizer(
lower_diffs: NDArray[float64],
upper_diffs: NDArray[float64],
) -> tuple[NDArray[np.float64], NDArray[np.float64]]
Transform bound constraint differences to the user domain.
This method transforms the differences between variable values and their lower/upper bounds from the optimizer's internal domain back to the user-defined domain. These differences are used to report constraint violations.
For example, if variables are scaled in the optimizer domain, the differences between the variables and their bounds must be scaled back to the user domain to accurately reflect the constraint violations in the user's original units.
The transformation is defined as: x_user = x_opt * scale
.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
lower_diffs
|
NDArray[float64]
|
The differences between the variable values and their lower bounds. |
required |
upper_diffs
|
NDArray[float64]
|
The differences between the variable values and their upper bounds. |
required |
Returns:
Type | Description |
---|---|
tuple[NDArray[float64], NDArray[float64]]
|
A tuple containing the transformed lower and upper differences. |
linear_constraints_diffs_from_optimizer
linear_constraints_diffs_from_optimizer(
lower_diffs: NDArray[float64],
upper_diffs: NDArray[float64],
) -> tuple[NDArray[np.float64], NDArray[np.float64]]
Transform linear constraint differences to the user domain.
This method transforms the differences between linear constraint values and their lower/upper bounds from the optimizer's internal domain back to the user-defined domain. These differences are used to report constraint violations.
This is implemented by re-scaling the equations with the weights that
were determined and stored by the
linear_constraints_to_optimizer
method.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
lower_diffs
|
NDArray[float64]
|
The differences between the linear constraint values and their lower bounds. |
required |
upper_diffs
|
NDArray[float64]
|
The differences between the linear constraint values and their upper bounds. |
required |
Returns:
Type | Description |
---|---|
tuple[NDArray[float64], NDArray[float64]]
|
A tuple containing the transformed lower and upper differences. |