Ejemplo n.º 1
0
    def make_cuts(self, coefs):
        # take the coefficient array and assemble cuts accordingly

        # this should have already been set in the extension !
        opt = self.opt

        # rows are
        # [ const, eta_coeff, *nonant_coeffs ]
        row_len = 1 + 1 + self.nonant_len
        outer_iter = int(coefs[-1])

        bundling = opt.bundling
        if opt.bundling:
            for bn, b in opt.local_subproblems.items():
                persistent_solver = sputils.is_persistent(b._solver_plugin)
                ## get an arbitrary scenario
                s = opt.local_scenarios[b.scen_list[0]]
                for idx, k in enumerate(opt.all_scenario_names):
                    row = coefs[row_len * idx:row_len * (idx + 1)]
                    # the row could be all zeros,
                    # which doesn't do anything
                    if (row == 0.).all():
                        continue
                    # rows are
                    # [ const, eta_coeff, *nonant_coeffs ]
                    linear_const = row[0]
                    linear_coefs = list(row[1:])
                    linear_vars = [b.eta[k]]

                    for ndn_i in s._nonant_indexes:
                        ## for bundles, we add the constrains only
                        ## to the reference first stage variables
                        linear_vars.append(b.ref_vars[ndn_i])

                    cut_expr = LinearExpression(constant=linear_const,
                                                linear_coefs=linear_coefs,
                                                linear_vars=linear_vars)
                    b._benders_cuts[outer_iter, k] = (None, cut_expr, 0)
                    if persistent_solver:
                        b._solver_plugin.add_constraint(
                            b._benders_cuts[outer_iter, k])

        else:
            for sn, s in opt.local_subproblems.items():
                persistent_solver = sputils.is_persistent(s._solver_plugin)
                for idx, k in enumerate(opt.all_scenario_names):
                    row = coefs[row_len * idx:row_len * (idx + 1)]
                    # the row could be all zeros,
                    # which doesn't do anything
                    if (row == 0.).all():
                        continue
                    # rows are
                    # [ const, eta_coeff, *nonant_coeffs ]
                    linear_const = row[0]
                    linear_coefs = list(row[1:])
                    linear_vars = [s.eta[k]]
                    linear_vars.extend(s._nonant_indexes.values())

                    cut_expr = LinearExpression(constant=linear_const,
                                                linear_coefs=linear_coefs,
                                                linear_vars=linear_vars)
                    s._benders_cuts[outer_iter, k] = (None, cut_expr, 0.)
                    if persistent_solver:
                        s._solver_plugin.add_constraint(
                            s._benders_cuts[outer_iter, k])

        # NOTE: the LShaped code negates the objective, so
        #       we do the same here for consistency
        ib = self.BestInnerBound
        ob = self.BestOuterBound
        if not opt.is_minimizing:
            ib = -ib
            ob = -ob
        add_cut = (isfinite(ib) or isfinite(ob)) and \
                ((ib < self.best_inner_bound) or (ob > self.best_outer_bound))
        if add_cut:
            self.best_inner_bound = ib
            self.best_outer_bound = ob
            for sn, s in opt.local_subproblems.items():
                persistent_solver = sputils.is_persistent(s._solver_plugin)
                prior_outer_iter = list(s._ib_constr.keys())
                s._ib_constr[outer_iter] = (ob, s._EF_obj, ib)
                if persistent_solver:
                    s._solver_plugin.add_constraint(s._ib_constr[outer_iter])
                # remove other ib constraints (we only need the tightest)
                for it in prior_outer_iter:
                    if persistent_solver:
                        s._solver_plugin.remove_constraint(s._ib_constr[it])
                    del s._ib_constr[it]

        ## helping the extention track cuts
        self.new_cuts = True
Ejemplo n.º 2
0
 def _build_sum_expression(variables, constant=0.):
     expr = LinearExpression()
     expr.linear_vars = [item[1] for item in variables]
     expr.linear_coefs = [item[0] for item in variables]
     expr.constant = constant
     return expr
Ejemplo n.º 3
0
    def create_subproblem(self, scenario_name):
        """ the subproblem creation function passed into the
            BendersCutsGenerator 
        """
        instance = self.local_scenarios[scenario_name]

        nonant_list, nonant_ids = _get_nonant_ids(instance) 

        # NOTE: since we use generate_standard_repn below, we need
        #       to unfix any nonants so they'll properly appear
        #       in the objective
        fixed_nonants = [ var for var in nonant_list if var.fixed ]
        for var in fixed_nonants:
            var.fixed = False

        # pulls the scenario objective expression, removes the first stage variables, and sets the new objective
        obj = find_active_objective(instance)

        if not hasattr(instance, "_mpisppy_probability"):
            instance._mpisppy_probability = 1. / self.scenario_count
        _mpisppy_probability = instance._mpisppy_probability

        repn = generate_standard_repn(obj.expr, quadratic=True)
        if len(repn.nonlinear_vars) > 0:
            raise ValueError("LShaped does not support models with nonlinear objective functions")

        linear_vars = list()
        linear_coefs = list()
        quadratic_vars = list()
        quadratic_coefs = list()
        ## we'll assume the constant is part of stage 1 (wlog it is), just
        ## like the first-stage bits of the objective
        constant = repn.constant 

        ## only keep the second stage variables in the objective
        for coef, var in zip(repn.linear_coefs, repn.linear_vars):
            id_var = id(var)
            if id_var not in nonant_ids:
                linear_vars.append(var)
                linear_coefs.append(_mpisppy_probability*coef)
        for coef, (x,y) in zip(repn.quadratic_coefs, repn.quadratic_vars):
            id_x = id(x)
            id_y = id(y)
            if id_x not in nonant_ids or id_y not in nonant_ids:
                quadratic_coefs.append(_mpisppy_probability*coef)
                quadratic_vars.append((x,y))

        # checks if model sense is max, if so negates the objective
        if not self.is_minimizing:
            for i,coef in enumerate(linear_coefs):
                linear_coefs[i] = -coef
            for i,coef in enumerate(quadratic_coefs):
                quadratic_coefs[i] = -coef

        expr = LinearExpression(constant=constant, linear_coefs=linear_coefs,
                                linear_vars=linear_vars)
        if quadratic_coefs:
            expr += pyo.quicksum(
                        (coef*x*y for coef,(x,y) in zip(quadratic_coefs, quadratic_vars))
                    )

        instance.del_component(obj)

        # set subproblem objective function
        instance.obj = pyo.Objective(expr=expr, sense=pyo.minimize)

        ## need to do this here for validity if computing the eta bound
        if self.relax_root:
            # relaxes any integrality constraints for the subproblem
            RelaxIntegerVars().apply_to(instance)

        if self.compute_eta_bound:
            for var in fixed_nonants:
                var.fixed = True
            opt = pyo.SolverFactory(self.options["sp_solver"])
            if self.options["sp_solver_options"]:
                for k,v in self.options["sp_solver_options"].items():
                    opt.options[k] = v

            if sputils.is_persistent(opt):
                set_instance_retry(instance, opt, scenario_name)
                res = opt.solve(tee=False)
            else:
                res = opt.solve(instance, tee=False)

            eta_lb = res.Problem[0].Lower_bound

            self.valid_eta_lb[scenario_name] = eta_lb

        # if not done above
        if not self.relax_root:
            # relaxes any integrality constraints for the subproblem
            RelaxIntegerVars().apply_to(instance)

        # iterates through constraints and removes first stage constraints from the model
        # the id dict is used to improve the speed of identifying the stage each variables belongs to
        for constr_data in list(itertools.chain(
                instance.component_data_objects(SOSConstraint, active=True, descend_into=True)
                , instance.component_data_objects(Constraint, active=True, descend_into=True))):
            if _first_stage_only(constr_data, nonant_ids):
                _del_con(constr_data)

        # creates the sub map to remove first stage variables from objective expression
        complicating_vars_map = pyo.ComponentMap()
        subproblem_to_root_vars_map = pyo.ComponentMap()

        # creates the complicating var map that connects the first stage variables in the sub problem to those in
        # the root problem -- also set the bounds on the subproblem root vars to be none for better cuts
        for var, rvar in zip(nonant_list, self.root_vars):
            if var.name not in rvar.name: # rvar.name may be part of a bundle
                raise Exception("Error: Complicating variable mismatch, sub-problem variables changed order")
            complicating_vars_map[rvar] = var
            subproblem_to_root_vars_map[var] = rvar 

            # these are already enforced in the root
            # don't need to be enfored in the subproblems
            var.setlb(None)
            var.setub(None)
            var.fixed = False

        # this is for interefacing with PH code
        instance._mpisppy_model.subproblem_to_root_vars_map = subproblem_to_root_vars_map

        if self.store_subproblems:
            self.subproblems[scenario_name] = instance

        return instance, complicating_vars_map
Ejemplo n.º 4
0
    def post_iter0(self):
        opt = self.opt
        # NOTE: the LShaped code negates the objective, so
        #       we do the same here for consistency
        if 'cross_scen_options' in opt.options and \
                'valid_eta_bound' in opt.options['cross_scen_options']:
            valid_eta_bound = opt.options['cross_scen_options']['valid_eta_bound']
            if not opt.is_minimizing:
                _eta_init = { k: -v for k,v in valid_eta_bound.items() }
            else:
                _eta_init = valid_eta_bound
            _eta_bounds = lambda m,k : (_eta_init[k], None)
        else:
            lb = (-sys.maxsize - 1) * 1. / len(opt.all_scenario_names)
            _eta_init = lambda m,k : lb
            _eta_bounds = lambda m,k : (lb, None)

        # eta is attached to each subproblem, regardless of bundles
        bundling = opt.bundling
        for k,s in opt.local_subproblems.items():
            s._mpisppy_model.eta = pyo.Var(opt.all_scenario_names, initialize=_eta_init, bounds=_eta_bounds)
            if sputils.is_persistent(s._solver_plugin):
                for var in s._mpisppy_model.eta.values():
                    s._solver_plugin.add_var(var)
            if bundling: ## create a refence to eta on each subproblem
                for sn in s.scen_list:
                    scenario = opt.local_scenarios[sn]
                    scenario._mpisppy_model.eta = { k : s._mpisppy_model.eta[k] for k in opt.all_scenario_names }

        ## hold the PH object harmless
        self._disable_W_and_prox()
        
        for k,s in opt.local_subproblems.items():

            obj = find_active_objective(s)

            repn = generate_standard_repn(obj.expr, quadratic=True)
            if len(repn.nonlinear_vars) > 0:
                raise ValueError("CrossScenario does not support models with nonlinear objective functions")

            if bundling:
                ## NOTE: this is slighly wasteful, in that for a bundle
                ##       the first-stage cost appears len(s.scen_list) times
                ##       If this really made a difference, we could use s.ref_vars
                ##       to do the substitution
                nonant_vardata_list = list()
                for sn in s.scen_list:
                    nonant_vardata_list.extend( \
                            opt.local_scenarios[sn]._mpisppy_node_list[0].nonant_vardata_list)
            else:
                nonant_vardata_list = s._mpisppy_node_list[0].nonant_vardata_list

            nonant_ids = set((id(var) for var in nonant_vardata_list))

            linear_coefs = list(repn.linear_coefs)
            linear_vars = list(repn.linear_vars)

            quadratic_coefs = list(repn.quadratic_coefs)

            # adjust coefficients by scenario/bundle probability
            scen_prob = s._mpisppy_probability
            for i,var in enumerate(repn.linear_vars):
                if id(var) not in nonant_ids:
                    linear_coefs[i] *= scen_prob

            for i,(x,y) in enumerate(repn.quadratic_vars):
                # only multiply through once
                if id(x) not in nonant_ids:
                    quadratic_coefs[i] *= scen_prob
                elif id(y) not in nonant_ids:
                    quadratic_coefs[i] *= scen_prob

            # NOTE: the LShaped code negates the objective, so
            #       we do the same here for consistency
            if not opt.is_minimizing:
                for i,coef in enumerate(linear_coefs):
                    linear_coefs[i] = -coef
                for i,coef in enumerate(quadratic_coefs):
                    quadratic_coefs[i] = -coef

            # add the other etas
            if bundling:
                these_scenarios = set(s.scen_list)
            else:
                these_scenarios = [k]

            eta_scenarios = list()
            for sn in opt.all_scenario_names:
                if sn not in these_scenarios:
                    linear_coefs.append(1)
                    linear_vars.append(s._mpisppy_model.eta[sn])
                    eta_scenarios.append(sn)

            expr = LinearExpression(constant=repn.constant, linear_coefs=linear_coefs,
                                    linear_vars=linear_vars)

            if repn.quadratic_vars:
                expr += pyo.quicksum(
                    (coef*x*y for coef,(x,y) in zip(quadratic_coefs, repn.quadratic_vars))
                )

            s._mpisppy_model.EF_obj = pyo.Expression(expr=expr)

            if opt.is_minimizing:
                s._mpisppy_model.EF_Obj = pyo.Objective(expr=s._mpisppy_model.EF_obj, sense=pyo.minimize)
            else:
                s._mpisppy_model.EF_Obj = pyo.Objective(expr=-s._mpisppy_model.EF_obj, sense=pyo.maximize)
            s._mpisppy_model.EF_Obj.deactivate()

            # add cut constraint dicts
            s._mpisppy_model.benders_cuts = pyo.Constraint(pyo.Any)
            s._mpisppy_model.inner_bound_constr = pyo.Constraint(pyo.Any)

        self._enable_W_and_prox()

        # try to get the initial eta LB cuts
        # (may not be available)
        opt.spcomm.get_from_cross_cuts()
Ejemplo n.º 5
0
    def _create_root_with_scenarios(self):

        ef_scenarios = self.root_scenarios

        ## we want the correct probabilities to be set when
        ## calling create_EF
        if len(ef_scenarios) > 1:
            def scenario_creator_wrapper(name, **creator_options):
                scenario = self.scenario_creator(name, **creator_options)
                if not hasattr(scenario, '_mpisppy_probability'):
                    scenario._mpisppy_probability = 1./len(self.all_scenario_names)
                return scenario
            root = sputils.create_EF(
                ef_scenarios,
                scenario_creator_wrapper,
                scenario_creator_kwargs=self.scenario_creator_kwargs,
            )

            nonant_list, nonant_ids = _get_nonant_ids_EF(root)
        else:
            root = self.scenario_creator(
                ef_scenarios[0],
                **self.scenario_creator_kwargs,
            )
            if not hasattr(root, '_mpisppy_probability'):
                root._mpisppy_probability = 1./len(self.all_scenario_names)

            nonant_list, nonant_ids = _get_nonant_ids(root)

        self.root_vars = nonant_list

        # creates the eta variables for scenarios that are NOT selected to be
        # included in the root problem
        eta_indx = [scenario_name for scenario_name in self.all_scenario_names
                        if scenario_name not in self.root_scenarios]
        self._add_root_etas(root, eta_indx)

        obj = find_active_objective(root)

        repn = generate_standard_repn(obj.expr, quadratic=True)
        if len(repn.nonlinear_vars) > 0:
            raise ValueError("LShaped does not support models with nonlinear objective functions")
        linear_vars = list(repn.linear_vars)
        linear_coefs = list(repn.linear_coefs)
        quadratic_coefs = list(repn.quadratic_coefs)

        # adjust coefficients by scenario/bundle probability
        scen_prob = root._mpisppy_probability
        for i,var in enumerate(repn.linear_vars):
            if id(var) not in nonant_ids:
                linear_coefs[i] *= scen_prob

        for i,(x,y) in enumerate(repn.quadratic_vars):
            # only multiply through once
            if id(x) not in nonant_ids:
                quadratic_coefs[i] *= scen_prob
            elif id(y) not in nonant_ids:
                quadratic_coefs[i] *= scen_prob

        # NOTE: the LShaped code negates the objective, so
        #       we do the same here for consistency
        if not self.is_minimizing:
            for i,coef in enumerate(linear_coefs):
                linear_coefs[i] = -coef
            for i,coef in enumerate(quadratic_coefs):
                quadratic_coefs[i] = -coef

        # add the etas
        for var in root.eta.values():
            linear_vars.append(var)
            linear_coefs.append(1)

        expr = LinearExpression(constant=repn.constant, linear_coefs=linear_coefs,
                                linear_vars=linear_vars)
        if repn.quadratic_vars:
            expr += pyo.quicksum(
                (coef*x*y for coef,(x,y) in zip(quadratic_coefs, repn.quadratic_vars))
            )

        root.del_component(obj)

        # set root objective function
        root.obj = pyo.Objective(expr=expr, sense=pyo.minimize)

        self.root = root
Ejemplo n.º 6
0
    def _create_root_no_scenarios(self):

        # using the first scenario as a basis
        root = self.scenario_creator(
            self.all_scenario_names[0], **self.scenario_creator_kwargs
        )

        if self.relax_root:
            RelaxIntegerVars().apply_to(root)

        nonant_list, nonant_ids = _get_nonant_ids(root)

        self.root_vars = nonant_list

        for constr_data in list(itertools.chain(
                root.component_data_objects(SOSConstraint, active=True, descend_into=True)
                , root.component_data_objects(Constraint, active=True, descend_into=True))):
            if not _first_stage_only(constr_data, nonant_ids):
                _del_con(constr_data)

        # delete the second stage variables
        for var in list(root.component_data_objects(Var, active=True, descend_into=True)):
            if id(var) not in nonant_ids:
                _del_var(var)

        self._add_root_etas(root, self.all_scenario_names)

        # pulls the current objective expression, adds in the eta variables,
        # and removes the second stage variables from the expression
        obj = find_active_objective(root)

        repn = generate_standard_repn(obj.expr, quadratic=True)
        if len(repn.nonlinear_vars) > 0:
            raise ValueError("LShaped does not support models with nonlinear objective functions")

        linear_vars = list()
        linear_coefs = list()
        quadratic_vars = list()
        quadratic_coefs = list()
        ## we'll assume the constant is part of stage 1 (wlog it is), just
        ## like the first-stage bits of the objective
        constant = repn.constant 

        ## only keep the first stage variables in the objective
        for coef, var in zip(repn.linear_coefs, repn.linear_vars):
            id_var = id(var)
            if id_var in nonant_ids:
                linear_vars.append(var)
                linear_coefs.append(coef)
        for coef, (x,y) in zip(repn.quadratic_coefs, repn.quadratic_vars):
            id_x = id(x)
            id_y = id(y)
            if id_x in nonant_ids and id_y in nonant_ids:
                quadratic_coefs.append(coef)
                quadratic_vars.append((x,y))

        # checks if model sense is max, if so negates the objective
        if not self.is_minimizing:
            for i,coef in enumerate(linear_coefs):
                linear_coefs[i] = -coef
            for i,coef in enumerate(quadratic_coefs):
                quadratic_coefs[i] = -coef

        # add the etas
        for var in root.eta.values():
            linear_vars.append(var)
            linear_coefs.append(1)

        expr = LinearExpression(constant=constant, linear_coefs=linear_coefs,
                                linear_vars=linear_vars)
        if quadratic_coefs:
            expr += pyo.quicksum(
                        (coef*x*y for coef,(x,y) in zip(quadratic_coefs, quadratic_vars))
                    )

        root.del_component(obj)

        # set root objective function
        root.obj = pyo.Objective(expr=expr, sense=pyo.minimize)

        self.root = root
Ejemplo n.º 7
0
def _create_EF_from_scen_dict(scen_dict,
                              EF_name=None,
                              nonant_for_fixed_vars=True):
    """ Create a ConcreteModel of the extensive form from a scenario
        dictionary.

        Args:
            scen_dict (dict): Dictionary whose keys are scenario names and
                values are ConcreteModel objects corresponding to each
                scenario.
            EF_name (str--optional): Name of the resulting EF model.
            nonant_for_fixed_vars (bool--optional): If True, enforces
                non-anticipativity constraints for all variables, including
                those which have been fixed. Deafult is True.

        Returns:
            EF_instance (ConcreteModel): ConcreteModel of extensive form with
                explicity non-anticipativity constraints.

        Notes:
            The non-anticipativity constraints are enforced by creating
            "reference variables" at each node in the scenario tree (excluding
            leaves) and enforcing that all the variables for each scenario at
            that node are equal to the reference variables.

            This function is called directly when creating bundles for PH.
 
            Does NOT assume that each scenario is equally likely. Raises an
            AttributeError if a scenario object is encountered which does not
            have a .PySP_prob attribute.

            Added the flag nonant_for_fixed_vars because original code only
            enforced non-anticipativity for non-fixed vars, which is not always
            desirable in the context of bundling. This allows for more
            fine-grained control.
    """
    is_min, clear = _models_have_same_sense(scen_dict)
    if (not clear):
        raise RuntimeError('Cannot build the extensive form out of models '
                           'with different objective senses')
    sense = pyo.minimize if is_min else pyo.maximize
    EF_instance = pyo.ConcreteModel(name=EF_name)
    EF_instance.EF_Obj = pyo.Objective(expr=0.0, sense=sense)
    EF_instance._PySP_feas_indicator = None
    EF_instance._PySP_subscen_names = []
    EF_instance.PySP_prob = 0
    for (sname, scenario_instance) in scen_dict.items():
        EF_instance.add_component(sname, scenario_instance)
        EF_instance._PySP_subscen_names.append(sname)
        # Now deactivate the scenario instance Objective
        scenario_objs = get_objs(scenario_instance)
        for obj_func in scenario_objs:
            obj_func.deactivate()
        obj_func = scenario_objs[0]  # Select the first objective
        try:
            EF_instance.EF_Obj.expr += scenario_instance.PySP_prob * obj_func.expr
            EF_instance.PySP_prob += scenario_instance.PySP_prob
        except AttributeError as e:
            raise AttributeError(
                "Scenario " + sname + " has no specified "
                "probability. Specify a value for the attribute "
                " PySP_prob and try again.") from e
    # Normalization does nothing when solving the full EF, but is required for
    # appropraite scaling of EFs used as bundles.
    EF_instance.EF_Obj.expr /= EF_instance.PySP_prob

    # For each node in the scenario tree, we need to collect the
    # nonanticipative vars and create the constraints for them,
    # which we do using a reference variable.
    ref_vars = dict()  # keys are _nonant_indexes (i.e. a node name and a
    # variable number)

    ref_suppl_vars = dict()

    EF_instance._PySP_nlens = dict()

    nonant_constr = pyo.Constraint(pyo.Any, name='_C_EF_')
    EF_instance.add_component('_C_EF_', nonant_constr)

    nonant_constr_suppl = pyo.Constraint(pyo.Any, name='_C_EF_suppl')
    EF_instance.add_component('_C_EF_suppl', nonant_constr_suppl)

    for (sname, s) in scen_dict.items():
        if (not hasattr(s, '_PySP_nlens')):
            nlens = {
                node.name: len(node.nonant_vardata_list)
                for node in s._PySPnode_list
            }
        else:
            nlens = s._PySP_nlens

        for (node_name, num_nonant_vars) in nlens.items():  # copy nlens to EF
            if (node_name in EF_instance._PySP_nlens.keys()
                    and num_nonant_vars != EF_instance._PySP_nlens[node_name]):
                raise RuntimeError("Number of non-anticipative variables is "
                                   "not consistent at node " + node_name +
                                   " in scenario " + sname)
            EF_instance._PySP_nlens[node_name] = num_nonant_vars

        nlens_ef_suppl = {
            node.name: len(node.nonant_ef_suppl_vardata_list)
            for node in s._PySPnode_list
        }

        for node in s._PySPnode_list:
            ndn = node.name
            for i in range(nlens[ndn]):
                v = node.nonant_vardata_list[i]
                if (ndn, i) not in ref_vars:
                    # create the reference variable as a singleton with long name
                    # xxxx maybe index by _nonant_index ???? rather than singleton VAR ???
                    ref_vars[(ndn, i)] = v
                # Add a non-anticipativity constraint, except in the case when
                # the variable is fixed and nonant_for_fixed_vars=False.
                else:
                    if (nonant_for_fixed_vars):
                        expr = LinearExpression(
                            linear_coefs=[1, -1],
                            linear_vars=[v, ref_vars[(ndn, i)]],
                            constant=0.)
                        nonant_constr[(ndn, i, sname)] = (expr, 0.0)
                    elif (not v.is_fixed()):
                        expr = LinearExpression(
                            linear_coefs=[1, -1],
                            linear_vars=[v, ref_vars[(ndn, i)]],
                            constant=0.)
                        nonant_constr[(ndn, i, sname)] = (expr, 0.0)

            for i in range(nlens_ef_suppl[ndn]):
                v = node.nonant_ef_suppl_vardata_list[i]
                if (ndn, i) not in ref_suppl_vars:
                    # create the reference variable as a singleton with long name
                    # xxxx maybe index by _nonant_index ???? rather than singleton VAR ???
                    ref_suppl_vars[(ndn, i)] = v
                # Add a non-anticipativity constraint, expect in the case when
                # the variable is fixed and nonant_for_fixed_vars=False.
                else:
                    if (nonant_for_fixed_vars):
                        expr = LinearExpression(
                            linear_coefs=[1, -1],
                            linear_vars=[v, ref_suppl_vars[(ndn, i)]],
                            constant=0.)
                        nonant_constr_suppl[(ndn, i, sname)] = (expr, 0.0)
                    elif (not v.is_fixed()):
                        expr = LinearExpression(
                            linear_coefs=[1, -1],
                            linear_vars=[v, ref_suppl_vars[(ndn, i)]],
                            constant=0.)
                        nonant_constr_suppl[(ndn, i, sname)] = (expr, 0.0)

    EF_instance.ref_vars = ref_vars
    EF_instance.ref_suppl_vars = ref_suppl_vars

    return EF_instance
Ejemplo n.º 8
0
 def neg_load_generate_mismatch_tolerance_rule(m):
     linear_vars = list(m.negLoadGenerateMismatch.values())
     linear_coefs = [1.] * len(linear_vars)
     return (0.,
             LinearExpression(linear_vars=linear_vars,
                              linear_coefs=linear_coefs), None)
Ejemplo n.º 9
0
def declare_ineq_p_branch_thermal_lbub(
        model,
        index_set,
        branches,
        p_thermal_limits,
        approximation_type=ApproximationType.BTHETA,
        slacks=False):
    """
    Create the inequality constraints for the branch thermal limits
    based on the power variables or expressions.
    """
    m = model
    con_set = decl.declare_set('_con_ineq_p_branch_thermal_lbub',
                               model=model,
                               index_set=index_set)

    # flag for if slacks are on the model
    if slacks:
        if not hasattr(model, 'pf_slack_pos'):
            raise Exception(
                'No positive slack branch variables on model, but slacks=True')
        if not hasattr(model, 'pf_slack_neg'):
            raise Exception(
                'No negative slack branch variables on model, but slacks=True')

    m.ineq_pf_branch_thermal_lb = pe.Constraint(con_set)
    m.ineq_pf_branch_thermal_ub = pe.Constraint(con_set)

    if approximation_type == ApproximationType.BTHETA or \
            approximation_type == ApproximationType.PTDF:
        for branch_name in con_set:
            if p_thermal_limits[branch_name] is None:
                continue

            if slacks and branch_name in m.pf_slack_neg:
                pf_bn = m.pf[branch_name]
                if hasattr(pf_bn, 'expr') and isinstance(
                        pf_bn.expr, LinearExpression):
                    ## create a copy
                    old_expr = pf_bn.expr
                    expr = LinearExpression(
                        constant=old_expr.constant,
                        linear_vars=old_expr.linear_vars[:] +
                        [m.pf_slack_neg[branch_name]],
                        linear_coefs=old_expr.linear_coefs[:] + [1],
                    )

                else:
                    expr = m.pf[branch_name] + m.pf_slack_neg[branch_name]
                m.ineq_pf_branch_thermal_lb[branch_name] = \
                    (-p_thermal_limits[branch_name], expr, None)
            else:
                m.ineq_pf_branch_thermal_lb[branch_name] = \
                    (-p_thermal_limits[branch_name], m.pf[branch_name], None)

            if slacks and branch_name in m.pf_slack_pos:
                pf_bn = m.pf[branch_name]
                if hasattr(pf_bn, 'expr') and isinstance(
                        pf_bn.expr, LinearExpression):
                    ## create a copy
                    old_expr = pf_bn.expr
                    expr = LinearExpression(
                        constant=old_expr.constant,
                        linear_vars=old_expr.linear_vars[:] +
                        [m.pf_slack_pos[branch_name]],
                        linear_coefs=old_expr.linear_coefs[:] + [-1],
                    )
                else:
                    expr = m.pf[branch_name] - m.pf_slack_pos[branch_name]
                m.ineq_pf_branch_thermal_lb[branch_name] = \
                    (None, expr, p_thermal_limits[branch_name])
            else:
                m.ineq_pf_branch_thermal_ub[branch_name] = \
                    (None, m.pf[branch_name], p_thermal_limits[branch_name])