Changeset 9489


Ignore:
Timestamp:
Dec 14, 2014 6:13:37 PM (4 years ago)
Author:
wehart
Message:

Removing the linear dualization logic from pyomo.bilevel.
This now calls the base.linear_dual transformation.

Location:
pyomo/trunk/pyomo
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • pyomo/trunk/pyomo/bilevel/plugins/dual.py

    r9252 r9489  
    1919from pyomo.core.plugins.transform.util import process_canonical_repn
    2020from pyomo.bilevel import SubModel
    21 
     21from pyomo.core.base.plugin import TransformationFactory
    2222import logging
    2323logger = logging.getLogger('pyomo.core')
     
    137137        Generate the dual of a submodel
    138138        """
    139         #
    140         # Start constructing the submodel
    141         #
    142         # Variables are constraints of submodel
    143         # Constraints are unfixed variables of submodel and the parent model.
    144         #
    145         vnames = set()
    146         for (name, data) in submodel.active_components(Constraint).items():
    147             vnames.add((name, data.is_indexed()))
    148         cnames = set(unfixed)
    149         for (name, data) in submodel.active_components(Var).items():
    150             cnames.add((name, data.is_indexed()))
    151         #
    152         dual = SubModel()
    153         for v, is_indexed in vnames:
    154             if is_indexed:
    155                 setattr(dual, v+'_Index', Set(dimen=None))
    156                 setattr(dual, v, Var(getattr(dual, v+'_Index')))
    157             else:
    158                 setattr(dual, v, Var())
    159         for cname, is_indexed in cnames:
    160             if is_indexed:
    161                 setattr(dual, cname+'_Index', Set(dimen=None))
    162                 setattr(dual, cname, Constraint(getattr(dual, cname+'_Index'), noruleinit=True))
    163                 setattr(dual, cname+'_lower_', Var(getattr(dual, cname+'_Index')))
    164                 setattr(dual, cname+'_upper_', Var(getattr(dual, cname+'_Index')))
    165             else:
    166                 setattr(dual, cname, Constraint(noruleinit=True))
    167                 setattr(dual, cname+'_lower_', Var())
    168                 setattr(dual, cname+'_upper_', Var())
    169         dual.construct()
    170         #
    171         A = {}
    172         b_coef = {}
    173         c_rhs = {}
    174         c_sense = {}
    175         d_sense = None
    176         #
    177         # Collect objective
    178         #
    179         for (oname, odata) in submodel.active_components(Objective).items():
    180             for ndx in odata:
    181                 if odata[ndx].sense == maximize:
    182                     o_terms = generate_canonical_repn(-1*odata[ndx].expr, compute_values=False)
    183                     d_sense = minimize
    184                 else:
    185                     o_terms = generate_canonical_repn(odata[ndx].expr, compute_values=False)
    186                     d_sense = maximize
    187                 for i in range(len(o_terms.variables)):
    188                     c_rhs[ o_terms.variables[i].parent_component().name, o_terms.variables[i].index() ] = o_terms.linear[i]
    189             # Stop after the first objective
    190             break
    191         #
    192         # Collect constraints
    193         #
    194         for (name, data) in submodel.active_components(Constraint).items():
    195             for ndx in data:
    196                 con = data[ndx]
    197                 body_terms = generate_canonical_repn(con.body, compute_values=False)
    198                 lower_terms = generate_canonical_repn(con.lower, compute_values=False) if not con.lower is None else None
    199                 upper_terms = generate_canonical_repn(con.upper, compute_values=False) if not con.upper is None else None
    200                 #
    201                 if body_terms.constant is None:
    202                     body_terms.constant = 0
    203                 if not lower_terms is None and not lower_terms.variables is None:
    204                     raise(RuntimeError, "Error during dualization:  Constraint '%s' has a lower bound that is non-constant")
    205                 if not upper_terms is None and not upper_terms.variables is None:
    206                     raise(RuntimeError, "Error during dualization:  Constraint '%s' has an upper bound that is non-constant")
    207                 #
    208                 for i in range(len(body_terms.variables)):
    209                     varname = body_terms.variables[i].parent_component().name
    210                     varndx = body_terms.variables[i].index()
    211                     A.setdefault(body_terms.variables[i].parent_component().name, {}).setdefault(varndx,[]).append( Bunch(coef=body_terms.linear[i], var=name, ndx=ndx) )
    212                    
    213                 #
    214                 if not con.equality:
    215                     #
    216                     # Inequality constraint
    217                     #
    218                     #if not (upper_terms is None or upper_terms.constant is None):
    219                     if lower_terms is None or lower_terms.constant is None:
    220                         #
    221                         # body <= upper
    222                         #
    223                         v = getattr(dual,name)
    224                         vardata = v.add(ndx)
    225                         v.domain = NonPositiveReals
    226                         b_coef[name,ndx] = upper_terms.constant - body_terms.constant
    227                     #elif not (lower_terms is None or lower_terms.constant is None):
    228                     elif upper_terms is None or upper_terms.constant is None:
    229                         #
    230                         # lower <= body
    231                         #
    232                         v = getattr(dual,name)
    233                         vardata = v.add(ndx)
    234                         v.domain = NonNegativeReals
    235                         b_coef[name,ndx] = lower_terms.constant - body_terms.constant
    236                     else:
    237                         #
    238                         # lower <= body <= upper
    239                         #
    240                         v = getattr(dual,name)
    241                         #
    242                         # Dual for lower bound
    243                         #
    244                         ndx_ = tuple(list(ndx).append('lb'))
    245                         vardata = v.add(ndx_)
    246                         vardata.domain = NonNegativeReals
    247                         b_coef[name,ndx] = lower_terms.constant - body_terms.constant
    248                         #
    249                         # Dual for upper bound
    250                         #
    251                         ndx_ = tuple(list(ndx).append('ub'))
    252                         vardata = v.add(ndx_)
    253                         vardata.domain = NonPositiveReals
    254                         b_coef[name,ndx] = upper_terms.constant - body_terms.constant
    255                 else:
    256                     #
    257                     # Equality constraint
    258                     #
    259                     v = getattr(dual,name)
    260                     vardata = v.add(ndx)
    261                     v.domain = Reals
    262                     b_coef[name,ndx] = lower_terms.constant - body_terms.constant
    263         #
    264         # Collect bound constraints
    265         #
    266         for (name, data) in itertools.chain(submodel.active_components(Var).items(), submodel._parent().active_components(Var).items()):
    267             #
    268             # Skip fixed variables (in the parent)
    269             #
    270             if not (name, data.is_indexed()) in cnames:
    271                 continue
    272             #
    273             # Iterate over all variable indices
    274             #
    275             for ndx in data:
    276                 var = data[ndx]
    277                 bounds = var.bounds
    278                 if bounds[0] is None and bounds[1] is None:
    279                     c_sense[name,ndx] = 'e'
    280                 elif bounds[0] is None:
    281                     if bounds[1] == 0.0:
    282                         c_sense[name,ndx] = 'g'
    283                     else:
    284                         c_sense[name,ndx] = 'e'
    285                         #
    286                         # Add constraint that defines the upper bound
    287                         #
    288                         name_ = name + "_upper_"
    289                         varname = data.parent_component().name
    290                         varndx = data[ndx].index()
    291                         A.setdefault(varname, {}).setdefault(varndx,[]).append( Bunch(coef=1.0, var=name_, ndx=ndx) )
    292                         #
    293                         v = getattr(dual,name_)
    294                         vardata = v.add(ndx)
    295                         v.domain = NonPositiveReals
    296                         b_coef[name_,ndx] = bounds[1]
    297                 elif bounds[1] is None:
    298                     if bounds[0] == 0.0:
    299                         c_sense[name,ndx] = 'l'
    300                     else:
    301                         c_sense[name,ndx] = 'e'
    302                         #
    303                         # Add constraint that defines the lower bound
    304                         #
    305                         name_ = name + "_lower_"
    306                         varname = data.parent_component().name
    307                         #from pyomo.core.base.component import Component
    308                         varndx = data[ndx].index()
    309                         A.setdefault(varname, {}).setdefault(varndx,[]).append( Bunch(coef=1.0, var=name_, ndx=ndx) )
    310                         #
    311                         v = getattr(dual,name_)
    312                         vardata = v.add(ndx)
    313                         v.domain = NonNegativeReals
    314                         b_coef[name_,ndx] = bounds[0]
    315                 else:
    316                     # Bounded above and below
    317                     c_sense[name,ndx] = 'e'
    318                     #
    319                     # Add constraint that defines the upper bound
    320                     #
    321                     name_ = name + "_upper_"
    322                     varname = data.parent_component().name
    323                     varndx = data[ndx].index()
    324                     A.setdefault(varname, {}).setdefault(varndx,[]).append( Bunch(coef=1.0, var=name_, ndx=ndx) )
    325                     #
    326                     v = getattr(dual,name_)
    327                     vardata = v.add(ndx)
    328                     v.domain = NonPositiveReals
    329                     b_coef[name_,ndx] = bounds[1]
    330                     #
    331                     # Add constraint that defines the lower bound
    332                     #
    333                     name_ = name + "_lower_"
    334                     varname = data.parent_component().name
    335                     varndx = data[ndx].index()
    336                     A.setdefault(varname, {}).setdefault(varndx,[]).append( Bunch(coef=1.0, var=name_, ndx=ndx) )
    337                     #
    338                     v = getattr(dual,name_)
    339                     vardata = v.add(ndx)
    340                     v.domain = NonNegativeReals
    341                     b_coef[name_,ndx] = bounds[0]
    342                     #raise IOError, "Variable bounded by (%s,%s)" % (str(bounds[0]), str(bounds[1]))
    343         #
    344         if d_sense == minimize:
    345             dual.o = Objective(expr=sum(- b_coef[name,ndx]*getattr(dual,name)[ndx] for name,ndx in b_coef), sense=d_sense)
    346         else:
    347             dual.o = Objective(expr=sum(b_coef[name,ndx]*getattr(dual,name)[ndx] for name,ndx in b_coef), sense=d_sense)
    348         #
    349         for cname in A:
    350             c = getattr(dual, cname)
    351             c_index = getattr(dual, cname+"_Index") if c.is_indexed() else None
    352             for ndx,terms in iteritems(A[cname]):
    353                 if not c_index is None and not ndx in c_index:
    354                     c_index.add(ndx)
    355                 expr = 0
    356                 for term in terms:
    357                     v = getattr(dual,term.var)
    358                     if not term.ndx in v:
    359                         v.add(term.ndx)
    360                     expr += term.coef * v[term.ndx]
    361                 if not (cname, ndx) in c_rhs:
    362                     c_rhs[cname, ndx] = 0.0
    363                 if c_sense[cname,ndx] == 'e':
    364                     c.add(ndx, expr - c_rhs[cname,ndx] == 0)
    365                 elif c_sense[cname,ndx] == 'l':
    366                     c.add(ndx, expr - c_rhs[cname,ndx] <= 0)
    367                 else:
    368                     c.add(ndx, expr - c_rhs[cname,ndx] >= 0)
    369         return dual
     139        transform = TransformationFactory('base.linear_dual')
     140        return transform._dualize(submodel, unfixed)
    370141
    371142    def _xfrm_bilinearities(self, dual):
  • pyomo/trunk/pyomo/bilevel/tests/test_linear_dual.py

    r9463 r9489  
    8282            print("Activating " + kwds['preprocess'])
    8383        #print(' '.join(args))
     84        #output = pyomo_main.run(args)
    8485        try:
    8586            if pproc:
  • pyomo/trunk/pyomo/core/plugins/transform/linear_dual.py

    r9487 r9489  
    1010
    1111from six import iteritems
    12 import itertools
    1312
    1413from pyutilib.misc import Bunch
     
    7372        return instance_
    7473
    75     def _dualize(self, block, unfixed=[], model=True):
     74    def _dualize(self, block, unfixed=[]):
    7675        """
    7776        Generate the dual of a block
     
    207206        # Collect bound constraints
    208207        #
    209         for (name, data) in block.active_components(Var).items():
     208        def all_vars(block):
     209            """
     210            This conditionally chains together the active variables in the current block with
     211            the active variables in all of the parent blocks (if any exist).
     212            """
     213            while not block is None:
     214                for (name, data) in block.active_components(Var).items():
     215                    yield (name, data)
     216                block = block.parent_block()
     217
     218        for (name, data) in all_vars(block):
    210219            #
    211220            # Skip fixed variables (in the parent)
Note: See TracChangeset for help on using the changeset viewer.