| Quintiq file version 2.0 | 
| #parent: #root | 
| Method InitConstraintsForShiftPatternFirstPeriod ( | 
|   CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, | 
|   const LibOpt_Scope scope, | 
|   const UnitPeriodTime up, | 
|   const ShiftPattern sp, | 
|   Real scalefactor_spisused_const1, | 
|   Real scalefactor_spisfirst_const1, | 
|   Real scalefactor_spisused_const2, | 
|   Real scalefactor_spisfirst_const2, | 
|   Real scalefactor_spisused_const3, | 
|   Real scalefactor_spisfirst_const3, | 
|   Real scalefactor_spisfirst_const4, | 
|   Real scalefactor_spisused_const4, | 
|   Real scalefactor_rhs_const2, | 
|   Real scalefactor_rhs_const3, | 
|   Real scalefactor_rhs_const4 | 
| ) const | 
| { | 
|   Description: 'Checks if a shift pattern is the first one in a sequence of assignments.' | 
|   TextBody: | 
|   [* | 
|     previousup := up.PreviousPlanningUnitPeriod(); | 
|      | 
|     // If this period does not have a previous unit period | 
|     if( isnull( previousup ) ) | 
|     { | 
|       // Constraint: any shift pattern on a period that doesn't have a previous period is considered the "first one" in a sequence of assignments. | 
|       // ShiftPatternIsFirst[sp][up0] = ShiftPatternIsUsed[sp][up0] | 
|       firstperiodconstr1 := program.FirstPeriodStartOfPlanningConstraints().New( sp, up ); | 
|       firstperiodconstr1.Sense( "=" ); | 
|       firstperiodconstr1.RHSValue( 0.0 ); | 
|        | 
|       firstperiodconstr1.NewTerm( 1.0 * scalefactor_spisfirst_const1, program.ShiftPatternIsFirstVariables().Get( sp, up ) ); | 
|       firstperiodconstr1.NewTerm( -1.0 * scalefactor_spisused_const1, program.ShiftPatternIsUsedVariables().Get( sp, up ) ); | 
|     } | 
|     else // This period has a previous unit period | 
|     { | 
|       // Constraint: when a shift pattern starts being used on unit, it is considered as the "first one" in a sequence of assignments. | 
|       // ShiftPatternIsFirst[sp][up] >= ShiftPatternIsUsed[sp][up] - ShiftPatternIsUsed[sp][up-1] | 
|       firstperiodconstr2 := program.FirstPeriodShiftOnUnitConstraints().New( sp, up ); | 
|       firstperiodconstr2.Sense( ">=" ); | 
|       firstperiodconstr2.RHSValue( 0.0 ); | 
|        | 
|       firstperiodconstr2.NewTerm( 1.0 * scalefactor_spisfirst_const2, program.ShiftPatternIsFirstVariables().Get( sp, up ) ); | 
|        | 
|       // If this unit period is in scope, add a term with the corresponding variable. Otherwise, update the RHS. | 
|       if( up.IsInScopeForShiftOptimization( scope ) ) | 
|       { | 
|         firstperiodconstr2.NewTerm( -1.0 * scalefactor_spisused_const2, program.ShiftPatternIsUsedVariables().Get( sp, up ) ); | 
|       } | 
|       else | 
|       { | 
|         newrhs := ifexpr( up.ShiftPattern() = sp, 1, 0 ); | 
|         firstperiodconstr2.RHSValue( newrhs * scalefactor_rhs_const2 ); | 
|       } | 
|        | 
|       // If the previous unit period is in scope, add a term with the corresponding variable. Otherwise, update the RHS. | 
|       if( previousup.IsInScopeForShiftOptimization( scope ) ) | 
|       { | 
|         firstperiodconstr2.NewTerm( 1.0 * scalefactor_spisused_const2, program.ShiftPatternIsUsedVariables().Get( sp, previousup ) ); | 
|       } | 
|       else | 
|       { | 
|         newterm := ifexpr( previousup.astype( UnitPeriodTime ).ShiftPattern() = sp, 1, 0 ); | 
|         newrhs := this.GetConstraintRHS( firstperiodconstr2, scalefactor_rhs_const2 ) - newterm; | 
|         firstperiodconstr2.RHSValue( newrhs * scalefactor_rhs_const2 ); | 
|       } | 
|        | 
|       // Constraint: a shift pattern cannot be the "first one" in a sequence of assignments if it is not used. | 
|       // ShiftPatternIsFirst[sp][up] <= ShiftPatternIsUsed[sp][up] | 
|       firstperiodconstr3 := program.FirstPeriodShiftNotUsedConstraints().New( sp, up ); | 
|       firstperiodconstr3.Sense( "<=" ); | 
|        | 
|       firstperiodconstr3.NewTerm( 1.0 * scalefactor_spisfirst_const3, program.ShiftPatternIsFirstVariables().Get( sp, up ) ); | 
|        | 
|       // If this unit period is in scope, add a term with the corresponding variable. Otherwise, update the RHS. | 
|       // Note: up can be out of scope when this method is called 1 unit period after the scope,  | 
|       // in order to set the "SPIsFirst" variable for the minimum duration constraint. | 
|       if( up.IsInScopeForShiftOptimization( scope ) ) | 
|       { | 
|         firstperiodconstr3.NewTerm( -1.0 * scalefactor_spisused_const3, program.ShiftPatternIsUsedVariables().Get( sp, up ) ); | 
|         firstperiodconstr3.RHSValue( 0.0 ); | 
|       } | 
|       else | 
|       { | 
|         newrhs := ifexpr( up.ShiftPattern() = sp, 1, 0 ); | 
|         firstperiodconstr3.RHSValue( newrhs * scalefactor_rhs_const3 ); | 
|       } | 
|        | 
|       // Constraint: a shift pattern cannot be the "first one" in a sequence of assignments if it is used during the previous period. | 
|       // ShiftPatternIsFirst[sp][up] <= 1 - ShiftPatternIsUsed[sp][up-1] | 
|       firstperiodconstr4 := program.FirstPeriodShiftAlreadyUsedConstraints().New( sp, up ); | 
|       firstperiodconstr4.Sense( "<=" ); | 
|        | 
|       firstperiodconstr4.NewTerm( 1.0 * scalefactor_spisfirst_const4, program.ShiftPatternIsFirstVariables().Get( sp, up ) ); | 
|        | 
|       if( previousup.IsInScopeForShiftOptimization( scope ) ) | 
|       { | 
|         firstperiodconstr4.NewTerm( 1.0 * scalefactor_spisused_const4, program.ShiftPatternIsUsedVariables().Get( sp, previousup ) ); | 
|         firstperiodconstr4.RHSValue( 1.0 * scalefactor_rhs_const4 ); | 
|       } | 
|       else | 
|       { | 
|         rhs := ifexpr( previousup.astype( UnitPeriodTime ).ShiftPattern() = sp, 0, 1 ); | 
|         firstperiodconstr4.RHSValue( rhs * scalefactor_rhs_const4 ); | 
|       } | 
|     } | 
|   *] | 
|   InterfaceProperties { Accessibility: 'Module' } | 
| } |