B _U@sddlZddlmmZddlmZddlmZm Z ddl m Z ddl m Z ddlmZmZddlmmmZddlmZmZmZddlmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,dd l-m.Z.m/Z/m0Z0dd l1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;dd lm?Z?m@Z@dd lAmBZCeDdZEiZFejGdddGdddeZHejGdddGdddeHZIdS)N) deprecated) ComponentMap ComponentSet)unique_component_name) ZeroConstant)ActiveComponent ComponentUID)TransformationTransformationFactory Reference)Block BooleanVar Connector ConstraintParamSetSetOfSuffixVar ExpressionSortComponentsTraversalStrategyAnyRangeSetRealsvalueNonNegativeIntegersLogicalConstraint)Disjunct Disjunction GDP_Error) #_warn_for_active_logical_constraint#clone_without_expression_components target_list is_child_ofget_src_disjunctionget_src_constraintget_transformed_constraintsget_src_disjunct_warn_for_active_disjunction_warn_for_active_disjunct)wraps) iteritemsiterkeys)refzpyomo.gdp.hullzgdp.hullz:Relax disjunctive model by forming the hull reformulation.)docc seZdZdZedZedejde dddedejd e d d d gd d dedejdej ddedejde dddfddZ ddZddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)ZdLd*d+Zd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;Ze e!dd?Z"e e#d@dAZ#e e$dBdCZ$dDdEZ%dFdGZ&dHdIZ'dJdKZ(Z)S)MHull_ReformulationaRelax disjunctive model by forming the hull reformulation. Relaxes a disjunctive model into an algebraic model by forming the hull reformulation of each disjunction. This transformation accepts the following keyword arguments: Parameters ---------- perspective_function : str The perspective function used for the disaggregated variables. Must be one of 'FurmanSawayaGrossmann' (default), 'LeeGrossmann', or 'GrossmannLee' EPS : float The value to use for epsilon [default: 1e-4] targets : (block, disjunction, or list of those types) The targets to transform. This can be a block, disjunction, or a list of blocks and Disjunctions [default: the instance] The transformation will create a new Block with a unique name beginning "_pyomo_gdp_hull_reformulation". That Block will contain an indexed Block named "relaxedDisjuncts", which will hold the relaxed disjuncts. This block is indexed by an integer indicating the order in which the disjuncts were relaxed. Each block has a dictionary "_constraintMap": 'srcConstraints': ComponentMap(: ), 'transformedConstraints':ComponentMap(: , : [] ) It will have a dictionary "_disaggregatedVarMap: 'srcVar': ComponentMap(:), 'disaggregatedVar': ComponentMap(:) And, last, it will have a ComponentMap "_bigMConstraintMap": : All transformed Disjuncts will have a pointer to the block their transformed constraints are on, and all transformed Disjunctions will have a pointer to the corresponding OR or XOR constraint. The _pyomo_gdp_hull_reformulation block will have a ComponentMap "_disaggregationConstraintMap": :ComponentMap(: ) zgdp.hulltargetsNz.target or list of targets that will be relaxeda This specifies the target or list of targets to relax as either a component or a list of components. If None (default), the entire model is transformed. Note that if the transformation is done out of place, the list of targets should be attached to the model before it is cloned, and the list will specify the targets on the cloned instance.)defaultdomain descriptionr/zperspective functionFurmanSawayaGrossmann LeeGrossmann GrossmannLeez5perspective function used for variable disaggregationan The perspective function used for variable disaggregation "LeeGrossmann" is the original NL convex hull from Lee & Grossmann (2000) [1]_, which substitutes nonlinear constraints h_ik(x) <= 0 with x_k = sum( nu_ik ) y_ik * h_ik( nu_ik/y_ik ) <= 0 "GrossmannLee" is an updated formulation from Grossmann & Lee (2003) [2]_, which avoids divide-by-0 errors by using: x_k = sum( nu_ik ) (y_ik + eps) * h_ik( nu_ik/(y_ik + eps) ) <= 0 "FurmanSawayaGrossmann" (default) is an improved relaxation [3]_ that is exact at 0 and 1 while avoiding numerical issues from the Lee & Grossmann formulation by using: x_k = sum( nu_ik ) ((1-eps)*y_ik + eps) * h_ik( nu_ik/((1-eps)*y_ik + eps) ) - eps * h_ki(0) * ( 1-y_ik ) <= 0 References ---------- .. [1] Lee, S., & Grossmann, I. E. (2000). New algorithms for nonlinear generalized disjunctive programming. Computers and Chemical Engineering, 24, 2125-2141 .. [2] Grossmann, I. E., & Lee, S. (2003). Generalized disjunctive programming: Nonlinear convex hull relaxation and algorithms. Computational Optimization and Applications, 26, 83-100. .. [3] Furman, K., Sawaya, N., and Grossmann, I. A computationally useful algebraic representation of nonlinear disjunctive convex sets using the perspective function. Optimization Online (2016). http://www.optimization-online.org/DB_HTML/2016/07/5544.html. EPSg-C6?z,Epsilon value to use in perspective function)r2r3r4assume_fixed_vars_permanentFzBoolean indicating whether or not to transform so that the the transformed model will still be valid when fixed Vars are unfixed.aq If True, the transformation will not disaggregate fixed variables. This means that if a fixed variable is unfixed after transformation, the transformed model is no longer valid. By default, the transformation will disagregate fixed variables so that any later fixing and unfixing will be valid in the transformed model. csZtt|t|jtdtdtdtdt dt dt dt dt dt|jt|jt|jt|ji|_dS)NF)superr0__init__r_transform_constraintrr rrrrrrrrr)rr*r _transform_block_on_disjunctr"_warn_for_active_logical_statementhandlers)self) __class__:/tmp/pip-unpacked-wheel-d4p3hk07/pyomo/gdp/plugins/hull.pyr;szHull_Reformulation.__init__cCsZ|d}t|tkrVx>t|D]2\}}||dkrDt|||<q |||q WdS)N LocalVars) componenttyperr,getrupdate)r@blocklocal_var_dict localVarsZdisjZvar_listrBrBrC_add_local_varss   z"Hull_Reformulation._add_local_varscCsPx(|jttdtjdD]}|||qWx |dk rJ||||}q,W|S)NT) descend_intoactivesort)component_data_objectsr r deterministicrL parent_block)r@rIrJbrBrBrC_get_local_var_suffixess    z*Hull_Reformulation._get_local_var_suffixescKs*trtz|j|f|WdtXdS)N) NAME_BUFFERAssertionError_apply_to_implclear)r@instancekwdsrBrBrC _apply_toszHull_Reformulation._apply_tocKs||di|_|j||jj}|dkr6|f}i}x|D]}t|||dshtd|j|jfq@|jt kr| r| |q| || q@|jttfkr| r||q||q@td|jt|fq@WdS)Noptions)parentchild knownBlocksz0Target '%s' is not a component on instance '%s'!zbTarget '%s' was not a Block, Disjunct, or Disjunction. It was of type %s and can't be transformed.)CONFIGpop_config set_valuer1r$r namectyper is_indexed_transform_disjunction_transform_disjunctionDataindexr r_transform_block_transform_blockDatarF)r@rYrZr1r_trBrBrCrWs.      z!Hull_Reformulation._apply_to_implcCsPt|d}t}|||tt|_tdddgd|_ttt|_ t |_ |S)NZ_pyomo_gdp_hull_reformulationlbubeq) initialize) rr add_componentrrelaxedDisjunctsrlbubrrdisaggregationConstraintsr_disaggregationConstraintMap)r@rYZtransBlockName transBlockrBrBrC_add_transformation_blocks  z,Hull_Reformulation._add_transformation_blockcCs(x"tt|D]}|||qWdS)N)sortedr-rk)r@objirBrBrCrjsz#Hull_Reformulation._transform_blockcCs4x.|jtdtjttftjdD]}||qWdS)NT)rNrOrMZ descent_order) component_objectsrrrQr rrZ PostfixDFSrg)r@ry disjunctionrBrBrCrk sz'Hull_Reformulation._transform_blockDatacCsZt|tst|jdk r |St|}|t||jdt dd|t ||_|S)NT)fully_qualified name_bufferZ_xor) isinstancerrV_algebraic_constraintr index_setrqrgetnamerU weakref_ref)r@r|rvZorCrBrBrC_add_xor_constraint*s    z&Hull_Reformulation._add_xor_constraintcCsp|js dS|jdk r"|}n||}|||}x&tt|D]}|||||qJW|dS)N) rNrrRrwrrxr-rh deactivate)r@ryrvZ xorConstraintrzrBrBrCrgCs  z)Hull_Reformulation._transform_disjunctioncs|js dS|jstd|j|dkrT|jdk rF|}n||}|}|||}|j }|j }t |j dkrtd|j dtdt}g} tt} |jj } x|j D]|} t} | <x\| jtdtjtdD]D}x>tj|j| dD]*| |kr| |qWqW|| | } qWg}g}x| D]fdd D}t |d krtt j!rt"d j dtd|nH| #|ddk r| |dkr|n |n |qNWd}x*|j D] } || j$7}|%| |||qW|||d ft&|||_xt'|D]\}d}x:|j D]0} | j(dkrtq`| (j)d }||7}q`W|||f|k|#dk r|||f||<nt}|<|||f||<qLW|*dS) NzVCannot do hull reformulation for Disjunction '%s' with OR constraint. Must be an XOR!rzIDisjunction '%s' is empty. This is likely indicative of a modeling error.T)r}r~)rNrOrM)Z include_fixedcsg|]}|kr|qSrBrB).0d)varvarsByDisjunctrBrC szAHull_Reformulation._transform_disjunctionData..zGAssuming '%s' is not a local var since it isused in multiple disjuncts.disaggregatedVar)+rNxorr rdparent_componentrrRrwrrtrulen disjunctsrrUrrrbr9rPrrrQr EXPRidentify_variablesbodyaddappendrTlogger isEnabledForloggingDEBUGdebugrG indicator_var_transform_disjunctr enumerate_transformation_block_disaggregatedVarMapr)r@ryrirvrZ orConstraintZdisaggregationConstraintZdisaggregationConstraintMapZ varOrder_setZvarOrderZlocalVarsByDisjunctZinclude_fixed_varsdisjunctZ disjunctVarsZconsvarSetrKrZor_exprrzZdisaggregatedExprrZthismaprB)rrrCrh\s                   z-Hull_Reformulation._transform_disjunctionDatacCs|jsT|jr:t|jdkr"dStd|jt|jf|jdkrTtd|jf|jdk rltd|j|j}|t|}t |_ t |_ t t d|_ t t d|_t |_t||_t||_d}|}x |dk r|jtkrP|}qW|dk r"ttjd} |_t}| |<x|D]} | j} | j} | dksP| dkr^td| jtttd| td| f| jd } t|j | j d t!d }|j "|| |dk r|#| | |jd | <| |jd | <t$|j%}|"|d|| r|#d|j| | k| r$|#d| |j| k||j| <q*Wx|D]} | j} | j} | dks^| dkrltd| jt| dkr| &dt| dkr| 'd| |jd | <| |jd | <t|| j d t!d d}t$|j%}|"||| r|#d|j| | k| r|#d| |j| k||j| <q:Wt(ddt)|jd D}t(ddt)|jd D}|*dd|D|+|||||,dS)Nrz\The disjunct '%s' is deactivated, but the indicator_var is fixed to %s. This makes no sense.zThe disjunct '%s' is deactivated, but the indicator_var is not fixed and the disjunct does not appear to have been relaxed. This makes no sense. (If the intent is to deactivate the disjunct, fix its indicator_var to 0.)zThe disjunct '%s' has been transformed, but a disjunction it appears in has not. Putting the same disjunct in multiple disjunctions is not supported.)srcConstraintstransformedConstraints)srcVarr) directionzqVariables that appear in disjuncts must be bounded in order to use the hull transformation! Missing bound for %s.)ZwithinZboundsrpF)r}r~rrZ_boundsrmrncss|]\}}t||fVqdS)N)id)rvnewVrBrBrC |sz9Hull_Reformulation._transform_disjunct..css|]\}}t|tfVqdS)N)rr)rrrrBrBrCr~scss|]}t|tfVqdS)N)rr)rrrBrBrCrs)-rNrZis_fixedrr rdrrrrr localVarReferencesZdisaggregatedVarsr_constraintMapr_bigMConstraintMaprZ _srcDisjunctrRrerrZLOCALrDrrmrnrrminmaxrrrUrqrrrsZsetlbZsetubdictr,rH_transform_block_componentsZ$_deactivate_without_fixing_indicator)r@ryrvrrKrrrelaxationBlockZ local_var_setZparent_disjunctZlocalVarSuffixrrmrnrZdisaggregatedVarNameZbigmConstraintZconNamevar_substitute_mapzero_substitute_maprBrBrCrs                             z&Hull_Reformulation._transform_disjunctc Cs|}|j}x8|jttddD]$}|t||jdtdt |q W| }x>|j t t jtdD](} | jdkrtqd|  } || |qdWxP|jdddD]>} |j| jd} | s| dkrtd| jq| | |||qWdS)N)rMrNT)r}r~)rOrMF)rNrMzNo hull transformation handler registered for modeling components of type %s. If your disjuncts contain non-GDP Pyomo components that require transformation, please transform them first.)rrr{rr rqrrrUr rRrPrrrQZalgebraic_constraint_transfer_var_referencesr?rGrer ) r@rIrrr disjunctBlockZ varRefBlockrZdestinationBlockryrvhandlerrBrBrCrs0    z.Hull_Reformulation._transform_block_componentscCsD|j}x8t|jD]*\}}|t|}t|_|j|jqWdS)N)rrr,rr rZtransfer_attributes_from)r@Z fromBlockZtoBlockZ disjunctListidxrZnewblockrBrBrCrs  z+Hull_Reformulation._transfer_var_referencescCst||tdS)N)r)rU)r@r|rrrrBrBrCr)sz/Hull_Reformulation._warn_for_active_disjunctioncCst||tdS)N)r*rU)r@Z innerdisjunctZ outerdisjunctrrrBrBrCr*sz,Hull_Reformulation._warn_for_active_disjunctcCst||tdS)N)r!rU)r@Zlogical_statmentrrrrBrBrCr>sz5Hull_Reformulation._warn_for_active_logical_statementcCs.x(tt|D]}||||||qWdS)N)rxr-r)r@rIrrrrzrBrBrCr=s z/Hull_Reformulation._transform_block_on_disjunctcs|}|}|jd}|j}t||jdtd} |rNt| |j } n t|j } | | | |rx| |d|<||d| <xTt t |D]B} || } | jsq| jdk} |jj|jj}| r|dkrt| j|d}|j| r|d kr&t| jtfd d t|Dd}|}n|d krdt| jtfd d t|Dd}|}n^|dkrt| jtfdd t|Dd}d||d}ntdnt| j|d}| jr| r|| jk}nptt|}t|dkrF| jsF|dd|dg|d| <| |d|d<q|d|| jk}|r| | df|| | dfg|d| <| |d| | df<q| d|| dg|d| <| |d| d<q| jdk rt!"t#j$r | jdtd}t!%d|| r || jk}n|d|| jk}|r| | df|| | dfg|d| <| |d| | df<n.| d|| dg|d| <| |d| d<| j&dk rt!"t#j$r| jdtd}t!%d|| r|| j&k}n|d|| j&k}|r| | df||d'| }|dk rV|(| | dfn| | dfg|d| <| |d| | df<q| d||d'| }|dk r|(| dn| dg|d| <| |d| d<qW|)dS)NrT)r}r~rr)rrr5) substituter6c3s|]\}}||fVqdS)NrB)rrsubs)yrBrCrsz;Hull_Reformulation._transform_constraint..r7c3s"|]\}}||fVqdS)NrB)rrr)r8rrBrCrsc3s*|]"\}}||dfVqdS)rNrB)rrr)r8rrBrCr%srzUnknown NL Hull moderroz'GDP(Hull): Transforming constraint '%s'rmrn)*rrRrrrrrUrfrrrsrqrxr-rNrZpolynomial_degreerbr8Zperspective_functionr"rrr, RuntimeErrorZequalitylowerlistrrrZfixrrrrrrupperrGrr)r@ryrrrrrvZvarMapZ constraintMaprdZ newConstraintrzcNLmodeZh_0Zsub_exprexprZ newConsExprr_nameZ transformedrB)r8rrCr<s               &              z(Hull_Reformulation._transform_constraintcCst|S)N)r()r@rvrBrBrCr(sz#Hull_Reformulation.get_src_disjunctcCst|S)N)r%)r@Zxor_constraintrBrBrCr%sz&Hull_Reformulation.get_src_disjunctioncCst|S)N)r&)r@ZtransformedConstraintrBrBrCr&sz%Hull_Reformulation.get_src_constraintcCst|S)N)r')r@Z srcConstraintrBrBrCr'sz.Hull_Reformulation.get_transformed_constraintscCsX|jdkrtd|j|}y|jd|Std|j|jfYnXdS)a\ Returns the disaggregated variable corresponding to the Var v and the Disjunct disjunct. If v is a local variable, this method will return v. Parameters ---------- v: a Var which appears in a constraint in a transformed Disjunct disjunct: a transformed Disjunct in which v appears Nz&Disjunct '%s' has not been transformedrzDIt does not appear '%s' is a variable which appears in disjunct '%s')rr rdrrerror)r@rrrvrBrBrCget_disaggregated_vars  z(Hull_Reformulation.get_disaggregated_varcCs>|}y|jd|Std|jYnXdS)a Returns the original model variable to which disaggregated_var corresponds. Parameters ---------- disaggregated_var: a Var which was created by the hull transformation as a disaggregated variable (and so appears on a transformation block of some Disjunct) rz3'%s' does not appear to be a disaggregated variableN)rRrrrrd)r@Zdisaggregated_varrvrBrBrC get_src_vars   zHull_Reformulation.get_src_varcCstx|jD]}|j}|dk rPqW|dkr6td|jy|j||Std|j|jfYnXdS)a Returns the disaggregation (re-aggregation?) constraint (which links the disaggregated variables to their original) corresponding to original_var and the transformation of disjunction. Parameters ---------- original_var: a Var which was disaggregated in the transformation of Disjunction disjunction disjunction: a transformed Disjunction containing original_var NzZDisjunction '%s' has not been properly transformed: None of its disjuncts are transformed.zTIt doesn't appear that '%s' is a variable that was disaggregated by Disjunction '%s')rrr rdrRrurr)r@Z original_varr|rrvrBrBrCget_disaggregation_constraints    z0Hull_Reformulation.get_disaggregation_constraintcCs:|}y |j|Std|jYnXdS)a Returns the IndexedConstraint which sets a disaggregated variable to be within its bounds when its Disjunct is active and to be 0 otherwise. (It is always an IndexedConstraint because each bound becomes a separate constraint.) Parameters ---------- v: a Var which was created by the hull transformation as a disaggregated variable (and so appears on a transformation block of some Disjunct) zxEither '%s' is not a disaggregated variable, or the disjunction that disaggregates it has not been properly transformed.N)rRrrrrd)r@rrvrBrBrCget_var_bounds_constraints   z,Hull_Reformulation.get_var_bounds_constraint)N)*__name__ __module__ __qualname____doc__cfgZ ConfigBlockr`ZdeclareZ ConfigValuer#ZInZ PositiveFloatboolr;rLrTr[rWrwrjrkrrgrhrrrr)r*r>r=r<r+r(r%r&r'rrrr __classcell__rBrB)rArCr0)sf6    *         *7  6r0z gdp.chullzBDeprecated name for the hull reformulation. Please use 'gdp.hull'.cs*eZdZeddddfddZZS)_Deprecated_Name_HullzOThe 'gdp.chull' name is deprecated. Please use the more apt 'gdp.hull' instead.z pyomo.gdpz5.7)rversioncstt|dS)N)r:rr;)r@)rArBrCr;sz_Deprecated_Name_Hull.__init__)rrrrr;rrBrB)rArCrsr)JrZpyomo.common.configcommonconfigrZ pyomo.commonrZpyomo.common.collectionsrrZpyomo.common.modelingrZpyomo.core.expr.numvaluerZpyomo.core.base.componentrrZpyomo.core.expr.currentcorercurrentrZpyomo.core.baser r r Z pyomo.corer r rrrrrrrrrrrrrrrrZ pyomo.gdprrr Zpyomo.gdp.utilr!r"r#r$r%r&r'r(r)r* functoolsr+sixr,r-weakrefr.r getLoggerrrUregisterr0rrBrBrBrC s>   P0   i