Source code for idaes.core.util.mpdisagg

# coding=utf-8
##############################################################################
# Institute for the Design of Advanced Energy Systems Process Systems
# Engineering Framework (IDAES PSE Framework) Copyright (c) 2018, by the
# software owners: The Regents of the University of California, through
# Lawrence Berkeley National Laboratory,  National Technology & Engineering
# Solutions of Sandia, LLC, Carnegie Mellon University, West Virginia
# University Research Corporation, et al. All rights reserved.
# 
# Please see the files COPYRIGHT.txt and LICENSE.txt for full copyright and
# license information, respectively. Both files are also available online
# at the URL "https://github.com/IDAES/idaes".
##############################################################################
"""
Utility functions for implementing
multi-parametric disaggregation lower bounds

Implementation of lower-bounding formulation given in:
Kolodziej, S., Castro, P. M., & Grossmann, I. E. (2013). Global
    optimization of bilinear programs with a multiparametric
    disaggregation technique. Journal of Global Optimization,
    57(4), 1039–1063. http://doi.org/10.1007/s10898-012-0022-1
"""
from __future__ import division
from pyomo.environ import Constraint, RangeSet, Reals, Binary, NonNegativeReals, Var, Param, Set
from .mccormick import _concat as cc

__author__ = "Qi Chen <qichen@andrew.cmu.edu>"

[docs]def setup_multiparametric_disagg(b, name, minPow, maxPow, *sets): setattr(b, name, Constraint(*sets)) digits = b.digits = RangeSet(0, 9) powers = b.powers = RangeSet(minPow, maxPow) b.minPow = Param(initialize=minPow) b.maxPow = Param(initialize=maxPow) skl = sets + (digits, powers) sl = sets + (powers,) b.y_hat = Var(*skl, domain=Reals) b.w_slack = Var(*sets, domain=Reals) b.dig_active = Var(*skl, domain=Binary) b.x_slack = Var(*sets, domain=NonNegativeReals) b.eq_x = Constraint(*sets) b.eq_y = Constraint(*sl) b.eq_y_hat_lb = Constraint(*skl) b.eq_y_hat_ub = Constraint(*skl) b.eq_z_sum = Constraint(*sl) mc = b.w_slack_mc = Set(initialize=['lb1', 'lb2', 'ub1', 'ub2']) sets_mc = sets + (mc,) b.eq_w_slack = Constraint(*sets_mc)
[docs]def add_mpDisagg_cut(b, name, indx, w, x, y, exists): constr = getattr(b, name) z = b.dig_active b.x_slack[indx].setub(10 ** b.minPow) constr.add(indx, expr=w == sum(10 ** l * k * b.y_hat[indx, k, l] for (k, l) in b.digits * b.powers) + b.w_slack[indx]) b.eq_x.add(indx, expr=x == sum(10 ** l * k * z[indx, k, l] for (k, l) in b.digits * b.powers) + b.x_slack[indx]) for l in b.powers: b.eq_y.add(cc(indx, l), expr=y == sum(b.y_hat[indx, k, l] for k in b.digits)) b.eq_z_sum.add(cc(indx, l), expr=sum(z[indx, k, l] for k in b.digits) == 1) for k in b.digits: b.eq_y_hat_lb.add(cc(indx, k) + (l,), expr=y.lb * z[indx, k, l] <= b.y_hat[indx, k, l]) b.eq_y_hat_ub.add(cc(indx, k) + (l,), expr=b.y_hat[indx, k, l] <= y.ub * z[indx, k, l]) for bnd in b.w_slack_mc: if bnd == 'lb1': b.eq_w_slack.add(cc(indx, bnd), expr=b.w_slack[indx] >= y.lb * b.x_slack[indx]) elif bnd == 'ub1': b.eq_w_slack.add(cc(indx, bnd), expr=b.w_slack[indx] <= y.ub * b.x_slack[indx]) elif bnd == 'lb2': b.eq_w_slack.add(cc(indx, bnd), expr=b.w_slack[indx] >= (y - y.ub) * 10 ** b.minPow + y.ub * b.x_slack[indx]) elif bnd == 'ub2': b.eq_w_slack.add(cc(indx, bnd), expr=b.w_slack[indx] <= (y - y.lb) * 10 ** b.minPow + y.lb * b.x_slack[indx])