B @`Z@sdZddlZddlmZmZddlmZmZddlm Z ddl m Z ddl m Z mZddlmZdd lmZmZmZmZmZmZmZmZmZmZmZmZmZmZm Z m!Z!dd l"m#Z#dd l$m%Z%m&Z&m'Z'ddl(m)m*m+Z,dd l-m.Z.m/Z/m0Z0dd l1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;ddlm?Z?ddl@mAZAmBZBddlCmDZEeFdZGiZHddZIe&jJdddGddde%ZKdS)z@Big-M Generalized Disjunctive Programming transformation module.N) ComponentMap ComponentSet) ConfigBlock ConfigValue) is_debug_set)unique_component_name) deprecateddeprecation_warning)compute_bounds_on_expr)Block BooleanVar Connector ConstraintParamSetSetOfSuffixVar ExpressionSortComponentsTraversalStrategyvalueRangeSetNonNegativeIntegersLogicalConstraint)ExternalFunction)TransformationTransformationFactory Reference)Disjunct Disjunction GDP_Error) #_warn_for_active_logical_constraint target_list is_child_ofget_src_disjunctionget_src_constraintget_transformed_constraints_get_constraint_transBlockget_src_disjunct_warn_for_active_disjunction_warn_for_active_disjunct)generate_standard_repn)wraps)iterkeys iteritems)refzpyomo.gdp.bigmcCst|ttfr|Sd|iS)N) isinstancedictr)valr4:/tmp/pip-unpacked-wheel-bi3529v6/pyomo/gdp/plugins/bigm.py_to_dict-sr6zgdp.bigmz*Relax disjunctive model using big-M terms.)docc seZdZdZedZedededddedede d d ded ed e d ddfddZ dRddZ ddZ ddZddZddZddZddZdd Zd!d"ZdSd#d$Zd%d&Zd'd(Zd)d*Zd+d,Zd-d.Zd/d0Zd1d2Zd3d4Zd5d6Zd7d8ZdTd9d:Z d;d<Z!d=d>Z"d?d@Z#e$e%dAdBZ%e$e&dCdDZ&e$e'dEdFZ'e$e(dGdHZ(e)dIdJdKdLdMZ*dNdOZ+dPdQZ,Z-S)UBigM_TransformationaRelax disjunctive model using big-M terms. Relaxes a disjunctive model into an algebraic model by adding Big-M terms to all disjunctive constraints. This transformation accepts the following keyword arguments: bigM: A user-specified value (or dict) of M values to use (see below) targets: the targets to transform [default: the instance] M values are determined as follows: 1) if the constraint appears in the bigM argument dict 2) if the constraint parent_component appears in the bigM argument dict 3) if any block which is an ancestor to the constraint appears in the bigM argument dict 3) if 'None' is in the bigM argument dict 4) if the constraint or the constraint parent_component appear in a BigM Suffix attached to any parent_block() beginning with the constraint's parent_block and moving up to the root model. 5) if None appears in a BigM Suffix attached to any parent_block() between the constraint and the root model. 6) if the constraint is linear, estimate M using the variable bounds M values may be a single value or a 2-tuple specifying the M for the lower bound and the upper bound of the constraint body. Specifying "bigM=N" is automatically mapped to "bigM={None: N}". The transformation will create a new Block with a unique name beginning "_pyomo_gdp_bigm_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(: ) 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. zgdp.bigmtargetsNz.target or list of targets that will be relaxedaJ This specifies the list of components to relax. 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 descriptionr7bigMz*Big-M value used for constraint relaxationz A user-specified value, dict, or ComponentMap of M values that override M-values found through model Suffixes or that would otherwise be calculated using variable domains.assume_fixed_vars_permanentFzBoolean indicating whether or not to transform so that the the transformed model will still be valid when fixed Vars are unfixed.a This is only relevant when the transformation will be estimating values for M. If True, the transformation will calculate M values assuming that fixed variables will always be fixed to their current values. This means that if a fixed variable is unfixed after transformation, the transformed model is potentially no longer valid. By default, the transformation will assume fixed variables could be unfixed in the future and will use their bounds to calculate the M value rather than their value. Note that this could make for a weaker LP relaxation while the variables remain fixed. csdtt|t|jtdtdtdtdt dt dt dt dt dt|jt|jt|jt|jtdi|_d|_dS)z!Initialize transformation object.FN)superr8__init__r_transform_constraintrr r rrrrrrr r*rr+r _transform_block_on_disjunctr"_warn_for_active_logical_statementrhandlers_generate_debug_messages)self) __class__r4r5r@s" zBigM_Transformation.__init__cCs>g}x4||k r8|d}t|tkr.|||}qW|S)NZBigM) componenttyperappend parent_block)rFblockstopping_block suffix_listbigmr4r4r5_get_bigm_suffix_lists     z)BigM_Transformation._get_bigm_suffix_listcCsDg}|dkr|Sx.|dk r>||kr4||||i|}qW|S)N)rJrK)rFZ bigm_argsrLarg_listr4r4r5_get_bigm_arg_lists  z&BigM_Transformation._get_bigm_arg_listcKsFtrttt|_t|_z|j|f|Wdt|jXdS)N) NAME_BUFFERAssertionErrorrloggerrEr used_args_apply_to_implclear)rFinstancekwdsr4r4r5 _apply_tos zBigM_Transformation._apply_toc Ks||di}d|kr2tddd|d|_|||j}|j|_|j}|dkr^|f}i}x|D]}t|||dstd|j |j fqh|j t kr| r| ||n||||qh|j ttfkr| r|||n |||qhtd|j t|fqhW|dk rt|t|j}t|d krd } x6|D].} t| d rl| d | j 7} n | d | 7} qLWt| dS) NoptionsZ default_bigMz9the 'default_bigM=' argument has been replaced by 'bigM='z5.4)version)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.rzWUnused arguments in the bigM map! These arguments were not used by the transformation: namez %s )CONFIGpopr r= set_valuer>r9r$r!ractyper is_indexed_transform_disjunction_transform_disjunctionDataindexr r_transform_block_transform_blockDatarIrkeysrVlenhasattrrUwarn) rFrYrZconfigr=r9r`tZ unused_argsZ warning_msgrHr4r4r5rWsN        z"BigM_Transformation._apply_to_implcCs:t|d}t}|||tt|_tddgd|_|S)NZ_pyomo_gdp_bigm_reformulationlbub)Z initialize)rr add_componentrrelaxedDisjunctsrlbub)rFrYZtransBlockName transBlockr4r4r5_add_transformation_blocks  z-BigM_Transformation._add_transformation_blockcCs*x$tt|D]}||||qWdS)N)sortedr.rk)rFobjr=ir4r4r5rj#sz$BigM_Transformation._transform_blockcCs6x0|jtdtjttftjdD]}|||qWdS)NT)activesort descend_intoZ descent_order) component_objectsr r deterministicr rrZ PostfixDFSrg)rFrzr= disjunctionr4r4r5rk'sz(BigM_Transformation._transform_blockDatacCspt|tst|jdk r |S|r4t|nt}d}t||jdt d|}| ||t ||_|S)NZ_xorT)fully_qualified name_buffer) r1r rT_algebraic_constraintrfr index_setrgetnamerSrt weakref_ref)rFrrwZorCnmZorCnamer4r4r5_add_xor_constraint1s   z'BigM_Transformation._add_xor_constraintcCsf|js dS|jdk r"|}n||}x(tt|D]}||||||q>W|dS)N)r|rrKrxryr.rh deactivate)rFrzr=rwr{r4r4r5rgOs z*BigM_Transformation._transform_disjunctionc Cs|js dS|dkr@|jdk r2|}n||}|||}|j}d}t|jdkr~t d|j dt dx@|jD]6}||j 7}| |} |||} ||||| | qW|r|dk||<n |dk||<t|||_|dS)NrzIDisjunction '%s' is empty. This is likely indicative of a modeling error.T)rr)r|parent_componentrrKrxrxorrmZ disjunctsr!rrS indicator_varrPrR_transform_disjunctrr) rFrzr=rirwZ xorConstraintrZor_exprdisjunctrNrQr4r4r5rhbs2         z.BigM_Transformation._transform_disjunctionDatacCs|jsT|jr:t|jdkr"dStd|jt|jf|jdkrTtd|jf|jdk rltd|j|j}|t|}i|_ t |_ t ||_t ||_ |||||||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.)r|rZis_fixedrr!ra_transformation_blockrurmbigm_srcr localVarReferencesr _srcDisjunct_transform_block_componentsZ$_deactivate_without_fixing_indicator)rFrzrwr=rQrNruZrelaxationBlockr4r4r5rs.        z'BigM_Transformation._transform_disjunctc Cs|}|j}x8|jttddD]$}|t||jdtdt |q W| } x>|j t t jtdD](} | jdkrtqd|  } || | qdWxR|jdddD]@} |j| jd} | s| dkrtd| jq| | ||||qWdS)N)r~r|T)rr)r}r~F)r|r~zNo BigM transformation handler registered for modeling components of type %s. If your disjuncts contain non-GDP Pyomo components that require transformation, please transform them first.)rrrrr rtrrrSrrKZcomponent_data_objectsr rrZalgebraic_constraint_transfer_transBlock_datarDgetrer!) rFrLrr=rQrN disjunctBlockZ varRefBlockvZdestinationBlockrzrwhandlerr4r4r5rs0    z/BigM_Transformation._transform_block_componentsc Csx|j}g}xRt|jD]D\}}|t|}|||}t||_t||_||qWx|D] }|j|=qdWdS)N)rur/rmZtransfer_attributes_fromrrrrJ) rFZ fromBlockZtoBlockZ disjunctListZ to_deleteidxrZnewblockoriginalr4r4r5r s     z-BigM_Transformation._transfer_transBlock_datacCst||tdS)N)r*rS)rFrrbigMargsrQrNr4r4r5r*%sz0BigM_Transformation._warn_for_active_disjunctioncCst||tdS)N)r+rS)rFZ innerdisjunctZ outerdisjunctrrQrNr4r4r5r+)sz-BigM_Transformation._warn_for_active_disjunctcCst||tdS)N)r"rS)rFZlogical_statmentrZinfodictrrNr4r4r5rC-sz6BigM_Transformation._warn_for_active_logical_statementcCs0x*tt|D]}|||||||qWdS)N)ryr.r)rFrLrrrQrNr{r4r4r5rB1sz0BigM_Transformation._transform_block_on_disjunctcCs t|dsttd|_|jS)N_constraintMap)srcConstraintstransformedConstraints)rnrr)rFrwr4r4r5_get_constraint_map_dict<s  z,BigM_Transformation._get_constraint_map_dictc Cstt|ttfsP|dkrd}n4y| |f}Wn$td|t|fYnXt|dkrptdt||f|S)N)NNzHError converting scalar M-value %s to (-M,M). Is %s not a numeric type?zuBig-M %s for constraint %s is not of length two. Expected either a single value or tuple or list of length two for M.) r1tuplelistrUerrorrIrmr!str)rFMconstraint_namer4r4r5_convert_M_to_tupleCs z'BigM_Transformation._convert_M_to_tuplecCs|}|j}||}|} |jdtd} t|| } |r^t| | j } | |d|<n t| j } | | | ||d| <xDt t |D]2} || }|jsqd}d}||||||\}}|d|df}|jr|jdtd}td| t|f|ddkr|jdk s2|ddkrr|jdk rr|j||d }|||||||\}}|d|df}|jr|jdtd}td | t|f|jdk r|ddkr||j| d|j|df}|dddf}|jdk r.|ddkr.|d||j| d|jf}|dddf}|jrZ|jdtd}td | t|f||f||<| jtkr| d }| d }n$|r| df}| df}nd}d}|jdk r|ddkrtd| |dd|j}| ||j|j|k| |g|d|<||d| |<|jdk r|ddkr@td| |dd|j}| ||j||jk|d |}|dk r|d|!| |n| |g|d|<||d| |<|"qWdS)NT)rrrr)NNNrzLGDP(BigM): The value for M for constraint '%s' from the BigM argument is %s.r)rMzMGDP(BigM): The value for M for constraint '%s' after checking suffixes is %s.zRGDP(BigM): The value for M for constraint '%s' after estimating (if needed) is %s.)rr)rsrrrszBCannot relax disjunctive constraint '%s' because M is not defined.)#rrrrKrrSrrfrrrvrtryr.r|_get_M_from_argsrErUdebugrlowerupperrPextend_update_M_from_suffixes _estimate_MbodyrGrr!raddrrJr)rFrzrrrQZdisjunct_suffix_listrwrZ constraintMapZdisjunctionRelaxationBlockZ cons_nameraZ newConstraintr{crrr_namerNZi_lbZi_ubZM_exprZ transformedr4r4r5rAXs                       z)BigM_Transformation._transform_constraintc Csx|||}|r<|ddk r<| r*||j|<|d||f}d}|rl|ddk rl| rZ||j|<|d||f}d}||||fS)NrFr)rrV) rFmrr need_lower need_uppersrckeyr from_argsr4r4r5_process_M_values   z$BigM_Transformation._process_M_valuec Csn|dkr||fS|jdk }|jdk }|jdtd}|} ||kr||} |j| |||||||dd \}}}}|s|s||fSnD| |kr|| } |j| |||||| |dd \}}}}|s|s||fSxV|D]N} xHt| D]<\} } |j| |||||| |dd \}}}}|s|s||fSqWqWd|krf|d} |j| |||||d|dd \}}}}|sf|sf||fS||fS)NT)rr)r)rrrrSrrr/)rF constraintrrQrrrrrr^rargrLr3r4r4r5rsf         z$BigM_Transformation._get_M_from_argsc Cs:|jdk o|ddk}|jdk o*|ddk}|jdtd}d}x|D]} || kr| |}||||||| ||\}}}}|s|s||fS|| krD|} | | }||||||| | |\}}}}|sD|sD||fSqDW|dkr2xN|D]F} d| kr| d}||||||| d|\}}}}|s|s||fSqW||fS)NrT)rr)rrrrSrr) rFrrNrrrrrrrOr^r4r4r5r(sN        z+BigM_Transformation._update_M_from_suffixescCst}|jsEXPRZidentify_variablesZfixedrr,Z is_nonlinearZconstant enumerateZ linear_coefsZ linear_varsrrrsr!rar r/Zfixr)rFexprraZ fixed_varsrZrepnrr{ZcoefvarZboundsjZexpr_lbZexpr_ubr3r4r4r5r^sB           zBigM_Transformation._estimate_McCst|S)N)r))rFrwr4r4r5r)sz$BigM_Transformation.get_src_disjunctcCst|S)N)r%)rFZxor_constraintr4r4r5r%sz'BigM_Transformation.get_src_disjunctioncCst|S)N)r&)rFZtransformedConstraintr4r4r5r&sz&BigM_Transformation.get_src_constraintcCst|S)N)r')rFZ srcConstraintr4r4r5r'sz/BigM_Transformation.get_transformed_constraintszThe get_m_value_src function is deprecated. Use the get_M_value_src function is you need source information or the get_M_value function if you only need values.z5.7.1)r]c Cst|}|j|\\}}}\}}}|jdk rT|jdk rT||k sF||k rTtd|j|jdk rn|dk rn||fS|jdk r|dk r||fS||fS)NzThis is why this method is deprecated: The lower and upper M values for constraint %s came from different sources, please use the get_M_value_src method.)r(rrrr!ra) rFrrwZ lower_valZ lower_sourceZ lower_keyZ upper_valZ upper_sourceZ upper_keyr4r4r5get_m_value_srcs z#BigM_Transformation.get_m_value_srccCst|}|j|S)aReturn a tuple indicating how the M value used to transform constraint was specified. (In particular, this can be used to verify which BigM Suffixes were actually necessary to the transformation.) Return is of the form: ((lower_M_val, lower_M_source, lower_M_key), (upper_M_val, upper_M_source, upper_M_key)) If the constraint does not have a lower bound (or an upper bound), the first (second) element will be (None, None, None). Note that if a constraint is of the form a <= expr <= b or is an equality constraint, it is not necessarily true that the source of lower_M and upper_M are the same. If the M value came from an arg, source is the dictionary itself and key is the key in that dictionary which gave us the M value. If the M value came from a Suffix, source is the BigM suffix used and key is the key in that Suffix. If the transformation calculated the value, both source and key are None. Parameters ---------- constraint: Constraint, which must be in the subtree of a transformed Disjunct )r(r)rFrrwr4r4r5get_M_value_srcsz#BigM_Transformation.get_M_value_srccCs&t|}|j|\}}|d|dfS)afReturns the M values used to transform constraint. Return is a tuple: (lower_M_value, upper_M_value). Either can be None if constraint does not have a lower or upper bound, respectively. Parameters ---------- constraint: Constraint, which must be in the subtree of a transformed Disjunct r)r(r)rFrrwrrr4r4r5 get_M_values zBigM_Transformation.get_M_value)N)N)F).__name__ __module__ __qualname____doc__rrbZdeclarerr#r6boolr@rPrRr[rWrxrjrkrrgrhrrrr*r+rCrBrrrArrrrr-r)r%r&r'rrrr __classcell__r4r4)rGr5r83sd/      >   5>6 | F6:!r8)LrloggingZpyomo.common.collectionsrrZpyomo.common.configrrZpyomo.common.logrZpyomo.common.modelingrZpyomo.common.deprecationrr Zpyomo.contrib.fbbt.fbbtr Z pyomo.corer r r rrrrrrrrrrrrrZpyomo.core.base.externalrZpyomo.core.baserrrZpyomo.core.expr.currentcorercurrentrZ pyomo.gdprr r!Zpyomo.gdp.utilr"r#r$r%r&r'r(r)r*r+Z pyomo.repnr, functoolsr-sixr.r/weakrefr0r getLoggerrUrSr6registerr8r4r4r4r5 s,   H 0