Beispiel #1
0
        def evaluate(self, x_val):
            """ Evaluates the breaks-based PWL function at the point whose x-coordinate is `x_val`.

            Args:
                x_val: The x value for which we want to compute the value of the function.

            Returns:
                The value of the PWL function at point `x_val`
                A DOcplexException exception is raised when evaluating at a discontinuity of the PWL function.
            """
            prev_break_index, index = -1, 0
            while index < len(self.breaksxy):
                break_1, break_2, index = self._get_break_at_index(index)
                if break_1 is None:
                    raise DOcplexException(
                        "Invalid PWL definition: no break point is defined")
                if break_1[0] < x_val:
                    prev_break_index = index
                else:
                    if break_1[0] == x_val and break_2 is not None:
                        raise DOcplexException(
                            "Cannot evaluate PWL at a discontinuity")
                    break
                index += 1
            y_val, _, _ = self._get_y_value(x_val, prev_break_index)
            return y_val
def compile_naming_function(keys,
                            user_name,
                            dimension=1,
                            key_format=None,
                            _default_key_format='_%s',
                            stringifier=str_flatten_tuple):
    # INTERNAL
    # builds a naming rule from an input , a dimension, and an optional meta-format
    # Makes sure the format string does contain the right number of format slots
    assert user_name is not None

    if is_string(user_name):
        if key_format is None:
            used_key_format = _default_key_format
        elif is_string(key_format):
            # -- make sure some %s is inside, otherwise add it
            if '%s' in key_format:
                used_key_format = key_format
            else:
                used_key_format = key_format + '%s'
        else:  # pragma: no cover
            raise DOcplexException(
                "key format expects string format or None, got: {0!r}".format(
                    key_format))

        fixed_format_string = fix_format_string(user_name, dimension,
                                                used_key_format)
        if 1 == dimension:
            return lambda k: fixed_format_string % stringifier(k)
        else:
            # here keys are tuples of size >= 2
            return lambda key_tuple: fixed_format_string % key_tuple

    elif is_function(user_name):
        return user_name

    elif is_iterable(user_name):
        # check that the iterable has same len as keys,
        # otherwise thereis no more default naming and None cannot appear in CPLEX name arrays
        list_names = list(user_name)
        if len(list_names) < len(keys):
            raise DOcplexException(
                "An array of names should have same len as keys, expecting: {0}, go: {1}"
                .format(len(keys), len(list_names)))
        key_to_names_dict = {k: nm for k, nm in izip(keys, list_names)}
        # use a closure
        return lambda k: key_to_names_dict[
            k]  # if k in key_to_names_dict else default_fn()

    else:
        raise DOcplexException(
            'Cannot use this for naming variables: {0!r} - expecting string, function or iterable'
            .format(user_name))
Beispiel #3
0
 def translate(self, arg):
     if is_number(arg):
         return PwlFunction._PwlAsSlopes(
             [(br[0], br[1] + arg) for br in self.slopebreaksx], self.lastslope,
             (self.anchor[0] + arg, self.anchor[1]))
     else:
         raise DOcplexException("Invalid type for argument: {0!s}.".format(arg))
Beispiel #4
0
    def subtract(self, arg):
        """ Subtracts an expression from this PWL function.

        Note:
            This method does not create a new function but modifies the `self` instance.

        Args:
            arg: The expression to be subtracted. Can be either a PWL function, or a number.

        Returns:
            The modified self.
        """
        if isinstance(arg, PwlFunction):
            if (isinstance(self.pwl_def, PwlFunction._PwlAsBreaks) and
                    isinstance(arg.pwl_def, PwlFunction._PwlAsBreaks)) or \
                    (isinstance(self.pwl_def, PwlFunction._PwlAsSlopes) and
                         isinstance(arg.pwl_def, PwlFunction._PwlAsSlopes)):
                self._pwl_def = self.pwl_def - arg.pwl_def
                self._set_pwl_definition(self._pwl_def)
            else:
                # Use Breaks representation
                self._pwl_def = self.pwl_def_as_breaks - arg.pwl_def_as_breaks
                self._set_pwl_definition(self._pwl_def)
        elif is_number(arg):
            self._pwl_def = self.pwl_def - arg
            self._set_pwl_definition(self._pwl_def)
        else:
            raise DOcplexException("Invalid type for right hand side operand: {0!s}.".format(arg))
        return self
Beispiel #5
0
        def __add__(self, arg):
            if isinstance(arg, PwlFunction._PwlAsBreaks):
                all_x_coord = sorted({br[0] for br in self.breaksxy + arg.breaksxy})
                all_breaks_left = self._get_all_breaks(all_x_coord)
                all_breaks_right = arg._get_all_breaks(all_x_coord)
                result_breaksxy = []
                # Both lists have same size, with same x-coord for breaks ==> perform the addition on each break
                for br_l, br_r in izip(all_breaks_left, all_breaks_right):
                    if isinstance(br_l, tuple) and isinstance(br_r, tuple):
                        result_breaksxy.append((br_l[0], br_l[1] + br_r[1]))
                    else:
                        if isinstance(br_l, tuple):
                            # br_r is a list containing 2 tuple pairs
                            result_breaksxy.append((br_l[0], br_l[1] + br_r[0][1]))
                            result_breaksxy.append((br_l[0], br_l[1] + br_r[1][1]))
                        elif isinstance(br_r, tuple):
                            # br_l is a list containing 2 tuple pairs
                            result_breaksxy.append((br_r[0], br_l[0][1] + br_r[1]))
                            result_breaksxy.append((br_r[0], br_l[1][1] + br_r[1]))
                        else:
                            # br_l and br_r are two lists, each containing 2 tuple pairs
                            result_breaksxy.append((br_l[0][0], br_l[0][1] + br_r[0][1]))
                            result_breaksxy.append((br_l[0][0], br_l[1][1] + br_r[1][1]))
                result_preslope = self.preslope + arg.preslope
                result_postslope = self.postslope + arg.postslope
                return PwlFunction._PwlAsBreaks(*self._remove_useless_intermediate_breaks(
                    result_preslope, result_breaksxy, result_postslope))

            elif is_number(arg):
                return PwlFunction._PwlAsBreaks(
                    self.preslope, [(br[0], br[1] + arg) for br in self.breaksxy], self.postslope)

            else:
                raise DOcplexException("Invalid type for right hand side operand: {0!s}.".format(arg))
Beispiel #6
0
 def __mul__(self, arg):
     if is_number(arg):
         return PwlFunction._PwlAsSlopes(*self._remove_useless_intermediate_slopes(
             [(br[0] * arg, br[1]) for br in self.slopebreaksx],
             self.lastslope * arg, (self.anchor[0], self.anchor[1] * arg)))
     else:
         raise DOcplexException("Invalid type for right hand side operand: {0!s}.".format(arg))
Beispiel #7
0
 def _get_y_value(self, x_coord, prev_break_index=-1):
     """
     :param x_coord:
     :param prev_break_index: this parameter is mandatory if a breakxy tuple does exist before x_coord. Otherwise
         an exception is raised.
     :return:
     """
     if prev_break_index < 0:
         break_1, break_2, last_ind = self._get_break_at_index(0)
         if break_1[0] < x_coord:
             raise DOcplexException(
                 "Invalid arguments passed to PwlAsBreaks._get_y_value()"
             )
         if break_1[0] == x_coord:
             y_coord_1 = break_1[1]
             y_coord_2 = None if break_2 is None else break_2[1]
             return y_coord_1, y_coord_2, last_ind
         y_coord_1 = break_1[1] - self.preslope * (break_1[0] - x_coord)
         return y_coord_1, None, -1
     break_1, break_2, last_ind = self._get_break_at_index(
         prev_break_index)
     next_break_1, next_break_2, next_last_ind = self._get_break_at_index(
         last_ind + 1)
     if next_break_1 is None:
         # x-coord is after last break
         last_break = break_1 if break_2 is None else break_2
         y_coord_1 = last_break[1] + self.postslope * (x_coord -
                                                       last_break[0])
         return y_coord_1, None, last_ind
     else:
         if x_coord == break_1[0]:
             # Here, one must have: x_coord > break_1[0]
             raise DOcplexException(
                 "Invalid arguments passed to PwlAsBreaks._get_y_value()"
             )
         if x_coord == next_break_1[0]:
             y_coord_1 = next_break_1[1]
             y_coord_2 = None if next_break_2 is None else next_break_2[
                 1]
             return y_coord_1, y_coord_2, next_last_ind
         y_coord_prev = break_1[1] if break_2 is None else break_2[1]
         y_coord_next = next_break_1[1]
         slope = (y_coord_next - y_coord_prev) / (next_break_1[0] -
                                                  break_1[0])
         y_coord_1 = y_coord_prev + slope * (x_coord - break_1[0])
         return y_coord_1, None, last_ind
Beispiel #8
0
 def __sub__(self, arg):
     if isinstance(arg, PwlFunction._PwlAsSlopes):
         return self + arg * (-1)
     elif is_number(arg):
         return PwlFunction._PwlAsSlopes(copy.deepcopy(self.slopebreaksx),
                                         self.lastslope, (self.anchor[0], self.anchor[1] - arg))
     else:
         raise DOcplexException("Invalid type for right hand side operand: {0!s}.".format(arg))
Beispiel #9
0
 def __sub__(self, arg):
     if isinstance(arg, PwlFunction._PwlAsBreaks):
         return self + arg * (-1)
     elif is_number(arg):
         return PwlFunction._PwlAsBreaks(
             self.preslope, [(br[0], br[1] - arg) for br in self.breaksxy], self.postslope)
     else:
         raise DOcplexException("Invalid type for right hand side operand: {0!s}.".format(arg))
Beispiel #10
0
 def translate(self, arg):
     if is_number(arg):
         return PwlFunction._PwlAsBreaks(self.preslope,
                                         [(br[0] + arg, br[1])
                                          for br in self.breaksxy],
                                         self.postslope)
     else:
         raise DOcplexException(
             "Invalid type for argument: {0!s}.".format(arg))
Beispiel #11
0
 def __mul__(self, arg):
     if is_number(arg):
         return PwlFunction._PwlAsBreaks(
             *self._remove_useless_intermediate_breaks(
                 self.preslope *
                 arg, [(br[0], br[1] * arg)
                       for br in self.breaksxy], self.postslope * arg))
     else:
         raise DOcplexException(
             "Invalid type for right hand side operand: {0!s}.".format(
                 arg))
Beispiel #12
0
    def _resolve_cplex(self, env):
        # INTERNAL
        if env is None:
            raise DOcplexException("need an environment to resolve cplex, got None")
        if not self._is_cplex_resolved():
            if env.has_cplex:
                from docplex.mp.cplex_engine import CplexEngine

                self._cplex_engine_type = CplexEngine
                self._engine_types_by_agent["cplex"] = CplexEngine
            else:
                self._cplex_engine_type = None
Beispiel #13
0
    def translate(self, arg):
        """ Translate this PWL function by a number.
        This method creates a new PWL function instance for which all breakpoints have been moved
        along the horizontal axis by the amount specified by `arg`.

        Args:
            arg: The number that is used to translate all breakpoints.

        Returns:
            The translated PWL function.
        """
        if is_number(arg):
            return PwlFunction(self.model, self.pwl_def.translate(arg))
        else:
            raise DOcplexException("Invalid type for argument: {0!s}.".format(arg))
 def _to_linear_operand(self, e, force_clone=False, msg=None):
     if isinstance(e, LinearOperand):
         if force_clone:
             return e.clone()
         else:
             return e
     elif is_number(e):
         return self.constant_expr(cst=e, safe_number=False)
     else:
         try:
             return e.to_linear_expr()
         except AttributeError:
             # delegate to the factory
             return self.linear_expr(e)
         except DocplexQuadToLinearException as qe:
             used_msg = msg.format(e) if msg else qe.message
             raise DOcplexException(used_msg)
Beispiel #15
0
        def __add__(self, arg):
            if isinstance(arg, PwlFunction._PwlAsSlopes):
                all_x_coord = sorted({sbr[1] for sbr in self.slopebreaksx + arg.slopebreaksx})
                all_slopebreaks_left = self._get_all_slopebreaks(all_x_coord)
                all_slopebreaks_right = arg._get_all_slopebreaks(all_x_coord)
                result_slopebreaksxy = []
                # Both lists have same size, with same x-coord for slopebreaks
                #   ==> perform the addition of slopes on each break
                for sbr_l, sbr_r in izip(all_slopebreaks_left, all_slopebreaks_right):
                    if isinstance(sbr_l, tuple) and isinstance(sbr_r, tuple):
                        result_slopebreaksxy.append((sbr_l[0] + sbr_r[0], sbr_l[1]))
                    else:
                        if isinstance(sbr_l, tuple):
                            # sbr_r is a list containing 2 tuple pairs
                            result_slopebreaksxy.append((sbr_l[0] + sbr_r[0][0], sbr_l[1]))
                            result_slopebreaksxy.append((sbr_r[1][0], sbr_l[1]))
                        elif isinstance(sbr_r, tuple):
                            # sbr_l is a list containing 2 tuple pairs
                            result_slopebreaksxy.append((sbr_l[0][0] + sbr_r[0], sbr_r[1]))
                            result_slopebreaksxy.append((sbr_l[1][0], sbr_r[1]))
                        else:
                            # sbr_l and sbr_r are two lists, each containing 2 tuple pairs
                            result_slopebreaksxy.append((sbr_l[0][0] + sbr_r[0][0], sbr_l[0][1]))
                            result_slopebreaksxy.append((sbr_l[1][0] + sbr_r[1][0], sbr_l[0][1]))
                result_lastslope = self.lastslope + arg.lastslope

                if self.anchor[0] == arg.anchor[0]:
                    result_anchor = (self.anchor[0], self.anchor[1] + arg.anchor[1])
                else:
                    # Compute a new anchor based on the last x-coord in the slopebreakx list + anchor point
                    anchor_l = self._get_safe_xy_anchor()
                    anchor_r = arg._get_safe_xy_anchor()
                    delta = anchor_r[0] - anchor_l[0]
                    if anchor_l[0] < anchor_r[0]:
                        result_anchor = (anchor_r[0], anchor_l[1] + anchor_r[1] + delta * self.lastslope)
                    else:
                        result_anchor = (anchor_l[0], anchor_l[1] + anchor_r[1] - delta * arg.lastslope)

                return PwlFunction._PwlAsSlopes(*self._remove_useless_intermediate_slopes(
                    result_slopebreaksxy, result_lastslope, result_anchor))

            elif is_number(arg):
                return PwlFunction._PwlAsSlopes(copy.deepcopy(self.slopebreaksx),
                                                self.lastslope, (self.anchor[0], self.anchor[1] + arg))
            else:
                raise DOcplexException("Invalid type for right hand side operand: {0!s}.".format(arg))
Beispiel #16
0
    def multiply(self, arg):
        """ Multiplies this PWL function by a number.

        Note:
            This method does not create a new function but modifies the `self` instance.

        Args:
            arg: The number that is used to multiply `self`.

        Returns:
            The modified `self`.
        """
        if is_number(arg):
            self._pwl_def = self.pwl_def * arg
            self._set_pwl_definition(self._pwl_def)
        else:
            raise DOcplexException("Invalid type for right hand side operand: {0!s}.".format(arg))
        return self
Beispiel #17
0
    def plot(self, lx=None, rx=None, k=1, **kwargs):  # pragma: no cover
        """
        This method displays the piecewise linear function using the matplotlib package, if found.

        :param lx: The value to show the `preslope` (must be before the first breakpoint x value).
        :param rx: The value to show the `postslope` (must be after the last breakpoint x value).
        :param k: Scaling factor to calculate default values for `rx` and/or `lx` if these arguments are not provided,
                based on mean interval length between the `x` values of breakpoints.
        :param kwargs: additional arguments to be passed to matplotlib plot() function
        """
        try:
            import matplotlib.pyplot as plt
        except ImportError:
            raise DOcplexException('matplotlib is required for plot()')
        bks = self.pwl_def_as_breaks.breaksxy
        xs = [bk[0] for bk in bks]
        ys = [bk[1] for bk in bks]
        # compute mean delta_x
        first_x = xs[0]
        last_x = xs[-1]
        nb_intervals = self._pwl_def_as_breaks.get_nb_intervals()
        # k times the mean interval length is used for left/right extra points
        kdx_m = k * (last_x -
                     first_x) / float(nb_intervals) if nb_intervals > 0 else 1

        if lx is None:
            lx = first_x - kdx_m
        ly = ys[0] - self.pwl_def_as_breaks.preslope * (first_x - lx)
        xs.insert(0, lx)
        ys.insert(0, ly)

        if rx is None or rx <= last_x:
            rx = last_x + kdx_m
        ry = ys[-1] + self.pwl_def_as_breaks.postslope * (rx - last_x)
        xs.append(rx)
        ys.append(ry)

        if plt:
            plt.plot(xs, ys, **kwargs)
            if self.name:
                plt.title('pwl: {0}'.format(self.name))
            plt.show()
Beispiel #18
0
 def parse(cls, arg, default_level=INFO):
     # INTERNAL
     if not arg:
         return default_level
     elif isinstance(arg, cls):
         return arg
     elif is_string(arg):
         return cls._name2level_map().get(arg.lower(), default_level)
     elif is_int(arg):
         if arg < 10:
             # anything below 10 is INFO
             return cls.INFO
         elif arg < 100:
             return cls.WARNING
         elif arg < 1000:
             return cls.ERROR
         else:
             # level fatal prints nothing except fatal errors
             return cls.FATAL
     else:
         raise DOcplexException("Cannot convert this to InfoLevel: {0!r}".format(arg))
Beispiel #19
0
 def terminate(self):
     raise DOcplexException("model has been terminated, no solve is possible...")
Beispiel #20
0
 def set_lp_start(self, var_stats, ct_stats):
     raise DOcplexException('set_lp_start() requires CPLEX, not available for {0}'.format(self.name))
Beispiel #21
0
 def get_cplex(self):
     raise DOcplexException("No CPLEX is available.")  # pragma: no cover
Beispiel #22
0
def docplex_fatal(msg, *args):
    resolved_message = resolve_pattern(msg, args)
    docplex_error_stop_here()
    raise DOcplexException(resolved_message)
Beispiel #23
0
 def fatal(self, msg, args=None):
     self._number_of_fatals += 1
     resolved_message = resolve_pattern(msg, args)
     docplex_error_stop_here()
     raise DOcplexException(resolved_message)
Beispiel #24
0
 def _simulate_error():
     raise DOcplexException("simulate exception")
Beispiel #25
0
 def get_cplex(self):
     raise DOcplexException(
         "{0} engine contains no instance of CPLEX".format(self.name))
 def cannot_modify(self, expr):
     raise DOcplexException("{0}: {1}".format(self._msg, expr))