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' }
|
}
|