Beispiel #1
0
def get_capacity_constraint(backend_model, parameter, loc_tech,
                            _equals=None, _max=None, _min=None, scale=None):

    decision_variable = getattr(backend_model, parameter)

    if not _equals:
        _equals = get_param(backend_model, parameter + '_equals', loc_tech)
    if not _max:
        _max = get_param(backend_model, parameter + '_max', loc_tech)
    if not _min:
        _min = get_param(backend_model, parameter + '_min', loc_tech)
    if po.value(_equals) is not False and po.value(_equals) is not None:
        if np.isinf(po.value(_equals)):
            e = exceptions.ModelError
            raise e('Cannot use inf for {}_equals for loc:tech `{}`'.format(parameter, loc_tech))
        if scale:
            _equals *= scale
        return decision_variable[loc_tech] == _equals
    else:
        if po.value(_min) == 0 and np.isinf(po.value(_max)):
            return po.Constraint.NoConstraint
        else:
            if scale:
                _max *= scale
                _min *= scale
            return (_min, decision_variable[loc_tech], _max)
Beispiel #2
0
    def solveModel(self, x, y, z):
        model = self.model
        opt = SolverFactory(self.config.solver)
        opt.options.update(self.config.solver_options)

        results = opt.solve(
            model, keepfiles=self.keepfiles, tee=self.stream_solver)

        if ((results.solver.status == SolverStatus.ok)
                and (results.solver.termination_condition == TerminationCondition.optimal)):
            model.solutions.load_from(results)
            for i in range(0, self.lx):
                x[i] = value(self.TRF.xvars[i])
            for i in range(0, self.ly):
                y[i] = value(self.TRF.y[i+1])
            for i in range(0, self.lz):
                z[i] = value(self.TRF.zvars[i])

            for obj in model.component_data_objects(Objective,active=True):
                return True, obj()

        else:
            print("Waring: solver Status: " + str(results.solver.status))
            print("And Termination Conditions: " + str(results.solver.termination_condition))
            return False, 0
Beispiel #3
0
def make2dPlot(expr, numticks=10, show_plot=False):
    mc_ccVals = [None] * (numticks + 1)
    mc_cvVals = [None] * (numticks + 1)
    aff_cc = [None] * (numticks + 1)
    aff_cv = [None] * (numticks + 1)
    fvals = [None] * (numticks + 1)
    mc_expr = mc(expr)
    x = next(identify_variables(expr))  # get the first variable
    tick_length = (x.ub - x.lb) / numticks
    xaxis = [x.lb + tick_length * n for n in range(numticks + 1)]

    x_val = value(x)  # initial value of x
    cc = mc_expr.subcc()  # Concave overestimator subgradient at x_val
    cv = mc_expr.subcv()  # Convex underestimator subgradient at x_val
    f_cc = mc_expr.concave()  # Concave overestimator value at x_val
    f_cv = mc_expr.convex()  # Convex underestimator value at x_val
    for i, x_tick in enumerate(xaxis):
        aff_cc[i] = cc[x] * (x_tick - x_val) + f_cc
        aff_cv[i] = cv[x] * (x_tick - x_val) + f_cv
        mc_expr.changePoint(x, x_tick)
        mc_ccVals[i] = mc_expr.concave()
        mc_cvVals[i] = mc_expr.convex()
        fvals[i] = value(expr)
    if show_plot:
        import matplotlib.pyplot as plt
        plt.plot(xaxis, fvals, 'r', xaxis, mc_ccVals, 'b--', xaxis,
                 mc_cvVals, 'b--', xaxis, aff_cc, 'k|', xaxis, aff_cv, 'k|')
        plt.show()
    return mc_ccVals, mc_cvVals, aff_cc, aff_cv
Beispiel #4
0
    def _estimate_M(self, expr, name):
        # Calculate a best guess at M
        repn = generate_standard_repn(expr)
        M = [0, 0]

        if not repn.is_nonlinear():
            if repn.constant is not None:
                for i in (0, 1):
                    if M[i] is not None:
                        M[i] += repn.constant

            for i, coef in enumerate(repn.linear_coefs or []):
                var = repn.linear_vars[i]
                bounds = (value(var.lb), value(var.ub))
                for i in (0, 1):
                    # reverse the bounds if the coefficient is negative
                    if coef > 0:
                        j = i
                    else:
                        j = 1 - i

                    if bounds[i] is not None:
                        M[j] += value(bounds[i]) * coef
                    else:
                        raise GDP_Error(
                            "Cannot estimate M for "
                            "expressions with unbounded variables."
                            "\n\t(found unbounded var %s while processing "
                            "constraint %s)" % (var.name, name))
        else:
            raise GDP_Error("Cannot estimate M for nonlinear "
                            "expressions.\n\t(found while processing "
                            "constraint %s)" % name)

        return tuple(M)
Beispiel #5
0
 def tear_diff_direct(self, G, tears):
     """
     Returns numpy arrays of values for src and dest members
     for all edges in the tears list of edge indexes.
     """
     svals = []
     dvals = []
     edge_list = self.idx_to_edge(G)
     for tear in tears:
         arc = G.edges[edge_list[tear]]["arc"]
         src, dest = arc.src, arc.dest
         sf = arc.expanded_block.component("splitfrac")
         for name, mem in src.iter_vars(names=True):
             if src.is_extensive(name) and sf is not None:
                 # TODO: same as above, what if there's no splitfrac
                 svals.append(value(mem * sf))
             else:
                 svals.append(value(mem))
             try:
                 index = mem.index()
             except AttributeError:
                 index = None
             dvals.append(value(self.source_dest_peer(arc, name, index)))
     svals = numpy.array(svals)
     dvals = numpy.array(dvals)
     return svals, dvals
Beispiel #6
0
def copy_var_list_values(from_list, to_list, config, skip_stale=False):
    """Copy variable values from one list to another."""
    for v_from, v_to in zip(from_list, to_list):
        if skip_stale and v_from.stale:
            continue  # Skip stale variable values.
        try:
            v_to.set_value(value(v_from, exception=False))
            if skip_stale:
                v_to.stale = False
        except ValueError as err:
            err_msg = getattr(err, 'message', str(err))
            var_val = value(v_from)
            rounded_val = int(round(var_val))
            # Check to see if this is just a tolerance issue
            if 'is not in domain Binary' in err_msg and (
                    fabs(var_val - 1) <= config.integer_tolerance or
                    fabs(var_val) <= config.integer_tolerance):
                v_to.set_value(rounded_val)
            elif 'is not in domain Integers' in err_msg and (
                    fabs(var_val - rounded_val) <= config.integer_tolerance):
                v_to.set_value(rounded_val)
            # Value is zero, but shows up as slightly less than zero.
            elif 'is not in domain NonNegativeReals' in err_msg and (
                    fabs(var_val) <= config.zero_tolerance):
                v_to.set_value(0)
            else:
                raise
Beispiel #7
0
def disjunctive_bound(var, scope):
    """Compute the disjunctive bounds for a variable in a given scope.

    Args:
        var (_VarData): Variable for which to compute bound
        scope (Component): The scope in which to compute the bound. If not a
            _DisjunctData, it will walk up the tree and use the scope of the
            most immediate enclosing _DisjunctData.

    Returns:
        numeric: the tighter of either the disjunctive lower bound, the
            variable lower bound, or (-inf, inf) if neither exist.

    """
    # Initialize to the global variable bound
    var_bnd = (
        value(var.lb) if var.has_lb() else -inf,
        value(var.ub) if var.has_ub() else inf)
    possible_disjunct = scope
    while possible_disjunct is not None:
        try:
            disj_bnd = possible_disjunct._disj_var_bounds.get(var, (-inf, inf))
            disj_bnd = (
                max(var_bnd[0], disj_bnd[0]),
                min(var_bnd[1], disj_bnd[1]))
            return disj_bnd
        except AttributeError:
            # possible disjunct does not have attribute '_disj_var_bounds'.
            # Try again with the scope's parent block.
            possible_disjunct = possible_disjunct.parent_block()
    # Unable to find '_disj_var_bounds' attribute within search scope.
    return var_bnd
Beispiel #8
0
def unit_capacity_systemwide_constraint_rule(backend_model, tech):
    """
    Set constraints to limit the number of purchased units of a single technology
    type across all locations in the model.

    The first valid case is applied:

    .. container:: scrolling-wrapper

        .. math::

            \\sum_{loc}\\boldsymbol{units}(loc::tech) + \\boldsymbol{purchased}(loc::tech)
            \\begin{cases}
                = units_{equals, systemwide}(tech),&
                    \\text{if } units_{equals, systemwide}(tech)\\\\
                \\leq units_{max, systemwide}(tech),&
                    \\text{if } units_{max, systemwide}(tech)\\\\
                \\text{unconstrained},& \\text{otherwise}
            \\end{cases}
            \\forall tech \\in techs

    """

    if tech in backend_model.techs_transmission_names:
        all_loc_techs = [
            i for i in backend_model.loc_techs_transmission
            if i.split('::')[1].split(':')[0] == tech
        ]
        multiplier = 2  # there are always two technologies associated with one link
    else:
        all_loc_techs = [
            i for i in backend_model.loc_techs
            if i.split('::')[1] == tech
        ]
        multiplier = 1

    max_systemwide = get_param(backend_model, 'units_max_systemwide', tech)
    equals_systemwide = get_param(backend_model, 'units_equals_systemwide', tech)

    if np.isinf(po.value(max_systemwide)) and not equals_systemwide:
        return po.Constraint.NoConstraint
    elif equals_systemwide and np.isinf(po.value(equals_systemwide)):
        raise ValueError(
            'Cannot use inf for energy_cap_equals_systemwide for tech `{}`'.format(tech)
        )

    sum_expr_units = sum(
        backend_model.units[loc_tech] for loc_tech in all_loc_techs
        if loc_tech_is_in(backend_model, loc_tech, 'loc_techs_milp')
    )
    sum_expr_purchase = sum(
        backend_model.purchased[loc_tech] for loc_tech in all_loc_techs
        if loc_tech_is_in(backend_model, loc_tech, 'loc_techs_purchase')
    )

    if equals_systemwide:
        return sum_expr_units + sum_expr_purchase == equals_systemwide * multiplier
    else:
        return sum_expr_units + sum_expr_purchase <= max_systemwide * multiplier
def resource_availability_supply_plus_constraint_rule(backend_model, loc_tech, timestep):
    """
    Limit production from supply_plus techs to their available resource.

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{resource_{con}}(loc::tech, timestep)
            \\leq available\\_resource(loc::tech, timestep)
            \\quad \\forall loc::tech \\in loc::techs_{supply^{+}}, \\forall timestep \\in timesteps

    If :math:`force\\_resource(loc::tech)` is set:

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{resource_{con}}(loc::tech, timestep)
            = available\\_resource(loc::tech, timestep)
            \\quad \\forall loc::tech \\in loc::techs_{supply^{+}}, \\forall timestep \\in timesteps

    Where:

    .. container:: scrolling-wrapper

        .. math::

            available\\_resource(loc::tech, timestep) = resource(loc::tech, timestep)
            \\times resource_{scale}(loc::tech)

    if :math:`loc::tech` is in :math:`loc::techs_{area}`:

    .. container:: scrolling-wrapper

        .. math::

            available\\_resource(loc::tech, timestep) = resource(loc::tech, timestep)
            \\times resource_{scale}(loc::tech)
            \\times resource_{area}(loc::tech)

    """
    resource = get_param(backend_model, 'resource', (loc_tech, timestep))
    resource_scale = get_param(backend_model, 'resource_scale', loc_tech)
    force_resource = get_param(backend_model, 'force_resource', loc_tech)
    resource_unit = get_param(backend_model, 'resource_unit', loc_tech)

    if po.value(resource_unit) == 'energy_per_area':
        available_resource = resource * resource_scale * backend_model.resource_area[loc_tech]
    elif po.value(resource_unit) == 'energy_per_cap':
        available_resource = resource * resource_scale * backend_model.energy_cap[loc_tech]
    else:
        available_resource = resource * resource_scale

    if po.value(force_resource):
        return backend_model.resource_con[loc_tech, timestep] == available_resource
    else:
        return backend_model.resource_con[loc_tech, timestep] <= available_resource
Beispiel #10
0
def log_infeasible_constraints(m, tol=1E-6, logger=logger):
    """Print the infeasible constraints in the model.

    Uses the current model state. Uses pyomo.util.infeasible logger unless one
    is provided.

    Args:
        m (Block): Pyomo block or model to check
        tol (float): feasibility tolerance

    """
    for constr in m.component_data_objects(
            ctype=Constraint, active=True, descend_into=True):
        # if constraint is an equality, handle differently
        if constr.equality and fabs(value(constr.lower - constr.body)) >= tol:
            logger.info('CONSTR {}: {} != {}'.format(
                constr.name, value(constr.body), value(constr.lower)))
            continue
        # otherwise, check LB and UB, if they exist
        if constr.has_lb() and value(constr.lower - constr.body) >= tol:
            logger.info('CONSTR {}: {} < {}'.format(
                constr.name, value(constr.body), value(constr.lower)))
        if constr.has_ub() and value(constr.body - constr.upper) >= tol:
            logger.info('CONSTR {}: {} > {}'.format(
                constr.name, value(constr.body), value(constr.upper)))
Beispiel #11
0
 def getInitialValue(self):
     x = np.zeros(self.lx, dtype=float)
     y = np.zeros(self.ly, dtype=float)
     z = np.zeros(self.lz, dtype=float)
     for i in range(0, self.lx):
         x[i] = value(self.TRF.xvars[i])
     for i in range(0, self.ly):
         #initialization of y?
         y[i] = 1
     for i in range(0, self.lz):
         z[i] = value(self.TRF.zvars[i])
     return x, y, z
Beispiel #12
0
def solve_NLP_feas(solve_data, config):
    m = solve_data.working_model.clone()
    add_feas_slacks(m)
    MindtPy = m.MindtPy_utils
    next(m.component_data_objects(Objective, active=True)).deactivate()
    for constr in m.component_data_objects(
            ctype=Constraint, active=True, descend_into=True):
        constr.deactivate()
    MindtPy.MindtPy_feas.activate()
    MindtPy.MindtPy_feas_obj = Objective(
        expr=sum(s for s in MindtPy.MindtPy_feas.slack_var[...]),
        sense=minimize)
    for v in MindtPy.variable_list:
        if v.is_binary():
            v.fix(int(round(v.value)))
    # m.pprint()  #print nlp feasibility problem for debugging
    with SuppressInfeasibleWarning():
        feas_soln = SolverFactory(config.nlp_solver).solve(
            m, **config.nlp_solver_args)
    subprob_terminate_cond = feas_soln.solver.termination_condition
    if subprob_terminate_cond is tc.optimal:
        copy_var_list_values(
            MindtPy.variable_list,
            solve_data.working_model.MindtPy_utils.variable_list,
            config)
        pass
    elif subprob_terminate_cond is tc.infeasible:
        raise ValueError('Feasibility NLP infeasible. '
                         'This should never happen.')
    else:
        raise ValueError(
            'MindtPy unable to handle feasibility NLP termination condition '
            'of {}'.format(subprob_terminate_cond))

    var_values = [v.value for v in MindtPy.variable_list]
    duals = [0 for _ in MindtPy.constraint_list]

    for i, constr in enumerate(MindtPy.constraint_list):
        # TODO rhs only works if constr.upper and constr.lower do not both have values.
        # Sometimes you might have 1 <= expr <= 1. This would give an incorrect rhs of 2.
        rhs = ((0 if constr.upper is None else constr.upper) +
               (0 if constr.lower is None else constr.lower))
        sign_adjust = 1 if value(constr.upper) is None else -1
        duals[i] = sign_adjust * max(
            0, sign_adjust * (rhs - value(constr.body)))

    if value(MindtPy.MindtPy_feas_obj.expr) == 0:
        raise ValueError(
            'Problem is not feasible, check NLP solver')

    return var_values, duals
Beispiel #13
0
def energy_capacity_systemwide_constraint_rule(backend_model, tech):
    """
    Set constraints to limit the capacity of a single technology type across all locations in the model.

    The first valid case is applied:

    .. container:: scrolling-wrapper

        .. math::

            \\sum_{loc}\\boldsymbol{energy_{cap}}(loc::tech)
            \\begin{cases}
                = energy_{cap, equals, systemwide}(loc::tech),&
                    \\text{if } energy_{cap, equals, systemwide}(loc::tech)\\\\
                \\leq energy_{cap, max, systemwide}(loc::tech),&
                    \\text{if } energy_{cap, max, systemwide}(loc::tech)\\\\
                \\text{unconstrained},& \\text{otherwise}
            \\end{cases}
            \\forall tech \\in techs

    """

    if tech in backend_model.techs_transmission_names:
        all_loc_techs = [
            i for i in backend_model.loc_techs_transmission
            if i.split('::')[1].split(':')[0] == tech
        ]
        multiplier = 2  # there are always two technologies associated with one link
    else:
        all_loc_techs = [
            i for i in backend_model.loc_techs
            if i.split('::')[1] == tech
        ]
        multiplier = 1

    max_systemwide = get_param(backend_model, 'energy_cap_max_systemwide', tech)
    equals_systemwide = get_param(backend_model, 'energy_cap_equals_systemwide', tech)

    if np.isinf(po.value(max_systemwide)) and not equals_systemwide:
        return po.Constraint.NoConstraint
    elif equals_systemwide and np.isinf(po.value(equals_systemwide)):
        raise exceptions.ModelError(
            'Cannot use inf for energy_cap_equals_systemwide for tech `{}`'.format(tech)
        )

    sum_expr = sum(backend_model.energy_cap[loc_tech] for loc_tech in all_loc_techs)

    if equals_systemwide:
        return sum_expr == equals_systemwide * multiplier
    else:
        return sum_expr <= max_systemwide * multiplier
Beispiel #14
0
def cost_var_constraint_rule(backend_model, cost, loc_tech, timestep):
    """
    Calculate costs from time-varying decision variables

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{cost_{var}}(cost, loc::tech, timestep) = cost_{prod}(cost, loc::tech, timestep) + cost_{con}(cost, loc::tech, timestep)

            cost_{prod}(cost, loc::tech, timestep) = cost_{om\\_prod}(cost, loc::tech, timestep) \\times weight(timestep) \\times \\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)

            prod\\_con\\_eff =
            \\begin{cases}
                = \\boldsymbol{resource_{con}}(loc::tech, timestep),&
                    \\text{if } loc::tech \\in loc\\_techs\\_supply\\_plus \\\\
                = \\frac{\\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{energy_eff(loc::tech, timestep)},&
                    \\text{if } loc::tech \\in loc\\_techs\\_supply \\\\
            \\end{cases}

            cost_{con}(cost, loc::tech, timestep) = cost_{om\\_con}(cost, loc::tech, timestep) \\times weight(timestep) \\times prod\\_con\\_eff

    """
    model_data_dict = backend_model.__calliope_model_data__

    cost_om_prod = get_param(backend_model, 'cost_om_prod', (cost, loc_tech, timestep))
    cost_om_con = get_param(backend_model, 'cost_om_con', (cost, loc_tech, timestep))
    weight = backend_model.timestep_weights[timestep]

    loc_tech_carrier = model_data_dict['data']['lookup_loc_techs'][loc_tech]

    if po.value(cost_om_prod):
        cost_prod = cost_om_prod * weight * backend_model.carrier_prod[loc_tech_carrier, timestep]
    else:
        cost_prod = 0

    if loc_tech_is_in(backend_model, loc_tech, 'loc_techs_supply_plus') and cost_om_con:
        cost_con = cost_om_con * weight * backend_model.resource_con[loc_tech, timestep]
    elif loc_tech_is_in(backend_model, loc_tech, 'loc_techs_supply') and cost_om_con:
        energy_eff = get_param(backend_model, 'energy_eff', (loc_tech, timestep))
        if po.value(energy_eff) > 0:  # in case energy_eff is zero, to avoid an infinite value
            cost_con = cost_om_con * weight * (backend_model.carrier_prod[loc_tech_carrier, timestep] / energy_eff)
        else:
            cost_con = 0
    else:
        cost_con = 0

    backend_model.cost_var_rhs[cost, loc_tech, timestep].expr = cost_prod + cost_con
    return (backend_model.cost_var[cost, loc_tech, timestep] ==
            backend_model.cost_var_rhs[cost, loc_tech, timestep])
Beispiel #15
0
 def generate_gofx(self, G, tears):
     edge_list = self.idx_to_edge(G)
     gofx = []
     for tear in tears:
         arc = G.edges[edge_list[tear]]["arc"]
         src = arc.src
         sf = arc.expanded_block.component("splitfrac")
         for name, mem in src.iter_vars(names=True):
             if src.is_extensive(name) and sf is not None:
                 # TODO: same as above, what if there's no splitfrac
                 gofx.append(value(mem * sf))
             else:
                 gofx.append(value(mem))
     gofx = numpy.array(gofx)
     return gofx
Beispiel #16
0
    def register_var(self, var, lb, ub):
        """Registers a new variable."""
        var_idx = self.var_to_idx[var]
        inf = float('inf')

        # Guard against errant None values in lb and ub
        lb = -inf if lb is None else lb
        ub = inf if ub is None else ub

        lb = max(var.lb if var.has_lb() else -inf, lb)
        ub = min(var.ub if var.has_ub() else inf, ub)
        var_val = value(var, exception=False)
        if lb == -inf:
            lb = -500000
            logger.warning(
                'Var %s missing lower bound. Assuming LB of %s'
                % (var.name, lb))
        if ub == inf:
            ub = 500000
            logger.warning(
                'Var %s missing upper bound. Assuming UB of %s'
                % (var.name, ub))
        if var_val is None:
            var_val = (lb + ub) / 2
            self.missing_value_warnings.append(
                'Var %s missing value. Assuming midpoint value of %s'
                % (var.name, var_val))
        return self.mcpp.newVar(
            lb, var_val, ub, self.num_vars, var_idx)
Beispiel #17
0
    def subproblem_solve(gdp, config):
        subproblem = gdp.clone()
        TransformationFactory('gdp.bigm').apply_to(subproblem)
        main_obj = next(subproblem.component_data_objects(Objective, active=True))
        obj_sign = 1 if main_obj.sense == minimize else -1

        try:
            result = SolverFactory(config.solver).solve(subproblem, **config.solver_args)
        except RuntimeError as e:
            config.logger.warning(
                "Solver encountered RuntimeError. Treating as infeasible. "
                "Msg: %s\n%s" % (str(e), traceback.format_exc()))
            var_values = [v.value for v in subproblem.GDPbb_utils.variable_list]
            return obj_sign * float('inf'), SolverResults(), var_values

        var_values = [v.value for v in subproblem.GDPbb_utils.variable_list]
        term_cond = result.solver.termination_condition
        if result.solver.status is SolverStatus.ok and any(
                term_cond == valid_cond for valid_cond in (tc.optimal, tc.locallyOptimal, tc.feasible)):
            return value(main_obj.expr), result, var_values
        elif term_cond == tc.unbounded:
            return obj_sign * float('-inf'), result, var_values
        elif term_cond == tc.infeasible:
            return obj_sign * float('inf'), result, var_values
        else:
            config.logger.warning("Unknown termination condition of %s" % term_cond)
            return obj_sign * float('inf'), result, var_values
Beispiel #18
0
def energy_capacity_max_purchase_constraint_rule(backend_model, loc_tech):
    """
    Set maximum energy capacity decision variable upper bound as a function of
    binary purchase variable

    The first valid case is applied:

    .. container:: scrolling-wrapper

        .. math::

            \\frac{\\boldsymbol{energy_{cap}}(loc::tech)}{energy_{cap, scale}(loc::tech)}
            \\begin{cases}
                = energy_{cap, equals}(loc::tech) \\times \\boldsymbol{purchased}(loc::tech),&
                    \\text{if } energy_{cap, equals}(loc::tech)\\\\
                \\leq energy_{cap, max}(loc::tech) \\times \\boldsymbol{purchased}(loc::tech),&
                    \\text{if } energy_{cap, max}(loc::tech)\\\\
                \\text{unconstrained},& \\text{otherwise}
            \\end{cases}
            \\forall loc::tech \\in loc::techs_{purchase}

    """
    energy_cap_max = get_param(backend_model, 'energy_cap_max', loc_tech)
    energy_cap_equals = get_param(backend_model, 'energy_cap_equals', loc_tech)
    energy_cap_scale = get_param(backend_model, 'energy_cap_scale', loc_tech)

    if po.value(energy_cap_equals):
        return backend_model.energy_cap[loc_tech] == (
            energy_cap_equals * energy_cap_scale * backend_model.purchased[loc_tech]
        )

    else:
        return backend_model.energy_cap[loc_tech] <= (
            energy_cap_max * energy_cap_scale * backend_model.purchased[loc_tech]
        )
Beispiel #19
0
 def pass_single_value(self, port, name, member, val, fixed):
     """
     Fix the value of the port member and add it to the fixed set.
     If the member is an expression, appropriately fix the value of
     its free variable. Error if the member is already fixed but
     different from val, or if the member has more than one free
     variable."
     """
     eq_tol = self.options["almost_equal_tol"]
     if member.is_fixed():
         if abs(value(member) - val) > eq_tol:
             raise RuntimeError(
                 "Member '%s' of port '%s' is already fixed but has a "
                 "different value (by > %s) than what is being passed to it"
                 % (name, port.name, eq_tol))
     elif member.is_expression_type():
         repn = generate_standard_repn(member - val)
         if repn.is_linear() and len(repn.linear_vars) == 1:
             # fix the value of the single variable
             fval = (0 - repn.constant) / repn.linear_coefs[0]
             var = repn.linear_vars[0]
             fixed.add(var)
             var.fix(fval)
         else:
             raise RuntimeError(
                 "Member '%s' of port '%s' had more than "
                 "one free variable when trying to pass a value "
                 "to it. Please fix more variables before passing "
                 "to this port." % (name, port.name))
     else:
         fixed.add(member)
         member.fix(val)
Beispiel #20
0
 def _collect_bilinear(self, expr, bilin, quad):
     if not expr.is_expression():
         return
     if type(expr) is _ProductExpression:
         if len(expr._numerator) != 2:
             for e in expr._numerator:
                 self._collect_bilinear(e, bilin, quad)
             # No need to check denominator, as this is poly_degree==2
             return
         if not isinstance(expr._numerator[0], _VarData) or \
                 not isinstance(expr._numerator[1], _VarData):
             raise RuntimeError("Cannot yet handle complex subexpressions")
         if expr._numerator[0] is expr._numerator[1]:
             quad.append( (expr, expr._numerator[0]) )
         else:
             bilin.append( (expr, expr._numerator[0], expr._numerator[1]) )
         return
     if type(expr) is _PowExpression and value(expr._args[1]) == 2:
         # Note: directly testing the value of the exponent above is
         # safe: we have already verified that this expression is
         # polynominal, so the exponent must be constant.
         tmp = _ProductExpression()
         tmp._numerator = [ expr._args[0], expr._args[0] ]
         tmp._denominator = []
         expr._args = (tmp, as_numeric(1))
         #quad.append( (tmp, tmp._args[0]) )
         self._collect_bilinear(tmp, bilin, quad)
         return 
     # All other expression types
     for e in expr._args:
         self._collect_bilinear(e, bilin, quad)
Beispiel #21
0
def cost_var_conversion_constraint_rule(backend_model, cost, loc_tech, timestep):
    """
    Add time-varying conversion technology costs

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{cost_{var}}(loc::tech, cost, timestep) =
            \\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)
            \\times timestep_{weight}(timestep) \\times cost_{om, prod}(loc::tech, cost, timestep)
            +
            \\boldsymbol{carrier_{con}}(loc::tech::carrier, timestep)
            \\times timestep_{weight}(timestep) \\times cost_{om, con}(loc::tech, cost, timestep)
            \\quad \\forall loc::tech \\in loc::techs_{cost_{var}, conversion}
    """
    model_data_dict = backend_model.__calliope_model_data__
    weight = backend_model.timestep_weights[timestep]

    loc_tech_carrier_in = (
        model_data_dict['data']['lookup_loc_techs_conversion'][('in', loc_tech)]
    )

    loc_tech_carrier_out = (
        model_data_dict['data']['lookup_loc_techs_conversion'][('out', loc_tech)]
    )

    cost_om_prod = get_param(backend_model, 'cost_om_prod',
                                (cost, loc_tech, timestep))
    cost_om_con = get_param(backend_model, 'cost_om_con',
                            (cost, loc_tech, timestep))
    if po.value(cost_om_prod):
        cost_prod = (cost_om_prod * weight *
            backend_model.carrier_prod[loc_tech_carrier_out, timestep])
    else:
        cost_prod = 0

    if po.value(cost_om_con):
        cost_con = (cost_om_con * weight * -1 *
            backend_model.carrier_con[loc_tech_carrier_in, timestep])
    else:
        cost_con = 0

    backend_model.cost_var_rhs[cost, loc_tech, timestep] = cost_prod + cost_con

    return (backend_model.cost_var[cost, loc_tech, timestep] ==
            backend_model.cost_var_rhs[cost, loc_tech, timestep])
Beispiel #22
0
def log_close_to_bounds(m, tol=1E-6, logger=logger):
    """Print the variables and constraints that are near their bounds.

    Fixed variables and equality constraints are excluded from this analysis.

    Args:
        m (Block): Pyomo block or model to check
        tol (float): bound tolerance
    """
    for var in m.component_data_objects(
            ctype=Var, descend_into=True):
        if var.fixed:
            continue
        if (var.has_lb() and var.has_ub() and
                fabs(value(var.ub - var.lb)) <= 2 * tol):
            continue  # if the bounds are too close, skip.
        if var.has_lb() and fabs(value(var.lb - var)) <= tol:
            logger.info('{} near LB of {}'.format(var.name, value(var.lb)))
        elif var.has_ub() and fabs(value(var.ub - var)) <= tol:
            logger.info('{} near UB of {}'.format(var.name, value(var.ub)))

    for constr in m.component_data_objects(
            ctype=Constraint, descend_into=True, active=True):
        if not constr.equality:
            if (constr.has_ub() and
                    fabs(value(constr.body - constr.upper)) <= tol):
                logger.info('{} near UB'.format(constr.name))
            if (constr.has_lb() and
                    fabs(value(constr.body - constr.lower)) <= tol):
                logger.info('{} near LB'.format(constr.name))
Beispiel #23
0
 def combine_and_fix(self, port, name, obj, evars, fixed):
     """
     For an extensive port member, combine the values of all
     expanded variables and fix the port member at their sum.
     Assumes that all expanded variables are fixed.
     """
     assert all(evar.is_fixed() for evar in evars)
     total = sum(value(evar) for evar in evars)
     self.pass_single_value(port, name, obj, total, fixed)
Beispiel #24
0
 def generate_first_x(self, G, tears):
     edge_list = self.idx_to_edge(G)
     x = []
     for tear in tears:
         arc = G.edges[edge_list[tear]]["arc"]
         for name, index, mem in arc.src.iter_vars(names=True):
             peer = self.source_dest_peer(arc, name, index)
             x.append(value(peer))
     x = numpy.array(x)
     return x
def balance_storage_constraint_rule(backend_model, loc_tech, timestep):
    """
    Balance carrier production and consumption of storage technologies,
    alongside any use of the stored volume.

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{storage}(loc::tech, timestep) =
            \\boldsymbol{storage}(loc::tech, timestep_{previous})
            \\times (1 - storage\\_loss(loc::tech, timestep))^{resolution(timestep)}
            - \\boldsymbol{carrier_{con}}(loc::tech::carrier, timestep)
            \\times \\eta_{energy}(loc::tech, timestep)
            - \\frac{\\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{\\eta_{energy}(loc::tech, timestep)}
            \\quad \\forall loc::tech \\in loc::techs_{storage}, \\forall timestep \\in timesteps
    """
    model_data_dict = backend_model.__calliope_model_data__['data']
    model_attrs = backend_model.__calliope_model_data__['attrs']

    energy_eff = get_param(backend_model, 'energy_eff', (loc_tech, timestep))

    if po.value(energy_eff) == 0:
        carrier_prod = 0
    else:
        loc_tech_carrier = model_data_dict['lookup_loc_techs'][loc_tech]
        carrier_prod = backend_model.carrier_prod[loc_tech_carrier, timestep] / energy_eff

    carrier_con = backend_model.carrier_con[loc_tech_carrier, timestep] * energy_eff

    current_timestep = backend_model.timesteps.order_dict[timestep]
    if current_timestep == 0 and not model_attrs['run.cyclic_storage']:
        storage_previous_step = get_param(backend_model, 'storage_initial', loc_tech)
    elif (hasattr(backend_model, 'storage_inter_cluster') and
            model_data_dict['lookup_cluster_first_timestep'][timestep]):
        storage_previous_step = 0
    else:
        if (hasattr(backend_model, 'clusters') and
                model_data_dict['lookup_cluster_first_timestep'][timestep]):
            previous_step = model_data_dict['lookup_cluster_last_timestep'][timestep]
        elif current_timestep == 0 and model_attrs['run.cyclic_storage']:
            previous_step = backend_model.timesteps[-1]
        else:
            previous_step = get_previous_timestep(backend_model.timesteps, timestep)
        storage_loss = get_param(backend_model, 'storage_loss', loc_tech)
        time_resolution = backend_model.timestep_resolution[previous_step]
        storage_previous_step = (
            ((1 - storage_loss) ** time_resolution) *
            backend_model.storage[loc_tech, previous_step]
        )

    return (
        backend_model.storage[loc_tech, timestep] ==
        storage_previous_step - carrier_prod - carrier_con
    )
Beispiel #26
0
def add_objective_linearization(solve_data, config):
    """Adds initial linearized objective in case it is nonlinear.

    This should be done for initializing the ECP method.

    """
    m = solve_data.working_model
    MindtPy = m.MindtPy_utils
    solve_data.mip_iter += 1
    gen = (obj for obj in MindtPy.jacs
           if obj is MindtPy.MindtPy_objective_expr)
    MindtPy.MindtPy_linear_cuts.mip_iters.add(solve_data.mip_iter)
    sign_adjust = 1 if MindtPy.obj.sense == minimize else -1
    # generate new constraints
    # TODO some kind of special handling if the dual is phenomenally small?
    for obj in gen:
        c = MindtPy.MindtPy_linear_cuts.ecp_cuts.add(expr=sign_adjust * sum(
            value(MindtPy.jacs[obj][id(var)]) * (var - value(var))
            for var in list(EXPR.identify_variables(obj.body))) +
                                                     value(obj.body) <= 0)
        MindtPy.ECP_constr_map[obj, solve_data.mip_iter] = c
Beispiel #27
0
def solve_bounding_problem(model, solver):
    results = SolverFactory(solver).solve(model)
    if results.solver.termination_condition is tc.optimal:
        return value(model._var_bounding_obj.expr)
    elif results.solver.termination_condition is tc.infeasible:
        return None
    elif results.solver.termination_condition is tc.unbounded:
        return -inf
    else:
        raise NotImplementedError(
            "Unhandled termination condition: %s"
            % results.solver.termination_condition)
Beispiel #28
0
def copy_var_list_values(from_list, to_list, config,
                         skip_stale=False, skip_fixed=True,
                         ignore_integrality=False):
    """Copy variable values from one list to another.

    Rounds to Binary/Integer if necessary
    Sets to zero for NonNegativeReals if necessary
    """
    for v_from, v_to in zip(from_list, to_list):
        if skip_stale and v_from.stale:
            continue  # Skip stale variable values.
        if skip_fixed and v_to.is_fixed():
            continue  # Skip fixed variables.
        try:
            # We don't want to trigger the reset of the global stale
            # indicator, so we will set this variable to be "stale",
            # knowing that set_value will switch it back to "not
            # stale"
            v_to.stale = True
            # NOTE: PEP 2180 changes the var behavior so that domain /
            # bounds violations no longer generate exceptions (and
            # instead log warnings).  This means that the following will
            # always succeed and the ValueError should never be raised.
            v_to.set_value(value(v_from, exception=False), skip_validation=True)
        except ValueError as err:
            err_msg = getattr(err, 'message', str(err))
            var_val = value(v_from)
            rounded_val = int(round(var_val))
            # Check to see if this is just a tolerance issue
            if ignore_integrality and v_to.is_integer():
                v_to.set_value(var_val, skip_validation=True)
            elif v_to.is_integer() and (fabs(var_val - rounded_val) <=
                                        config.integer_tolerance):
                v_to.set_value(rounded_val, skip_validation=True)
            elif abs(var_val) <= config.zero_tolerance and 0 in v_to.domain:
                v_to.set_value(0, skip_validation=True)
            else:
                config.logger.error(
                    'Unknown validation domain error setting variable %s', (v_to.name,))
                raise
Beispiel #29
0
def handle_master_mip_optimal(master_mip, solve_data, config):
    """
    This function copies the result from 'solve_OA_master' to the working model and updates the upper/lower bound. This
    function is called after an optimal solution is found for the master problem.

    Parameters
    ----------
    master_mip: Pyomo model
        the MIP master problem
    solve_data: MindtPy Data Container
        data container that holds solve-instance data
    config: ConfigBlock
        contains the specific configurations for the algorithm
    """
    # proceed. Just need integer values
    MindtPy = master_mip.MindtPy_utils
    main_objective = next(
        master_mip.component_data_objects(Objective, active=True))
    # check if the value of binary variable is valid
    for var in MindtPy.variable_list:
        if var.value is None and var.is_integer():
            config.logger.warning(
                "Integer variable {} not initialized. It is set to it's lower bound"
                .format(var.name))
            var.value = var.lb  # nlp_var.bounds[0]
    # warm start for the nlp subproblem
    copy_var_list_values(master_mip.MindtPy_utils.variable_list,
                         solve_data.working_model.MindtPy_utils.variable_list,
                         config)

    if main_objective.sense == minimize:
        solve_data.LB = max(value(MindtPy.MindtPy_oa_obj.expr), solve_data.LB)
        solve_data.LB_progress.append(solve_data.LB)
    else:
        solve_data.UB = min(value(MindtPy.MindtPy_oa_obj.expr), solve_data.UB)
        solve_data.UB_progress.append(solve_data.UB)
    config.logger.info(
        'MIP %s: OBJ: %s  LB: %s  UB: %s' %
        (solve_data.mip_iter, value(
            MindtPy.MindtPy_oa_obj.expr), solve_data.LB, solve_data.UB))
Beispiel #30
0
def get_capacity_constraint(backend_model,
                            parameter,
                            loc_tech,
                            _equals=None,
                            _max=None,
                            _min=None,
                            scale=None):

    decision_variable = getattr(backend_model, parameter)

    if not _equals:
        _equals = get_param(backend_model, parameter + '_equals', loc_tech)
    if not _max:
        _max = get_param(backend_model, parameter + '_max', loc_tech)
    if not _min:
        _min = get_param(backend_model, parameter + '_min', loc_tech)
    if po.value(_equals) is not False and po.value(_equals) is not None:
        if np.isinf(po.value(_equals)):
            e = exceptions.ModelError
            raise e('Cannot use inf for {}_equals for loc:tech `{}`'.format(
                parameter, loc_tech))
        if scale:
            _equals *= scale
        return decision_variable[loc_tech] == _equals
    else:
        if np.isinf(po.value(_max)):
            _max = None  # to disable upper bound
        if po.value(_min) == 0 and po.value(_max) is None:
            return po.Constraint.NoConstraint
        else:
            if scale:
                _max *= scale
                _min *= scale
            return (_min, decision_variable[loc_tech], _max)
Beispiel #31
0
    def _estimate_M(self, expr, name):
        # Calculate a best guess at M
        repn = generate_standard_repn(expr, quadratic=False)
        M = [0, 0]

        if not repn.is_nonlinear():
            if repn.constant is not None:
                for i in (0, 1):
                    if M[i] is not None:
                        M[i] += repn.constant

            for i, coef in enumerate(repn.linear_coefs or []):
                var = repn.linear_vars[i]
                bounds = (value(var.lb), value(var.ub))
                for i in (0, 1):
                    # reverse the bounds if the coefficient is negative
                    if coef > 0:
                        j = i
                    else:
                        j = 1 - i

                    if bounds[i] is not None:
                        M[j] += value(bounds[i]) * coef
                    else:
                        raise GDP_Error(
                            "Cannot estimate M for "
                            "expressions with unbounded variables."
                            "\n\t(found unbounded var %s while processing "
                            "constraint %s)" % (var.name, name))
        else:
            # expression is nonlinear. Try using `contrib.fbbt` to estimate.
            expr_lb, expr_ub = compute_bounds_on_expr(expr)
            if expr_lb is None or expr_ub is None:
                raise GDP_Error("Cannot estimate M for unbounded nonlinear "
                                "expressions.\n\t(found while processing "
                                "constraint %s)" % name)
            else:
                M = (expr_lb, expr_ub)

        return tuple(M)
Beispiel #32
0
def copy_var_list_values(from_list, to_list, config,
                         skip_stale=False, skip_fixed=True,
                         ignore_integrality=False):
    """Copy variable values from one list to another.

    Rounds to Binary/Integer if neccessary
    Sets to zero for NonNegativeReals if neccessary
    """
    for v_from, v_to in zip(from_list, to_list):
        if skip_stale and v_from.stale:
            continue  # Skip stale variable values.
        if skip_fixed and v_to.is_fixed():
            continue  # Skip fixed variables.
        try:
            v_to.set_value(value(v_from, exception=False))
            if skip_stale:
                v_to.stale = False
        except ValueError as err:
            err_msg = getattr(err, 'message', str(err))
            var_val = value(v_from)
            rounded_val = int(round(var_val))
            # Check to see if this is just a tolerance issue
            if ignore_integrality \
                and ('is not in domain Binary' in err_msg
                or 'is not in domain Integers' in err_msg):
               v_to.value = value(v_from, exception=False)
            elif 'is not in domain Binary' in err_msg and (
                    fabs(var_val - 1) <= config.integer_tolerance or
                    fabs(var_val) <= config.integer_tolerance):
                v_to.set_value(rounded_val)
            # TODO What about PositiveIntegers etc?
            elif 'is not in domain Integers' in err_msg and (
                    fabs(var_val - rounded_val) <= config.integer_tolerance):
                v_to.set_value(rounded_val)
            # Value is zero, but shows up as slightly less than zero.
            elif 'is not in domain NonNegativeReals' in err_msg and (
                    fabs(var_val) <= config.zero_tolerance):
                v_to.set_value(0)
            else:
                raise
Beispiel #33
0
 def _add_vars(self, var_seq):
     if not var_seq:
         return
     var_num = self._solver_model.getnumvar()
     vnames = tuple(
         self._symbol_map.getSymbol(v, self._labeler) for v in var_seq)
     vtypes = tuple(map(self._mosek_vartype_from_var, var_seq))
     lbs = tuple(
         value(v) if v.fixed else -inf if value(v.lb) is None else value(v.
                                                                         lb)
         for v in var_seq)
     ubs = tuple(
         value(v) if v.fixed else inf if value(v.ub) is None else value(v.ub
                                                                        )
         for v in var_seq)
     fxs = tuple(v.is_fixed() for v in var_seq)
     bound_types = tuple(map(self._mosek_bounds, lbs, ubs, fxs))
     self._solver_model.appendvars(len(var_seq))
     var_ids = range(var_num, var_num + len(var_seq))
     _vnames = tuple(map(self._solver_model.putvarname, var_ids, vnames))
     self._solver_model.putvartypelist(var_ids, vtypes)
     self._solver_model.putvarboundlist(var_ids, bound_types, lbs, ubs)
     self._pyomo_var_to_solver_var_map.update(zip(var_seq, var_ids))
     self._solver_var_to_pyomo_var_map.update(zip(var_ids, var_seq))
     self._referenced_variables.update(zip(var_seq, [0] * len(var_seq)))
Beispiel #34
0
 def update_vars(self, *solver_vars):
     """
     Update multiple scalar variables in solver model. This method allows fixing/unfixing,
     changing variable types and bounds.
     Parameters
     ----------
     *solver_var: Constraint (scalar Constraint or single _ConstraintData)
     """
     try:
         var_ids = []
         for v in solver_vars:
             var_ids.append(self._pyomo_var_to_solver_var_map[v])
         vtypes = tuple(map(self._mosek_vartype_from_var, solver_vars))
         lbs = tuple(
             value(v) if v.fixed else
             -float('inf') if value(v.lb) is None else value(v.lb)
             for v in solver_vars)
         ubs = tuple(
             value(v) if v.
             fixed else float('inf') if value(v.ub) is None else value(v.ub)
             for v in solver_vars)
         fxs = tuple(v.is_fixed() for v in solver_vars)
         bound_types = tuple(map(self._mosek_bounds, lbs, ubs, fxs))
         self._solver_model.putvartypelist(var_ids, vtypes)
         self._solver_model.putvarboundlist(var_ids, bound_types, lbs, ubs)
     except KeyError:
         print(v.name)
         v_name = self._symbol_map.getSymbol(v, self._labeler)
         raise ValueError(
             "Variable {} needs to be added before it can be modified.".
             format(v_name))
Beispiel #35
0
    def _add_node(u, stage, succ, pred):
        if node_name_attribute is not None:
            if node_name_attribute not in tree.node[u]:
                raise KeyError(
                    "node '%s' missing name attribute: '%s'"
                    % (u, node_name_attribute))
            node_name = tree.node[u][node_name_attribute]
        else:
            node_name = u
        m.NodeStage[node_name] = m.Stages[stage]
        if u == root:
            m.ConditionalProbability[node_name] = 1.0
        else:
            assert u in pred
            # prior to networkx ~2.0, we used a .edge attribute on DiGraph,
            # which no longer exists.
            if hasattr(tree, 'edge'):
                edge = tree.edge[pred[u]][u]
            else:
                edge = tree.edges[pred[u],u]
            probability = None
            if edge_probability_attribute is not None:
                if edge_probability_attribute not in edge:
                    raise KeyError(
                        "edge '(%s, %s)' missing probability attribute: '%s'"
                        % (pred[u], u, edge_probability_attribute))
                probability = edge[edge_probability_attribute]
            else:
                probability = 1.0/len(succ[pred[u]])
            m.ConditionalProbability[node_name] = probability
        if u in succ:
            child_names = []
            for v in succ[u]:
                child_names.append(
                    _add_node(v, stage+1, succ, pred))
            total_probability = 0.0
            for child_name in child_names:
                m.Children[node_name].add(child_name)
                total_probability += \
                    value(m.ConditionalProbability[child_name])
            if abs(total_probability - 1.0) > 1e-5:
                raise ValueError(
                    "edge probabilities leaving node '%s' "
                    "do not sum to 1 (total=%r)"
                    % (u, total_probability))
        else:
            # a leaf node
            scenario_name = node_to_scenario[u]
            m.ScenarioLeafNode[scenario_name] = node_name
            m.Children[node_name].clear()

        return node_name
Beispiel #36
0
 def exitNode(self, node, values):
     node = super().exitNode(node, values)
     if node.__class__ is not EXPR.ExternalFunctionExpression:
         return node
     if id(node._fcn) not in self.efSet:
         return node
     # At this point we know this is an ExternalFunctionExpression
     # node that we want to replace with an auliliary variable (y)
     new_args = []
     seen = ComponentSet()
     # TODO: support more than PythonCallbackFunctions
     assert isinstance(node._fcn, PythonCallbackFunction)
     #
     # Note: the first argument to PythonCallbackFunction is the
     # function ID.  Since we are going to complain about constant
     # parameters, we need to skip the first argument when processing
     # the argument list.  This is really not good: we should allow
     # for constant arguments to the functions, and we should relax
     # the restriction that the external functions implement the
     # PythonCallbackFunction API (that restriction leads unfortunate
     # things later; i.e., accessing the private _fcn attribute
     # below).
     for arg in values[1][1:]:
         if type(arg) in nonpyomo_leaf_types or arg.is_fixed():
             # We currently do not allow constants or parameters for
             # the external functions.
             raise RuntimeError(
                 "TrustRegion does not support black boxes with "
                 "constant or parameter inputs\n\tExpression: %s" %
                 (node, ))
         if arg.is_expression_type():
             # All expressions (including simple linear expressions)
             # are replaced with a single auxiliary variable (and
             # eventually an additional constraint equating the
             # auxiliary variable to the original expression)
             _x = self.trf.x.add()
             _x.set_value(value(arg))
             self.trf.conset.add(_x == arg)
             new_args.append(_x)
         else:
             # The only thing left is bare variables: check for duplicates.
             if arg in seen:
                 raise RuntimeError(
                     "TrustRegion does not support black boxes with "
                     "duplicate input arguments\n\tExpression: %s" %
                     (node, ))
             seen.add(arg)
             new_args.append(arg)
     _y = self.trf.y.add()
     self.trf.external_fcns.append(node)
     self.trf.exfn_xvars.append(new_args)
     return _y
Beispiel #37
0
    def handle_lazy_subproblem_infeasible(self, fixed_nlp, solve_data, config,
                                          opt):
        """Solves feasibility NLP subproblem and adds cuts according to the specified strategy.

        Parameters
        ----------
        fixed_nlp : Pyomo model
            Integer-variable-fixed NLP model.
        solve_data : MindtPySolveData
            Data container that holds solve-instance data.
        config : ConfigBlock
            The specific configurations for MindtPy.
        opt : SolverFactory
            The cplex_persistent solver.
        """
        # TODO try something else? Reinitialize with different initial
        # value?
        config.logger.info('NLP subproblem was locally infeasible.')
        solve_data.nlp_infeasible_counter += 1
        if config.calculate_dual:
            for c in fixed_nlp.MindtPy_utils.constraint_list:
                rhs = ((0 if c.upper is None else c.upper) +
                       (0 if c.lower is None else c.lower))
                sign_adjust = 1 if c.upper is None else -1
                fixed_nlp.dual[c] = (sign_adjust *
                                     max(0, sign_adjust *
                                         (rhs - value(c.body))))
            dual_values = list(
                fixed_nlp.dual[c]
                for c in fixed_nlp.MindtPy_utils.constraint_list)
        else:
            dual_values = None

        config.logger.info('Solving feasibility problem')
        feas_subproblem, feas_subproblem_results = solve_feasibility_subproblem(
            solve_data, config)
        # In OA algorithm, OA cuts are generated based on the solution of the subproblem
        # We need to first copy the value of variables from the subproblem and then add cuts
        copy_var_list_values(feas_subproblem.MindtPy_utils.variable_list,
                             solve_data.mip.MindtPy_utils.variable_list,
                             config)
        if config.strategy == 'OA':
            self.add_lazy_oa_cuts(solve_data.mip, dual_values, solve_data,
                                  config, opt)
            if config.add_regularization is not None:
                add_oa_cuts(solve_data.mip, dual_values, solve_data, config)
        elif config.strategy == 'GOA':
            self.add_lazy_affine_cuts(solve_data, config, opt)
        if config.add_no_good_cuts:
            var_values = list(v.value
                              for v in fixed_nlp.MindtPy_utils.variable_list)
            self.add_lazy_no_good_cuts(var_values, solve_data, config, opt)
    def test_integer_arithmetic_non1_coefficients(self):
        m = ConcreteModel()
        m.x = Var(bounds=(0,9))
        m.y = Var(bounds=(-5, 5))
        m.c1 = Constraint(expr=4*m.x + m.y >= 4)
        m.c2 = Constraint(expr=m.y >= 2*m.x)

        fme = TransformationFactory('contrib.fourier_motzkin_elimination')
        
        fme.apply_to( m, vars_to_eliminate=m.x,
                      constraint_filtering_callback=None,
                      do_integer_arithmetic=True, verbose=True)

        constraints = m._pyomo_contrib_fme_transformation.projected_constraints

        self.assertEqual(len(constraints), 3)

        cons = constraints[3]
        self.assertEqual(value(cons.lower), -32)
        self.assertIs(cons.body, m.y)
        self.assertIsNone(cons.upper)

        cons = constraints[2]
        self.assertEqual(value(cons.lower), 0)
        self.assertIsNone(cons.upper)
        repn = generate_standard_repn(cons.body)
        self.assertTrue(repn.is_linear())
        self.assertEqual(len(repn.linear_coefs), 1)
        self.assertIs(repn.linear_vars[0], m.y)
        self.assertEqual(repn.linear_coefs[0], 2)

        cons = constraints[1]
        self.assertEqual(value(cons.lower), 4)
        self.assertIsNone(cons.upper)
        repn = generate_standard_repn(cons.body)
        self.assertTrue(repn.is_linear())
        self.assertEqual(len(repn.linear_coefs), 1)
        self.assertIs(repn.linear_vars[0], m.y)
        self.assertEqual(repn.linear_coefs[0], 3)
Beispiel #39
0
def solve_GLOA_master(solve_data, config):
    """Solve the rigorous outer approximation master problem."""
    m = solve_data.linear_GDP.clone()
    GDPopt = m.GDPopt_utils
    solve_data.mip_iteration += 1

    mip_results = solve_linear_GDP(m, solve_data, config)
    if mip_results:
        if GDPopt.objective.sense == minimize:
            solve_data.LB = max(value(GDPopt.objective.expr), solve_data.LB)
        else:
            solve_data.UB = min(value(GDPopt.objective.expr), solve_data.UB)
        solve_data.iteration_log[(solve_data.master_iteration,
                                  solve_data.mip_iteration,
                                  solve_data.nlp_iteration)] = (
                                      value(GDPopt.objective.expr),
                                      value(GDPopt.objective.expr),
                                      mip_results[1]  # mip_var_values
                                  )
        config.logger.info(
            'ITER %s.%s.%s-MIP: OBJ: %s  LB: %s  UB: %s' %
            (solve_data.master_iteration, solve_data.mip_iteration,
             solve_data.nlp_iteration, value(
                 GDPopt.objective.expr), solve_data.LB, solve_data.UB))
    else:
        # Master problem was infeasible.
        if solve_data.master_iteration == 1:
            config.logger.warning(
                'GDPopt initialization may have generated poor '
                'quality cuts.')
        # set optimistic bound to infinity
        if GDPopt.objective.sense == minimize:
            solve_data.LB = float('inf')
        else:
            solve_data.UB = float('-inf')
    # Call the MILP post-solve callback
    config.master_postsolve(m, solve_data)

    return mip_results
Beispiel #40
0
    def handle_lazy_NLP_subproblem_optimal(self, fixed_nlp, solve_data, config,
                                           opt):
        """Copies result to mip(explaination see below), updates bound, adds OA and integer cut,
        stores best solution if new one is best"""
        for c in fixed_nlp.tmp_duals:
            if fixed_nlp.dual.get(c, None) is None:
                fixed_nlp.dual[c] = fixed_nlp.tmp_duals[c]
        dual_values = list(fixed_nlp.dual[c]
                           for c in fixed_nlp.MindtPy_utils.constraint_list)

        main_objective = next(
            fixed_nlp.component_data_objects(Objective, active=True))
        if main_objective.sense == minimize:
            solve_data.UB = min(value(main_objective.expr), solve_data.UB)
            solve_data.solution_improved = solve_data.UB < solve_data.UB_progress[
                -1]
            solve_data.UB_progress.append(solve_data.UB)
        else:
            solve_data.LB = max(value(main_objective.expr), solve_data.LB)
            solve_data.solution_improved = solve_data.LB > solve_data.LB_progress[
                -1]
            solve_data.LB_progress.append(solve_data.LB)

        config.logger.info('NLP {}: OBJ: {}  LB: {}  UB: {}'.format(
            solve_data.nlp_iter, value(main_objective.expr), solve_data.LB,
            solve_data.UB))

        if solve_data.solution_improved:
            solve_data.best_solution_found = fixed_nlp.clone()

        if config.strategy == 'OA':
            # In OA algorithm, OA cuts are generated based on the solution of the subproblem
            # We need to first copy the value of variables from the subproblem and then add cuts
            # since value(constr.body), value(jacs[constr][var]), value(var) are used in self.add_lazy_oa_cuts()
            copy_var_list_values(fixed_nlp.MindtPy_utils.variable_list,
                                 solve_data.mip.MindtPy_utils.variable_list,
                                 config)
            self.add_lazy_oa_cuts(solve_data.mip, dual_values, solve_data,
                                  config, opt)
Beispiel #41
0
 def updateSurrogateModel(self):
     """
     The parameters needed for the surrogate model are the values of:
         b(w_k)      : basis_model_output
         d(w_k)      : truth_model_output
         grad b(w_k) : grad_basis_model_output
         grad d(w_k) : grad_truth_model_output
     """
     b = self.data
     for i, y in b.ef_outputs.items():
         b.basis_model_output[i] = value(b.basis_expressions[y])
         b.truth_model_output[i] = value(b.truth_models[y])
         # Basis functions are Pyomo expressions (in theory)
         gradBasis = differentiate(b.basis_expressions[y],
                                   wrt_list=b.ef_inputs[i])
         # These, however, are external functions
         gradTruth = differentiate(b.truth_models[y],
                                   wrt_list=b.ef_inputs[i])
         for j, w in enumerate(b.ef_inputs[i]):
             b.grad_basis_model_output[i, j] = gradBasis[j]
             b.grad_truth_model_output[i, j] = gradTruth[j]
             b.value_of_ef_inputs[i, j] = value(w)
Beispiel #42
0
def init_rNLP(solve_data, config):
    """Initialize by solving the rNLP (relaxed binary variables)."""
    solve_data.nlp_iter += 1
    m = solve_data.working_model.clone()
    config.logger.info("NLP %s: Solve relaxed integrality" %
                       (solve_data.nlp_iter, ))
    MindtPy = m.MindtPy_utils
    TransformationFactory('core.relax_integrality').apply_to(m)
    with SuppressInfeasibleWarning():
        results = SolverFactory(config.nlp_solver).solve(
            m, **config.nlp_solver_args)
    subprob_terminate_cond = results.solver.termination_condition
    if subprob_terminate_cond is tc.optimal:
        main_objective = next(m.component_data_objects(Objective, active=True))
        nlp_solution_values = list(v.value for v in MindtPy.variable_list)
        dual_values = list(m.dual[c] for c in MindtPy.constraint_list)
        # Add OA cut
        if main_objective.sense == minimize:
            solve_data.LB = value(main_objective.expr)
        else:
            solve_data.UB = value(main_objective.expr)
        config.logger.info('NLP %s: OBJ: %s  LB: %s  UB: %s' %
                           (solve_data.nlp_iter, value(main_objective.expr),
                            solve_data.LB, solve_data.UB))
        if config.strategy == 'OA':
            copy_var_list_values(m.MindtPy_utils.variable_list,
                                 solve_data.mip.MindtPy_utils.variable_list,
                                 config,
                                 ignore_integrality=True)
            add_oa_cuts(solve_data.mip, dual_values, solve_data, config)
    elif subprob_terminate_cond is tc.infeasible:
        # TODO fail? try something else?
        config.logger.info('Initial relaxed NLP problem is infeasible. '
                           'Problem may be infeasible.')
    else:
        raise ValueError(
            'MindtPy unable to handle relaxed NLP termination condition '
            'of %s. Solver message: %s' %
            (subprob_terminate_cond, results.solver.message))
Beispiel #43
0
 def tear_diff_direct(self, G, tears):
     """
     Returns numpy arrays of values for src and dest members
     for all edges in the tears list of edge indexes.
     """
     svals = []
     dvals = []
     edge_list = self.idx_to_edge(G)
     for tear in tears:
         arc = G.edges[edge_list[tear]]["arc"]
         src, dest = arc.src, arc.dest
         sf = arc.expanded_block.component("splitfrac")
         for name, index, mem in src.iter_vars(names=True):
             if src.is_extensive(name) and sf is not None:
                 # TODO: same as above, what if there's no splitfrac
                 svals.append(value(mem * sf))
             else:
                 svals.append(value(mem))
             dvals.append(value(self.source_dest_peer(arc, name, index)))
     svals = numpy.array(svals)
     dvals = numpy.array(dvals)
     return svals, dvals
Beispiel #44
0
 def test_unbalanced(self):
     G = networkx.DiGraph()
     G.add_node("R")
     G.add_node("0")
     G.add_node("1")
     G.add_edge("R", "0")
     G.add_edge("R", "1")
     G.add_node("00")
     G.add_node("01")
     G.add_edge("0", "00")
     G.add_edge("0", "01")
     model = ScenarioTreeModelFromNetworkX(G,
                                           edge_probability_attribute=None)
     self.assertEqual(sorted(list(model.Stages)),
                      sorted(["Stage1", "Stage2", "Stage3"]))
     self.assertEqual(sorted(list(model.Nodes)),
                      sorted(["R", "0", "1", "00", "01"]))
     self.assertEqual(sorted(list(model.Children["R"])), sorted(["0", "1"]))
     self.assertEqual(sorted(list(model.Children["0"])),
                      sorted(["00", "01"]))
     self.assertEqual(sorted(list(model.Children["1"])), sorted([]))
     self.assertEqual(sorted(list(model.Children["00"])), sorted([]))
     self.assertEqual(sorted(list(model.Children["01"])), sorted([]))
     self.assertEqual(sorted(list(model.Scenarios)),
                      sorted(["00", "01", "1"]))
     self.assertEqual(value(model.ConditionalProbability["R"]), 1.0)
     self.assertEqual(value(model.ConditionalProbability["0"]), 0.5)
     self.assertEqual(value(model.ConditionalProbability["1"]), 0.5)
     self.assertEqual(value(model.ConditionalProbability["00"]), 0.5)
     self.assertEqual(value(model.ConditionalProbability["01"]), 0.5)
     model.StageCost["Stage1"] = "c1"
     model.StageCost["Stage2"] = "c2"
     model.StageCost["Stage3"] = "c3"
     model.StageVariables["Stage1"].add("x")
     model.StageVariables["Stage2"].add("x")
     self.assertEqual(model.Bundling.value, False)
     self.assertEqual(list(model.Bundles), [])
     self.assertEqual(len(model.BundleScenarios), 0)
     ScenarioTree(scenariotreeinstance=model)
Beispiel #45
0
def update_subproblem_progress_indicators(solved_model, solve_data, config):
    """Update the progress indicators for the subproblem."""
    GDPopt = solved_model.GDPopt_utils
    objective = next(solved_model.component_data_objects(Objective, active=True))
    if objective.sense == minimize:
        old_UB = solve_data.UB
        solve_data.UB = min(value(objective.expr), solve_data.UB)
        solve_data.feasible_solution_improved = (solve_data.UB < old_UB)
    else:
        old_LB = solve_data.LB
        solve_data.LB = max(value(objective.expr), solve_data.LB)
        solve_data.feasible_solution_improved = (solve_data.LB > old_LB)
    solve_data.iteration_log[
        (solve_data.master_iteration,
         solve_data.mip_iteration,
         solve_data.nlp_iteration)
    ] = (
        value(objective.expr),
        value(objective.expr),
        [v.value for v in GDPopt.variable_list]
    )

    if solve_data.feasible_solution_improved:
        solve_data.best_solution_found = solved_model.clone()

    improvement_tag = (
        "(IMPROVED) " if solve_data.feasible_solution_improved else "")
    lb_improved, ub_improved = (
        ("", improvement_tag)
        if objective.sense == minimize
        else (improvement_tag, ""))
    config.logger.info(
        'ITER {:d}.{:d}.{:d}-NLP: OBJ: {:.10g}  LB: {:.10g} {:s} UB: {:.10g} {:s}'.format(
            solve_data.master_iteration,
            solve_data.mip_iteration,
            solve_data.nlp_iteration,
            value(objective.expr),
            solve_data.LB, lb_improved,
            solve_data.UB, ub_improved))
Beispiel #46
0
def update_subproblem_progress_indicators(solved_model, solve_data, config):
    """Update the progress indicators for the subproblem."""
    GDPopt = solved_model.GDPopt_utils
    objective = next(solved_model.component_data_objects(Objective, active=True))
    if objective.sense == minimize:
        old_UB = solve_data.UB
        solve_data.UB = min(value(objective.expr), solve_data.UB)
        solve_data.feasible_solution_improved = (solve_data.UB < old_UB)
    else:
        old_LB = solve_data.LB
        solve_data.LB = max(value(objective.expr), solve_data.LB)
        solve_data.feasible_solution_improved = (solve_data.LB > old_LB)
    solve_data.iteration_log[
        (solve_data.master_iteration,
         solve_data.mip_iteration,
         solve_data.nlp_iteration)
    ] = (
        value(objective.expr),
        value(objective.expr),
        [v.value for v in GDPopt.variable_list]
    )

    if solve_data.feasible_solution_improved:
        solve_data.best_solution_found = solved_model.clone()

    improvement_tag = (
        "(IMPROVED) " if solve_data.feasible_solution_improved else "")
    lb_improved, ub_improved = (
        ("", improvement_tag)
        if objective.sense == minimize
        else (improvement_tag, ""))
    config.logger.info(
        'ITER {:d}.{:d}.{:d}-NLP: OBJ: {:.10g}  LB: {:.10g} {:s} UB: {:.10g} {:s}'.format(
            solve_data.master_iteration,
            solve_data.mip_iteration,
            solve_data.nlp_iteration,
            value(objective.expr),
            solve_data.LB, lb_improved,
            solve_data.UB, ub_improved))
Beispiel #47
0
def back_off_constraint_with_calculated_cut_violation(cut, transBlock_rHull,
                                                      bigm_to_hull_map, opt,
                                                      stream_solver, TOL):
    """Calculates the maximum violation of cut subject to the relaxed hull
    constraints. Increases this violation by TOL (to account for optimality 
    tolerance in solving the problem), and, if it finds that cut can be violated
    up to this tolerance, makes it more conservative such that it no longer can.

    Parameters
    ----------
    cut: The cut to be made more conservative, a Constraint
    transBlock_rHull: the relaxed hull model's transformation Block
    bigm_to_hull_map: Dictionary mapping ids of bigM variables to the 
                      corresponding variables on the relaxed hull instance
    opt: SolverFactory object for solving the maximum violation problem
    stream_solver: Whether or not to set tee=True while solving the maximum
                   violation problem.
    TOL: An absolute tolerance to be added to the calculated cut violation,
         to account for optimality tolerance in the maximum violation problem
         solve.
    """
    instance_rHull = transBlock_rHull.model()
    logger.info("Post-processing cut: %s" % cut.expr)
    # Take a constraint. We will solve a problem maximizing its violation
    # subject to rHull. We will add some user-specified tolerance to that
    # violation, and then add that much padding to it if it can be violated.
    transBlock_rHull.separation_objective.deactivate()

    transBlock_rHull.infeasibility_objective = Objective(
        expr=clone_without_expression_components(cut.body,
                                                 substitute=bigm_to_hull_map))

    results = opt.solve(instance_rHull, tee=stream_solver)
    if verify_successful_solve(results) is not NORMAL:
        logger.warning("Problem to determine how much to "
                       "back off the new cut "
                       "did not solve normally. Leaving the constraint as is, "
                       "which could lead to numerical trouble%s" % (results,))
        # restore the objective
        transBlock_rHull.del_component(transBlock_rHull.infeasibility_objective)
        transBlock_rHull.separation_objective.activate()
        return

    # we're minimizing, val is <= 0
    val = value(transBlock_rHull.infeasibility_objective) - TOL
    if val <= 0:
        logger.info("\tBacking off cut by %s" % val)
        cut._body += abs(val)
    # else there is nothing to do: restore the objective
    transBlock_rHull.del_component(transBlock_rHull.infeasibility_objective)
    transBlock_rHull.separation_objective.activate()
Beispiel #48
0
 def visit(self, node, values):
     if node.__class__ is not EXPR.ExternalFunctionExpression:
         return node
     if id(node._fcn) not in self.efSet:
         return node
     # At this point we know this is an ExternalFunctionExpression
     # node that we want to replace with an auliliary variable (y)
     new_args = []
     seen = ComponentSet()
     # TODO: support more than PythonCallbackFunctions
     assert isinstance(node._fcn, PythonCallbackFunction)
     #
     # Note: the first argument to PythonCallbackFunction is the
     # function ID.  Since we are going to complain about constant
     # parameters, we need to skip the first argument when processing
     # the argument list.  This is really not good: we should allow
     # for constant arguments to the functions, and we should relax
     # the restriction that the external functions implement the
     # PythonCallbackFunction API (that restriction leads unfortunate
     # things later; i.e., accessing the private _fcn attribute
     # below).
     for arg in list(values)[1:]:
         if type(arg) in nonpyomo_leaf_types or arg.is_fixed():
             # We currently do not allow constants or parameters for
             # the external functions.
             raise RuntimeError(
                 "TrustRegion does not support black boxes with "
                 "constant or parameter inputs\n\tExpression: %s"
                 % (node,) )
         if arg.is_expression_type():
             # All expressions (including simple linear expressions)
             # are replaced with a single auxiliary variable (and
             # eventually an additional constraint equating the
             # auxiliary variable to the original expression)
             _x = self.trf.x.add()
             _x.set_value( value(arg) )
             self.trf.conset.add(_x == arg)
             new_args.append(_x)
         else:
             # The only thing left is bare variables: check for duplicates.
             if arg in seen:
                 raise RuntimeError(
                     "TrustRegion does not support black boxes with "
                     "duplicate input arguments\n\tExpression: %s"
                     % (node,) )
             seen.add(arg)
             new_args.append(arg)
     _y = self.trf.y.add()
     self.trf.external_fcns.append(node)
     self.trf.exfn_xvars.append(new_args)
     return _y
Beispiel #49
0
def resource_area_constraint_rule(backend_model, loc_tech):
    """
    Set upper and lower bounds for resource_area.

    The first valid case is applied:

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{resource_{area}}(loc::tech)
            \\begin{cases}
                = resource_{area, equals}(loc::tech),& \\text{if } resource_{area, equals}(loc::tech)\\\\
                \\leq resource_{area, max}(loc::tech),& \\text{if } resource_{area, max}(loc::tech)\\\\
                \\text{unconstrained},& \\text{otherwise}
            \\end{cases}
            \\forall loc::tech \\in loc::techs_{area}

    and (if ``equals`` not enforced):

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{resource_{area}}(loc::tech) \\geq resource_{area, min}(loc::tech)
            \\quad \\forall loc::tech \\in loc::techs_{area}
    """
    energy_cap_max = get_param(backend_model, 'energy_cap_max', loc_tech)
    area_per_energy_cap = get_param(backend_model,
                                    'resource_area_per_energy_cap', loc_tech)

    if po.value(energy_cap_max) == 0 and not po.value(area_per_energy_cap):
        # If a technology has no energy_cap here, we force resource_area to zero,
        # so as not to accrue spurious costs
        return backend_model.resource_area[loc_tech] == 0
    else:
        return get_capacity_constraint(backend_model, 'resource_area',
                                       loc_tech)
Beispiel #50
0
def handle_main_optimal(main_mip, solve_data, config, update_bound=True):
    """This function copies the results from 'solve_main' to the working model and updates
    the upper/lower bound. This function is called after an optimal solution is found for 
    the main problem.

    Parameters
    ----------
    main_mip : Pyomo model
        The MIP main problem.
    solve_data : MindtPySolveData
        Data container that holds solve-instance data.
    config : ConfigBlock
        The specific configurations for MindtPy.
    update_bound : bool, optional
        Whether to update the bound, by default True.
        Bound will not be updated when handling regularization problem.
    """
    # proceed. Just need integer values
    MindtPy = main_mip.MindtPy_utils
    # check if the value of binary variable is valid
    for var in MindtPy.discrete_variable_list:
        if var.value is None:
            config.logger.warning(
                f"Integer variable {var.name} not initialized.  "
                "Setting it to its lower bound")
            var.set_value(var.lb, skip_validation=True)  # nlp_var.bounds[0]
    # warm start for the nlp subproblem
    copy_var_list_values(main_mip.MindtPy_utils.variable_list,
                         solve_data.working_model.MindtPy_utils.variable_list,
                         config)

    if update_bound:
        update_dual_bound(solve_data, value(MindtPy.mip_obj.expr))
        config.logger.info(
            solve_data.log_formatter.format(
                solve_data.mip_iter, 'MILP', value(MindtPy.mip_obj.expr),
                solve_data.LB, solve_data.UB, solve_data.rel_gap,
                get_main_elapsed_time(solve_data.timing)))
Beispiel #51
0
 def beforeChild(self, node, child):
     if type(child) in nonpyomo_leaf_types:
         # This means the child is POD
         # i.e., int, float, string
         return False, str(child)
     elif child.is_variable_type():
         return False, str(self.variable_label_map.getSymbol(child))
     elif child.is_parameter_type():
         return False, str(value(child))
     elif not child.is_expression_type():
         return False, str(child)
     else:
         # this is an expression node
         return True, ""
Beispiel #52
0
 def beforeChild(self, node, child):
     if type(child) in nonpyomo_leaf_types:
         # This means the child is POD
         # i.e., int, float, string
         return False, str(child)
     elif child.is_variable_type():
         return False, str(self.variable_label_map.getSymbol(child))
     elif child.is_parameter_type():
         return False, str(value(child))
     elif not child.is_expression_type():
         return False, str(child)
     else:
         # this is an expression node
         return True, ""
Beispiel #53
0
 def beforeChild(self, node, child, child_idx):
     if type(child) in nonpyomo_leaf_types:
         # This means the child is POD
         # i.e., int, float, string
         return False, str(child)
     elif child.is_expression_type():
         return True, ""
     elif child.is_numeric_type():
         if child.is_fixed():
             return False, str(value(child))
         else:
             return False, str(self.variable_label_map.getSymbol(child))
     else:
         return False, str(child)
Beispiel #54
0
def copy_var_list_values(from_list, to_list, config, skip_stale=False):
    """Copy variable values from one list to another."""
    for v_from, v_to in zip(from_list, to_list):
        if skip_stale and v_from.stale:
            continue  # Skip stale variable values.
        try:
            v_to.set_value(value(v_from, exception=False))
            if skip_stale:
                v_to.stale = False
        except ValueError as err:
            err_msg = getattr(err, 'message', str(err))
            var_val = value(v_from)
            rounded_val = round(var_val)
            # Check to see if this is just a tolerance issue
            if 'is not in domain Binary' in err_msg and (
                    fabs(var_val - 1) <= config.integer_tolerance
                    or fabs(var_val) <= config.integer_tolerance):
                v_to.set_value(rounded_val)
            elif 'is not in domain Integers' in err_msg and (
                    fabs(var_val - rounded_val) <= config.integer_tolerance):
                v_to.set_value(rounded_val)
            else:
                raise
    def test_combine_three_inequalities_and_flatten_blocks(self):
        m = ConcreteModel()
        m.x = Var()
        m.y = Var()
        m.b = Block()
        m.b.c = Constraint(expr=m.x >= 2)
        m.c = Constraint(expr=m.y <= m.x)
        m.b.b2 = Block()
        m.b.b2.c = Constraint(expr=m.y >= 4)
        TransformationFactory('contrib.fourier_motzkin_elimination').apply_to(
            m, vars_to_eliminate=m.y)

        constraints = m._pyomo_contrib_fme_transformation.projected_constraints
        self.assertEqual(len(constraints), 2)
        cons = constraints[1]
        self.assertEqual(value(cons.lower), 2)
        self.assertIsNone(cons.upper)
        self.assertIs(cons.body, m.x)

        cons = constraints[2]
        self.assertEqual(value(cons.lower), 4)
        self.assertIsNone(cons.upper)
        self.assertIs(cons.body, m.x)
Beispiel #56
0
 def generate_first_x(self, G, tears):
     edge_list = self.idx_to_edge(G)
     x = []
     for tear in tears:
         arc = G.edges[edge_list[tear]]["arc"]
         for name, mem in arc.src.iter_vars(names=True):
             try:
                 index = mem.index()
             except AttributeError:
                 index = None
             peer = self.source_dest_peer(arc, name, index)
             x.append(value(peer))
     x = numpy.array(x)
     return x
Beispiel #57
0
def init_rNLP(solve_data, config):
    """Initialize by solving the rNLP (relaxed binary variables)."""
    solve_data.nlp_iter += 1
    m = solve_data.working_model.clone()
    config.logger.info(
        "NLP %s: Solve relaxed integrality" % (solve_data.nlp_iter,))
    MindtPy = m.MindtPy_utils
    TransformationFactory('core.relax_integrality').apply_to(m)
    with SuppressInfeasibleWarning():
        results = SolverFactory(config.nlp_solver).solve(
            m, **config.nlp_solver_args)
    subprob_terminate_cond = results.solver.termination_condition
    if subprob_terminate_cond is tc.optimal:
        main_objective = next(m.component_data_objects(Objective, active=True))
        nlp_solution_values = list(v.value for v in MindtPy.variable_list)
        dual_values = list(m.dual[c] for c in MindtPy.constraint_list)
        # Add OA cut
        if main_objective.sense == minimize:
            solve_data.LB = value(main_objective.expr)
        else:
            solve_data.UB = value(main_objective.expr)
        config.logger.info(
            'NLP %s: OBJ: %s  LB: %s  UB: %s'
            % (solve_data.nlp_iter, value(main_objective.expr),
               solve_data.LB, solve_data.UB))
        if config.strategy == 'OA':
            add_oa_cut(nlp_solution_values, dual_values, solve_data, config)
    elif subprob_terminate_cond is tc.infeasible:
        # TODO fail? try something else?
        config.logger.info(
            'Initial relaxed NLP problem is infeasible. '
            'Problem may be infeasible.')
    else:
        raise ValueError(
            'MindtPy unable to handle relaxed NLP termination condition '
            'of %s. Solver message: %s' %
            (subprob_terminate_cond, results.solver.message))
Beispiel #58
0
def detect_effectively_discrete_vars(block, equality_tolerance):
    """Detect effectively discrete variables.

    These continuous variables are the sum of discrete variables.

    """
    # Map of effectively_discrete var --> inducing constraints
    effectively_discrete = ComponentMap()

    for constr in block.component_data_objects(Constraint, active=True):
        if constr.lower is None or constr.upper is None:
            continue  # skip inequality constraints
        if fabs(value(constr.lower) -
                value(constr.upper)) > equality_tolerance:
            continue  # not equality constriant. Skip.
        if constr.body.polynomial_degree() not in (1, 0):
            continue  # skip nonlinear expressions
        repn = generate_standard_repn(constr.body)
        if len(repn.linear_vars) < 2:
            # TODO should this be < 2 or < 1?
            # TODO we should make sure that trivial equality relations are
            # preprocessed before this, or we will end up reformulating
            # expressions that we do not need to here.
            continue
        non_discrete_vars = list(v for v in repn.linear_vars
                                 if v.is_continuous())
        if len(non_discrete_vars) == 1:
            # We know that this is an effectively discrete continuous
            # variable. Add it to our identified variable list.
            var = non_discrete_vars[0]
            inducing_constraints = effectively_discrete.get(var, [])
            inducing_constraints.append(constr)
            effectively_discrete[var] = inducing_constraints
        # TODO we should eventually also look at cases where all other
        # non_discrete_vars are effectively_discrete_vars

    return effectively_discrete
Beispiel #59
0
 def _get_cone_data(self, con):
     cone_type, cone_param, cone_members = None, 0, None
     if isinstance(con, quadratic):
         cone_type = self._mosek.conetype.quad
         cone_members = [con.r] + list(con.x)
     elif isinstance(con, rotated_quadratic):
         cone_type = self._mosek.conetype.rquad
         cone_members = [con.r1, con.r2] + list(con.x)
     elif self._version[0] >= 9:
         if isinstance(con, primal_exponential):
             cone_type = self._mosek.conetype.pexp
             cone_members = [con.r, con.x1, con.x2]
         elif isinstance(con, primal_power):
             cone_type = self._mosek.conetype.ppow
             cone_param = value(con.alpha)
             cone_members = [con.r1, con.r2] + list(con.x)
         elif isinstance(con, dual_exponential):
             cone_type = self._mosek.conetype.dexp
             cone_members = [con.r, con.x1, con.x2]
         elif isinstance(con, dual_power):
             cone_type = self._mosek.conetype.dpow
             cone_param = value(con.alpha)
             cone_members = [con.r1, con.r2] + list(con.x)
     return (cone_type, cone_param, ComponentSet(cone_members))
Beispiel #60
0
def storage_capacity_max_purchase_constraint_rule(backend_model, loc_tech):
    """
    Set maximum storage capacity, by either storage_cap_max.equals or a combination
    of energy_cap_max/equals and charge_rate.

    The first valid case is applied:

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{storage_{cap}}(loc::tech)
            \\begin{cases}
                = storage_{cap, equals}(loc::tech) \\times \\boldsymbol{purchased},&
                    \\text{if } storage_{cap, equals} \\\\
                = \\frac{energy_{cap, equals}(loc::tech)}{charge\_rate} \\times
                    \\boldsymbol{purchased} \\times energy_{cap, scale},&
                    \\text{if } energy_{cap, equals}(loc::tech) \\text{ and }
                    \\text{ and } charge_{rate}(loc::tech)\\\\
                \\leq storage_{cap, max}(loc::tech) \\times \\boldsymbol{purchased},&
                    \\text{if } storage_{cap, max}(loc::tech)\\\\
                \\leq \\frac{energy_{cap, max}(loc::tech)}{charge\_rate}
                    \\times \\boldsymbol{purchased} \\times energy_{cap, scale},&
                    \\text{if } energy_{cap, max}(loc::tech) \\text{ and }
                    charge_{rate}(loc::tech)\\\\
                \\text{unconstrained},& \\text{otherwise}
            \\end{cases}
            \\forall loc::tech \\in loc::techs_{purchase, store}

    """
    energy_cap_max = get_param(backend_model, 'energy_cap_max', loc_tech)
    energy_cap_equals = get_param(backend_model, 'energy_cap_equals', loc_tech)
    energy_cap_scale = get_param(backend_model, 'energy_cap_scale', loc_tech)
    storage_cap_max = get_param(backend_model, 'storage_cap_max', loc_tech)
    storage_cap_equals = get_param(backend_model, 'storage_cap_equals',
                                   loc_tech)
    charge_rate = get_param(backend_model, 'charge_rate', loc_tech)

    if po.value(storage_cap_equals):
        return backend_model.storage_cap[loc_tech] == (
            storage_cap_equals * backend_model.purchased[loc_tech])

    elif po.value(energy_cap_equals) and po.value(charge_rate):
        return backend_model.storage_cap[loc_tech] == (
            (energy_cap_equals / charge_rate) * energy_cap_scale *
            backend_model.purchased[loc_tech])
    elif po.value(storage_cap_max):
        return backend_model.storage_cap[loc_tech] <= (
            storage_cap_max * backend_model.purchased[loc_tech])

    elif po.value(energy_cap_max) and po.value(charge_rate):
        return backend_model.storage_cap[loc_tech] <= (
            (energy_cap_max / charge_rate) * energy_cap_scale *
            backend_model.purchased[loc_tech])
    else:
        return po.Constraint.Skip