Ejemplo n.º 1
0
    def _apply_to(self, instance, **kwds):
        #
        # Setup transformation data
        #
        tdata = instance._transformation_data['mpec.simple_disjunction']
        tdata.compl_cuids = []
        #
        # Iterate over the model finding Complementarity components
        #
        for complementarity in instance.component_objects(Complementarity, active=True,
                                                          descend_into=(Block, Disjunct),
                                                          sort=SortComponents.deterministic):
            block = complementarity.parent_block()

            for index in sorted(complementarity.keys()):
                _data = complementarity[index]
                if not _data.active:
                    continue
                #
                _e1 = _data._canonical_expression(_data._args[0])
                _e2 = _data._canonical_expression(_data._args[1])
                if len(_e1)==3 and len(_e2) == 3 and (_e1[0] is None) + (_e1[2] is None) + (_e2[0] is None) + (_e2[2] is None) != 2:
                    raise RuntimeError("Complementarity condition %s must have exactly two finite bounds" % _data.name)
                if len(_e1) == 3 and _e1[0] is None and _e1[2] is None:
                    #
                    # Swap _e1 and _e2.  The ensures that 
                    # only e2 will be an unconstrained expression
                    #
                    _e1, _e2 = _e2, _e1
                if _e2[0] is None and _e2[2] is None:
                    if len(_e1) == 2:
                        _data.c = Constraint(expr=_e1)
                    else:
                        _data.expr1 = Disjunct()
                        _data.expr1.c0 = Constraint(expr= _e1[0] == _e1[1])
                        _data.expr1.c1 = Constraint(expr= _e2[1] >= 0)
                        #
                        _data.expr2 = Disjunct()
                        _data.expr2.c0 = Constraint(expr= _e1[1] == _e1[2])
                        _data.expr2.c1 = Constraint(expr= _e2[1] <= 0)
                        #
                        _data.expr3 = Disjunct()
                        _data.expr3.c0 = Constraint(expr= inequality(_e1[0], _e1[1], _e1[2]))
                        _data.expr3.c1 = Constraint(expr= _e2[1] == 0)
                        _data.complements = Disjunction(expr=(_data.expr1, _data.expr2, _data.expr3))
                else:
                    if _e1[0] is None:
                        tmp1 = _e1[2] - _e1[1]
                    else:
                        tmp1 = _e1[1] - _e1[0]
                    if _e2[0] is None:
                        tmp2 = _e2[2] - _e2[1]
                    else:
                        tmp2 = _e2[1] - _e2[0]
                    _data.expr1 = Disjunct()
                    _data.expr1.c0 = Constraint(expr= tmp1 >= 0)
                    _data.expr1.c1 = Constraint(expr= tmp2 == 0)
                    #
                    _data.expr2 = Disjunct()
                    _data.expr2.c0 = Constraint(expr= tmp1 == 0)
                    _data.expr2.c1 = Constraint(expr= tmp2 >= 0)
                    #
                    _data.complements = Disjunction(expr=(_data.expr1, _data.expr2))
            tdata.compl_cuids.append( ComponentUID(complementarity) )
            block.reclassify_component_type(complementarity, Block)
Ejemplo n.º 2
0
    # Deactivate the old disjunctions / disjuncts
    #
    for i in ans.DISJUNCTIONS:
        disjunctions[i].deactivate()
        for d in disjunctions[i].disjuncts:
            d._deactivate_without_fixing_indicator()

    return ans


if __name__ == '__main__':
    from pyomo.environ import ConcreteModel, Constraint, Var
    m = ConcreteModel()

    def _d(d, i):
        d.x = Var(range(i))
        d.silly = Constraint(expr=d.indicator_var == i)

    m.d = Disjunct([1, 2], rule=_d)

    def _e(e, i):
        e.y = Var(range(2, i))

    m.e = Disjunct([3, 4, 5], rule=_e)

    m.dd = Disjunction(expr=[m.d[1], m.d[2]])
    m.ee = Disjunction(expr=[m.e[3], m.e[4], m.e[5]])
    m.Z = apply_basic_step([m.dd, m.ee])

    m.pprint()
Ejemplo n.º 3
0
def apply_basic_step(disjunctions_or_constraints):
    #
    # Basic steps only apply to XOR'd disjunctions
    #
    disjunctions = list(obj for obj in disjunctions_or_constraints
                        if obj.ctype == Disjunction)
    constraints = list(obj for obj in disjunctions_or_constraints
                       if obj.ctype == Constraint)
    for d in disjunctions:
        if not d.xor:
            raise ValueError(
                "Basic steps can only be applied to XOR'd disjunctions\n\t"
                "(raised by disjunction %s)" % (d.name, ))
        if not d.active:
            logger.warning("Warning: applying basic step to a previously "
                           "deactivated disjunction (%s)" % (d.name, ))

    ans = Block(concrete=True)
    ans.DISJUNCTIONS = Set(initialize=range(len(disjunctions)))
    ans.INDEX = Set(dimen=len(disjunctions),
                    initialize=_squish_singletons(
                        itertools.product(*tuple(
                            range(len(d.disjuncts)) for d in disjunctions))))

    #
    # Form the individual disjuncts for the new basic step
    #
    ans.disjuncts = Disjunct(ans.INDEX)
    for idx in ans.INDEX:
        #
        # Each source disjunct will be copied (cloned) into its own
        # subblock
        #
        ans.disjuncts[idx].src = Block(ans.DISJUNCTIONS)
        for i in ans.DISJUNCTIONS:
            tmp = _clone_all_but_indicator_vars(
                disjunctions[i].disjuncts[idx[i] if isinstance(idx, tuple
                                                               ) else idx])
            for k, v in list(tmp.component_map().items()):
                if v.parent_block() is not tmp:
                    # Skip indicator_var and binary_indicator_var
                    continue
                tmp.del_component(k)
                ans.disjuncts[idx].src[i].add_component(k, v)
        # Copy in the constraints corresponding to the improper disjunctions
        ans.disjuncts[idx].improper_constraints = ConstraintList()
        for constr in constraints:
            if constr.is_indexed():
                for indx in constr:
                    ans.disjuncts[idx].improper_constraints.add(
                        (constr[indx].lower, constr[indx].body,
                         constr[indx].upper))
                    constr[indx].deactivate()
            # need this so that we can take an improper basic step with a
            # ConstraintData
            else:
                ans.disjuncts[idx].improper_constraints.add(
                    (constr.lower, constr.body, constr.upper))
                constr.deactivate()

    #
    # Link the new disjunct indicator_var's to the original
    # indicator_var's.  Since only one of the new
    #
    NAME_BUFFER = {}
    ans.indicator_links = ConstraintList()
    for i in ans.DISJUNCTIONS:
        for j in range(len(disjunctions[i].disjuncts)):
            orig_var = disjunctions[i].disjuncts[j].indicator_var
            orig_binary_var = orig_var.get_associated_binary()
            ans.indicator_links.add(orig_binary_var == sum(
                ans.disjuncts[idx].binary_indicator_var for idx in ans.INDEX
                if (idx[i] if isinstance(idx, tuple) else idx) == j))
            # and throw on a Reference to original on the block
            for v in (orig_var, orig_binary_var):
                name_base = v.getname(fully_qualified=True,
                                      name_buffer=NAME_BUFFER)
                ans.add_component(unique_component_name(ans, name_base),
                                  Reference(v))

    # Form the new disjunction
    ans.disjunction = Disjunction(expr=[ans.disjuncts[i] for i in ans.INDEX])

    #
    # Deactivate the old disjunctions / disjuncts
    #
    for i in ans.DISJUNCTIONS:
        disjunctions[i].deactivate()
        for d in disjunctions[i].disjuncts:
            d._deactivate_without_fixing_indicator()

    return ans
Ejemplo n.º 4
0
def apply_basic_step(disjunctions_or_constraints):
    #
    # Basic steps only apply to XOR'd disjunctions
    #
    disjunctions = list(obj for obj in disjunctions_or_constraints
                        if obj.ctype == Disjunction)
    constraints = list(obj for obj in disjunctions_or_constraints
                       if obj.ctype == Constraint)
    for d in disjunctions:
        if not d.xor:
            raise ValueError(
                "Basic steps can only be applied to XOR'd disjunctions\n\t"
                "(raised by disjunction %s)" % (d.name, ))
        if not d.active:
            logger.warning("Warning: applying basic step to a previously "
                           "deactivated disjunction (%s)" % (d.name, ))

    ans = Block(concrete=True)
    ans.DISJUNCTIONS = Set(initialize=xrange(len(disjunctions)))
    ans.INDEX = Set(dimen=len(disjunctions),
                    initialize=_squish_singletons(
                        itertools.product(*tuple(
                            xrange(len(d.disjuncts)) for d in disjunctions))))

    #
    # Form the individual disjuncts for the new basic step
    #
    ans.disjuncts = Disjunct(ans.INDEX)
    for idx in ans.INDEX:
        #
        # Each source disjunct will be copied (cloned) into its own
        # subblock
        #
        ans.disjuncts[idx].src = Block(ans.DISJUNCTIONS)
        for i in ans.DISJUNCTIONS:
            tmp = _pseudo_clone(
                disjunctions[i].disjuncts[idx[i] if isinstance(idx, tuple
                                                               ) else idx])
            for k, v in list(iteritems(tmp.component_map())):
                if k == 'indicator_var':
                    continue
                tmp.del_component(k)
                ans.disjuncts[idx].src[i].add_component(k, v)
        # Copy in the constraints corresponding to the improper disjunctions
        ans.disjuncts[idx].improper_constraints = ConstraintList()
        for constr in constraints:
            for indx in constr:
                ans.disjuncts[idx].improper_constraints.add(
                    (constr[indx].lower, constr[indx].body,
                     constr[indx].upper))
                constr[indx].deactivate()

    #
    # Link the new disjunct indicator_var's to the original
    # indicator_var's.  Since only one of the new
    #
    ans.indicator_links = ConstraintList()
    for i in ans.DISJUNCTIONS:
        for j in xrange(len(disjunctions[i].disjuncts)):
            ans.indicator_links.add(
                disjunctions[i].disjuncts[j].indicator_var == sum(
                    ans.disjuncts[idx].indicator_var for idx in ans.INDEX
                    if (idx[i] if isinstance(idx, tuple) else idx) == j))

    # Form the new disjunction
    ans.disjunction = Disjunction(expr=[ans.disjuncts[i] for i in ans.INDEX])

    #
    # Deactivate the old disjunctions / disjuncts
    #
    for i in ans.DISJUNCTIONS:
        disjunctions[i].deactivate()
        for d in disjunctions[i].disjuncts:
            d._deactivate_without_fixing_indicator()

    return ans