Esempio n. 1
0
    def _apply_to(self, model, rename=True):
        # create a map of component to scaling factor
        component_scaling_factor_map = ComponentMap()

        # if the scaling_method is 'user', get the scaling parameters from the suffixes
        if self._scaling_method == 'user':
            # perform some checks to make sure we have the necessary suffixes
            if type(model.component('scaling_factor')) is not Suffix:
                raise ValueError(
                    "ScaleModel transformation called with scaling_method='user'"
                    ", but cannot find the suffix 'scaling_factor' on the model"
                )

            # get the scaling factors
            for c in model.component_data_objects(ctype=(Var, Constraint,
                                                         Objective),
                                                  descend_into=True):
                component_scaling_factor_map[
                    c] = self._get_float_scaling_factor(model, c)
        else:
            raise ValueError(
                "ScaleModel transformation: unknown scaling_method found"
                "-- supported values: 'user' ")

        if rename:
            # rename all the Vars, Constraints, and Objectives
            # from foo to scaled_foo
            component_list = list(
                model.component_objects(ctype=[Var, Constraint, Objective]))
            scaled_component_to_original_name_map = rename_components(
                model=model,
                component_list=component_list,
                prefix='scaled_',
            )
        else:
            scaled_component_to_original_name_map = ComponentMap([
                (comp, comp.name) for comp in model.component_objects(
                    ctype=[Var, Constraint, Objective])
            ])

        # scale the variable bounds and values and build the variable substitution map
        # for scaling vars in constraints
        variable_substitution_map = ComponentMap()
        already_scaled = set()
        for variable in [
                var for var in model.component_objects(ctype=Var,
                                                       descend_into=True)
        ]:
            # set the bounds/value for the scaled variable
            for k in variable:
                v = variable[k]
                if id(v) in already_scaled:
                    continue
                already_scaled.add(id(v))
                scaling_factor = component_scaling_factor_map[v]
                variable_substitution_map[v] = v / scaling_factor

                if v.lb is not None:
                    v.setlb(v.lb * scaling_factor)
                if v.ub is not None:
                    v.setub(v.ub * scaling_factor)
                if scaling_factor < 0:
                    temp = v.lb
                    v.setlb(v.ub)
                    v.setub(temp)

                if v.value is not None:
                    # Since the value was OK in the unscaled space, it
                    # should be safe to assume it is still valid in the
                    # scaled space)
                    v.set_value(value(v) * scaling_factor,
                                skip_validation=True)

        # scale the objectives/constraints and perform the scaled variable substitution
        scale_constraint_dual = False
        if type(model.component('dual')) is Suffix:
            scale_constraint_dual = True

        # translate the variable_substitution_map (ComponentMap)
        # to variable_substition_dict (key: id() of component)
        # ToDo: We should change replace_expressions to accept a ComponentMap as well
        variable_substitution_dict = {
            id(k): variable_substitution_map[k]
            for k in variable_substitution_map
        }

        already_scaled = set()
        for component in model.component_objects(ctype=(Constraint, Objective),
                                                 descend_into=True):
            for k in component:
                c = component[k]
                if id(c) in already_scaled:
                    continue
                already_scaled.add(id(c))
                # perform the constraint/objective scaling and variable sub
                scaling_factor = component_scaling_factor_map[c]
                if isinstance(c, _ConstraintData):
                    body = scaling_factor * \
                           replace_expressions(expr=c.body,
                                               substitution_map=variable_substitution_dict,
                                               descend_into_named_expressions=True,
                                               remove_named_expressions=True)

                    # scale the rhs
                    lower = c.lower
                    upper = c.upper
                    if lower is not None:
                        lower = lower * scaling_factor
                    if upper is not None:
                        upper = upper * scaling_factor

                    if scaling_factor < 0:
                        lower, upper = upper, lower

                    if scale_constraint_dual and c in model.dual:
                        dual_value = model.dual[c]
                        if dual_value is not None:
                            model.dual[c] = dual_value / scaling_factor

                    if c.equality:
                        c.set_value((lower, body))
                    else:
                        c.set_value((lower, body, upper))

                elif isinstance(c, _ObjectiveData):
                    c.expr = scaling_factor * \
                             replace_expressions(expr=c.expr,
                                                 substitution_map=variable_substitution_dict,
                                                 descend_into_named_expressions=True,
                                                 remove_named_expressions=True)
                else:
                    raise NotImplementedError(
                        'Unknown object type found when applying scaling factors in ScaleModel transformation - Internal Error'
                    )

        model.component_scaling_factor_map = component_scaling_factor_map
        model.scaled_component_to_original_name_map = scaled_component_to_original_name_map

        return model
def make_separation_problem(model_data, config):
    """
    Swap out uncertain param Param objects for Vars
    Add uncertainty set constraints and separation objectives
    """
    separation_model = model_data.original.clone()
    separation_model.del_component("coefficient_matching_constraints")
    separation_model.del_component("coefficient_matching_constraints_index")

    uncertain_params = separation_model.util.uncertain_params
    separation_model.util.uncertain_param_vars = param_vars = Var(
        range(len(uncertain_params)))
    map_new_constraint_list_to_original_con = ComponentMap()

    if config.objective_focus is ObjectiveType.worst_case:
        separation_model.util.zeta = Param(initialize=0, mutable=True)
        constr = Constraint(expr=separation_model.first_stage_objective +
                            separation_model.second_stage_objective -
                            separation_model.util.zeta <= 0)
        separation_model.add_component("epigraph_constr", constr)

    substitution_map = {}
    #Separation problem initialized to nominal uncertain parameter values
    for idx, var in enumerate(list(param_vars.values())):
        param = uncertain_params[idx]
        var.set_value(param.value, skip_validation=True)
        substitution_map[id(param)] = var

    separation_model.util.new_constraints = constraints = ConstraintList()

    uncertain_param_set = ComponentSet(uncertain_params)
    for c in separation_model.component_data_objects(Constraint):
        if any(v in uncertain_param_set
               for v in identify_mutable_parameters(c.expr)):
            if c.equality:
                constraints.add(
                    replace_expressions(expr=c.lower,
                                        substitution_map=substitution_map) ==
                    replace_expressions(expr=c.body,
                                        substitution_map=substitution_map))
            elif c.lower is not None:
                constraints.add(
                    replace_expressions(expr=c.lower,
                                        substitution_map=substitution_map) <=
                    replace_expressions(expr=c.body,
                                        substitution_map=substitution_map))
            elif c.upper is not None:
                constraints.add(
                    replace_expressions(expr=c.upper,
                                        substitution_map=substitution_map) >=
                    replace_expressions(expr=c.body,
                                        substitution_map=substitution_map))
            else:
                raise ValueError(
                    "Unable to parse constraint for building the separation problem."
                )
            c.deactivate()
            map_new_constraint_list_to_original_con[constraints[
                constraints.index_set().last()]] = c

    separation_model.util.map_new_constraint_list_to_original_con = map_new_constraint_list_to_original_con

    # === Add objectives first so that the uncertainty set
    #     Constraints do not get picked up into the set
    #	  of performance constraints which become objectives
    make_separation_objective_functions(separation_model, config)
    add_uncertainty_set_constraints(separation_model, config)

    # === Deactivate h(x,q) == 0 constraints
    for c in separation_model.util.h_x_q_constraints:
        c.deactivate()

    return separation_model
Esempio n. 3
0
    def _apply_to(self, model, **kwds):
        # create a map of component to scaling factor
        component_scaling_factor_map = ComponentMap()

        # if the scaling_method is 'user', get the scaling parameters from the suffixes
        if self._scaling_method == 'user':
            # perform some checks to make sure we have the necessary suffixes
            if type(model.component('scaling_factor')) is not Suffix:
                raise ValueError("ScaleModel transformation called with scaling_method='user'"
                                 ", but cannot find the suffix 'scaling_factor' on the model")

            # get the scaling factors
            for c in model.component_data_objects(ctype=(Var, Constraint, Objective), descend_into=True):
                component_scaling_factor_map[c] = self._get_float_scaling_factor(model, c)
        else:
            raise ValueError("ScaleModel transformation: unknown scaling_method found"
                             "-- supported values: 'user' ")

        # rename all the Vars, Constraints, and Objectives from foo to scaled_foo
        scaled_component_to_original_name_map = \
            rename_components(model=model,
                              component_list=list(model.component_objects(ctype=[Var, Constraint, Objective])),
                              prefix='scaled_')

        # scale the variable bounds and values and build the variable substitution map
        # for scaling vars in constraints
        variable_substitution_map = ComponentMap()
        for variable in [var for var in model.component_objects(ctype=Var, descend_into=True)]:
            # set the bounds/value for the scaled variable
            for k in variable:
                v = variable[k]
                scaling_factor = component_scaling_factor_map[v]
                variable_substitution_map[v] = v / scaling_factor

                if v.lb is not None:
                    v.setlb(v.lb * scaling_factor)
                if v.ub is not None:
                    v.setub(v.ub * scaling_factor)
                if scaling_factor < 0:
                    temp = v.lb
                    v.setlb(v.ub)
                    v.setub(temp)

                if v.value is not None:
                    v.value = value(v) * scaling_factor

        # scale the objectives/constraints and perform the scaled variable substitution
        scale_constraint_dual = False
        if type(model.component('dual')) is Suffix:
            scale_constraint_dual = True

        # translate the variable_substitution_map (ComponentMap)
        # to variable_substition_dict (key: id() of component)
        # ToDo: We should change replace_expressions to accept a ComponentMap as well
        variable_substitution_dict = dict()
        for k in variable_substitution_map:
            variable_substitution_dict[id(k)] = variable_substitution_map[k]

        for component in model.component_objects(ctype=(Constraint, Objective), descend_into=True):
            for k in component:
                c = component[k]
                # perform the constraint/objective scaling and variable sub
                scaling_factor = component_scaling_factor_map[c]
                if isinstance(c, _ConstraintData):
                    body = scaling_factor * \
                           replace_expressions(expr=c.body,
                                               substitution_map=variable_substitution_dict,
                                               descend_into_named_expressions=True,
                                               remove_named_expressions=True)

                    # scale the rhs
                    if c._lower is not None:
                        c._lower = c._lower * scaling_factor
                    if c._upper is not None:
                        c._upper = c._upper * scaling_factor

                    if scaling_factor < 0:
                        c._lower, c._upper = c._upper, c._lower

                    if scale_constraint_dual and c in model.dual:
                        dual_value = model.dual[c]
                        if dual_value is not None:
                            model.dual[c] = dual_value / scaling_factor

                    c.set_value((c._lower, body, c._upper))

                elif isinstance(c, _ObjectiveData):
                    c.expr = scaling_factor * \
                             replace_expressions(expr=c.expr,
                                                 substitution_map=variable_substitution_dict,
                                                 descend_into_named_expressions=True,
                                                 remove_named_expressions=True)
                else:
                    raise NotImplementedError(
                        'Unknown object type found when applying scaling factors in ScaleModel transformation - Internal Error')

        model.component_scaling_factor_map = component_scaling_factor_map
        model.scaled_component_to_original_name_map = scaled_component_to_original_name_map

        return model