B u `ֻ@sdZddlZddlmZmZddlmZmZddlm Z ddl m Z ddl m Z ddlmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZdd lm Z dd l!m"Z"m#Z#m$Z$ddl%m&m'm(Z)dd l*m+Z+m,Z,m-Z-dd l.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8dd l9m:Z:ddl;mZ>m?Z?ddl@mAZBeCdZDiZEddZFe#jGdddGddde"ZHdS)z@Big-M Generalized Disjunctive Programming transformation module.N) ComponentMap ComponentSet) ConfigBlock ConfigValue)unique_component_name) deprecated)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)valr2:/tmp/pip-unpacked-wheel-n62dbgi3/pyomo/gdp/plugins/bigm.py_to_dict,sr4zgdp.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 descriptionr5bigMz*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. cs^tt|t|jtdtdtdtdt dt dt dt dt dt|jt|jt|jt|jtdi|_dS)z!Initialize transformation object.FN)superr6__init__r _transform_constraintrr r rrr rrrrr(rr)r _transform_block_on_disjunctr"_warn_for_active_logical_statementrhandlers)self) __class__r2r3r>s zBigM_Transformation.__init__cCs>g}x4||k r8|d}t|tkr.|||}qW|S)NZBigM) componenttyperappend parent_block)rCblockstopping_block suffix_listbigmr2r2r3_get_bigm_suffix_lists     z)BigM_Transformation._get_bigm_suffix_listcCsDg}|dkr|Sx.|dk r>||kr4||||i|}qW|S)N)rGrH)rCZ bigm_argsrIarg_listr2r2r3_get_bigm_arg_lists  z&BigM_Transformation._get_bigm_arg_listcKs<trtt|_z|j|f|Wdt|jXdS)N) NAME_BUFFERAssertionErrorr used_args_apply_to_implclear)rCinstancekwdsr2r2r3 _apply_tos zBigM_Transformation._apply_toc Ks||di}d|kr0td|d|_|||j}|j|_|j}|dkr\|f}i}x|D]}t|||dst d|j |j fqf|j t kr| r|||n||||qf|j ttfkr| r|||n |||qft d|j t|fqfW|dk rt|t|j}t|dkrd} x6|D].} t| d rj| d | j 7} n | d | 7} qJWt| dS) NoptionsZ default_bigMzEDEPRECATED: the 'default_bigM=' argument has been replaced by 'bigM=')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 )CONFIGpoploggerwarnr; set_valuer<r7r"rr\ctyper is_indexed_transform_disjunction_transform_disjunctionDataindexr r_transform_block_transform_blockDatarFrkeysrRlenhasattr) rCrUrVconfigr;r7r[tZ unused_argsZ warning_msgrEr2r2r3rSsL         z"BigM_Transformation._apply_to_implcCs:t|d}t}|||tt|_tddgd|_|S)NZ_pyomo_gdp_bigm_reformulationlbub)Z initialize)rr add_componentrrelaxedDisjunctsrlbub)rCrUZtransBlockName transBlockr2r2r3_add_transformation_blocks  z-BigM_Transformation._add_transformation_blockcCs*x$tt|D]}||||qWdS)N)sortedr,rh)rCobjr;ir2r2r3rg sz$BigM_Transformation._transform_blockcCs6x0|jtdtjttftjdD]}|||qWdS)NT)activesort descend_intoZ descent_order) component_objectsrr deterministicr rrZ PostfixDFSrd)rCrvr; disjunctionr2r2r3rh$sz(BigM_Transformation._transform_blockDatacCspt|tst|jdk r |S|r4t|nt}d}t||jdt d|}| ||t ||_|S)NZ_xorT)fully_qualified name_buffer) r/rrQ_algebraic_constraintrcr index_setrgetnamerPrp weakref_ref)rCr}rsZorCnmZorCnamer2r2r3_add_xor_constraint.s   z'BigM_Transformation._add_xor_constraintcCsf|js dS|jdk r"|}n||}x(tt|D]}||||||q>W|dS)N)rxrrHrtrur,re deactivate)rCrvr;rsrwr2r2r3rdLs 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)r~r)rxparent_componentrrHrtrxorrjZ disjunctsrrrP indicator_varrMrO_transform_disjunctrr) rCrvr;rfrsZ xorConstraintrZor_exprdisjunctrKrNr2r2r3re_s2         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.)rxrZis_fixedrrr\_transformation_blockrqrjbigm_srcr localVarReferencesr _srcDisjunct_transform_block_componentsZ$_deactivate_without_fixing_indicator)rCrvrsr;rNrKrqZrelaxationBlockr2r2r3rs.        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)rzrxT)r~r)ryrzF)rxrzzNo 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.)rrr{rr rprrrPrrHZcomponent_data_objectsrrr|Zalgebraic_constraint_transfer_transBlock_datarBgetrbr) rCrIrr;rNrK disjunctBlockZ varRefBlockvZdestinationBlockrvrshandlerr2r2r3rs0    z/BigM_Transformation._transform_block_componentsc Csx|j}g}xRt|jD]D\}}|t|}|||}t||_t||_||qWx|D] }|j|=qdWdS)N)rqr-rjZtransfer_attributes_fromrrrrG) rCZ fromBlockZtoBlockZ disjunctListZ to_deleteidxrZnewblockoriginalr2r2r3rs     z-BigM_Transformation._transfer_transBlock_datacCst||tdS)N)r(rP)rCr}rbigMargsrNrKr2r2r3r("sz0BigM_Transformation._warn_for_active_disjunctioncCst||tdS)N)r)rP)rCZ innerdisjunctZ outerdisjunctrrNrKr2r2r3r)&sz-BigM_Transformation._warn_for_active_disjunctcCst||tdS)N)r rP)rCZlogical_statmentrZinfodictrrKr2r2r3rA*sz6BigM_Transformation._warn_for_active_logical_statementcCs0x*tt|D]}|||||||qWdS)N)rur,r)rCrIrrrNrKrwr2r2r3r@.sz0BigM_Transformation._transform_block_on_disjunctcCs t|dsttd|_|jS)N_constraintMap)srcConstraintstransformedConstraints)rkrr)rCrsr2r2r3_get_constraint_map_dict9s  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.) r/tuplelistr_errorrFrjrstr)rCMconstraint_namer2r2r3_convert_M_to_tuple@s z'BigM_Transformation._convert_M_to_tuplecCs|}|j}||}|} |jdtd} t|| } |r^t| | j } | |d|<n t| j } | | | ||d| <xXt t |D]F} || }|jsqd}d}||||||\}}|d|df}ttjr|jdtd}td| t|f|ddkr |jdk s:|ddkrz|jdk rz|j||d }|||||||\}}|d|df}ttjr|jdtd}td | t|f|jdk r|ddkr||j| d|j|df}|dddf}|jdk r<|ddkr<|d||j| d|jf}|dddf}ttjrn|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|ddkrTtd| |dd|j }| !||j||jk|d"|}|dk r|d|#| |n| |g|d|<||d| |<|$qWdS)NT)r~rrr)NNNrzLGDP(BigM): The value for M for constraint '%s' from the BigM argument is %s.r)rJzMGDP(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.)rn)rornrozBCannot relax disjunctive constraint '%s' because M is not defined.)%rrrrHrrPrrcr rrrrprur,rx_get_M_from_argsr_ isEnabledForloggingDEBUGdebugrlowerupperrMextend_update_M_from_suffixes _estimate_MbodyrDrrraddrrGr)rCrvrrrNZdisjunct_suffix_listrsrZ constraintMapZdisjunctionRelaxationBlockZ cons_namer\Z newConstraintrwcrrr_namerKZi_lbZi_ubZM_exprZ transformedr2r2r3r?Us                       z)BigM_Transformation._transform_constraintc Csx|||}|r<|ddk r<| r*||j|<|d||f}d}|rl|ddk rl| rZ||j|<|d||f}d}||||fS)NrFr)rrR) rCmrr need_lower need_uppersrckeyr from_argsr2r2r3_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)r~r)r)rrrrPrrr-)rC constraintrrNrrrrrrYrargrIr1r2r2r3rsf         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)r~r)rrrrPrr) rCrrKrrrrrrrLrYr2r2r3r%sN        z+BigM_Transformation._update_M_from_suffixescCst}|jsrMrOrWrSrtrgrhrrdrerrrr(r)rAr@rrr?rrrrr+r'r#r$r%rrrr __classcell__r2r2)rDr3r62sd/      >   5>6 | F6:!r6)IrrZpyomo.common.collectionsrrZpyomo.common.configrrZpyomo.common.modelingrZpyomo.common.deprecationrZpyomo.contrib.fbbt.fbbtrZ pyomo.corer r r r r rrrrrrrrrrrZpyomo.core.base.externalrZpyomo.core.baserrrZpyomo.core.expr.currentcorercurrentrZ pyomo.gdprrrZpyomo.gdp.utilr r!r"r#r$r%r&r'r(r)Z pyomo.repnr* functoolsr+sixr,r-weakrefr.r getLoggerr_rPr4registerr6r2r2r2r3 s*   H 0