Source code for pybrops.opt.soln.BinarySolution

"""
Partial implementation of the SetSolution interface.
"""

# list of all public imports in the module
__all__ = [
    "BinarySolution",
    "check_is_BinarySolution",
]

# imports
from numbers import Integral
from numbers import Real
from typing import Union
import numpy
from pybrops.core.error.error_type_numpy import check_ndarray_dtype_is_bool_or_integer
from pybrops.core.error.error_value_numpy import check_ndarray_is_binary
from pybrops.core.error.error_value_numpy import check_ndarray_len_eq
from pybrops.core.error.error_value_numpy import check_ndarray_shape_eq
from pybrops.opt.soln.Solution import Solution

[docs] class BinarySolution( Solution, ): """ Class for optimization problem solutions with binary decision variables. """ ########################## Special Object Methods ########################## # implementation of abstract method def __init__( self, ndecn: Integral, decn_space: Union[numpy.ndarray,None], decn_space_lower: Union[numpy.ndarray,Integral,bool,None], decn_space_upper: Union[numpy.ndarray,Integral,bool,None], nobj: Integral, obj_wt: Union[numpy.ndarray,Real,None], nineqcv: Union[Integral,None], ineqcv_wt: Union[numpy.ndarray,Real,None], neqcv: Union[Integral,None], eqcv_wt: Union[numpy.ndarray,Real,None], nsoln: Integral, soln_decn: numpy.ndarray, soln_obj: numpy.ndarray, soln_ineqcv: Union[numpy.ndarray,None], soln_eqcv: Union[numpy.ndarray,None], **kwargs: dict ) -> None: """ Constructor for BinarySolution. Parameters ---------- ndecn : Integral Number of decision variables. decn_space : numpy.ndarray A 1d array containing the set of available elements decn_space_lower : numpy.ndarray A 1d array representing the lower bound of the decision variables. decn_space_upper : numpy.ndarray A 1d array representing the upper bound of the decision variables. nobj : Integral Number of objectives for the problem. obj_wt : numpy.ndarray, Real, None Objective function weights. Weights from this vector are applied to objective function values via the Hadamard product. If values are ``1.0`` or ``-1.0``, this can be used to specify minimizing and maximizing objectives, respectively. If ``obj_wt`` is ``numpy.ndarray``, then the array must be of shape ``(nobj,)``. If ``obj_wt`` is ``Real``, then the value is broadcast to a ``numpy.ndarray`` of shape ``(nobj,)``. If ``obj_wt`` is ``None``, then the value ``1.0`` is broadcast to a ``numpy.ndarray`` of shape ``(nobj,)``. This assumes that all objectives are to be minimized. nineqcv : Integral, None Number of inequality constraint violation functions. This is equivalent to the vector length returned by the ``ineqcv_trans`` function. Must be ``Integral`` greater than or equal to zero. If ``nineqcv`` is ``None``, then set to zero. ineqcv_wt : numpy.ndarray, None Inequality constraint violation function weights. Weights from this vector are applied to inequality constraint violation function values via the Hadamard product. If values are ``1.0`` or ``-1.0``, this can be used to specify minimizing and maximizing constraints, respectively. If ``ineqcv_wt`` is ``numpy.ndarray``, then the array must be of shape ``(nineqcv,)``. If ``ineqcv_wt`` is ``Real``, then the value is broadcast to a ``numpy.ndarray`` of shape ``(nineqcv,)``. If ``ineqcv_wt`` is ``None``, then the value ``1.0`` is broadcast to a ``numpy.ndarray`` of shape ``(nineqcv,)``. This assumes that all constraints are to be minimized. neqcv : Integral, None Number of equality constraint violations. This is equivalent to the vector length returned by the ``eqcv_trans`` function. Must be ``Integral`` greater than or equal to zero. If ``neqcv`` is ``None``, then set to zero. eqcv_wt : numpy.ndarray, None Equality constraint violation function weights. Weights from this vector are applied to equality constraint violation function values via the Hadamard product. If values are ``1.0`` or ``-1.0``, this can be used to specify minimizing and maximizing constraints, respectively. If ``eqcv_wt`` is ``numpy.ndarray``, then the array must be of shape ``(neqcv,)``. If ``eqcv_wt`` is ``Real``, then the value is broadcast to a ``numpy.ndarray`` of shape ``(neqcv,)``. If ``eqcv_wt`` is ``None``, then the value ``1.0`` is broadcast to a ``numpy.ndarray`` of shape ``(neqcv,)``. This assumes that all constraints are to be minimized. nsoln : Integral Number of solutions. soln_decn : numpy.ndarray Solution decision vectors for each solution. This matrix is of shape ``(nsoln,ndecn)``. soln_obj : numpy.ndarray Solution objective vectors for each solution. This matrix is of shape ``(nsoln,nobj)``. soln_ineqcv : numpy.ndarray Solution inequality constraint violiation vectors for each solution. This matrix is of shape ``(nsoln,nineqcv)`` soln_eqcv : numpy.ndarray Solution equality constraint violiation vectors for each solution. This matrix is of shape ``(nsoln,neqcv)`` kwargs : dict Additional keyword arguments. """ # order dependent assignments self.ndecn = ndecn self.decn_space = decn_space self.decn_space_lower = decn_space_lower self.decn_space_upper = decn_space_upper self.nobj = nobj self.obj_wt = obj_wt self.nineqcv = nineqcv self.ineqcv_wt = ineqcv_wt self.neqcv = neqcv self.eqcv_wt = eqcv_wt self.nsoln = nsoln self.soln_decn = soln_decn self.soln_obj = soln_obj self.soln_ineqcv = soln_ineqcv self.soln_eqcv = soln_eqcv ############################ Object Properties ############################# # override decn_space setter properties @Solution.decn_space.setter def decn_space(self, value: Union[numpy.ndarray,None]) -> None: """Set decision space boundaries.""" if isinstance(value, numpy.ndarray): check_ndarray_dtype_is_bool_or_integer(value, "decn_space") check_ndarray_shape_eq(value, "decn_space", (2,self.ndecn)) check_ndarray_is_binary(value, "decn_space") elif value is None: pass else: raise TypeError("'decn_space' must be of type numpy.ndarray or None") self._decn_space = value # override decn_space setter properties @Solution.decn_space_lower.setter def decn_space_lower(self, value: Union[numpy.ndarray,Integral,bool,None]) -> None: """Set lower boundary of the decision space.""" if isinstance(value, numpy.ndarray): check_ndarray_dtype_is_bool_or_integer(value, "decn_space_lower") check_ndarray_len_eq(value, "decn_space_lower", self.ndecn) check_ndarray_is_binary(value, "decn_space") elif isinstance(value, Integral): value = numpy.repeat(value, self.ndecn) elif isinstance(value, bool): value = numpy.repeat(value, self.ndecn) elif value is None: pass else: raise TypeError("'decn_space_lower' must be of type numpy.ndarray, an Integral type, bool, or None") self._decn_space_lower = value # override decn_space setter properties @Solution.decn_space_upper.setter def decn_space_upper(self, value: Union[numpy.ndarray,Integral,bool,None]) -> None: """Set upper boundary of the decision space.""" if isinstance(value, numpy.ndarray): check_ndarray_dtype_is_bool_or_integer(value, "decn_space_upper") check_ndarray_len_eq(value, "decn_space_upper", self.ndecn) check_ndarray_is_binary(value, "decn_space") elif isinstance(value, Integral): value = numpy.repeat(value, self.ndecn) elif isinstance(value, bool): value = numpy.repeat(value, self.ndecn) elif value is None: pass else: raise TypeError("'decn_space_upper' must be of type numpy.ndarray, an Integral type, bool, or None") self._decn_space_upper = value
################################## Utilities ###################################
[docs] def check_is_BinarySolution(v: object, vname: str) -> None: """ Check if object is of type BinarySolution, otherwise raise TypeError. Parameters ---------- v : object Any Python object to test. vname : str Name of variable to print in TypeError message. """ if not isinstance(v, BinarySolution): raise TypeError("'{0}' must be of type BinarySolution.".format(vname))