コード例 #1
0
    def _create_using(self, model, **kwds):
        """
        Tranform a model to its Lagrangian dual.
        """

        # Optional naming schemes for dual variables and constraints
        constraint_suffix = kwds.pop("dual_constraint_suffix", "_constraint")
        variable_prefix = kwds.pop("dual_variable_prefix", "p_")

        # Optional naming schemes to pass to StandardForm
        sf_kwds = {}
        sf_kwds["slack_names"] = kwds.pop("slack_names", "auxiliary_slack")
        sf_kwds["excess_names"] = kwds.pop("excess_names", "auxiliary_excess")
        sf_kwds["lb_names"] = kwds.pop("lb_names", "_lower_bound")
        sf_kwds["ub_names"] = kwds.pop("ub_names", "_upper_bound")
        sf_kwds["pos_suffix"] = kwds.pop("pos_suffix", "_plus")
        sf_kwds["neg_suffix"] = kwds.pop("neg_suffix", "_minus")

        # Get the standard form model
        sf_transform = StandardForm()
        sf = sf_transform(model, **sf_kwds)

        # Roughly, parse the objectives and constraints to form A, b, and c of
        #
        # min  c'x
        # s.t. Ax  = b
        #       x >= 0
        #
        # and create a new model from them.

        # We use sparse matrix representations

        # {constraint_name: {variable_name: coefficient}}
        A = _sparse(lambda: _sparse(0))

        # {constraint_name: coefficient}
        b = _sparse(0)

        # {variable_name: coefficient}
        c = _sparse(0)

        # Walk constaints
        for (con_name, con_array) in sf.component_map(Constraint, active=True).items():
            for con in (con_array[ndx] for ndx in con_array._index):
                # The qualified constraint name
                cname = "%s%s" % (variable_prefix, con.local_name)

                # Process the body of the constraint
                body_terms = process_canonical_repn(
                    generate_standard_repn(con.body))

                # Add a numeric constant to the 'b' vector, if present
                b[cname] -= body_terms.pop(None, 0)

                # Add variable coefficients to the 'A' matrix
                row = _sparse(0)
                for (vname, coef) in body_terms.items():
                    row["%s%s" % (vname, constraint_suffix)] += coef

                # Process the upper bound of the constraint. We rely on
                # StandardForm to produce equality constraints, thus
                # requiring us only to check the lower bounds.
                lower_terms = process_canonical_repn(
                    generate_standard_repn(con.lower))

                # Add a numeric constant to the 'b' matrix, if present
                b[cname] += lower_terms.pop(None, 0)

                # Add any variables to the 'A' matrix, if present
                for (vname, coef) in lower_terms.items():
                    row["%s%s" % (vname, constraint_suffix)] -= coef

                A[cname] = row

        # Walk objectives. Multiply all coefficients by the objective's 'sense'
        # to convert maximizing objectives to minimizing ones.
        for (obj_name, obj_array) in sf.component_map(Objective, active=True).items():
            for obj in (obj_array[ndx] for ndx in obj_array._index):
                # The qualified objective name

                # Process the objective
                terms = process_canonical_repn(
                    generate_standard_repn(obj.expr))

                # Add coefficients
                for (name, coef) in terms.items():
                    c["%s%s" % (name, constraint_suffix)] += coef*obj_array.sense

        # Form the dual
        dual = AbstractModel()

        # Make constraint index set
        constraint_set_init = []
        for (var_name, var_array) in sf.component_map(Var, active=True).items():
            for var in (var_array[ndx] for ndx in var_array._index):
                constraint_set_init.append("%s%s" %
                                           (var.local_name, constraint_suffix))

        # Make variable index set
        variable_set_init = []
        dual_variable_roots = []
        for (con_name, con_array) in sf.component_map(Constraint, active=True).items():
            for con in (con_array[ndx] for ndx in con_array._index):
                dual_variable_roots.append(con.local_name)
                variable_set_init.append("%s%s" % (variable_prefix, con.local_name))

        # Create the dual Set and Var objects
        dual.var_set = Set(initialize=variable_set_init)
        dual.con_set = Set(initialize=constraint_set_init)
        dual.vars = Var(dual.var_set)

        # Make the dual constraints
        def constraintRule(A, c, ndx, model):
            return sum(A[v][ndx] * model.vars[v] for v in model.var_set) <= \
                   c[ndx]
        dual.cons = Constraint(dual.con_set,
                               rule=partial(constraintRule, A, c))

        # Make the dual objective (maximizing)
        def objectiveRule(b, model):
            return sum(b[v] * model.vars[v] for v in model.var_set)
        dual.obj = Objective(rule=partial(objectiveRule, b), sense=maximize)

        return dual.create()
コード例 #2
0
ファイル: dual_transformation.py プロジェクト: qtothec/pyomo
    def _create_using(self, model, **kwds):
        """
        Tranform a model to its Lagrangian dual.
        """

        # Optional naming schemes for dual variables and constraints
        constraint_suffix = kwds.pop("dual_constraint_suffix", "_constraint")
        variable_prefix = kwds.pop("dual_variable_prefix", "p_")

        # Optional naming schemes to pass to StandardForm
        sf_kwds = {}
        sf_kwds["slack_names"] = kwds.pop("slack_names", "auxiliary_slack")
        sf_kwds["excess_names"] = kwds.pop("excess_names", "auxiliary_excess")
        sf_kwds["lb_names"] = kwds.pop("lb_names", "_lower_bound")
        sf_kwds["ub_names"] = kwds.pop("ub_names", "_upper_bound")
        sf_kwds["pos_suffix"] = kwds.pop("pos_suffix", "_plus")
        sf_kwds["neg_suffix"] = kwds.pop("neg_suffix", "_minus")

        # Get the standard form model
        sf_transform = StandardForm()
        sf = sf_transform(model, **sf_kwds)

        # Roughly, parse the objectives and constraints to form A, b, and c of
        #
        # min  c'x
        # s.t. Ax  = b
        #       x >= 0
        #
        # and create a new model from them.

        # We use sparse matrix representations

        # {constraint_name: {variable_name: coefficient}}
        A = _sparse(lambda: _sparse(0))

        # {constraint_name: coefficient}
        b = _sparse(0)

        # {variable_name: coefficient}
        c = _sparse(0)

        # Walk constaints
        for (con_name, con_array) in sf.component_map(Constraint, active=True).items():
            for con in (con_array[ndx] for ndx in con_array._index):
                # The qualified constraint name
                cname = "%s%s" % (variable_prefix, con.local_name)

                # Process the body of the constraint
                body_terms = process_canonical_repn(
                    generate_canonical_repn(con.body))

                # Add a numeric constant to the 'b' vector, if present
                b[cname] -= body_terms.pop(None, 0)

                # Add variable coefficients to the 'A' matrix
                row = _sparse(0)
                for (vname, coef) in body_terms.items():
                    row["%s%s" % (vname, constraint_suffix)] += coef

                # Process the upper bound of the constraint. We rely on
                # StandardForm to produce equality constraints, thus
                # requiring us only to check the lower bounds.
                lower_terms = process_canonical_repn(
                    generate_canonical_repn(con.lower))

                # Add a numeric constant to the 'b' matrix, if present
                b[cname] += lower_terms.pop(None, 0)

                # Add any variables to the 'A' matrix, if present
                for (vname, coef) in lower_terms.items():
                    row["%s%s" % (vname, constraint_suffix)] -= coef

                A[cname] = row

        # Walk objectives. Multiply all coefficients by the objective's 'sense'
        # to convert maximizing objectives to minimizing ones.
        for (obj_name, obj_array) in sf.component_map(Objective, active=True).items():
            for obj in (obj_array[ndx] for ndx in obj_array._index):
                # The qualified objective name

                # Process the objective
                terms = process_canonical_repn(
                    generate_canonical_repn(obj.expr))

                # Add coefficients
                for (name, coef) in terms.items():
                    c["%s%s" % (name, constraint_suffix)] += coef*obj_array.sense

        # Form the dual
        dual = AbstractModel()

        # Make constraint index set
        constraint_set_init = []
        for (var_name, var_array) in sf.component_map(Var, active=True).items():
            for var in (var_array[ndx] for ndx in var_array._index):
                constraint_set_init.append("%s%s" %
                                           (var.local_name, constraint_suffix))

        # Make variable index set
        variable_set_init = []
        dual_variable_roots = []
        for (con_name, con_array) in sf.component_map(Constraint, active=True).items():
            for con in (con_array[ndx] for ndx in con_array._index):
                dual_variable_roots.append(con.local_name)
                variable_set_init.append("%s%s" % (variable_prefix, con.local_name))

        # Create the dual Set and Var objects
        dual.var_set = Set(initialize=variable_set_init)
        dual.con_set = Set(initialize=constraint_set_init)
        dual.vars = Var(dual.var_set)

        # Make the dual constraints
        def constraintRule(A, c, ndx, model):
            return sum(A[v][ndx] * model.vars[v] for v in model.var_set) <= \
                   c[ndx]
        dual.cons = Constraint(dual.con_set,
                               rule=partial(constraintRule, A, c))

        # Make the dual objective (maximizing)
        def objectiveRule(b, model):
            return sum(b[v] * model.vars[v] for v in model.var_set)
        dual.obj = Objective(rule=partial(objectiveRule, b), sense=maximize)

        return dual.create()
コード例 #3
0
    def _create_using(self, model, **kwds):
        """
        Force all variables to lie in the nonnegative orthant.

        Required arguments:
            model       The model to transform.

        Optional keyword arguments:
          pos_suffix    The suffix applied to the 'positive' component of
                            converted variables. Default is '_plus'.
          neg_suffix    The suffix applied to the 'positive' component of
                            converted variables. Default is '_minus'.
        """
        #
        # Optional naming schemes
        #
        pos_suffix = kwds.pop("pos_suffix", "_plus")
        neg_suffix = kwds.pop("neg_suffix", "_minus")
        #
        # We first perform an abstract problem transformation. Then, if model
        # data is available, we instantiate the new model. If not, we construct
        # a mapping that can later be used to populate the new model.
        #
        nonneg = model.clone()
        components = collectAbstractComponents(nonneg)

        # Map from variable base names to a {index, rule} map
        constraint_rules = {}

        # Map from variable base names to a rule defining the domains for that
        # variable
        domain_rules = {}

        # Map from variable base names to its set of indices
        var_indices = {}

        # Map from fully qualified variable names to replacement expressions.
        # For now, it is actually a map from a variable name to a closure that
        # must later be evaulated with a model containing the replacement
        # variables.
        var_map = {}

        #
        # Get the constraints that enforce the bounds and domains of each
        # variable
        #
        for var_name in components["Var"]:
            var = nonneg.__getattribute__(var_name)

            # Individual bounds and domains
            orig_bounds = {}
            orig_domain = {}

            # New indices
            indices = set()

            # Map from constraint names to a constraint rule.
            constraints = {}

            # Map from variable indices to a domain
            domains = {}

            for ndx in var:
                # Fully qualified variable name
                vname = create_name(str(var_name), ndx)

                # We convert each index to a string to avoid difficult issues
                # regarding appending a suffix to tuples.
                #
                # If the index is None, this casts the index to a string,
                # which doesn't match up with how Pyomo treats None indices
                # internally. Replace with "" to be consistent.
                if ndx is None:
                    v_ndx = ""
                else:
                    v_ndx = str(ndx)

                # Get the variable bounds
                lb = value(var[ndx].lb)
                ub = value(var[ndx].ub)
                orig_bounds[ndx] = (lb, ub)

                # Get the variable domain
                if var[ndx].domain is not None:
                    orig_domain[ndx] = var[ndx].domain
                else:
                    orig_domain[ndx] = var.domain

                # Determine the replacement expression. Either a new single
                # variable with the same attributes, or a sum of two new
                # variables.
                #
                # If both the bounds and domain allow for negative values,
                # replace the variable with the sum of nonnegative ones.

                bounds_neg = (orig_bounds[ndx] == (None, None)
                              or orig_bounds[ndx][0] is None
                              or orig_bounds[ndx][0] < 0)
                domain_neg = (orig_domain[ndx] is None
                              or orig_domain[ndx].bounds()[0] is None
                              or orig_domain[ndx].bounds()[0] < 0)
                if bounds_neg and domain_neg:
                    # Make two new variables.
                    posVarSuffix = "%s%s" % (v_ndx, pos_suffix)
                    negVarSuffix = "%s%s" % (v_ndx, neg_suffix)

                    new_indices = (posVarSuffix, negVarSuffix)

                    # Replace the original variable with a sum expression
                    expr_dict = {posVarSuffix: 1, negVarSuffix: -1}
                else:
                    # Add the new index. Lie if is 'None', since Pyomo treats
                    # 'None' specially as a key.
                    #
                    # More lies: don't let a blank index exist. Replace it with
                    # '_'. I don't actually have a justification for this other
                    # than that allowing "" as a key will eventually almost
                    # certainly lead to a strange bug.
                    if v_ndx is None:
                        t_ndx = "None"
                    elif v_ndx == "":
                        t_ndx = "_"
                    else:
                        t_ndx = v_ndx

                    new_indices = (t_ndx, )

                    # Replace the original variable with a sum expression
                    expr_dict = {t_ndx: 1}

                # Add the new indices
                for x in new_indices:
                    indices.add(x)

                # Replace the original variable with an expression
                var_map[vname] = partial(self.sumRule, var_name, expr_dict)

                # Enforce bounds as constraints
                if orig_bounds[ndx] != (None, None):
                    cname = "%s_%s" % (vname, "bounds")
                    tmp = orig_bounds[ndx]
                    constraints[cname] = partial(self.boundsConstraintRule,
                                                 tmp[0], tmp[1], var_name,
                                                 expr_dict)

                # Enforce the bounds of the domain as constraints
                if orig_domain[ndx] != None:
                    cname = "%s_%s" % (vname, "domain_bounds")
                    tmp = orig_domain[ndx].bounds()
                    constraints[cname] = partial(self.boundsConstraintRule,
                                                 tmp[0], tmp[1], var_name,
                                                 expr_dict)

                # Domain will either be NonNegativeReals, NonNegativeIntegers,
                # or Binary. We consider Binary because some solvers may
                # optimize over binary variables.
                if var[ndx].is_continuous():
                    for x in new_indices:
                        domains[x] = NonNegativeReals
                elif var[ndx].is_binary():
                    for x in new_indices:
                        domains[x] = Binary
                elif var[ndx].is_integer():
                    for x in new_indices:
                        domains[x] = NonNegativeIntegers
                else:
                    logger.warning("Warning: domain '%s' not recognized, "
                                   "defaulting to 'NonNegativeReals'" %
                                   (var.domain, ))
                    for x in new_indices:
                        domains[x] = NonNegativeReals

            constraint_rules[var_name] = constraints
            domain_rules[var_name] = partial(self.exprMapRule, domains)
            var_indices[var_name] = indices

        # Remove all existing variables.
        toRemove = []
        for (attr_name, attr) in nonneg.__dict__.items():
            if isinstance(attr, Var):
                toRemove.append(attr_name)
        for attr_name in toRemove:
            nonneg.__delattr__(attr_name)

        # Add the sets defining the variables, then the variables
        for (k, v) in var_indices.items():
            sname = "%s_indices" % k
            nonneg.__setattr__(sname, Set(initialize=v))
            nonneg.__setattr__(
                k,
                Var(nonneg.__getattribute__(sname),
                    domain=domain_rules[k],
                    bounds=(0, None)))

        # Construct the model to get the variables and their indices
        # recognized in the model
        ##nonneg = nonneg.create()

        # Safe to evaluate the modifiedVars mapping
        for var in var_map:
            var_map[var] = var_map[var](nonneg)

        # Map from constraint base names to maps from indices to expressions
        constraintExprs = {}

        #
        # Convert all modified variables in all constraints in the original
        # problem
        #
        for conName in components["Constraint"]:
            con = nonneg.__getattribute__(conName)

            # Map from constraint indices to a corrected expression
            exprMap = {}

            for (ndx, cdata) in con._data.items():
                lower = _walk_expr(cdata.lower, var_map)
                body = _walk_expr(cdata.body, var_map)
                upper = _walk_expr(cdata.upper, var_map)

                # Lie if ndx is None. Pyomo treats 'None' indices specially.
                if ndx is None:
                    ndx = "None"

                # Cast indices to strings, otherwise tuples ruin everything
                exprMap[str(ndx)] = (lower, body, upper)

            # Add to list of expression maps
            constraintExprs[conName] = exprMap

        # Map from constraint base names to maps from indices to expressions
        objectiveExprs = {}

        #
        # Convert all modified variables in all objectives in the original
        # problem
        #
        for objName in components["Objective"]:
            obj = nonneg.__getattribute__(objName)

            # Map from objective indices to a corrected expression
            exprMap = {}

            for (ndx, odata) in obj._data.items():
                exprMap[ndx] = _walk_expr(odata.expr, var_map)

            # Add to list of expression maps
            objectiveExprs[objName] = exprMap

        # Make the modified original constraints
        for (conName, ruleMap) in constraintExprs.items():
            # Make the set of indices
            sname = conName + "_indices"
            _set = Set(initialize=ruleMap.keys())
            nonneg.__setattr__(sname, _set)
            _set.construct()

            # Define the constraint
            _con = Constraint(nonneg.__getattribute__(sname),
                              rule=partial(self.exprMapRule, ruleMap))
            nonneg.__setattr__(conName, _con)
            _con.construct()

        # Make the bounds constraints
        for (varName, ruleMap) in constraint_rules.items():
            conName = varName + "_constraints"
            # Make the set of indices
            sname = conName + "_indices"
            _set = Set(initialize=ruleMap.keys())
            nonneg.__setattr__(sname, _set)
            _set.construct()

            # Define the constraint
            _con = Constraint(nonneg.__getattribute__(sname),
                              rule=partial(self.delayedExprMapRule, ruleMap))
            nonneg.__setattr__(conName, _con)
            _con.construct()

        # Make the objectives
        for (objName, ruleMap) in objectiveExprs.items():
            # Make the set of indices
            sname = objName + "_indices"
            _set = Set(initialize=ruleMap.keys())
            nonneg.__setattr__(sname, _set)
            _set.construct()

            # Define the constraint
            _obj = Objective(nonneg.__getattribute__(sname),
                             rule=partial(self.exprMapRule, ruleMap))
            nonneg.__setattr__(objName, _obj)
            _obj.construct()

        return nonneg
コード例 #4
0
    def _create_using(self, model, **kwds):
        """
        Force all variables to lie in the nonnegative orthant.

        Required arguments:
            model       The model to transform.

        Optional keyword arguments:
          pos_suffix    The suffix applied to the 'positive' component of
                            converted variables. Default is '_plus'.
          neg_suffix    The suffix applied to the 'positive' component of
                            converted variables. Default is '_minus'.
        """
        #
        # Optional naming schemes
        #
        pos_suffix = kwds.pop("pos_suffix", "_plus")
        neg_suffix = kwds.pop("neg_suffix", "_minus")
        #
        # We first perform an abstract problem transformation. Then, if model
        # data is available, we instantiate the new model. If not, we construct
        # a mapping that can later be used to populate the new model.
        #
        nonneg = model.clone()
        components = collectAbstractComponents(nonneg)

        # Map from variable base names to a {index, rule} map
        constraint_rules = {}

        # Map from variable base names to a rule defining the domains for that
        # variable
        domain_rules = {}

        # Map from variable base names to its set of indices
        var_indices = {}

        # Map from fully qualified variable names to replacement expressions.
        # For now, it is actually a map from a variable name to a closure that
        # must later be evaulated with a model containing the replacement
        # variables.
        var_map = {}

        #
        # Get the constraints that enforce the bounds and domains of each
        # variable
        #
        for var_name in components["Var"]:
            var = nonneg.__getattribute__(var_name)

            # Individual bounds and domains
            orig_bounds = {}
            orig_domain = {}

            # New indices
            indices = set()

            # Map from constraint names to a constraint rule.
            constraints = {}

            # Map from variable indices to a domain
            domains = {}

            for ndx in var:
                # Fully qualified variable name
                vname = create_name(str(var_name), ndx)

                # We convert each index to a string to avoid difficult issues
                # regarding appending a suffix to tuples.
                #
                # If the index is None, this casts the index to a string,
                # which doesn't match up with how Pyomo treats None indices
                # internally. Replace with "" to be consistent.
                if ndx is None:
                    v_ndx = ""
                else:
                    v_ndx = str(ndx)

                # Get the variable bounds
                lb = var[ndx].lb
                ub = var[ndx].ub
                if lb is not None:
                    lb = value(lb)
                if ub is not None:
                    ub = value(ub)
                orig_bounds[ndx] = (lb, ub)

                # Get the variable domain
                if var[ndx].domain is not None:
                    orig_domain[ndx] = var[ndx].domain
                else:
                    orig_domain[ndx] = var.domain

                # Determine the replacement expression. Either a new single
                # variable with the same attributes, or a sum of two new
                # variables.
                #
                # If both the bounds and domain allow for negative values,
                # replace the variable with the sum of nonnegative ones.

                bounds_neg = (orig_bounds[ndx] == (None, None) or
                              orig_bounds[ndx][0] is None or
                              orig_bounds[ndx][0] < 0)
                domain_neg = (orig_domain[ndx] is None or
                              orig_domain[ndx].bounds()[0] is None or
                              orig_domain[ndx].bounds()[0] < 0)
                if bounds_neg and domain_neg:
                    # Make two new variables.
                    posVarSuffix = "%s%s" % (v_ndx, pos_suffix)
                    negVarSuffix = "%s%s" % (v_ndx, neg_suffix)

                    new_indices = (posVarSuffix, negVarSuffix)

                    # Replace the original variable with a sum expression
                    expr_dict = {posVarSuffix: 1, negVarSuffix: -1}
                else:
                    # Add the new index. Lie if is 'None', since Pyomo treats
                    # 'None' specially as a key.
                    #
                    # More lies: don't let a blank index exist. Replace it with
                    # '_'. I don't actually have a justification for this other
                    # than that allowing "" as a key will eventually almost
                    # certainly lead to a strange bug.
                    if v_ndx is None:
                        t_ndx = "None"
                    elif v_ndx == "":
                        t_ndx = "_"
                    else:
                        t_ndx = v_ndx

                    new_indices = (t_ndx,)

                    # Replace the original variable with a sum expression
                    expr_dict = {t_ndx: 1}

                # Add the new indices
                for x in new_indices:
                    indices.add(x)

                # Replace the original variable with an expression
                var_map[vname] = partial(self.sumRule,
                                         var_name,
                                         expr_dict)

                # Enforce bounds as constraints
                if orig_bounds[ndx] != (None, None):
                    cname = "%s_%s" % (vname, "bounds")
                    tmp = orig_bounds[ndx]
                    constraints[cname] = partial(
                        self.boundsConstraintRule,
                        tmp[0],
                        tmp[1],
                        var_name,
                        expr_dict)

                # Enforce the bounds of the domain as constraints
                if orig_domain[ndx] != None:
                    cname = "%s_%s" % (vname, "domain_bounds")
                    tmp = orig_domain[ndx].bounds()
                    constraints[cname] = partial(
                        self.boundsConstraintRule,
                        tmp[0],
                        tmp[1],
                        var_name,
                        expr_dict)

                # Domain will either be NonNegativeReals, NonNegativeIntegers,
                # or Binary. We consider Binary because some solvers may
                # optimize over binary variables.
                if isinstance(orig_domain[ndx], RealSet):
                    for x in new_indices:
                        domains[x] = NonNegativeReals
                elif isinstance(orig_domain[ndx], IntegerSet):
                    for x in new_indices:
                        domains[x] = NonNegativeIntegers
                elif isinstance(orig_domain[ndx], BooleanSet):
                    for x in new_indices:
                        domains[x] = Binary
                else:
                    print ("Warning: domain '%s' not recognized, " + \
                           "defaulting to 'Reals'") % (str(var.domain))
                    for x in new_indices:
                        domains[x] = Reals

            constraint_rules[var_name] = constraints
            domain_rules[var_name] = partial(self.exprMapRule, domains)
            var_indices[var_name] = indices

        # Remove all existing variables.
        toRemove = []
        for (attr_name, attr) in nonneg.__dict__.items():
            if isinstance(attr, Var):
                toRemove.append(attr_name)
        for attr_name in toRemove:
            nonneg.__delattr__(attr_name)

        # Add the sets defining the variables, then the variables
        for (k, v) in var_indices.items():
            sname = "%s_indices" % k
            nonneg.__setattr__(sname, Set(initialize=v))
            nonneg.__setattr__(k, Var(nonneg.__getattribute__(sname),
                                      domain = domain_rules[k],
                                      bounds = (0, None)))

        # Construct the model to get the variables and their indices
        # recognized in the model
        ##nonneg = nonneg.create()

        # Safe to evaluate the modifiedVars mapping
        for var in var_map:
            var_map[var] = var_map[var](nonneg)

        # Map from constraint base names to maps from indices to expressions
        constraintExprs = {}

        #
        # Convert all modified variables in all constraints in the original
        # problem
        #
        for conName in components["Constraint"]:
            con = nonneg.__getattribute__(conName)

            # Map from constraint indices to a corrected expression
            exprMap = {}

            for (ndx, cdata) in con._data.items():
                lower = self._walk_expr(cdata.lower, var_map)
                body  = self._walk_expr(cdata.body,  var_map)
                upper = self._walk_expr(cdata.upper, var_map)

                # Lie if ndx is None. Pyomo treats 'None' indices specially.
                if ndx is None:
                    ndx = "None"

                # Cast indices to strings, otherwise tuples ruin everything
                exprMap[str(ndx)] = (lower, body, upper)

            # Add to list of expression maps
            constraintExprs[conName] = exprMap

        # Map from constraint base names to maps from indices to expressions
        objectiveExprs = {}

        #
        # Convert all modified variables in all objectives in the original
        # problem
        #
        for objName in components["Objective"]:
            obj = nonneg.__getattribute__(objName)

            # Map from objective indices to a corrected expression
            exprMap = {}

            for (ndx, odata) in obj._data.items():
                exprMap[ndx] = self._walk_expr(odata.expr, var_map)

            # Add to list of expression maps
            objectiveExprs[objName] = exprMap


        # Make the modified original constraints
        for (conName, ruleMap) in constraintExprs.items():
            # Make the set of indices
            sname = conName + "_indices"
            _set = Set(initialize=ruleMap.keys())
            nonneg.__setattr__(sname, _set)
            _set.construct()

            # Define the constraint
            _con = Constraint( nonneg.__getattribute__(sname),
                               rule=partial(self.exprMapRule, ruleMap) )
            nonneg.__setattr__(conName, _con)
            _con.construct()

        # Make the bounds constraints
        for (varName, ruleMap) in constraint_rules.items():
            conName = varName + "_constraints"
            # Make the set of indices
            sname = conName + "_indices"
            _set = Set(initialize=ruleMap.keys())
            nonneg.__setattr__(sname, _set)
            _set.construct()

            # Define the constraint
            _con = Constraint(nonneg.__getattribute__(sname),
                              rule=partial(self.delayedExprMapRule, ruleMap))
            nonneg.__setattr__(conName, _con)
            _con.construct()

        # Make the objectives
        for (objName, ruleMap) in objectiveExprs.items():
            # Make the set of indices
            sname = objName + "_indices"
            _set = Set(initialize=ruleMap.keys())
            nonneg.__setattr__(sname, _set)
            _set.construct()

            # Define the constraint
            _obj = Objective(nonneg.__getattribute__(sname),
                             rule=partial(self.exprMapRule, ruleMap))
            nonneg.__setattr__(objName, _obj)
            _obj.construct()

        return nonneg