def _fix_vars(self, expr, model):
     """ Walk through the S-expression, fixing variables. """
     if expr._args is None:
         return expr
     _args = []
     for i in range(len(expr._args)):
         if isinstance(expr._args[i], _ExpressionBase):
             _args.append(self._fix_vars(expr._args[i], model))
         elif (isinstance(expr._args[i], Var) or isinstance(
                 expr._args[i], _VarData)) and expr._args[i].fixed:
             if expr._args[i].value != 0.0:
                 _args.append(
                     NumericConstant(None, None, expr._args[i].value))
         else:
             _args.append(expr._args[i])
     expr._args = _args
     return expr
Пример #2
0
    def _transform_disjunct(self, obj, transBlock, varSet, localVars):
        if hasattr(obj, "_gdp_transformation_info"):
            infodict = obj._gdp_transformation_info
            # If the user has something with our name that is not a dict, we
            # scream. If they have a dict with this name then we are just going
            # to use it...
            if type(infodict) is not dict:
                raise GDP_Error(
                    "Disjunct %s contains an attribute named "
                    "_gdp_transformation_info. The transformation requires "
                    "that it can create this attribute!" % obj.name)
        else:
            infodict = obj._gdp_transformation_info = {}
        # deactivated means either we've already transformed or user deactivated
        if not obj.active:
            if obj.indicator_var.is_fixed():
                if value(obj.indicator_var) == 0:
                    # The user cleanly deactivated the disjunct: there
                    # is nothing for us to do here.
                    return
                else:
                    raise GDP_Error(
                        "The disjunct %s is deactivated, but the "
                        "indicator_var is fixed to %s. This makes no sense." %
                        (obj.name, value(obj.indicator_var)))
            if not infodict.get('relaxed', False):
                raise GDP_Error(
                    "The disjunct %s is deactivated, but the "
                    "indicator_var is not fixed and the disjunct does not "
                    "appear to have been relaxed. This makes no sense." %
                    (obj.name, ))

        if 'chull' in infodict:
            # we've transformed it (with CHull), so don't do it again.
            return

        # add reference to original disjunct to info dict on
        # transformation block
        relaxedDisjuncts = transBlock.relaxedDisjuncts
        relaxationBlock = relaxedDisjuncts[len(relaxedDisjuncts)]
        relaxationBlockInfo = relaxationBlock._gdp_transformation_info = {
            'src': obj,
            'srcVars': ComponentMap(),
            'srcConstraints': ComponentMap(),
            'boundConstraintToSrcVar': ComponentMap(),
        }
        infodict['chull'] = chull = {
            'relaxationBlock': relaxationBlock,
            'relaxedConstraints': ComponentMap(),
            'disaggregatedVars': ComponentMap(),
            'bigmConstraints': ComponentMap(),
        }

        # if this is a disjunctData from an indexed disjunct, we are
        # going to want to check at the end that the container is
        # deactivated if everything in it is. So we save it in our
        # dictionary of things to check if it isn't there already.
        disjParent = obj.parent_component()
        if disjParent.is_indexed() and \
           disjParent not in transBlock.disjContainers:
            transBlock.disjContainers.add(disjParent)

        # add the disaggregated variables and their bigm constraints
        # to the relaxationBlock
        for var in varSet:
            lb = var.lb
            ub = var.ub
            if lb is None or ub is None:
                raise GDP_Error("Variables that appear in disjuncts must be "
                                "bounded in order to use the chull "
                                "transformation! Missing bound for %s." %
                                (var.name))

            disaggregatedVar = Var(within=Reals,
                                   bounds=(min(0, lb), max(0, ub)),
                                   initialize=var.value)
            # naming conflicts are possible here since this is a bunch
            # of variables from different blocks coming together, so we
            # get a unique name
            disaggregatedVarName = unique_component_name(
                relaxationBlock, var.local_name)
            relaxationBlock.add_component(disaggregatedVarName,
                                          disaggregatedVar)
            chull['disaggregatedVars'][var] = disaggregatedVar
            relaxationBlockInfo['srcVars'][disaggregatedVar] = var

            bigmConstraint = Constraint(transBlock.lbub)
            relaxationBlock.add_component(disaggregatedVarName + "_bounds",
                                          bigmConstraint)
            if lb:
                bigmConstraint.add('lb',
                                   obj.indicator_var * lb <= disaggregatedVar)
            if ub:
                bigmConstraint.add('ub',
                                   disaggregatedVar <= obj.indicator_var * ub)
            chull['bigmConstraints'][var] = bigmConstraint
            relaxationBlockInfo['boundConstraintToSrcVar'][
                bigmConstraint] = var

        for var in localVars:
            lb = var.lb
            ub = var.ub
            if lb is None or ub is None:
                raise GDP_Error("Variables that appear in disjuncts must be "
                                "bounded in order to use the chull "
                                "transformation! Missing bound for %s." %
                                (var.name))
            if value(lb) > 0:
                var.setlb(0)
            if value(ub) < 0:
                var.setub(0)

            # naming conflicts are possible here since this is a bunch
            # of variables from different blocks coming together, so we
            # get a unique name
            conName = unique_component_name(relaxationBlock,
                                            var.local_name + "_bounds")
            bigmConstraint = Constraint(transBlock.lbub)
            relaxationBlock.add_component(conName, bigmConstraint)
            bigmConstraint.add('lb', obj.indicator_var * lb <= var)
            bigmConstraint.add('ub', var <= obj.indicator_var * ub)
            chull['bigmConstraints'][var] = bigmConstraint
            relaxationBlockInfo['boundConstraintToSrcVar'][
                bigmConstraint] = var

        var_substitute_map = dict(
            (id(v), newV) for v, newV in iteritems(chull['disaggregatedVars']))
        zero_substitute_map = dict(
            (id(v), NumericConstant(0))
            for v, newV in iteritems(chull['disaggregatedVars']))
        zero_substitute_map.update(
            (id(v), NumericConstant(0)) for v in localVars)

        # Transform each component within this disjunct
        self._transform_block_components(obj, obj, infodict,
                                         var_substitute_map,
                                         zero_substitute_map)

        # deactivate disjunct so we know we've relaxed it
        obj._deactivate_without_fixing_indicator()
        infodict['relaxed'] = True