| | 424 | |
| | 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. |
| | 426 | |
| | 427 | In 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}}}. |
| | 428 | |
| | 429 | The following figure shows a small sample and overview: |
| | 430 | |
| | 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. |
| | 434 | |
| | 435 | Specific 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}}}: |
| | 436 | |
| | 437 | {{{ |
| | 438 | #!cs |
| | 439 | protected override IEnumerable<IOperator> GetOperators() { |
| | 440 | return base.GetOperators().Where(o => o is ITimeWindowedOperator).Cast<IOperator>(); |
| | 441 | } |
| | 442 | }}} |
| | 443 | |
| | 445 | |
| | 446 | The first step in implementing new operators is to create the marker interface for the VRP variant. |
| | 447 | |
| | 448 | {{{ |
| | 449 | #!cs |
| | 450 | public interface IMultiTripOperator : IVRPOperator { } |
| | 451 | }}} |
| | 452 | |
| | 453 | After that, we need to link all our {{{MultiTripOperators}}} implementations to the {{{MultiTripProblemInstance}}}. This is done by overriding the {{{GetOperators}}} method. If you implement a complete new {{{Encoding}}} the method would look like this: |
| | 454 | |
| | 455 | {{{ |
| | 456 | #!cs |
| | 457 | protected override IEnumerable<IOperator> GetOperators() { |
| | 458 | return base.GetOperators().Where(o => o is IMultiTripOperator).Cast<IOperator>(); |
| | 459 | } |
| | 460 | }}} |
| | 461 | |
| | 462 | In the case of this tutorial we are extending the {{{PotvinEncoding}}}, which defines multiple {{{Operators}}} already. Therefore we want to reuse the existing {{{Operators}}} for our {{{MultiTripEncoding}}} (e.g. the {{{Manipulators}}} and {{{Crossovers}}}). Because we will derive our {{{MultiTripOperators}}} from the {{{PotvinOperators}}} we could simply use all the {{{Operators}}} specified in the base {{{ProblemInstance}}}. |
| | 463 | |
| | 464 | However, we cannot use all {{{PotvinOperators}}}, we need to rule out the {{{PotvinCreators}}}. If someone accidently configures a {{{PotvinCreator}}}, plain {{{PotvinEncoding}}} instances are created and our own {{{MultiTripOperators}}}, which rely on the additional data, will not work. Therefore if an {{{Operator}}} is a {{{VRPCreator}}} it implies that it is a {{{MultiTripOperator}}}. |
| | 465 | |
| | 466 | For a similar reason we cannot reuse {{{Operators}}} from other {{{Encodings}}}, which is usually possible due to conversion between them. If we convert our {{{MultiTripEncoding}}} to a different {{{Encoding}}} we lose the information about the delimiters. Therefore we can only reuse the {{{PotvinOperators}}} because no conversion is required this way. |
| | 467 | |
| | 468 | {{{ |
| | 469 | #!cs |
| | 470 | protected override IEnumerable<IOperator> GetOperators() { |
| | 471 | return base.GetOperators() |
| | 472 | .Where(o => o is IPotvinOperator) |
| | 473 | // is IVRPCreator implicates is IMultiTripOperator |
| | 474 | .Where(o => !(o is IVRPCreator) || (o is IMultiTripOperator)).Cast<IOperator>(); |
| | 475 | } |
| | 476 | }}} |
| | 477 | |
| | 478 | |