Free cookie consent management tool by TermsFeed Policy Generator

Changes between Version 3 and Version 4 of Documentation/Howto/ImplementANewVRPEncoding


Ignore:
Timestamp:
02/20/14 11:42:57 (10 years ago)
Author:
pfleck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Documentation/Howto/ImplementANewVRPEncoding

    v3 v4  
    167167= Sample Foundations =
    168168
    169 In order to implement the sample we need a new {{{ProblemInstance}}} and a new {{{Evaluator}}} for the '''MultiTrip VRP''' variant. For detailed information about creating new {{{VRPInstances}}} and {{{VRPEvaluators}}} see [wiki:UsersHowtosImplementANewVRPProblemInstance How to ... implement a new VRP ProblemInstance] and [wiki:UsersHowtosImplementANewVRPEvaluator How to ... implement a new VRP Evaluator].
     169In order to implement the sample we need a new {{{ProblemInstance}}} and a new {{{Evaluator}}} for the ''MultiTrip VRP'' variant. For detailed information about creating new {{{VRPInstances}}} and {{{VRPEvaluators}}} see [wiki:UsersHowtosImplementANewVRPProblemInstance How to ... implement a new VRP ProblemInstance] and [wiki:UsersHowtosImplementANewVRPEvaluator How to ... implement a new VRP Evaluator].
    170170
    171171== MultiTripVRPInstance ==
     
    251251}}}
    252252
    253 We will override more methods in the {{{MultiTripProblemInstance}}} class when we deal with '''operators''' in this tutorial later.
     253We will override more methods in the {{{MultiTripProblemInstance}}} class when we deal with ''operators'' in this tutorial later.
    254254
    255255== MultiTripEvaluator ==
     
    423423== Link Encoding/Operators to VRP variants ==
    424424
    425 Because different encodings store different information, encodings are able to handle different VRP variants. Each variant specify a '''marker interface''' to indicate its "variant type" (e.g. TimeWindowedOperator). A VRP variant compatible encoding can implement this variant type (e.g. {{{GVROperator}}} implements the {{{TimeWindowedOperator}}}). This way, each encoding can specify compatible variants and implements the operators based on the encodings abilities.
     425Because different encodings store different information, encodings are able to handle different VRP variants. Each variant specify a ''marker interface'' to indicate its "variant type" (e.g. TimeWindowedOperator). A VRP variant compatible encoding can implement this variant type (e.g. {{{GVROperator}}} implements the {{{TimeWindowedOperator}}}). This way, each encoding can specify compatible variants and implements the operators based on the encodings abilities.
    426426
    427427In order to link the compatible operators to a VRP variant, the {{{ProblemInstance}}} have to provide a list of compatible {{{Operators}}}. Because a {{{ProblemInstance}}} usually derives from a base {{{ProblemInstance}}}, it uses the operators from the base implementation and selects only the compatible ones. For instance, the {{{CVRPTWProblemInstance}}} uses the operators from the {{{CVRPProblemInstance}}} and only uses those operators which implement the {{{TimeWindowedOperator}}}.
     
    429429The following figure shows a small sample and overview:
    430430
    431 [[Image(1_MTVRP_operator_featuremodel.png, 600px)]]
    432 
    433 The {{{SingleDepotOperator}}}, {{{CapcaitatedOperator}}} and {{{TimeWindowedOperator}}} represent '''VRP variants''' or '''parts of VRP variants'''. The {{{AlbaOperator}}} implements all three of them and therefore can be used for all of them. In comparison, the {{{GVROperator}}} (not show in the diagram) does not implement {{{MultiDepotOperator}}}(also not shown) and therefore is not compatible with variants that use multiple depots.
     431[[Image(1_MTVRP_operator_featuremodel.png, 800px)]]
     432
     433The {{{SingleDepotOperator}}}, {{{CapcaitatedOperator}}} and {{{TimeWindowedOperator}}} represent ''VRP variants'' or ''parts of VRP variants''. The {{{AlbaOperator}}} implements all three of them and therefore can be used for all of them. In comparison, the {{{GVROperator}}} (not show in the diagram) does not implement {{{MultiDepotOperator}}}(also not shown) and therefore is not compatible with variants that use multiple depots.
    434434
    435435Specific and {{{VRPProblemInstances}}} then specifies which operators are compatible. For instance the {{{CVRPProblemInstance}}} filters the operators by {{{CapacitatedOperator}}}. The {{{CVRPTWProblemInstance}}}, which derives from {{{CVRPProblemInstances}}} used the prefiltered operators and filters by {{{TimeWindowedOperator}}}:
     
    476476}}}
    477477
    478 
    479478== Implementing new Creator ==
     479
     480The implementation of the new {{{MultiTripIterativeInsertionCreator}}} is very easy. We use the functionality of the {{{IterativeInsertionCreator}}} of the {{{PotvinEncoding}}} to create a {{{PotvinEncoding}}} and convert it with the method from the previous section of the tutorial.
     481
     482Note that all initial solution candidates created with no delimiters, because random delimiters would mainly yield infeasible solutions, which are hard to repair afterwards.
     483
     484{{{
     485#!cs
     486[Item("MultiTripIterativeInsertionCreator", "Creates a randomly initialized VRP solution.")]
     487[StorableClass]
     488public sealed class MultiTripIterativeInsertionCreator
     489  : PotvinCreator, IStochasticOperator, IMultiTripOperator {
     490 
     491  #region IStochasticOperator Members
     492  public ILookupParameter<IRandom> RandomParameter {
     493    get { return (LookupParameter<IRandom>)Parameters["Random"]; }
     494  }
     495  #endregion
     496 
     497  [StorableConstructor]
     498  private MultiTripIterativeInsertionCreator(bool deserializing)
     499    : base(deserializing) { }
     500 
     501  public MultiTripIterativeInsertionCreator()
     502    : base() {
     503    Parameters.Add(new LookupParameter<IRandom>("Random", "The pseudo random number generator."));
     504  }
     505 
     506  public override IDeepCloneable Clone(Cloner cloner) {
     507    return new MultiTripIterativeInsertionCreator(this, cloner);
     508  }
     509 
     510  private MultiTripIterativeInsertionCreator(MultiTripIterativeInsertionCreator original, Cloner cloner)
     511    : base(original, cloner) {
     512  }
     513 
     514  public override IOperation InstrumentedApply() {
     515    PotvinEncoding singleTripSolution = IterativeInsertionCreator.CreateSolution(
     516      ProblemInstanceParameter.ActualValue, RandomParameter.ActualValue, false);
     517 
     518    VRPToursParameter.ActualValue = MultiTripEncoding.ConvertFrom(ProblemInstanceParameter.ActualValue, singleTripSolution);
     519 
     520    return base.InstrumentedApply();
     521  }
     522}
     523}}}
     524
     525A more intelligent {{{Creator}}}, which implements a heuristic to place reasonable delimiters for initial solutions would be nice and would help the algorithm a lot, but is not part of this tutorial.
     526
    480527== Implementing new Manipulator ==
     528
     529The {{{MultiTripManipulator}}} randomly flips a delimiter in a random tour. This is a very simple mutation and many more implementations are possible, for example to shift a delimiter within a tour. Also a more intelligent manipulators are possible, for example a manipulator who looks for good delimiter positions in long sub-tours, or one who tries to remove delimiters in short sub-tours.
     530
     531{{{
     532#!cs
     533[Item("MultiTripManipulator", "The manimulation operator which flips a random tour delimiter in a multi trip VRP.")]
     534[StorableClass]
     535public class MultiTripManipulator
     536  : PotvinManipulator, IMultiTripOperator {
     537
     538  [StorableConstructor]
     539  private MultiTripManipulator(bool deserializing) : base(deserializing) { }
     540 
     541  public MultiTripManipulator() : base() { }
     542 
     543  public override IDeepCloneable Clone(Cloner cloner) {
     544    return new MultiTripManipulator(this, cloner);
     545  }
     546 
     547  private MultiTripManipulator(MultiTripManipulator original, Cloner cloner)
     548    : base(original, cloner) {
     549  }
     550 
     551  protected override void Manipulate(IRandom random, PotvinEncoding individual) {
     552    var multiTripIndividual = individual as MultiTripEncoding;
     553    if (multiTripIndividual != null && multiTripIndividual.Tours.Count > 0) {
     554      int tour = random.Next(individual.Tours.Count);
     555 
     556      if (multiTripIndividual.Tours[tour].Stops.Count > 0) {
     557        int position = random.Next(multiTripIndividual.Tours[tour].Stops.Count);
     558 
     559        multiTripIndividual.FlipDelimiter(tour, position);
     560      }
     561    }
     562  }
     563}
     564}}}
     565
    481566== Implement new Crossover ==
    482567
     568To implement a new {{{Crossover}}} which only combines two sets of ''delimiters'' would not yield  good results. Therefore we implement a crossover that first performs a {{{PotvinRouteBasedCrossover}}} and afterwards copy the delimiters from the copied tour into the new replaced tour of the new solution.
     569
     570Unfortunately, the implementation of the crossover does not return which route was replaced, so we have to look it up first with a small helper method. Then we copy the delimiters from the old tour onto the new, replaced tour.
     571
     572{{{
     573#!cs
     574[Item("MultiTripRBX", "The RBX crossover for multi-trip VRP representations.")]
     575[StorableClass]
     576public class MultiTripRBX
     577  : PotvinCrossover, IMultiTripOperator {
     578 
     579  [StorableConstructor]
     580  private MultiTripRBX(bool deserializing) : base(deserializing) { }
     581 
     582  public MultiTripRBX()
     583    : base() { }
     584 
     585  public override IDeepCloneable Clone(Cloner cloner) {
     586    return new MultiTripRBX(this, cloner);
     587  }
     588 
     589  private MultiTripRBX(MultiTripRBX original, Cloner cloner)
     590    : base(original, cloner) {
     591  }
     592 
     593  private int FindReplacedTour(PotvinEncoding original, PotvinEncoding manipulated) {
     594    int replacedTour = -1;
     595    for (int tourIdx = 0; tourIdx < original.Tours.Count; tourIdx++) {
     596      if (original.Tours[tourIdx].Stops.Count != manipulated.Tours[tourIdx].Stops.Count) {
     597        replacedTour = tourIdx;
     598        break;
     599      }
     600 
     601      for (int stopIdx = 0; stopIdx < original.Tours[tourIdx].Stops.Count; stopIdx++) {
     602        if (original.Tours[tourIdx].Stops[stopIdx] != manipulated.Tours[tourIdx].Stops[stopIdx]) {
     603          replacedTour = tourIdx;
     604          break;
     605        }
     606      }
     607 
     608      if (replacedTour >= 0)
     609        break;
     610    }
     611 
     612    return replacedTour;
     613  }
     614 
     615  protected override PotvinEncoding Crossover(IRandom random, PotvinEncoding parent1, PotvinEncoding parent2) {
     616    MultiTripEncoding p1 = parent1 as MultiTripEncoding;
     617    MultiTripEncoding p2 = parent2 as MultiTripEncoding;
     618 
     619    PotvinEncoding child = PotvinRouteBasedCrossover.Apply(random, parent1, parent2, ProblemInstance, AllowInfeasibleSolutions.Value.Value);
     620    MultiTripEncoding ch = child as MultiTripEncoding;
     621 
     622    if (ch != null && p1 != null) {
     623      int tourIdx = FindReplacedTour(parent2, child);
     624      if (tourIdx != -1) {
     625        ch.TripDelimiters[tourIdx] = p1.TripDelimiters[tourIdx];
     626      }
     627    }
     628 
     629    return child;
     630  }
     631}
     632}}}
     633
    483634= Result =
     635
    484636== Configure Algorithm ==
     637
     638Before we can run the {{{MultiTrip}}} variant inside an algorithm we need to configure the algorithm beforehand. This tutorial provides step by step instructions on how to setup the algorithm and load the problem instance. To avoid this procedure you could write a new {{{VRPDataInterpreter}}} (see [wiki:UsersHowtosImplementANewVRPProblemInstance How to ... implement a new VRP ProblemInstance]). In the attachments of this tutorial you also find a configured ready-to-run algorithm.
     639
     6401. Create a new {{{Genetic Algorithm}}} (you can chose a variant like Offspring Selection GA too, then the configuration changes slightly)
     641  a. Set a new {{{Vehicle Routing Problem}}}
     642  b. Set the {{{ProblemInstance}}} to a new {{{MultiTripVRPInstance}}}
     6432. Configure the {{{Genetic Algorithm}}}
     644  a. In the {{{Problem}}} set the {{{SolutionCreator}}} to {{{MultiTripIterativeInsertionCreator}}} (if not already set automatically)
     645  b. In the {{{Algorithm Parameters}}} set the {{{Crossover}}} to {{{MultiTripRBX }}}(if you like, you can use the other {{{PotvinCrossovers}}} as well in a {{{MultiVRPSolutionCrossover}}})
     646  c. Set the {{{Mutator}}} to a {{{MultiVRPSolutionManipulator}}}
     647    i. Enable the {{{MultiTripManipulator}}}, {{{PotvinOneLevelExchange}}} and {{{PotvinTwoLevelExchange}}} manipulator
     648    i. If you want, increase the ''propability'' of the {{{MultiTripManipulator}}} (e.g. to 2)
     649  d. If you want, activate the {{{CapacityRelaxion}}} in the Analyzers
     650  e. Set the MutationProbability to 25%
     651  f. Set the PopulationSize to 20 (or higher for better results)
     652  g. Set the Generations to 2000 (or higher for better results)
     6533. Open a separate {{{Vehicle Routing Problem}}}
     654  a. Open a {{{CVRP problem}}} (your own or from a library) (e.g. Augerat P-n50-k7)
     655  b. Open the original {{GA ProblemInstance}}} and the {{{ProblemInstance}} from the new separate problem side by side
     656  c. Copy the {{{Coordinates}}} and {{{Demands}}} to the empty {{{MultiTripVRPInstance}}} by drag and drop them
     657  d. Set the remaining parameters (capacity, vehicles, ...)
     658  e. Set the {{{MaxDistance}}} (e.g. to 500)
     6594. Run the Algorithm
     660
    485661== Interpretation ==
     662
     663To visualize the sub-tours of a vehicle use the visualization-patch from the attachments. Compared to the original CVRP solution, now the algorithm finds solutions with less vehicles.
     664
     665If you set the {{{MaxDistance}}} high enough, the algorithm will find a solution with only one vehicle. However the algorithm needs very long and needs a bit of luck to find the optimal vehicle usage because our mutation and crossover operators actualy does not perform well. The {{{PotvinCrossovers}}} always treat tours at whole and ignore the tour delimiters. A specialized crossover which merges small ''sub-tours'' into other tours and preserves the ''sub-tours'' would be a good solution. Still, the solutions yielded by the algorithm use less vehicles than the original CVRP variant.
     666
     667[[Image(2_MTVRP_result.png, 700px)]]