Source code for pyomo.duality.plugins

#  ___________________________________________________________________________
#
#  Pyomo: Python Optimization Modeling Objects
#  Copyright (c) 2008-2024
#  National Technology and Engineering Solutions of Sandia, LLC
#  Under the terms of Contract DE-NA0003525 with National Technology and
#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
#  rights in this software.
#  This software is distributed under the 3-clause BSD License.
#  ___________________________________________________________________________

import logging

from pyomo.common.deprecation import deprecated
from pyomo.core.base import (
    Transformation,
    TransformationFactory,
    Var,
    Constraint,
    Objective,
    minimize,
    NonNegativeReals,
    NonPositiveReals,
    Reals,
    Block,
    Model,
    ConcreteModel,
)
from pyomo.duality.collect import collect_linear_terms


[docs] def load(): pass
logger = logging.getLogger('pyomo.core') # # This transformation creates a new block that # is the dual of the specified block. If no block is # specified, then the entire model is dualized. # This returns a new Block object. #
[docs] @TransformationFactory.register( 'duality.linear_dual', doc="[DEPRECATED] Dualize a linear model" ) @deprecated( "Use of the pyomo.duality package is deprecated. There are known bugs " "in pyomo.duality, and we do not recommend the use of this code. " "Development of dualization capabilities has been shifted to " "the Pyomo Adversarial Optimization (PAO) library. Please contact " "William Hart for further details (wehart@sandia.gov).", version='5.6.2', ) class LinearDual_PyomoTransformation(Transformation):
[docs] def __init__(self): super(LinearDual_PyomoTransformation, self).__init__()
def _create_using(self, instance, **kwds): options = kwds.pop('options', {}) bname = options.get('block', None) # # Iterate over the model collecting variable data, # until the block is found. # block = None if block is None: block = instance else: for name, data in instance.component_map(Block, active=True).items(): if name == bname: block = instance if block is None: raise RuntimeError("Missing block: " + bname) # # Generate the dual # instance_ = self._dualize(block) return instance_ def _dualize(self, block, unfixed=[]): """ Generate the dual of a block """ # # Collect linear terms from the block # (A, b_coef, c_rhs, c_sense, d_sense, vnames, cnames, v_domain) = ( collect_linear_terms(block, unfixed) ) ##print(A) ##print(vnames) ##print(cnames) ##print(list(A.keys())) ##print("---") ##print(A.keys()) ##print(c_sense) ##print(c_rhs) # # Construct the block # if isinstance(block, Model): dual = ConcreteModel() else: dual = Block() dual.construct() _vars = {} def getvar(name, ndx=None): v = _vars.get((name, ndx), None) if v is None: v = Var() if ndx is None: v_name = name elif type(ndx) is tuple: v_name = "%s[%s]" % (name, ','.join(map(str, ndx))) else: v_name = "%s[%s]" % (name, str(ndx)) setattr(dual, v_name, v) _vars[name, ndx] = v return v # # Construct the objective # if d_sense == minimize: dual.o = Objective( expr=sum( -b_coef[name, ndx] * getvar(name, ndx) for name, ndx in b_coef ), sense=d_sense, ) else: dual.o = Objective( expr=sum(b_coef[name, ndx] * getvar(name, ndx) for name, ndx in b_coef), sense=d_sense, ) # # Construct the constraints # for cname in A: for ndx, terms in A[cname].items(): expr = 0 for term in terms: expr += term.coef * getvar(term.var, term.ndx) if not (cname, ndx) in c_rhs: c_rhs[cname, ndx] = 0.0 if c_sense[cname, ndx] == 'e': e = expr - c_rhs[cname, ndx] == 0 elif c_sense[cname, ndx] == 'l': e = expr - c_rhs[cname, ndx] <= 0 else: e = expr - c_rhs[cname, ndx] >= 0 c = Constraint(expr=e) if ndx is None: c_name = cname elif type(ndx) is tuple: c_name = "%s[%s]" % (cname, ','.join(map(str, ndx))) else: c_name = "%s[%s]" % (cname, str(ndx)) setattr(dual, c_name, c) # for (name, ndx), domain in v_domain.items(): v = getvar(name, ndx) flag = type(ndx) is tuple and (ndx[-1] == 'lb' or ndx[-1] == 'ub') if domain == 1: v.domain = NonNegativeReals elif domain == -1: v.domain = NonPositiveReals else: # TODO: verify that this case is possible v.domain = Reals return dual