| Quintiq file version 2.0 | 
| #parent: #root | 
| Method ReExecuteOptimizerSlidingWindows ( | 
|   CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, | 
|   const RunContextForCapacityPlanning runcontext, | 
|   LibOpt_Task task | 
| ) | 
| { | 
|   TextBody: | 
|   [* | 
|     // Unfreeze the slack variables | 
|     // Since we will change some variables from continuous to integer, it could be that the slacks from the previous run are insufficient | 
|     isunfreeze := true; | 
|     scope := task.Scope();  | 
|     this.FreezeZeroSlack( program, isunfreeze, runcontext, scope  ); | 
|      | 
|     periodslastwindow := selectset( scope.GetPeriodInSlidingWindow(), Elements, period, true ); | 
|      | 
|     // Select the first period in the next window | 
|     // From the first period in the previous window we move NumberOfPeriodsPerSlide forward | 
|     // Each period that we move forward is added to the set of newly frozen periods | 
|     firstperiod := minselect( periodslastwindow, Elements, period, true, period.Start() ); | 
|      | 
|     newfrozenperiods := construct( Period_MPs ); | 
|     for( i:= 1; | 
|          i <= runcontext.NumberOfPeriodsPerSlide() | 
|          and not isnull( firstperiod.NextPlanningPeriod() ); | 
|          i++ ) | 
|     { | 
|       newfrozenperiods.Add( firstperiod ); | 
|       firstperiod := firstperiod.NextPlanningPeriod(); | 
|     } | 
|      | 
|     // Remove from scope the periods that are no longer in the active window | 
|     traverse( newfrozenperiods, Elements, period, period.GetIsInSlidingWindow( scope ) ) | 
|     { | 
|       period.PeriodInSlidingWindow().Delete();  | 
|     } | 
|      | 
|     // Add periods in the new window to the scope and select them | 
|     this.SetSlidingWindowPeriods( firstperiod, runcontext, scope ); | 
|     periodsnextwindow := selectset( scope.GetPeriodInSlidingWindow(), Elements, period, true ); | 
|      | 
|     // Freeze the binary/integer variables that are in the newly frozen periods | 
|     // First freeze the semicontinous PTQty variable | 
|     if( runcontext.UseProcessMinimumQuantity() or runcontext.UseLotSize() ) | 
|     { | 
|       traverse( newfrozenperiods, Elements, period, | 
|                 period.IsWithinLotSizeHorizon() ) | 
|       { | 
|         traverse( period, UnitPeriod, unitperiod, | 
|                  scope.Contains( unitperiod.UnitPeriodInOptimizerRun() ) ) | 
|         { | 
|           operations := this.GetOperationsForUnitPeriod( scope, unitperiod ); | 
|           traverse( operations, Elements, operation ) | 
|           { | 
|             // Freeze the period task operation minimum process quantity variables | 
|             if( runcontext.UseProcessMinimumQuantity() | 
|                 and operation.HasMinimumQuantity() ) | 
|             { | 
|               ptvar := program.PTQtyVariables().Get( operation, period );  | 
|               optimalvalue := this.GetOptimalValue( ptvar ); | 
|               this.FreezeVariableWithSlack( ptvar, optimalvalue ); | 
|             } | 
|              | 
|             // Freeze the period task operation lotsize variables | 
|             if( runcontext.UseLotSize() | 
|                 and operation.HasLotSize() ) | 
|             { | 
|               ptnroflotsvar := program.PTNrOfLotsVariables().Get( operation, period ); | 
|               optimalvalue := this.GetOptimalValue( ptnroflotsvar ); | 
|               this.FreezeVariableWithSlack( ptnroflotsvar, optimalvalue ); | 
|             } | 
|              | 
|             // Freeze the operation input lot size variables | 
|             if( runcontext.UseLotSize() | 
|                 and operation.HasInputLotSize() ) | 
|             { | 
|               periodsfordd := construct( Period_MPs, constcontent ); // periods for dependent demand | 
|              | 
|               // Consider all relevant periods for the dependent demand | 
|               CapacityPlanningSuboptimizer::GetOperationDependentDemandPeriods( period, operation, &periodsfordd, this.GetPeriodsFromPeriodTaskOperation() ); // period itself may be included twice  | 
|               periodsfordd := periodsfordd.Unique(); | 
|                | 
|               traverse( periodsfordd, Elements, ddperiod, | 
|                         period.IsWithinLotSizeHorizon() ) | 
|               {  | 
|                 // Freeze the operation input lot size variables | 
|                 traverse( operation,  | 
|                           OperationInput,  | 
|                           input, | 
|                           input.ProductInStockingPoint_MP().HasInputLotSize()  | 
|                           and ( input.HasRegularProductforOptimizer() or input.GetIsProductInOptimizerRun( runcontext.IsPostProcessing() ) ) )  | 
|                 { | 
|                   operationinputnroflotsvar := program.OperationInputNrOfLotsVariables().Get( input, ddperiod ); | 
|                   optimalvalue := this.GetOptimalValue( operationinputnroflotsvar ); | 
|                   this.FreezeVariableWithSlack( operationinputnroflotsvar, optimalvalue ); | 
|                 } | 
|               } | 
|             } | 
|           } | 
|         } | 
|         // Freeze the trip lotsize variables | 
|         if( runcontext.UseLotSize() ) | 
|         { | 
|           traverse( period, UnitPeriod.astype( UnitPeriodTransportBase ), unitperiod, | 
|                     unitperiod.HasLotSize() ) | 
|           { | 
|             traverse( unitperiod, AsDepartureUnitPeriod, trip, | 
|                       scope.Contains(  trip.TripInOptimizerRun() ) ) | 
|             { | 
|               // TripNrOfLots variable UoM: Number | 
|               tripnroflotsvar := program.TripNrOfLotsVariables().Get( trip ); | 
|               optimalvalue := this.GetOptimalValue( tripnroflotsvar ); | 
|               this.FreezeVariableWithSlack( tripnroflotsvar, optimalvalue ); | 
|             } | 
|           } | 
|         } | 
|       } | 
|     } | 
|      | 
|     remainingwindowperiods := periodsnextwindow.Intersect( periodslastwindow ); | 
|     newwindowperiods := periodsnextwindow.Difference( remainingwindowperiods ); | 
|      | 
|     // Make set variables in the periods that are new in the sliding window to integer | 
|     if( runcontext.UseProcessMinimumQuantity() or runcontext.UseLotSize() ) | 
|     { | 
|       traverse( newwindowperiods, Elements, period, | 
|                 period.IsWithinLotSizeHorizon() ) | 
|       { | 
|         traverse( period, UnitPeriod, unitperiod, | 
|                  scope.Contains(  unitperiod.UnitPeriodInOptimizerRun() ) ) | 
|         { | 
|           operations := this.GetOperationsForUnitPeriod( scope, unitperiod ); | 
|           traverse( operations, Elements, operation ) | 
|           { | 
|             // Set the period task operation minimum process quantity variables that are new to the sliding window to semicontinous | 
|             if( runcontext.UseProcessMinimumQuantity() | 
|                 and operation.HasMinimumQuantity() ) | 
|             { | 
|               ptvar := program.PTQtyVariables().Get( operation, period ); | 
|               ptvar.VariableType( 'SemiContinuous' ); | 
|               lowerbound := operation.MinimumQuantity() / operation.QuantityToProcessFactor();    | 
|               if ( lowerbound > 0 )  | 
|               { | 
|                 this.FreezeVariableLowerBound( ptvar, lowerbound ); | 
|               } | 
|             } | 
|             // Set the period task operation lotsize variables that are new to the sliding window to integer | 
|             if( runcontext.UseLotSize() | 
|                 and operation.HasLotSize() ) | 
|             { | 
|               ptnroflotsvar := program.PTNrOfLotsVariables().Get( operation, period ); | 
|               ptnroflotsvar.VariableType( 'Integer' ); | 
|             } | 
|              | 
|             // Set the operation input lot size variables that are new to the sliding window to integer | 
|             if( runcontext.UseLotSize() | 
|                 and operation.HasInputLotSize() ) | 
|             { | 
|               periodsfordd := construct( Period_MPs, constcontent ); // periods for dependent demand | 
|              | 
|               // Consider all relevant periods for the dependent demand | 
|               CapacityPlanningSuboptimizer::GetOperationDependentDemandPeriods( period, operation, &periodsfordd, this.GetPeriodsFromPeriodTaskOperation() ); // period may be added twice | 
|               periodsfordd := periodsfordd.Unique();  | 
|                      | 
|               traverse( periodsfordd, Elements, ddperiod, | 
|                         period.IsWithinLotSizeHorizon() ) | 
|               { | 
|                 traverse( operation, OperationInput, input, | 
|                           input.GetIsProductInOptimizerRun( runcontext.IsPostProcessing() ) | 
|                           and input.ProductInStockingPoint_MP().HasInputLotSize() ) | 
|                 { | 
|                   operationinputnroflotsvar := program.OperationInputNrOfLotsVariables().Get( input, ddperiod ); | 
|                   operationinputnroflotsvar.VariableType( 'Integer' ); | 
|                 } | 
|               } | 
|             } | 
|           } | 
|         } | 
|          | 
|         // Set the trip lotsize variables that are new to the sliding window to integer | 
|         if( runcontext.UseLotSize() ) | 
|         { | 
|           traverse( period, UnitPeriod.astype( UnitPeriodTransportBase ), unitperiod, | 
|                     unitperiod.HasLotSize() ) | 
|           { | 
|             traverse( unitperiod, AsDepartureUnitPeriod, trip, | 
|                       scope.Contains(  trip.TripInOptimizerRun() ) ) | 
|             { | 
|               // TripNrOfLots variable UoM: Number | 
|               tripnroflotsvar := program.TripNrOfLotsVariables().Get( trip ); | 
|               tripnroflotsvar.VariableType( 'Integer' ); | 
|             } | 
|           } | 
|         } | 
|       } | 
|     } | 
|      | 
|     // Add the new window periods to the algorithmrun | 
|     traverse( newwindowperiods, Elements, period ) | 
|     { | 
|       scope.Add( period.PeriodInSlidingWindow( relnew ) );   | 
|     } | 
|      | 
|     // reset lower bounds on goal variables for the next window | 
|     traverse( this, MacroPlan.StrategyMacroPlan.StrategyLevelMacroPlan, level )  | 
|     { | 
|       var := program.GoalForLevelVariables().Get( level );  | 
|       var.LowerBound( Real::MinReal() );  | 
|     } | 
|     // Remove the active goals | 
|     traverse( program.Goal().Terms(), Elements, term ) | 
|     { | 
|       term.Coefficient( 0.0 ); | 
|     } | 
|      | 
|      | 
|      | 
|     // Reexecute the algorithm and start from the first level and reactivate the level 1 goals | 
|     this.ReExecute( program ); | 
|     this.CreateSubOptimizerLevels( runcontext, task );  | 
|     this.ActivateGoals( program, runcontext, scope ); | 
|      | 
|     info( "----------- Sliding the lotsize window -----------" ); | 
|     info( "-------- New window starts at ", minselect( periodsnextwindow, Elements, period, true, period.Start() ).Start() ); | 
|     info( "------------- Reexecuting algorithm --------------" ); | 
|   *] | 
|   InterfaceProperties { Accessibility: 'Module' } | 
| } |