Quintiq file version 2.0
|
#parent: #root
|
StaticMethod IndependentPathStrategy (POAAlgorithm poa) as POAAlgorithm
|
{
|
TextBody:
|
[*
|
LibOpt_SuboptimizerPOA::StrategyStart( poa );
|
// -------------------------------------------------------------------------- //
|
// Strategy for independent path problems, for example vehicle routing //
|
// problems //
|
// -------------------------------------------------------------------------- //
|
|
strategy := poa.Strategy();
|
|
// ----- Parameters for the strategy -----
|
// String used to identify the expression used for time in this POA. This
|
// strategy needs an expression for time.
|
timeexpressionname := LibOpt_SuboptimizerPOA::GetStrategySetting_TimeExpressionName( poa, 'time' );
|
// The total duration of iteratively improving the solution in this strategy.
|
// This does not include the time spend on creating and improving an initial
|
// solution. More time spend on iterive improvement will give a higher chance
|
// on better results.
|
iterativeduration := LibOpt_SuboptimizerPOA::GetStrategySetting_IterativeDuration( poa, Duration::Seconds( 60 ) );
|
// The number of threads used throughout the strategy execution. The threads
|
// are all busy from begin till end.
|
nrthreads := LibOpt_SuboptimizerPOA::GetStrategySetting_NrThreads( poa, 3 );
|
|
// ----- Advanced Parameters for the strategy -----
|
// The number of moves (plan possibilities of planelements) that make it in the
|
// final population. Moves that are estimated to be better have a higher chance
|
// to be in the population. All moves in the population are fully propagated,
|
// after which the best move is carried out. A higher number will mean more
|
// precise results because full propagation gives the precise score of a move.
|
// This comes at the cost of more time needed in propagation.
|
maxpopulation := LibOpt_SuboptimizerPOA::GetStrategySetting_MaxPopulation( poa, 3 );
|
// The percentage of available planelements that is destructed by the random
|
// destruction action
|
randomdestructionpercentage := LibOpt_SuboptimizerPOA::GetStrategySetting_RandomDestructionPercentage( poa, 5.0 );
|
// The percentage of paths that is destructed by the path destruction action
|
pathdestructionpercentage := LibOpt_SuboptimizerPOA::GetStrategySetting_PathDestructionPercentage( poa, 0.0 );
|
// The chance during one iteration that the path destuction action is executed.
|
// Where as a minimum 1 path is destructed.
|
pathdestructionchance := LibOpt_SuboptimizerPOA::GetStrategySetting_PathDestructionChance( poa, 0.0 );
|
// The percentage of available planelements that is destructed by the area stop
|
// destruction action
|
areastopdestructionpercentage := LibOpt_SuboptimizerPOA::GetStrategySetting_AreaStopDestructionPercentage( poa, 17.0 );
|
// The chance during one iteration that the area stop destruction action is
|
// executed
|
areastopdestructionchance := LibOpt_SuboptimizerPOA::GetStrategySetting_AreaStopDestructionChance( poa, 0.5 );
|
// The number of unplanned elements that is considered by the random
|
// construction action
|
randomconstructiongroupsize := LibOpt_SuboptimizerPOA::GetStrategySetting_RandomConstructionGroupSize( poa, 7 );
|
// The duration between the possibility of a reset to the globally best solution
|
// found.
|
durationbetweenrestarttoglobal := LibOpt_SuboptimizerPOA::GetStrategySetting_DurationBetweenRestartToGlobal( poa, Duration::Seconds( 3.5 ) );
|
// The chance that a solution is restarted to the globally best solution
|
restarttoglobalchance := LibOpt_SuboptimizerPOA::GetStrategySetting_RestartToGlobalChance( poa, 0.6 );
|
|
// The duration between logging information during the iterative strategy
|
durationbetweeniterativereports := LibOpt_SuboptimizerPOA::GetStrategySetting_DurationBetweenIterativeReports( poa, Duration::Seconds( 5 ) );
|
// Log file name prefix. '' means no logging
|
logfilename := LibOpt_SuboptimizerPOA::GetStrategySetting_LogFileName( poa, '' );
|
// Toggle info statements
|
printinfo := LibOpt_SuboptimizerPOA::GetStrategySetting_PrintInfo( poa, true );
|
|
// -------------------------------------------------------------------------- //
|
// Print parameter values and initial score //
|
// -------------------------------------------------------------------------- //
|
|
if( printinfo )
|
{
|
info( 'parameter timeexpressionname =' , timeexpressionname );
|
info( 'parameter iterativeduration =' , iterativeduration );
|
info( 'parameter nrthreads =' , nrthreads );
|
info( 'parameter maxpopulation =' , maxpopulation );
|
info( 'parameter randomdestructionpercentage =' , randomdestructionpercentage );
|
info( 'parameter pathdestructionpercentage =' , pathdestructionpercentage );
|
info( 'parameter pathdestructionchance =' , pathdestructionchance );
|
info( 'parameter areastopdestructionpercentage =' , areastopdestructionpercentage );
|
info( 'parameter areastopdestructionchance =' , areastopdestructionchance );
|
info( 'parameter randomconstructiongroupsize =' , randomconstructiongroupsize );
|
info( 'parameter durationbetweenrestarttoglobal =' , durationbetweenrestarttoglobal );
|
info( 'parameter restarttoglobalchance =' , restarttoglobalchance );
|
info( 'parameter logfilename =' , logfilename );
|
info( 'initial score', strategy.BestSolution().TotalScore() );
|
}
|
|
// -------------------------------------------------------------------------- //
|
// Initialize general settings //
|
// -------------------------------------------------------------------------- //
|
|
// For all constraints change MaxDownStreamDepth to MaxNumber where applicable.
|
// For independent path problems MaxNumber gives generally the best results.
|
{
|
traverse( poa, Constraints.astype( POAEndConstraint ), c, c.MaxDownStreamDepth() <> Number::MaxNumber() )
|
{
|
c.MaxDownStreamDepth( Number::MaxNumber() );
|
debuginfo( 'Warning: POAEndConstraint', c.Role(), 'MaxDownStreamDepth was changed to MaxNumber, because that will improve the move estimates' );
|
}
|
|
traverse( poa, Constraints.astype( POACapacityConstraint ), c, c.MaxDownStreamDepth() <> Number::MaxNumber() )
|
{
|
c.MaxDownStreamDepth( Number::MaxNumber() );
|
debuginfo( 'Warning: POACapacityConstraint', c.Role(), 'MaxDownStreamDepth was changed to MaxNumber, because that will improve the move estimates' );
|
}
|
|
traverse( poa, Constraints.astype( POAInTimeConstraint ), c, c.MaxDownStreamDepth() <> Number::MaxNumber() )
|
{
|
c.MaxDownStreamDepth( Number::MaxNumber() );
|
debuginfo( 'Warning: POAInTimeConstraint', c.Role(), 'MaxDownStreamDepth was changed to MaxNumber, because that will improve the move estimates' );
|
}
|
}
|
|
timeexpression := select( poa, Expressions, e, true, e.Role() = timeexpressionname );
|
verify( not isnull( timeexpression ),
|
"The strategy needs an expression that is called 'time' and will be used as the expression representing time
|
" );
|
|
planstrategy := strategy.PlanStrategy();
|
// Apply parameter
|
planstrategy.MaxPopulation( maxpopulation );
|
// the population of moves per path is infinite
|
planstrategy.MaxPathPopulation( maxpopulation );
|
|
// -------------------------------------------------------------------------- //
|
// Initial Strategy //
|
// -------------------------------------------------------------------------- //
|
//
|
// The initial strategy will be used to plan all remaining planelements, and do
|
// some initial improvement. After that improvement will only be made by
|
// iterativestrategy.
|
|
initialstrategy := strategy.NewMetaStrategy( 'initialstrategy' );
|
if( logfilename <> '' )
|
{
|
initialstrategy.LogFileName( logfilename + '_InitialStrategy', true );
|
}
|
|
// The only step used in the initial strategy.
|
initialstep := initialstrategy.NewStep( 'initialstep' );
|
// Room for one start solution.
|
initialstep.StartSolutionPool().Capacity( 1 );
|
// Use initial solution as the single starting solution.
|
initialstep.StartSolutionPool().Add( poa.Solution() );
|
// The step is repeated a number of times equal to the number of threads, each
|
// time starting from the same initial solution. Each repetition is carried out
|
// by its own thread.
|
initialstep.Repetitions( nrthreads );
|
// The step happens once in each thread. It will not be carried out on the
|
// results of a previous iteration.
|
initialstep.MaximumIterationsActions( 1 );
|
// 1 000 000 seconds pratically infinity
|
initialstep.MaximumSecondsActions( 1000000.0 );
|
// The result of each thread is stored.
|
initialstep.ResultSolutionPool().Capacity( nrthreads );
|
|
actions := initialstep.Actions();
|
|
// Use insertion heuristic, which choses a path, and plans one element a time on
|
// that path based on the time expression. When no more elements fit on the path
|
// a new path is chosen. This continues until there are not paths left,
|
insertionheuristic := actions.NewInsertionHeuristic( timeexpression );
|
// Try to plan all unplanned planelements.
|
insertionheuristic.Nodes( Number::MaxNumber() );
|
|
// Use one node improvement action, which selects any planned or unplanned
|
// element and tries to find a better position for that element. Depending
|
// on the improvement made, a new element is selected and the process
|
// repeats itself.
|
onenodeimpr := actions.NewRandomOneNodeImprovement();
|
// By setting to 0.0 any improvement will make the process repeat itself.
|
onenodeimpr.MinimalImprovementPercentage().Set( 0.0 );
|
|
// Start execution of the strategy and display the duration
|
executestarttime := DateTime::ActualTime();
|
debuginfo( 'execute initial actions' );
|
initialstrategy.Execute( nrthreads, Real::MaxReal() );
|
debuginfo( 'initial actions execution duration', DateTime::ActualTime() - executestarttime );
|
|
// -------------------------------------------------------------------------- //
|
// Iterative Strategy //
|
// -------------------------------------------------------------------------- //
|
//
|
// iterativestrategy will repeatedly run on the start solution generated by
|
// initialstrategy.
|
|
iterativestrategy := strategy.NewMetaStrategy( 'iterativestrategy' );
|
if( logfilename <> '' )
|
{
|
iterativestrategy.LogFileName( logfilename + '_IterativeStrategy', true );
|
}
|
|
// The only step used in the iterative strategy.
|
iterativestep := iterativestrategy.NewStep( 'iterativestep' );
|
// Use the result of each thread for the initial stategy as starting point for
|
// the iterative strategy. One thread will start for each of these starting
|
// points.
|
iterativestep.StartSolutionPool().Use( initialstep.ResultSolutionPool() );
|
// There is no limit on the number of times this step starts again within a
|
// single thread.
|
iterativestep.MaximumIterationsActions( Number::MaxNumber() );
|
// Execution of the step must not take longer then the reporting duration.
|
iterativestep.MaximumSecondsActions( durationbetweenrestarttoglobal.MinutesAsReal() * 60.0 );
|
// The result of each thread is stored.
|
iterativestep.ResultSolutionPool().Capacity( nrthreads );
|
|
actions := iterativestep.Actions();
|
|
// The number of elements available for planning.
|
nrplanelements := poa.PlanElements( relsize );
|
|
randomstopdestr := actions.NewRandomStopDestruction();
|
randomstopdestr.SegmentsMinimum( round( randomdestructionpercentage / 100.0 * nrplanelements ) );
|
randomstopdestr.SegmentsMaximum( round( randomdestructionpercentage / 100.0 * nrplanelements ) );
|
randomstopdestr.SegmentLengthMaximum( 1 );
|
randomstopdestr.SegmentLengthMinimum( 1 );
|
|
// The number of paths available for planning.
|
nrpaths := sum( poa, PathTypes, t, true, t.MaxCount() );
|
|
// Use path destruction, which randomly chooses a number of paths to be
|
// destructed.
|
pathdestr1 := actions.NewRandomPathDestruction();
|
// The number of chosen paths is pathdestructionpercentage% of the available
|
// paths. Rounded, so possibly zero.
|
pathdestr1.Paths( maxvalue( 1, round( pathdestructionpercentage / 100.0 * nrpaths ) ) );
|
pathdestr1.ExecutionChance().Set( pathdestructionchance );
|
|
// Use area stop destruction, which choses one stop to be destructed and
|
// destructs the area surrounding that node. The length of the time expression
|
// transition between stops determines if two stops belong to the same area.
|
areastopdestr := actions.NewRandomAreaStopDestruction( timeexpression );
|
// By specifing the number of stops
|
areastopdestr.Stops( round( areastopdestructionpercentage / 100.0 * nrplanelements ) );
|
areastopdestr.ExecutionChance().Set( areastopdestructionchance );
|
|
// Use random construction, which
|
// (1) chooses a number of unplanned elements equal to
|
// 'randomconstructiongroupsize'.
|
// (2) determines the best move for each element by making estimates for all
|
// moves and propagating the moves that make it in the population.
|
// (3) carry out the best move of the element that was best
|
randomcons := actions.NewRandomConstruction();
|
// Set the number of unplanned elements to consider.
|
randomcons.GroupSize( randomconstructiongroupsize );
|
|
onenodeimpr := actions.NewRandomOneNodeImprovement();
|
// By setting to 0.0 any improvement will make the process repeat itself.
|
onenodeimpr.MinimalImprovementPercentage().Set( 0.0 );
|
|
// Keep executing the iterative meta strategy until the time limit is reached
|
iterativeendtime := DateTime::ActualTime() + iterativeduration;
|
lastreporttime := DateTime::ActualTime() - durationbetweeniterativereports;
|
while( DateTime::ActualTime() < iterativeendtime )
|
{
|
executeduration := minvalue( durationbetweenrestarttoglobal, iterativeendtime - DateTime::ActualTime() );
|
|
// Call meta strategy execution
|
iterativestrategy.Execute( nrthreads, executeduration.MinutesAsReal() * 60.0 );
|
|
// Fill start solution
|
traverse( iterativestep.ResultSolutionPool().UseSolutions(), Solutions, s )
|
{
|
if( Real::Random() < restarttoglobalchance )
|
{
|
iterativestep.StartSolutionPool().Add( strategy.BestSolution() );
|
}
|
else
|
{
|
iterativestep.StartSolutionPool().Add( s );
|
}
|
}
|
|
if( printinfo and DateTime::ActualTime() - lastreporttime >= durationbetweeniterativereports )
|
{
|
lastreporttime := DateTime::ActualTime();
|
|
info( 'iterative time remaining', iterativeendtime - DateTime::ActualTime() );
|
|
i := 0;
|
traverse( iterativestep.StartSolutionPool(), Solutions, s )
|
{
|
info( i, ': iterative result solution score', s.TotalScore() );
|
i++;
|
}
|
|
info( 'iterations', actions.Iterations().Value() );
|
info( 'improvement iterations', actions.IterationsImproved().Value() );
|
|
// After logging reset statistics for the next iteration
|
actions.ResetStatistics();
|
}
|
}
|
LibOpt_SuboptimizerPOA::StrategyFinish( poa );
|
return poa;
|
*]
|
}
|