Esempio n. 1
0
    def validate(self,
                 equal_slopes_tolerance=1e-6):
        """
        Validate this piecewise linear function by verifying
        various properties of the breakpoints and values
        lists (e.g., that the list of breakpoints is
        nondecreasing).

        Args:
            equal_slopes_tolerance (float): Tolerance used
                check if consecutive slopes are nearly
                equal. If any are found, validation will
                fail. Default is 1e-6.

        Returns:
            int:
                a function characterization code (see \
                :func:`util.characterize_function`)

        Raises:
            PiecewiseValidationError: if validation fails
        """

        breakpoints = [_value(x) for x in self._breakpoints]
        values = [_value(x) for x in self._values]
        if not is_nondecreasing(breakpoints):
            raise PiecewiseValidationError(
                "The list of breakpoints is not nondecreasing: %s"
                % (str(breakpoints)))

        ftype, slopes = characterize_function(breakpoints, values)
        for i in range(1, len(slopes)):
            if (slopes[i-1] is not None) and \
               (slopes[i] is not None) and \
               (abs(slopes[i-1] - slopes[i]) <= equal_slopes_tolerance):
                raise PiecewiseValidationError(
                    "Piecewise function validation detected slopes "
                    "of consecutive line segments to be within %s "
                    "of one another. This may cause numerical issues. "
                    "To avoid this error, set the 'equal_slopes_tolerance' "
                    "keyword to a smaller value or disable validation."
                    % (equal_slopes_tolerance))

        return ftype
Esempio n. 2
0
 def __call__(self, x):
     """Evaluates the piecewise linear function at the
     given point using interpolation. Note that step functions are
     assumed lower-semicontinuous."""
     i = bisect.bisect_left(_shadow_list(self.breakpoints), x)
     if i == 0:
         xP = _value(self.breakpoints[i])
         if xP == x:
             return float(_value(self.values[i]))
     elif i != len(self.breakpoints):
         xL = _value(self.breakpoints[i - 1])
         xU = _value(self.breakpoints[i])
         assert xL <= xU
         if (xL <= x) and (x <= xU):
             yL = _value(self.values[i - 1])
             yU = _value(self.values[i])
             return yL + (float(yU - yL) / (xU - xL)) * (x - xL)
     raise ValueError(
         "The point %s is outside of the "
         "function domain: [%s,%s]." %
         (x, _value(self.breakpoints[0]), _value(self.breakpoints[-1])))
Esempio n. 3
0
 def __getitem__(self, i):
     return _value(self._x.__getitem__(i))
Esempio n. 4
0
    def validate(self,
                 equal_slopes_tolerance=1e-6,
                 require_bounded_input_variable=True,
                 require_variable_domain_coverage=True):
        """
        Validate this piecewise linear function by verifying
        various properties of the breakpoints, values, and
        input variable (e.g., that the list of breakpoints
        is nondecreasing).

        Args:
            equal_slopes_tolerance (float): Tolerance used
                check if consecutive slopes are nearly
                equal. If any are found, validation will
                fail. Default is 1e-6.
            require_bounded_input_variable (bool): Indicates
                if the input variable is required to have
                finite upper and lower bounds. Default is
                :const:`True`. Setting this keyword to
                :const:`False` can be used to allow general
                expressions to be used as the input in place
                of a variable.
            require_variable_domain_coverage (bool):
                Indicates if the function domain (defined by
                the endpoints of the breakpoints list) needs
                to cover the entire domain of the input
                variable. Default is :const:`True`. Ignored
                for any bounds of variables that are not
                finite, or when the input is not assigned a
                variable.

        Returns:
            int:
                a function characterization code (see \
                :func:`util.characterize_function`)

        Raises:
            PiecewiseValidationError: if validation fails
        """
        ftype = self._f.validate(equal_slopes_tolerance=equal_slopes_tolerance)
        assert ftype in (1, 2, 3, 4, 5)

        input_var = self.input.expr
        if not isinstance(input_var, IVariable):
            input_var = None

        if require_bounded_input_variable and \
           ((input_var is None) or \
            (not input_var.has_lb()) or \
            (not input_var.has_ub())):
            raise PiecewiseValidationError(
                "Piecewise function input is not a "
                "variable with finite upper and lower "
                "bounds: %s. To avoid this error, set the "
                "'require_bounded_input_variable' keyword "
                "to False or disable validation." % (str(input_var)))

        if require_variable_domain_coverage and \
           (input_var is not None):
            domain_lb = _value(self.breakpoints[0])
            domain_ub = _value(self.breakpoints[-1])
            if input_var.has_lb() and \
               _value(input_var.lb) < domain_lb:
                raise PiecewiseValidationError(
                    "Piecewise function domain does not include "
                    "the lower bound of the input variable: "
                    "%s.ub = %s > %s. To avoid this error, set "
                    "the 'require_variable_domain_coverage' "
                    "keyword to False or disable validation." %
                    (input_var.name, _value(input_var.lb), domain_lb))
            if input_var.has_ub() and \
               _value(input_var.ub) > domain_ub:
                raise PiecewiseValidationError(
                    "Piecewise function domain does not include "
                    "the upper bound of the input variable: "
                    "%s.ub = %s > %s. To avoid this error, set "
                    "the 'require_variable_domain_coverage' "
                    "keyword to False or disable validation." %
                    (input_var.name, _value(input_var.ub), domain_ub))

        return ftype