Source code for gemseo.problems.optimization.hock_schittkowski_71

# 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.

r"""Hock & Schittkowski problem 71.

This module implements the Hock & Schittkowski non-linear programming problem 71.

See: Willi Hock and Klaus Schittkowski. (1981) Test Examples for
Nonlinear Programming Codes. Lecture Notes in Economics and Mathematical
Systems Vol. 187, Springer-Verlag.
Based on MATLAB code by Peter Carbonetto.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from numpy import array

from gemseo.algos.design_space import DesignSpace
from gemseo.algos.optimization_problem import OptimizationProblem
from gemseo.core.mdo_functions.mdo_function import MDOFunction

if TYPE_CHECKING:
    from gemseo.typing import NumberArray


[docs] class HockSchittkowski71(OptimizationProblem): """Hock and Schittkowski problem 71.""" def __init__( self, initial_guess: NumberArray = (1.0, 5.0, 5.0, 1.0), ): """Initialize the Hock Schittkowski 71 problem. Args: initial_guess: The initial guess for the optimal solution. """ design_space = DesignSpace() design_space.add_variable( "x", size=4, lower_bound=[1.0, 1.0, 1.0, 1.0], upper_bound=[5.0, 5.0, 5.0, 5.0], ) design_space.set_current_value(array(initial_guess)) super().__init__(design_space) self.objective = MDOFunction( self.compute_objective, name="hock_schittkoski_71", f_type=MDOFunction.FunctionType.OBJ, jac=self.compute_objective_jacobian, expr="x_1 * x_4 * (x_1 + x_2 + x_3) + x_3", input_names=["x"], dim=1, ) equality_constraint = MDOFunction( self.compute_equality_constraint, name="equality_constraint", f_type=MDOFunction.ConstraintType.EQ, jac=self.compute_equality_constraint_jacobian, expr="(x_1**2 + x_2**2 + x_3**2 + x_4**2) - 40", input_names=["x"], dim=1, ) self.add_constraint( equality_constraint, constraint_type=MDOFunction.ConstraintType.EQ ) inequality_constraint = MDOFunction( self.compute_inequality_constraint, name="inequality_constraint", f_type=MDOFunction.ConstraintType.INEQ, jac=self.compute_inequality_constraint_jacobian, expr="25 - (x_1 * x_2 * x_3 * x_4)", input_names=["x"], dim=1, ) self.add_constraint( inequality_constraint, constraint_type=MDOFunction.ConstraintType.INEQ )
[docs] @staticmethod def compute_objective(design_variables: NumberArray) -> NumberArray: """Compute the objectives of the Hock and Schittkowski 71 function. Args: design_variables: The design variables vector. Returns: The objective function value. """ return ( design_variables[0] * design_variables[3] * (sum(design_variables[0:3])) + design_variables[2] )
[docs] @staticmethod def compute_objective_jacobian(design_variables: NumberArray) -> NumberArray: """Compute the Jacobian of objective function. Args: design_variables: The design variables vector. Returns: The gradient of the objective functions wrt the design variables. """ x_1, x_2, x_3, x_4 = design_variables return array([ x_1 * x_4 + x_4 * (x_1 + x_2 + x_3), x_1 * x_4, x_1 * x_4 + 1.0, x_1 * (x_1 + x_2 + x_3), ])
[docs] @staticmethod def compute_equality_constraint(design_variables: NumberArray) -> NumberArray: """Compute the equality constraint function. Args: design_variables: The design variables vector. Returns: The equality constraint's value. """ x_1, x_2, x_3, x_4 = design_variables return array([x_1**2 + x_2**2 + x_3**2 + x_4**2 - 40])
[docs] @staticmethod def compute_inequality_constraint(design_variables: NumberArray) -> NumberArray: """Compute the inequality constraint function. Args: design_variables: The design variables vector. Returns: The inequality constraint's value. """ x_1, x_2, x_3, x_4 = design_variables return array([25 - x_1 * x_2 * x_3 * x_4])
[docs] @staticmethod def compute_equality_constraint_jacobian( design_variables: NumberArray, ) -> NumberArray: """Compute the equality constraint's Jacobian. Args: design_variables: The design variables vector. Returns: The Jacobian of the equality constraint function wrt the design variables. """ x_1, x_2, x_3, x_4 = design_variables return array([ 2 * x_1, 2 * x_2, 2 * x_3, 2 * x_4, ])
[docs] @staticmethod def compute_inequality_constraint_jacobian( design_variables: NumberArray, ) -> NumberArray: """Compute the inequality constraint's Jacobian. Args: design_variables: The design variables vector. Returns: The Jacobian of the inequality constraint function wrt the design variables. """ x_1, x_2, x_3, x_4 = design_variables return array([ -x_2 * x_3 * x_4, -x_1 * x_3 * x_4, -x_1 * x_2 * x_4, -x_1 * x_2 * x_3, ])
[docs] @staticmethod def get_solution() -> tuple[NumberArray, NumberArray]: """Return the analytical solution of the problem. Returns: The theoretical optimum of the problem. """ x_opt = array([0.99999999, 4.74299964, 3.82114998, 1.37940829]) f_opt = x_opt[0] * x_opt[3] * sum(x_opt[0:3]) + x_opt[2] return x_opt, f_opt