# ___________________________________________________________________________ # # Pyomo: Python Optimization Modeling Objects # Copyright 2017 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 six import iteritems from pyomo.common.deprecation import deprecated from pyomo.core.base import (Transformation, TransformationFactory, Var, Constraint, Objective, Set, minimize, NonNegativeReals, NonPositiveReals, Reals, Block, Model, ConcreteModel) from pyomo.duality.collect import collect_linear_terms from pyomo.common.deprecation import deprecated 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. # @TransformationFactory.register('duality.linear_dual', doc="Dualize a linear model") class LinearDual_PyomoTransformation(Transformation): @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') 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 iteritems(A[cname]): 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 iteritems(v_domain): 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