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; 
 | 
  *] 
 | 
} 
 |