yanweiyuan3
2023-08-09 588bc7829387dfc761cc25f06f77d4c81818bd10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
Quintiq file version 2.0
#parent: #root
Method HasConvergencedForFocusLevel (
  LibOpt_Task task
) as Boolean
{
  TextBody:
  [*
    value := false; 
    window := this.ConvergenceWindowSize(); 
    snapshotserror := selectset( task, 
                                Run.Snapshot.astype( LibOpt_SnapshotError ), 
                                s,
                                true, 
                                true ); 
    
    value := snapshotserror.Size() > this.MaxError(); 
    
    if ( not value and not task.Scope().IsGeneratedByPreProductionSelector() ) 
    {
      snapshots := selectsortedset( task, Run.SnapshotMacroPlannerOptimizerAccepted, s, s.FocusLevel() = this.FocusLevel(), -s.SequenceNr() ).SelectFirst( window );
        
      if ( snapshots.Size() > 0 ) 
      {
        runcontext := RunContextForCapacityPlanning::GetRunContextCapacityPlanning( task.Run() );
    
        islimitingforshiftoptimization := false; 
        if ( runcontext.UseShiftOptimization() ) 
        {
          traverse( task.Run().Optimization().astype( Optimization ).MacroPlan(), 
                    Unit, 
                    unit, 
                    unit.IsInOptimizerPuzzle() ) 
          {
            islimitingforshiftoptimization := islimitingforshiftoptimization or exists( unit, UnitShiftPatternAllowed, usa, true, not usa.IsActive() ); 
            if ( not islimitingforshiftoptimization ) 
            {
              traverse( unit.GetAllChildren(), Elements, child ) 
              {
                islimitingforshiftoptimization := islimitingforshiftoptimization or exists( child, UnitShiftPatternAllowed, usa, true, not usa.IsActive() ); 
              }
            }
          }
        }    
        
        iscampaignsequencing_or_shiftopt := runcontext.UseCampaignSequenceOptimizer() or islimitingforshiftoptimization; // don't take shortcuts because we limit binaries 
        
        lastsnapshots := snapshots.SelectFirst( minvalue(  snapshots.Size(), window ) ); 
        lastsnapshot := snapshots.Element( 0 );   
        
        maxbestscorelevel := max( lastsnapshots, Elements, s, true, RealVector::Construct( s.BestFoundScoresForLevels() ).Get( this.FocusLevel() ) ); 
        minbestscorelevel := min( lastsnapshots, Elements, s, true, RealVector::Construct( s.BestFoundScoresForLevels() ).Get( this.FocusLevel() ) ); 
        movement_relative := guard( ( maxbestscorelevel - minbestscorelevel ) / ( 0.5 * abs( maxbestscorelevel) + 0.5* abs( minbestscorelevel )), 0.0 );  
        absolute_movement := abs( maxbestscorelevel - minbestscorelevel ); // around 0 relative movement becomes noisy
        movement := minvalue(  movement_relative, absolute_movement ); 
        lastsnapshot.MaxScoreConvergenceWindow( maxbestscorelevel ); 
        lastsnapshot.MinScoreConvergenceWindow( minbestscorelevel ); 
        lastsnapshot.MovementScoreConvergenceWindow( movement ); 
        debuginfo( 'maxscore=', maxbestscorelevel, 'minscore = ', minbestscorelevel, 'movement=', movement, '( stop when < ', this.ConvergenceThreshold(), ')' ); 
        avgsubopttime := average( lastsnapshots, Elements, s, true, s.DurationSecondsSubOptimizer() ); 
                               
        if ( movement < this.ConvergenceThreshold() and snapshots.Size() >= window )  
        {
          value := true; 
          lastsnapshot.StopCriteriumInfo( lastsnapshot.StopCriteriumInfo() + 'Converged. Avg time=' + [String] avgsubopttime );  
        }
        
        if ( not value and this.HasTimedOutLocalDuration( task ) ) 
        {
          lastsnapshot.StopCriteriumInfo( lastsnapshot.StopCriteriumInfo() + 'iteration time out' );  
          value := true; 
        }
        
        if ( not value and this.HasTimedOutGlobalDuration( task ) ) 
        {
          lastsnapshot.StopCriteriumInfo( lastsnapshot.StopCriteriumInfo() + 'global time out' );  
          value := true; 
        }
        
        // check for some shortcuts to exit the level
        if ( not value ) 
        {
          mp := task.Run().Optimization().astype( Optimization ).MacroPlan(); 
          enoughscalinginfocollected := not this.IsEnabledAutoScaling() 
                                        or counter( mp, Optimization.AlgorithmScaling.ScaleFactorsSuggestedForLevel, s, true, s.FocusLevel() = this.FocusLevel() ) > 0; 
    
          // check if at best possible KPI (if it is known)
          level := select(  mp, StrategyMacroPlan.StrategyLevelMacroPlan, slm, true, slm.Level() = this.FocusLevel() ); 
          lastsnapshot := maxselect(  task, Run.Snapshot.astype( SnapshotMacroPlannerOptimizer ), s, s.IsAccepted() and s.FocusLevel() = this.FocusLevel(), s.TimeStamp() );
          if ( not isnull( lastsnapshot ) ) 
          { 
            rv := RealVector::Construct( lastsnapshot.RollbackKPI() ); 
            lastscore := rv.Get( this.FocusLevel() );  
            value := guard( abs( level.KPIUpperBound() - lastscore) < this.CutOffForOptimal(), false ) and enoughscalinginfocollected; 
            if ( value ) 
            {
                lastsnapshot.StopCriteriumInfo( lastsnapshot.StopCriteriumInfo() + 'level kpi (' + [String] lastscore + ')within threhold (' + [String]this.CutOffForOptimal() + ') of best possible value ( ' + [String] level.KPIUpperBound() + ')' );  
            }
            else 
            {
              
              noincrease := guard( snapshots.Element( 1 ).NrOperationPeriodTaskInOptimizerRun() = lastsnapshot.NrOperationPeriodTaskInOptimizerRun() 
                                   and snapshots.Element( 1 ).NrProductInTripOptimizerRun() = lastsnapshot.NrProductInTripOptimizerRun(), 
                                   false ); 
              // check if last was full puzzle size and optimal cplex
              value := lastsnapshot.NrCampaignSequenceCombisTotal() = lastsnapshot.NrCampaignSequenceCombisActive()
                       and lastsnapshot.NumberOfPISPIPPlanningGlobal() = lastsnapshot.NrPISPIPPlanningOptimizerRun()
                       and lastsnapshot.NrOperationPeriodTaskInOptimizerRun() >= lastsnapshot.NrOperationPeriodTaskInGlobal() 
                       and lastsnapshot.NrProductInTripOptimizerRun() >= lastsnapshot.NrProductInTripGlobal()
                       and lastsnapshot.AllLevelsOptimal()
                       and lastsnapshot.IsAccepted()
                       and this.FocusLevel() = lastsnapshot.FocusLevel()
                       and noincrease
                       and enoughscalinginfocollected
                       and not iscampaignsequencing_or_shiftopt
                       and not lastsnapshot.Comment() ~ Translations::LibOpt_Rollback(); 
              if ( value ) 
              {
                  lastsnapshot.StopCriteriumInfo( lastsnapshot.StopCriteriumInfo() + 'neighborhood at max size and cplex optimal' );  
              }
              else
              {
                value := this.StopForBenchmarking( task, lastsnapshot, runcontext, lastscore ) and enoughscalinginfocollected;   
                if ( value ) 
                {
                  lastsnapshot.StopCriteriumInfo( lastsnapshot.StopCriteriumInfo() + 'stopping for benchmark purpose' );   
                }
              }
            }
          }
        } // end look for shortcuts 
      }    
    }
    
    return value;
  *]
  InterfaceProperties { Accessibility: 'Module' }
}