Exemplo n.º 1
0
def _build_equality_set(m):
    """Construct an equality set map.

    Maps all variables to the set of variables that are linked to them by
    equality. Mapping takes place using id(). That is, if you have x = y, then
    you would have id(x) -> ComponentSet([x, y]) and id(y) -> ComponentSet([x,
    y]) in the mapping.

    """
    #: dict: map of var UID to the set of all equality-linked var UIDs
    eq_var_map = ComponentMap()
    relevant_vars = ComponentSet()
    for constr in m.component_data_objects(ctype=Constraint,
                                           active=True,
                                           descend_into=True):
        # Check to make sure the constraint is of form v1 - v2 == 0
        if (value(constr.lower) == 0 and value(constr.upper) == 0 and
                constr.body.polynomial_degree() == 1):
            repn = generate_standard_repn(constr.body)
            # only take the variables with nonzero coefficients
            vars_ = [v for i, v in enumerate(repn.linear_vars)
                     if repn.linear_coefs[i]]
            if (len(vars_) == 2 and
                    sorted(l for l in repn.linear_coefs if l) == [-1, 1]):
                # this is an a == b constraint.
                v1 = vars_[0]
                v2 = vars_[1]
                set1 = eq_var_map.get(v1, ComponentSet([v1]))
                set2 = eq_var_map.get(v2, ComponentSet([v2]))
                relevant_vars.update([v1, v2])
                set1.update(set2)  # set1 is now the union
                for v in set1:
                    eq_var_map[v] = set1

    return eq_var_map, relevant_vars
Exemplo n.º 2
0
 def canonical_form(self, compute_values=True):
     """Build a canonical representation of the body of
     this constraints"""
     from pyomo.repn.standard_repn import \
         StandardRepn
     variables = []
     coefficients = []
     constant = 0
     for v, c in self.terms:
         if v.is_expression_type():
             v = v.expr
         if not v.fixed:
             variables.append(v)
             if compute_values:
                 coefficients.append(value(c))
             else:
                 coefficients.append(c)
         else:
             if compute_values:
                 constant += value(c) * v()
             else:
                 constant += c * v
     repn = StandardRepn()
     repn.linear_vars = tuple(variables)
     repn.linear_coefs = tuple(coefficients)
     repn.constant = constant
     return repn
Exemplo n.º 3
0
    def visiting_potential_leaf(self, node):
        if node.__class__ in nonpyomo_leaf_types:
            self.bnds_dict[node] = (node, node)
            return True, None

        if node.is_variable_type():
            if node.is_fixed():
                lb = value(node.value)
                ub = lb
            else:
                lb = value(node.lb)
                ub = value(node.ub)
                if lb is None:
                    lb = -math.inf
                if ub is None:
                    ub = math.inf
            self.bnds_dict[node] = (lb, ub)
            return True, None

        if not node.is_expression_type():
            assert is_fixed(node)
            val = value(node)
            self.bnds_dict[node] = (val, val)
            return True, None

        return False, None
Exemplo n.º 4
0
def _get_equality_linked_variables(constraint):
    """Return the two variables linked by an equality constraint x == y.

    If the constraint does not match this form, skip it.

    """
    if value(constraint.lower) != 0 or value(constraint.upper) != 0:
        # LB and UB on constraint must be zero; otherwise, return empty tuple.
        return ()
    if constraint.body.polynomial_degree() != 1:
        # must be a linear constraint; otherwise, return empty tuple.
        return ()

    # Generate the standard linear representation
    repn = generate_standard_repn(constraint.body)
    nonzero_coef_vars = tuple(v for i, v in enumerate(repn.linear_vars)
                              # if coefficient on variable is nonzero
                              if repn.linear_coefs[i] != 0)
    if len(nonzero_coef_vars) != 2:
        # Expect two variables with nonzero cofficient in constraint;
        # otherwise, return empty tuple.
        return ()
    if sorted(coef for coef in repn.linear_coefs if coef != 0) != [-1, 1]:
        # Expect a constraint of form x == y --> 0 == -1 * x + 1 * y;
        # otherwise, return empty tuple.
        return ()
    # Above checks are satisifed. Return the variables.
    return nonzero_coef_vars
Exemplo n.º 5
0
    def visiting_potential_leaf(self, node):
        """
        Visiting a potential leaf.

        Return True if the node is not expanded.
        """
        if node.__class__ in nonpyomo_leaf_types:
            return True, node

        if node.is_parameter_type():
            if node._component()._mutable:
                raise FixedExpressionError()
            return True, value(node)


        if node.is_variable_type():
            if node.fixed:
                raise FixedExpressionError()
            else:
                raise NonConstantExpressionError()

        if not node.is_expression_type():
            return True, value(node)

        return False, None
Exemplo n.º 6
0
def _fix_equality_fixed_variables(model, scaling_tolerance=1E-10):
    """Detects variables fixed by a constraint: ax=b.

    Fixes the variable to the constant value (b/a) and deactivates the relevant
    constraint.

    This sub-transformation is different than contrib.detect_fixed_vars because
    it looks for x = const rather than x.lb = x.ub.

    """
    for constraint in model.component_data_objects(
        ctype=Constraint, active=True, descend_into=True
    ):
        if not (constraint.has_lb() and constraint.has_ub()):
            # Constraint is not an equality. Skip.
            continue
        if value(constraint.lower) != value(constraint.upper):
            # Constraint is not an equality. Skip.
            continue
        if constraint.body.polynomial_degree() != 1:
            # Constraint is not linear. Skip.
            continue

        # Generate the standard linear representation
        repn = generate_standard_repn(constraint.body)
        # Generator of tuples with the coefficient and variable object for
        # nonzero coefficients.
        nonzero_coef_vars = (
            (repn.linear_coefs[i], v)
            for i, v in enumerate(repn.linear_vars)
            # if coefficient on variable is nonzero
            if repn.linear_coefs[i] != 0)
        # get the coefficient and variable object
        coef, var = next(nonzero_coef_vars)
        if next(nonzero_coef_vars, None) is not None:
            # Expect one variable with nonzero cofficient in constraint;
            # otherwise, skip.
            continue
        # Constant term on the constraint body
        const = repn.constant if repn.constant is not None else 0

        if abs(coef) <= scaling_tolerance:
            logger.warn(
                "Skipping fixed variable processing for constraint %s: "
                "%s * %s + %s = %s because coefficient %s is below "
                "tolerance of %s. Check your problem scaling." %
                (constraint.name, coef, var.name, const,
                 value(constraint.lower), coef, scaling_tolerance))
            continue

        # Constraint has form lower <= coef * var + const <= upper. We know that
        # lower = upper, so coef * var + const = lower.
        var_value = (value(constraint.lower) - const) / coef

        var.fix(var_value)
        constraint.deactivate()
Exemplo n.º 7
0
 def is_binary(self):
     """Returns :const:`True` when the domain type is
     :class:`IntegerSet` and the bounds are within
     [0,1]."""
     lb, ub = self.bounds
     return self.is_integer() and \
         (lb is not None) and \
         (ub is not None) and \
         (value(lb) >= 0) and \
         (value(ub) <= 1)
Exemplo n.º 8
0
    def _apply_to(self, instance, **kwargs):
        config = self.CONFIG(kwargs)
        if config.tmp and not hasattr(instance, '_tmp_trivial_deactivated_constrs'):
            instance._tmp_trivial_deactivated_constrs = ComponentSet()
        elif config.tmp:
            logger.warning(
                'Deactivating trivial constraints on the block {} for which '
                'trivial constraints were previously deactivated. '
                'Reversion will affect all deactivated constraints.'.format(
                    instance.name))

        # Trivial constraints are those that do not contain any variables, ie.
        # the polynomial degree is 0
        trivial_constraints = (
            constr
            for constr in instance.component_data_objects(
                ctype=Constraint, active=True, descend_into=True)
            if constr.body.polynomial_degree() == 0)

        for constr in trivial_constraints:
            # We need to check each constraint to sure that it is not violated.
            constr_lb = value(
                constr.lower) if constr.has_lb() else float('-inf')
            constr_ub = value(
                constr.upper) if constr.has_ub() else float('inf')
            constr_value = value(constr.body)

            # Check if the lower bound is violated outside a given tolerance
            if (constr_value + config.tolerance <= constr_lb):
                if config.ignore_infeasible:
                    continue
                else:
                    raise ValueError(
                        'Trivial constraint {} violates LB {} ≤ BODY {}.'
                        .format(constr.name, constr_lb, constr_value))

            # Check if the upper bound is violated outside a given tolerance
            if (constr_value >= constr_ub + config.tolerance):
                if config.ignore_infeasible:
                    continue
                else:
                    raise ValueError(
                        'Trivial constraint {} violates BODY {} ≤ UB {}.'
                        .format(constr.name, constr_value, constr_ub))

            # Constraint is not infeasible. Deactivate it.
            if config.tmp:
                instance._tmp_trivial_deactivated_constrs.add(constr)
            config.return_trivial.append(constr)
            constr.deactivate()
Exemplo n.º 9
0
 def construct(self, values=None):
     """
     Initialize set data
     """
     if self._constructed:
         return
     timer = ConstructionTimer(self)
     self._constructed=True
     #
     # We call value() here for cases like Expressions, mutable
     # Params and the like
     #
     self._start_val = value(self._start)
     self._end_val = value(self._end)
     self._step_val = value(self._step)
     #
     # The set generates integer values if the starting value,
     # step and end value are all integers.  Otherwise, the set
     # generates real values.
     #
     if type(self._start_val) is int and type(self._step) is int and type(self._end_val) is int:
         self.domain = Integers
     else:
         self.domain = Reals
     #
     # Compute the set length and upper bound
     #
     if self.filter is None and self.validate is None:
         #
         # Directly compute the number of elements in the set, from
         # which the upper-bound is computed.
         #
         self._len = int(math.floor((self._end_val-self._start_val+self._step_val+1e-7)//self._step_val))
         ub = self._start_val + (self._len-1)*self._step_val
     else:
         #
         # Iterate through the set to compute the upper bound
         # and number of elements.
         #
         ub = self._start_val
         ctr=0
         for i in self:
             ub = i
             ctr += 1
         self._len = ctr
     #
     # Set the bounds information
     #
     self._bounds = (self._start_val, ub)
     timer.report()
Exemplo n.º 10
0
def _detect_fixed_variables(m):
    """Detect fixed variables due to constraints of form var = const."""
    new_fixed_vars = ComponentSet()
    for constr in m.component_data_objects(ctype=Constraint,
                                           active=True,
                                           descend_into=True):
        if constr.equality and constr.body.polynomial_degree() == 1:
            repn = generate_standard_repn(constr.body)
            if len(repn.linear_vars) == 1 and repn.linear_coefs[0]:
                var = repn.linear_vars[0]
                coef = float(repn.linear_coefs[0])
                const = repn.constant
                var_val = (value(constr.lower) - value(const)) / coef
                var.fix(var_val)
                new_fixed_vars.add(var)
    return new_fixed_vars
Exemplo n.º 11
0
    def visiting_potential_leaf(self, node):
        """
        Visiting a potential leaf.

        Return True if the node is not expanded.
        """
        if node.__class__ in nonpyomo_leaf_types:
            return True, node

        if node.is_variable_type():
            return True, value(node)

        if not node.is_expression_type():
            return True, value(node)

        return False, None
Exemplo n.º 12
0
    def _apply_to(self, instance, **kwargs):
        config = self.CONFIG(kwargs)

        if config.tmp:
            instance._xfrm_detect_fixed_vars_old_values = ComponentMap()

        for var in instance.component_data_objects(
                ctype=Var, descend_into=True):
            if var.fixed or var.lb is None or var.ub is None:
                # if the variable is already fixed, or if it is missing a
                # bound, we skip it.
                continue
            if fabs(value(var.lb) - value(var.ub)) <= config.tolerance:
                if config.tmp:
                    instance._xfrm_detect_fixed_vars_old_values[var] = \
                        var.value
                var.fix(var.lb)
Exemplo n.º 13
0
    def _apply_to(self, instance, **kwds):
        config = self.CONFIG(kwds)
        if config.tmp and not hasattr(instance, '_tmp_propagate_original_bounds'):
            instance._tmp_propagate_original_bounds = Suffix(
                direction=Suffix.LOCAL)
        eq_var_map, relevant_vars = _build_equality_set(instance)
        processed = ComponentSet()
        # Go through each variable in an equality set to propagate the variable
        # bounds to all equality-linked variables.
        for var in relevant_vars:
            # If we have already processed the variable, skip it.
            if var in processed:
                continue

            var_equality_set = eq_var_map.get(var, ComponentSet([var]))

            #: variable lower bounds in the equality set
            lbs = [v.lb for v in var_equality_set if v.has_lb()]
            max_lb = max(lbs) if len(lbs) > 0 else None
            #: variable upper bounds in the equality set
            ubs = [v.ub for v in var_equality_set if v.has_ub()]
            min_ub = min(ubs) if len(ubs) > 0 else None

            # Check  for error due to bound cross-over
            if max_lb is not None and min_ub is not None and max_lb > min_ub:
                # the lower bound is above the upper bound. Raise a ValueError.
                # get variable with the highest lower bound
                v1 = next(v for v in var_equality_set if v.lb == max_lb)
                # get variable with the lowest upper bound
                v2 = next(v for v in var_equality_set if v.ub == min_ub)
                raise ValueError(
                    'Variable {} has a lower bound {} '
                    ' > the upper bound {} of variable {}, '
                    'but they are linked by equality constraints.'
                    .format(v1.name, value(v1.lb), value(v2.ub), v2.name))

            for v in var_equality_set:
                if config.tmp:
                    # TODO warn if overwriting
                    instance._tmp_propagate_original_bounds[v] = (
                        v.lb, v.ub)
                v.setlb(max_lb)
                v.setub(min_ub)

            processed.update(var_equality_set)
Exemplo n.º 14
0
 def finalize(self, ans):
     if isinstance(ans, cmodel.Node):
         return ans
     else:
         if len(self._constant_pool) == 0:
             self._constant_pool = set(cmodel.create_constants(100))
         const = self._constant_pool.pop()
         const.value = value(ans)
         return const
Exemplo n.º 15
0
 def __call__(self, exception=True):
     try:
         return sum(value(c, exception=exception) * \
                    v(exception=exception) for v,c in self.terms)
     except (ValueError, TypeError):
         if exception:
             raise ValueError("one or more terms "
                              "could not be evaluated")
         return None
Exemplo n.º 16
0
 def slack(self):
     """
     Returns the smaller of lslack and uslack values
     """
     if self.lower is None:
         return value(self.upper) - value(self.body)
     elif self.upper is None:
         return value(self.body) - value(self.lower)
     return min(
         value(self.upper) - value(self.body),
         value(self.body) - value(self.lower))
Exemplo n.º 17
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 xrange(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
Exemplo n.º 18
0
    def visiting_potential_leaf(self, node):
        if node.__class__ in nonpyomo_leaf_types:
            return True, None

        if node.is_variable_type():
            lb, ub = self.bnds_dict[node]

            if node.is_binary() or node.is_integer():
                """
                This bit of code has two purposes:
                1) Improve the bounds on binary and integer variables with the fact that they are integer.
                2) Account for roundoff error. If the lower bound of a binary variable comes back as 
                   1e-16, the lower bound may actually be 0. This could potentially cause problems when 
                   handing the problem to a MIP solver. Some solvers are robust to this, but some may not be
                   and may give the wrong solution. Even if the correct solution is found, this could 
                   introduce numerical problems.
                """
                lb = max(math.floor(lb), math.ceil(lb - self.integer_tol))
                ub = min(math.ceil(ub), math.floor(ub + self.integer_tol))
                if lb < value(node.lb):
                    lb = value(node.lb)  # don't make the bounds worse than the original bounds
                if ub > value(node.ub):
                    ub = value(node.ub)  # don't make the bounds worse than the original bounds
                self.bnds_dict[node] = (lb, ub)

            lb, ub = self.bnds_dict[node]
            if lb != -math.inf:
                node.setlb(lb)
            if ub != math.inf:
                node.setub(ub)
            return True, None

        if not node.is_expression_type():
            return True, None

        if node.__class__ in _prop_bnds_root_to_leaf_map:
            _prop_bnds_root_to_leaf_map[node.__class__](node, self.bnds_dict)
        else:
            logger.warning('Unsupported expression type for FBBT: {0}. Bounds will not be improved in this part of '
                           'the tree.'
                           ''.format(str(type(node))))

        return False, None
Exemplo n.º 19
0
    def _apply_to(self, instance, overwrite=False):
        """Apply the transformation.

        Kwargs:
            overwrite: if False, transformation will not overwrite existing
                variable values.
        """
        for var in instance.component_data_objects(ctype=Var,
                                                   descend_into=True):
            if var.fixed:
                continue
            if var.value is not None and not overwrite:
                continue
            if var.lb is not None and value(var.lb) > 0:
                var.set_value(value(var.lb))
            elif var.ub is not None and value(var.ub) < 0:
                var.set_value(value(var.ub))
            else:
                var.set_value(0)
Exemplo n.º 20
0
 def _pprint(self):
     """Print component information."""
     headers = [
         ("Size", len(self)),
         ("Index", self._index if self.is_indexed() else None),
     ]
     if self._units is not None:
         headers.append(('Units', str(self._units)))
     return ( headers,
              self._data.items(),
              ( "Lower","Value","Upper","Fixed","Stale","Domain"),
              lambda k, v: [ value(v.lb),
                             v.value,
                             value(v.ub),
                             v.fixed,
                             v.stale,
                             v.domain
                             ]
              )
Exemplo n.º 21
0
    def visiting_potential_leaf(self, node):
        """
        Visiting a potential leaf.

        Return True if the node is not expanded.
        """
        #print("ISLEAF")
        #print(node.__class__)
        if node is None:
            return True, None

        if node.__class__ in native_types:
            return True, _ftoa(node)

        if node.is_expression_type():
            # we will descend into this, so type checking will happen later
            if node.is_component_type():
                self.treechecker(node)
            return False, None

        if node.is_component_type():
            if isinstance(node, ICategorizedObject):
                _ctype = node.ctype
            else:
                _ctype = node.type()
            if _ctype not in valid_expr_ctypes_minlp:
                # Make sure all components in active constraints
                # are basic ctypes we know how to deal with.
                raise RuntimeError(
                    "Unallowable component '%s' of type %s found in an active "
                    "constraint or objective.\nThe GAMS writer cannot export "
                    "expressions with this component type." %
                    (node.name, _ctype.__name__))

        if node.is_variable_type():
            if node.fixed:
                return True, _ftoa(value(node))
            else:
                self.variables.add(id(node))
                label = self.smap.getSymbol(node)
                return True, label

        return True, _ftoa(value(node))
Exemplo n.º 22
0
 def _apply_operation(self, result):
     obj = result[0].__getitem__(tuple(result[1:]))
     if obj.__class__ in nonpyomo_leaf_types:
         return obj
     # Note that because it is possible (likely) that the result
     # could be an IndexedComponent_slice object, must test "is
     # True", as the slice will return a list of values.
     if obj.is_numeric_type() is True:
         obj = value(obj)
     return obj
Exemplo n.º 23
0
 def _add_variables(self, variables: List[_GeneralVarData]):
     cvars = cmodel.create_vars(len(variables))
     for ndx, v in enumerate(variables):
         cv = cvars[ndx]
         cv.name = self._symbol_map.getSymbol(v, self._var_labeler)
         if not v.is_continuous():
             raise NotImplementedError('NLWriter currently only supports continuous variables')
         lb = value(v.lb)
         ub = value(v.ub)
         if lb is not None:
             cv.lb = lb
         if ub is not None:
             cv.ub = ub
         if v.value is not None:
             cv.value = v.value
         if v.is_fixed():
             cv.fixed = True
         self._pyomo_var_to_solver_var_map[id(v)] = cv
         self._solver_var_to_pyomo_var_map[cv] = v
Exemplo n.º 24
0
    def _apply_to(self, instance, overwrite=False):
        """Apply the transformation.

        Kwargs:
            overwrite: if False, transformation will not overwrite existing
                variable values.
        """
        for var in instance.component_data_objects(
                ctype=Var, descend_into=True):
            if var.fixed:
                continue
            if var.value is not None and not overwrite:
                continue
            if var.lb is not None and value(var.lb) > 0:
                var.set_value(value(var.lb))
            elif var.ub is not None and value(var.ub) < 0:
                var.set_value(value(var.ub))
            else:
                var.set_value(0)
Exemplo n.º 25
0
 def _initialize_members(self, init_set):
     """Initialize variable data for all indices in a set."""
     #
     # Initialize values
     #
     if self._value_init_rule is not None:
         #
         # Initialize values with a rule
         #
         if self.is_indexed():
             for key in init_set:
                 vardata = self._data[key]
                 val = apply_indexed_rule(self,
                                          self._value_init_rule,
                                          self._parent(),
                                          key)
                 val = value(val)
                 vardata.set_value(val)
         else:
             val = self._value_init_rule(self._parent())
             val = value(val)
             self.set_value(val)
     elif self._value_init_value is not None:
         #
         # Initialize values with a value
         if self._value_init_value.__class__ is dict:
             for key in init_set:
                 # Skip indices that are not in the
                 # dictionary. This arises when
                 # initializing VarList objects with a
                 # dictionary.
                 # What does this continue do here?
                 if not key in self._value_init_value:
                     continue
                 val = self._value_init_value[key]
                 vardata = self._data[key]
                 vardata.set_value(val)
         else:
             val = value(self._value_init_value)
             for key in init_set:
                 vardata = self._data[key]
                 vardata.set_value(val)
Exemplo n.º 26
0
 def uslack(self):
     """
     Returns the value of U-f(x) for constraints of the form:
         (L <=) f(x) <= U
         U >= f(x) (>= L)
     """
     ub = self.ub
     if ub is None:
         return _inf
     else:
         return ub - value(self.body)
Exemplo n.º 27
0
 def lslack(self):
     """
     Returns the value of f(x)-L for constraints of the form:
         L <= f(x) (<= U)
         (U >=) f(x) >= L
     """
     lb = self.lb
     if lb is None:
         return _inf
     else:
         return value(self.body) - lb
Exemplo n.º 28
0
    def _transformContainer(self, obj):
        """Find all disjuncts in the container and transform them."""
        for disjunct in obj.component_data_objects(ctype=Disjunct,
                                                   active=True,
                                                   descend_into=True):
            _binary = disjunct.binary_indicator_var
            if fabs(value(_binary) - 1) <= self.config.integer_tolerance:
                disjunct.indicator_var.fix(True)
                self._transformContainer(disjunct)
            elif fabs(value(_binary)) <= self.config.integer_tolerance:
                disjunct.deactivate()
            else:
                raise ValueError(
                    'Non-binary indicator variable value %s for disjunct %s' %
                    (disjunct.name, value(_binary)))

        for disjunction in obj.component_data_objects(ctype=Disjunction,
                                                      active=True,
                                                      descend_into=True):
            self._transformDisjunctionData(disjunction)
Exemplo n.º 29
0
 def ub(self):
     """Access the value of the upper bound of a constraint expression."""
     bound = value(self._ub())
     if bound is not None and not math.isfinite(bound):
         if bound == _inf:
             bound = None
         else:
             raise ValueError(
                 "Constraint '%s' created with an invalid non-finite "
                 "upper bound (%s)." % (self.name, bound))
     return bound
Exemplo n.º 30
0
    def __init__(self, var_list, symbol_map):
        self.binary = []
        self.ints = []
        self.positive = []
        self.reals = []

        # categorize variables
        for var in var_list:
            v = symbol_map.getObject(var)
            if v.is_binary():
                self.binary.append(var)
            elif v.is_integer():
                if (v.has_lb() and (value(v.lb) >= 0)) and \
                   (v.has_ub() and (value(v.ub) <= 1)):
                    self.binary.append(var)
                else:
                    self.ints.append(var)
            elif value(v.lb) == 0:
                self.positive.append(var)
            else:
                self.reals.append(var)
Exemplo n.º 31
0
 def lslack(self):
     """Lower slack (value - lb). Returns :const:`None` if
     the variable value is :const:`None`."""
     val = self.value
     if val is None:
         return None
     lb = self.lb
     if lb is None:
         lb = _neg_inf
     else:
         lb = value(lb)
     return val - lb
Exemplo n.º 32
0
 def uslack(self):
     """Upper slack (ub - value). Returns :const:`None` if
     the variable value is :const:`None`."""
     val = self.value
     if val is None:
         return None
     ub = self.ub
     if ub is None:
         ub = _pos_inf
     else:
         ub = value(ub)
     return ub - val
Exemplo n.º 33
0
 def slack(self):
     """
     Returns the smaller of lslack and uslack values
     """
     lb = self.lb
     ub = self.ub
     body = value(self.body)
     if lb is None:
         return ub - body
     elif ub is None:
         return body - lb
     return min(ub - body, body - lb)
Exemplo n.º 34
0
 def uslack(self):
     """Upper slack (ub - value). Returns :const:`None` if
     the variable value is :const:`None`."""
     val = self.value
     if val is None:
         return None
     ub = self.ub
     if ub is None:
         ub = _pos_inf
     else:
         ub = value(ub)
     return ub - val
Exemplo n.º 35
0
 def _update_variables(self, variables: List[_GeneralVarData]):
     for v in variables:
         cv = self._pyomo_var_to_solver_var_map[id(v)]
         if not v.is_continuous():
             raise NotImplementedError('NLWriter currently only supports continuous variables')
         lb = value(v.lb)
         ub = value(v.ub)
         if lb is None:
             cv.lb = -cmodel.inf
         else:
             cv.lb = lb
         if ub is None:
             cv.ub = cmodel.inf
         else:
             cv.ub = ub
         if v.value is not None:
             cv.value = v.value
         if v.is_fixed():
             cv.fixed = True
         else:
             cv.fixed = False
Exemplo n.º 36
0
    def _add_var(self, var):
        varname = self._symbol_map.getSymbol(var, self._labeler)
        vtype = self._gurobi_vtype_from_var(var)
        if var.has_lb():
            lb = value(var.lb)
        else:
            lb = -self._gurobipy.GRB.INFINITY
        if var.has_ub():
            ub = value(var.ub)
        else:
            ub = self._gurobipy.GRB.INFINITY

        gurobipy_var = self._solver_model.addVar(lb=lb, ub=ub, vtype=vtype, name=varname)

        self._pyomo_var_to_solver_var_map[var] = gurobipy_var
        self._solver_var_to_pyomo_var_map[gurobipy_var] = var
        self._referenced_variables[var] = 0

        if var.is_fixed():
            gurobipy_var.setAttr('lb', var.value)
            gurobipy_var.setAttr('ub', var.value)
Exemplo n.º 37
0
    def __init__(self, var_list, symbol_map):
        self.binary = []
        self.ints = []
        self.positive = []
        self.reals = []

        # categorize variables
        for var in var_list:
            v = symbol_map.getObject(var)
            if v.is_binary():
                self.binary.append(var)
            elif v.is_integer():
                if (v.has_lb() and (value(v.lb) >= 0)) and \
                   (v.has_ub() and (value(v.ub) <= 1)):
                    self.binary.append(var)
                else:
                    self.ints.append(var)
            elif value(v.lb) == 0:
                self.positive.append(var)
            else:
                self.reals.append(var)
Exemplo n.º 38
0
 def lslack(self):
     """Lower slack (value - lb). Returns :const:`None` if
     the variable value is :const:`None`."""
     val = self.value
     if val is None:
         return None
     lb = self.lb
     if lb is None:
         lb = _neg_inf
     else:
         lb = value(lb)
     return val - lb
Exemplo n.º 39
0
    def _apply_to(self, model, **kwds):
        config = self.CONFIG(kwds)

        for constr in model.component_data_objects(ctype=Constraint,
                                                   active=True,
                                                   descend_into=True):
            # Check if the constraint is k * x + c1 <= c2 or c2 <= k * x + c1
            repn = generate_standard_repn(constr.body)
            if not repn.is_linear() or len(repn.linear_vars) != 1:
                # Skip nonlinear constraints, trivial constraints, and those
                # that involve more than one variable.
                continue
            else:
                var = repn.linear_vars[0]
                const = repn.constant
                coef = float(repn.linear_coefs[0])

            if coef == 0:
                # Skip trivial constraints
                continue
            elif coef > 0:
                if constr.has_ub():
                    new_ub = (value(constr.upper) - const) / coef
                    var_ub = float('inf') if var.ub is None else var.ub
                    var.setub(min(var_ub, new_ub))
                if constr.has_lb():
                    new_lb = (value(constr.lower) - const) / coef
                    var_lb = float('-inf') if var.lb is None else var.lb
                    var.setlb(max(var_lb, new_lb))
            elif coef < 0:
                if constr.has_ub():
                    new_lb = (value(constr.upper) - const) / coef
                    var_lb = float('-inf') if var.lb is None else var.lb
                    var.setlb(max(var_lb, new_lb))
                if constr.has_lb():
                    new_ub = (value(constr.lower) - const) / coef
                    var_ub = float('inf') if var.ub is None else var.ub
                    var.setub(min(var_ub, new_ub))

            if var.is_integer() or var.is_binary():
                # Make sure that the lb and ub are integral. Use safe construction if near to integer.
                if var.has_lb():
                    var.setlb(
                        int(
                            min(math.ceil(var.lb - config.tolerance),
                                math.ceil(var.lb))))
                if var.has_ub():
                    var.setub(
                        int(
                            max(math.floor(var.ub + config.tolerance),
                                math.floor(var.ub))))

            if var is not None and var.value is not None:
                _adjust_var_value_if_not_feasible(var)

            if (config.detect_fixed and var.has_lb() and var.has_ub() and
                    fabs(value(var.lb) - value(var.ub)) <= config.tolerance):
                var.fix(var.lb)

            constr.deactivate()
Exemplo n.º 40
0
    def visiting_potential_leaf(self, node):
        """
        Visiting a potential leaf.

        Return True if the node is not expanded.
        """
        if node is None:
            return True, None

        if node.__class__ in native_types:
            return True, ftoa(node)

        if node.is_expression_type():
            # we will descend into this, so type checking will happen later
            if node.is_component_type():
                self.treechecker(node)
            return False, None

        if node.is_component_type():
            if node.ctype not in valid_expr_ctypes_minlp:
                # Make sure all components in active constraints
                # are basic ctypes we know how to deal with.
                raise RuntimeError(
                    "Unallowable component '%s' of type %s found in an active "
                    "constraint or objective.\nThe GAMS writer cannot export "
                    "expressions with this component type."
                    % (node.name, node.ctype.__name__))
            if node.ctype is not Var:
                # For these, make sure it's on the right model. We can check
                # Vars later since they don't disappear from the expressions
                self.treechecker(node)

        if node.is_variable_type():
            if node.fixed:
                return True, ftoa(value(node))
            else:
                label = self.smap.getSymbol(node)
                return True, label

        return True, ftoa(value(node))
Exemplo n.º 41
0
    def visiting_potential_leaf(self, node):
        """
        Visiting a potential leaf.

        Return True if the node is not expanded.
        """
        #print("ISLEAF")
        #print(node.__class__)

        if node.__class__ in native_types:
            return True, ftoa(node)

        if node.is_expression_type():
            # Special handling if NPV and semi-NPV types:
            if not node.is_potentially_variable():
                return True, ftoa(value(node))
            if node.__class__ is EXPR.MonomialTermExpression:
                return True, self._monomial_to_string(node)
            if node.__class__ is EXPR.LinearExpression:
                return True, self._linear_to_string(node)
            # we will descend into this, so type checking will happen later
            return False, None

        if node.is_component_type():
            if node.ctype not in valid_expr_ctypes_minlp:
                # Make sure all components in active constraints
                # are basic ctypes we know how to deal with.
                raise RuntimeError(
                    "Unallowable component '%s' of type %s found in an active "
                    "constraint or objective.\nThe GAMS writer cannot export "
                    "expressions with this component type." %
                    (node.name, node.ctype.__name__))

        if node.is_fixed():
            return True, ftoa(value(node))
        else:
            assert node.is_variable_type()
            self.variables.add(id(node))
            return True, self.smap.getSymbol(node)
Exemplo n.º 42
0
 def _transformDisjunctData(self, obj):
     """Fix the disjunct either to a Block or a deactivated Block."""
     if fabs(value(obj.indicator_var) - 1) <= self.config.integer_tolerance:
         # Disjunct is active. Convert to Block.
         obj.parent_block().reclassify_component_type(obj, Block)
         obj.indicator_var.fix(1)
         # Process the components attached to this disjunct.
         self._transformContainer(obj)
     elif fabs(value(obj.indicator_var)) <= self.config.integer_tolerance:
         obj.parent_block().reclassify_component_type(obj, Block)
         obj.indicator_var.fix(0)
         # Deactivate all constituent constraints and disjunctions
         # HACK I do not deactivate the whole block because some writers
         # do not look for variables in deactivated blocks.
         for constr in obj.component_objects(
                 ctype=(Constraint, Disjunction),
                 active=True, descend_into=True):
             constr.deactivate()
     else:
         raise ValueError(
             'Non-binary indicator variable value %s for disjunct %s'
             % (obj.name, value(obj.indicator_var)))
Exemplo n.º 43
0
    def _apply_to(self, instance):
        for constr in instance.component_data_objects(ctype=Constraint,
                                                      active=True,
                                                      descend_into=True):
            if not constr.body.polynomial_degree() == 1:
                continue  # constraint not linear. Skip.

            repn = generate_standard_repn(constr.body)
            if (constr.has_ub() and (
                (repn.constant is None and value(constr.upper) == 0) or
                repn.constant == value(constr.upper)
            )):
                # term1 + term2 + term3 + ... <= 0
                # all var terms need to be non-negative
                if all(
                    # variable has 0 coefficient
                    coef == 0 or
                    # variable is non-negative and has non-negative coefficient
                    (repn.linear_vars[i].has_lb() and
                     value(repn.linear_vars[i].lb) >= 0 and
                     coef >= 0) or
                    # variable is non-positive and has non-positive coefficient
                    (repn.linear_vars[i].has_ub() and
                     value(repn.linear_vars[i].ub) <= 0 and
                     coef <= 0) for i, coef in enumerate(repn.linear_coefs)):
                    for i, coef in enumerate(repn.linear_coefs):
                        if not coef == 0:
                            repn.linear_vars[i].fix(0)
                    continue
            if (constr.has_lb() and (
                (repn.constant is None and value(constr.lower) == 0) or
                repn.constant == value(constr.lower)
            )):
                # term1 + term2 + term3 + ... >= 0
                # all var terms need to be non-positive
                if all(
                    # variable has 0 coefficient
                    coef == 0 or
                    # variable is non-negative and has non-positive coefficient
                    (repn.linear_vars[i].has_lb() and
                     value(repn.linear_vars[i].lb) >= 0 and
                     coef <= 0) or
                    # variable is non-positive and has non-negative coefficient
                    (repn.linear_vars[i].has_ub() and
                     value(repn.linear_vars[i].ub) <= 0 and
                     coef >= 0) for i, coef in enumerate(repn.linear_coefs)):
                    for i, coef in enumerate(repn.linear_coefs):
                        if not coef == 0:
                            repn.linear_vars[i].fix(0)
Exemplo n.º 44
0
    def _add_var(self, var):
        varname = self._symbol_map.getSymbol(var, self._labeler)
        vtype = self._mosek_vtype_from_var(var)
        if var.has_lb():
            lb = value(var.lb)
        else:
            lb = '0'
        if var.has_ub():
            ub = value(var.ub)
        else:
            ub = '0'

        bound_type = self.set_var_boundtype(var, ub, lb)
        self._solver_model.appendvars(1)
        index = self._solver_model.getnumvar() - 1
        self._solver_model.putvarbound(index, bound_type, float(lb), float(ub))
        self._solver_model.putvartype(index, vtype)
        self._solver_model.putvarname(index, varname)

        self._pyomo_var_to_solver_var_map[var] = index
        self._solver_var_to_pyomo_var_map[index] = var
        self._referenced_variables[var] = 0
Exemplo n.º 45
0
    def _apply_to(self, instance):
        for constr in instance.component_data_objects(ctype=Constraint,
                                                      active=True,
                                                      descend_into=True):
            if not constr.body.polynomial_degree() == 1:
                continue  # constraint not linear. Skip.

            repn = generate_standard_repn(constr.body)
            if (constr.has_ub() and (
                (repn.constant is None and value(constr.upper) == 0) or
                repn.constant == value(constr.upper)
            )):
                # term1 + term2 + term3 + ... <= 0
                # all var terms need to be non-negative
                if all(
                    # variable has 0 coefficient
                    coef == 0 or
                    # variable is non-negative and has non-negative coefficient
                    (repn.linear_vars[i].has_lb() and
                     value(repn.linear_vars[i].lb) >= 0 and
                     coef >= 0) or
                    # variable is non-positive and has non-positive coefficient
                    (repn.linear_vars[i].has_ub() and
                     value(repn.linear_vars[i].ub) <= 0 and
                     coef <= 0) for i, coef in enumerate(repn.linear_coefs)):
                    for i, coef in enumerate(repn.linear_coefs):
                        if not coef == 0:
                            repn.linear_vars[i].fix(0)
                    continue
            if (constr.has_lb() and (
                (repn.constant is None and value(constr.lower) == 0) or
                repn.constant == value(constr.lower)
            )):
                # term1 + term2 + term3 + ... >= 0
                # all var terms need to be non-positive
                if all(
                    # variable has 0 coefficient
                    coef == 0 or
                    # variable is non-negative and has non-positive coefficient
                    (repn.linear_vars[i].has_lb() and
                     value(repn.linear_vars[i].lb) >= 0 and
                     coef <= 0) or
                    # variable is non-positive and has non-negative coefficient
                    (repn.linear_vars[i].has_ub() and
                     value(repn.linear_vars[i].ub) <= 0 and
                     coef >= 0) for i, coef in enumerate(repn.linear_coefs)):
                    for i, coef in enumerate(repn.linear_coefs):
                        if not coef == 0:
                            repn.linear_vars[i].fix(0)
Exemplo n.º 46
0
    def visiting_potential_leaf(self, node):
        """
        Visiting a potential leaf.

        Return True if the node is not expanded.
        """
        if node is None:
            return True, None

        if node.__class__ in native_types:
            return True, str(node)

        if node.is_variable_type():
            if node.fixed:
                return True, str(value(node))
            label = self.smap.getSymbol(node)
            return True, label

        if not node.is_expression_type():
            return True, str(value(node))

        return False, None
Exemplo n.º 47
0
    def display(self, prefix="", ostream=None):
        """
        Print component state information

        This duplicates logic in Component.pprint()
        """
        if not self.active:
            return
        if ostream is None:
            ostream = sys.stdout
        tab="    "
        ostream.write(prefix+self.local_name+" : ")
        ostream.write("Size="+str(len(self)))

        ostream.write("\n")
        tabular_writer( ostream, prefix+tab,
                        ((k,v) for k,v in iteritems(self._data) if v.active),
                        ( "Lower","Body","Upper" ),
                        lambda k, v: [ value(v.lower),
                                       v.body(),
                                       value(v.upper),
                                       ] )
Exemplo n.º 48
0
    def display(self, prefix="", ostream=None):
        """
        Print component state information

        This duplicates logic in Component.pprint()
        """
        if not self.active:
            return
        if ostream is None:
            ostream = sys.stdout
        tab="    "
        ostream.write(prefix+self.local_name+" : ")
        ostream.write("Size="+str(len(self)))

        ostream.write("\n")
        tabular_writer( ostream, prefix+tab,
                        ((k,v) for k,v in iteritems(self._data) if v.active),
                        ( "Lower","Body","Upper" ),
                        lambda k, v: [ value(v.lower),
                                       v.body(),
                                       value(v.upper),
                                       ] )
Exemplo n.º 49
0
    def _add_var(self, var):
        varname = self._symbol_map.getSymbol(var, self._labeler)
        vtype = self._gurobi_vtype_from_var(var)
        if var.has_lb():
            lb = value(var.lb)
        else:
            lb = -self._gurobipy.GRB.INFINITY
        if var.has_ub():
            ub = value(var.ub)
        else:
            ub = self._gurobipy.GRB.INFINITY
        if var.is_fixed():
            lb = value(var.value)
            ub = value(var.value)

        gurobipy_var = self._solver_model.addVar(lb=lb, ub=ub, vtype=vtype, name=varname)

        self._pyomo_var_to_solver_var_map[var] = gurobipy_var
        self._solver_var_to_pyomo_var_map[gurobipy_var] = var
        self._referenced_variables[var] = 0

        self._needs_updated = True
Exemplo n.º 50
0
    def update_var(self, var):
        """Update a single variable in the solver's model.

        This will update bounds, fix/unfix the variable as needed, and
        update the variable type.

        Parameters
        ----------
        var: Var (scalar Var or single _VarData)

        """
        # see PR #366 for discussion about handling indexed
        # objects and keeping compatibility with the
        # pyomo.kernel objects
        #if var.is_indexed():
        #    for child_var in var.values():
        #        self.update_var(child_var)
        #    return
        if var not in self._pyomo_var_to_solver_var_map:
            raise ValueError(
                'The Var provided to update_var needs to be added first: {0}'.
                format(var))
        gurobipy_var = self._pyomo_var_to_solver_var_map[var]
        vtype = self._gurobi_vtype_from_var(var)
        if var.is_fixed():
            lb = var.value
            ub = var.value
        else:
            lb = -self._gurobipy.GRB.INFINITY
            ub = self._gurobipy.GRB.INFINITY
            if var.has_lb():
                lb = value(var.lb)
            if var.has_ub():
                ub = value(var.ub)
        gurobipy_var.setAttr('lb', lb)
        gurobipy_var.setAttr('ub', ub)
        gurobipy_var.setAttr('vtype', vtype)
        self._needs_updated = True
Exemplo n.º 51
0
    def _add_var(self, var):
        varname = self._symbol_map.getSymbol(var, self._labeler)
        vtype = self._cplex_vtype_from_var(var)
        if var.has_lb():
            lb = value(var.lb)
        else:
            lb = -self._cplex.infinity
        if var.has_ub():
            ub = value(var.ub)
        else:
            ub = self._cplex.infinity

        self._solver_model.variables.add(lb=[lb], ub=[ub], types=[vtype], names=[varname])

        self._pyomo_var_to_solver_var_map[var] = varname
        self._solver_var_to_pyomo_var_map[varname] = var
        self._pyomo_var_to_ndx_map[var] = self._ndx_count
        self._ndx_count += 1
        self._referenced_variables[var] = 0

        if var.is_fixed():
            self._solver_model.variables.set_lower_bounds(varname, var.value)
            self._solver_model.variables.set_upper_bounds(varname, var.value)
Exemplo n.º 52
0
    def _add_var(self, var):
        varname = self._symbol_map.getSymbol(var, self._labeler)
        vtype = self._cplex_vtype_from_var(var)
        if var.has_lb():
            lb = value(var.lb)
        else:
            lb = -self._cplex.infinity
        if var.has_ub():
            ub = value(var.ub)
        else:
            ub = self._cplex.infinity

        self._solver_model.variables.add(lb=[lb], ub=[ub], types=[vtype], names=[varname])

        self._pyomo_var_to_solver_var_map[var] = varname
        self._solver_var_to_pyomo_var_map[varname] = var
        self._pyomo_var_to_ndx_map[var] = self._ndx_count
        self._ndx_count += 1
        self._referenced_variables[var] = 0

        if var.is_fixed():
            self._solver_model.variables.set_lower_bounds(varname, var.value)
            self._solver_model.variables.set_upper_bounds(varname, var.value)
Exemplo n.º 53
0
    def _apply_to(self, instance, **kwds):
        config = self.CONFIG(kwds)
        if config.tmp and not hasattr(instance, '_tmp_propagate_fixed'):
            instance._tmp_propagate_fixed = ComponentSet()
        eq_var_map, relevant_vars = _build_equality_set(instance)
        #: ComponentSet: The set of all fixed variables
        fixed_vars = ComponentSet((v for v in relevant_vars if v.fixed))
        newly_fixed = _detect_fixed_variables(instance)
        if config.tmp:
            instance._tmp_propagate_fixed.update(newly_fixed)
        fixed_vars.update(newly_fixed)
        processed = ComponentSet()
        # Go through each fixed variable to propagate the 'fixed' status to all
        # equality-linked variabes.
        for v1 in fixed_vars:
            # If we have already processed the variable, skip it.
            if v1 in processed:
                continue

            eq_set = eq_var_map.get(v1, ComponentSet([v1]))
            for v2 in eq_set:
                if (v2.fixed and value(v1) != value(v2)):
                    raise ValueError(
                        'Variables {} and {} have conflicting fixed '
                        'values of {} and {}, but are linked by '
                        'equality constraints.'
                        .format(v1.name,
                                v2.name,
                                value(v1),
                                value(v2)))
                elif not v2.fixed:
                    v2.fix(value(v1))
                    if config.tmp:
                        instance._tmp_propagate_fixed.add(v2)
            # Add all variables in the equality set to the set of processed
            # variables.
            processed.update(eq_set)
Exemplo n.º 54
0
    def visiting_potential_leaf(self, node):
        if node.__class__ in nonpyomo_leaf_types:
            self.val_dict[node] = node
            if node not in self.der_dict:
                self.der_dict[node] = 0
            return True, node

        if not node.is_expression_type():
            val = value(node)
            self.val_dict[node] = val
            if node not in self.der_dict:
                self.der_dict[node] = 0
            return True, val

        return False, None
Exemplo n.º 55
0
    def test_pickle(self):
        v = variable()
        e = noclone(v)
        self.assertEqual(type(e), noclone)
        self.assertIs(type(e.expr), variable)
        eup = pickle.loads(
            pickle.dumps(e))
        self.assertEqual(type(eup), noclone)
        self.assertTrue(e is not eup)
        self.assertIs(type(eup.expr), variable)
        self.assertIs(type(e.expr), variable)
        self.assertTrue(eup.expr is not e.expr)

        del e
        del v

        v = variable(value=1)
        b = block()
        b.v = v
        eraw = b.v + 1
        b.e = 1 + noclone(eraw)
        bup = pickle.loads(
            pickle.dumps(b))
        self.assertTrue(isinstance(bup.e, NumericValue))
        self.assertEqual(value(bup.e), 3.0)
        b.v.value = 2
        self.assertEqual(value(b.e), 4.0)
        self.assertEqual(value(bup.e), 3.0)
        bup.v.value = -1
        self.assertEqual(value(b.e), 4.0)
        self.assertEqual(value(bup.e), 1.0)

        self.assertIs(b.v.parent, b)
        self.assertIs(bup.v.parent, bup)

        del b.v
Exemplo n.º 56
0
    def _apply_to(self, instance, overwrite=False):
        """Apply the transformation.

        Kwargs:
            overwrite: if False, transformation will not overwrite existing
                variable values.
        """
        for var in instance.component_data_objects(
                ctype=Var, descend_into=True):
            if var.fixed:
                continue
            if var.value is not None and not overwrite:
                continue
            if var.lb is None and var.ub is None:
                # If LB and UB do not exist, set variable value to 0
                var.set_value(0)
            elif var.lb is None:
                # if one bound does not exist, set variable value to the other
                var.set_value(value(var.ub))
            elif var.ub is None:
                # if one bound does not exist, set variable value to the other
                var.set_value(value(var.lb))
            else:
                var.set_value((value(var.lb) + value(var.ub)) / 2.)
Exemplo n.º 57
0
 def uslack(self):
     """Upper slack (ub - body). Returns :const:`None` if
     a value for the body can not be computed."""
     # this method is written so that constraint
     # types that build the body expression on the
     # fly do not have to here
     body = self(exception=False)
     if body is None:
         return None
     ub = self.ub
     if ub is None:
         ub = _pos_inf
     else:
         ub = value(ub)
     return ub - body
Exemplo n.º 58
0
 def lslack(self):
     """Lower slack (body - lb). Returns :const:`None` if
     a value for the body can not be computed."""
     # this method is written so that constraint
     # types that build the body expression on the
     # fly do not have to here
     body = self(exception=False)
     if body is None:
         return None
     lb = self.lb
     if lb is None:
         lb = _neg_inf
     else:
         lb = value(lb)
     return body - lb
Exemplo n.º 59
0
    def __call__(self, exception=False):
        """Compute the value of this expression.

        Args:
            exception (bool): Indicates if an exception
                should be raised when instances of
                NumericValue fail to evaluate due to one or
                more objects not being initialized to a
                numeric value (e.g, one or more variables in
                an algebraic expression having the value
                None). Default is :const:`True`.

        Returns:
            numeric value or None
        """
        return value(self._expr, exception=exception)