Treffer: PyVRP: a high-performance VRP solver package

Title:
PyVRP: a high-performance VRP solver package
Publication Year:
2023
Collection:
Computer Science
Document Type:
Report Working Paper
DOI:
10.1287/ijoc.2023.0055
Accession Number:
edsarx.2403.13795
Database:
arXiv

Weitere Informationen

We introduce PyVRP, a Python package that implements hybrid genetic search in a state-of-the-art vehicle routing problem (VRP) solver. The package is designed for the VRP with time windows (VRPTW), but can be easily extended to support other VRP variants. PyVRP combines the flexibility of Python with the performance of C++, by implementing (only) performance critical parts of the algorithm in C++, while being fully customisable at the Python level. PyVRP is a polished implementation of the algorithm that ranked 1st in the 2021 DIMACS VRPTW challenge and, after improvements, ranked 1st on the static variant of the EURO meets NeurIPS 2022 vehicle routing competition. The code follows good software engineering practices, and is well-documented and unit tested. PyVRP is freely available under the liberal MIT license. Through numerical experiments we show that PyVRP achieves state-of-the-art results on the VRPTW and capacitated VRP. We hope that PyVRP enables researchers and practitioners to easily and quickly build on a state-of-the-art VRP solver.
Comment: Pre-print of accepted paper in INFORMS Journal on Computing. 24 pages, 1 figure, 2 listings

AN0179391267;7ee01jul.24;2024Sep04.05:01;v2.2.500

PyVRP: A High-Performance VRP Solver Package 

We introduce PyVRP, a Python package that implements hybrid genetic search in a state-of-the-art vehicle routing problem (VRP) solver. The package is designed for the VRP with time windows (VRPTW) but can be easily extended to support other VRP variants. PyVRP combines the flexibility of Python with the performance of C++ by implementing (only) performance-critical parts of the algorithm in C++ while being fully customizable at the Python level. PyVRP is a polished implementation of the algorithm that ranked first in the 2021 DIMACS VRPTW challenge and, after improvements, ranked first on the static variant of the EURO meets NeurIPS 2022 vehicle routing competition. The code follows good software engineering practices and is well documented and unit tested. PyVRP is freely available under the liberal MIT license. Through numerical experiments, we show that PyVRP achieves state-of-the-art results on the VRPTW and capacitated VRP. We hope that PyVRP enables researchers and practitioners to easily and quickly build on a state-of-the-art VRP solver. History: Accepted by Ted Ralphs, Area Editor for Software Tools. This paper has been accepted for the INFORMS Journal on Computing Special Issue on Software Tools for Vehicle Routing. Funding: Funding was provided by TKI Dinalog, Topsector Logistics, and the Dutch Ministry of Economic Affairs and Climate Policy. Supplemental Material: The software that supports the findings of this study is available within the paper and its Supplemental Information (https://pubsonline.informs.org/doi/suppl/10.1287/ijoc.2023.0055) as well as from the IJOC GitHub software repository (https://github.com/INFORMSJoC/2023.0055). The complete IJOC Software and Data Repository is available at https://informsjoc.github.io/. There is a video associated with this paper. Click here to view the Video Overview. To save the file, right click and choose "Save Link As" from the menu.

Keywords: vehicle routing problem; time windows; hybrid genetic search; open source; C++; Python

1. Introduction

This paper describes PyVRP, a Python package that provides a high-performance implementation of the hybrid genetic search (HGS) algorithm for vehicle routing problems (VRPs) ([18]). PyVRP currently supports two well-known VRP variants: the capacitated VRP (CVRP) and the VRP with time windows (VRPTW) ([14]). The implementation builds on the open-source HGS-CVRP implementation of [17] but has added support for time windows and has been completely redesigned to be easy to use as a highly customizable Python package while maintaining speed and state-of-the-art performance.

Whereas HGS-CVRP is implemented completely in C++, PyVRP adopts a different philosophy: only performance-critical parts of the algorithm are implemented in C++, and all other parts are implemented in Python. Besides easily using the algorithm, this gives the user additional flexibility to customize the algorithm using Python. The provided HGS implementation is one example of a large family of VRP algorithms that can be built using the building blocks that PyVRP provides. As the performance-critical parts remain in C++, the added flexibility and ease of use that Python offers barely impact the algorithm performance.

PyVRP comes with precompiled binaries for Windows, MacOS, and Linux and can be easily installed from the Python package index using "pip install pyvrp." This allows users to directly solve VRP instances or implement variants of the HGS algorithm using Python, inspired by the examples in PyVRP's documentation. Users can customize various aspects of the algorithm using Python, including population management, crossover strategies, granular neighborhoods, and operator selection in the local search. Additionally, for advanced use cases such as supporting additional VRP variants, users can build and install PyVRP directly from the source code. We actively welcome community contributions to develop support for additional VRP variants within PyVRP and provide some guidelines for this in our online documentation.

The goal of PyVRP, which is made available under the liberal MIT license, is to provide an easy-to-use, extensible, and well-documented VRP solver that generates state-of-the-art results on a variety of VRP variants. This can be used by practitioners to solve practical problems and by researchers as a starting point or strong baseline when aiming to improve the state of the art. The name "PyVRP" has deliberately been chosen to not mention a specific algorithm or VRP variant, providing flexibility with respect to the underlying heuristic algorithms and supported VRP variants.

Through the Python ecosystem, we enable a wide audience to easily use the software. We especially hope that PyVRP will help machine learning (ML) researchers interested in vehicle routing to easily build on the state of the art and move beyond LKH-3 ([4]) as the most commonly used baseline ([1]). Using ML for vehicle routing problems is a promising and active research area, but so far, it has not been able to advance the state of the art; this may change when ML researchers can build on a flexible and high-quality implementation of a state-of-the-art VRP solver.

PyVRP is a complete Python library for solving multiple VRP variants, accompanied by unit tests, online documentation, and examples on its use cases. The library has been tested in practice: earlier versions of the software ranked first in the VRPTW track of the 12th DIMACS implementation challenge ([6]) and, after improvements, ranked first on the static VRPTW variant of the EURO meets NeurIPS 2022 vehicle routing competition ([16]). Compared with the versions used to win these challenges, the PyVRP implementation has been simplified further and significantly rewritten to improve its overall design and testability. In particular, complex components with limited contribution to the overall performance have been removed to strike a balance between simplicity and performance. The result is simpler and more robust than the individual challenge solvers, which were quite complex and optimized for the specific challenge problem sets. In Section 6, we show that PyVRP still yields excellent performance, using numerical experiments on public benchmarks following the conventions used in the DIMACS implementation challenge.

The rest of this paper is structured as follows. In Section 2, we briefly introduce the CVRP and VRPTW and the benchmarking conventions PyVRP supports. In Section 3, we discuss several other open-source VRP solvers and highlight the novelty of PyVRP. Then, in Sections 4 and 5, we discuss the technical implementation and PyVRP package, respectively. In Section 5, we present two examples to demonstrate how the package can be used. Section 6 presents PyVRP's performance on established benchmark instances. Finally, Section 7 concludes the paper.

2. Problem Description

PyVRP currently supports two VRP variants: CVRP and VRPTW. The CVRP aims to construct multiple routes, each starting and ending at the same depot, to serve a set of customers while minimizing total distance. The total demand of customers in a single vehicle is limited by the vehicle capacity. The VRPTW generalizes the CVRP by adding the constraint that each customer must be visited within a certain time window. For both CVRP and VRPTW, PyVRP supports minimizing distances, not the number of vehicles used. A simple procedure to support fleet minimization can be developed on top of PyVRP by first finding a feasible solution with some number of vehicles and then removing one vehicle at a time until no feasible solution is found. PyVRP has been designed to handle instances of these problems with up to several thousand customers.

2.1. CVRP

Formally, the capacitated VRP consists of customers <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>i</mi><mo>=</mo><mn>1</mn><mo>,</mo><mo>...</mo><mo>,</mo><mi>n</mi></mrow></math> with demands <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mrow><mi>q</mi></mrow><mi>i</mi></msub><mo>&#8805;</mo><mn>0</mn></mrow></math> , which must be served from a common depot denoted as zero. The goal is to visit all customers using a fixed fleet of vehicles, each of which starts at, and returns to, the depot while minimizing the total distance traveled, where the distance from customer (or depot) i to j is denoted as <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mrow><mi>d</mi></mrow><mrow><mi>i</mi><mi>j</mi></mrow></msub><mo>&#8805;</mo><mn>0</mn></mrow></math> . The total demand in each vehicle should not exceed the vehicle capacity Q > 0.

2.2. VRPTW

For the VRPTW, each customer additionally has a service time <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mrow><mi>s</mi></mrow><mi>i</mi></msub><mo>&#8805;</mo><mn>0</mn></mrow></math> , an earliest arrival time <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mrow><mi>e</mi></mrow><mi>i</mi></msub><mo>&#8805;</mo><mn>0</mn></mrow></math> , and latest arrival time <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mrow><mi>l</mi></mrow><mi>i</mi></msub><mo>&#8805;</mo><mn>0</mn><mo /><mo stretchy="false">(</mo><msub><mrow><mi>e</mi></mrow><mi>i</mi></msub><mo>&#8804;</mo><msub><mrow><mi>l</mi></mrow><mi>i</mi></msub><mo stretchy="false">)</mo></mrow></math> , in between which service should start. A vehicle can wait at customer i when arriving too early, but cannot arrive after l<subs>i</subs>. The time to travel from customer (or depot) i to j is given by <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mrow><mi>t</mi></mrow><mrow><mi>i</mi><mi>j</mi></mrow></msub><mo>&#8805;</mo><mn>0</mn></mrow></math> . Whereas in academic benchmarks, the duration t<subs>ij</subs> is typically set equal to the distance d<subs>ij</subs>, PyVRP supports separate distance and duration matrices, as is commonly encountered in practice.

2.3. Conventions

There are different conventions on the definitions of the constraints and objectives for CVRP and VRPTW, especially relating to rounding of (Euclidean) distances and other data in existing benchmark instances (see, e.g., [15]). PyVRP supports integer distances and durations, which should be provided explicitly by the user. Additionally, PyVRP can be compiled to use double precision data as well, but that is not enabled by default for performance reasons: we found, during initial experimentation, that working with double precision data is somewhat slower than using integers. For working with benchmark instances, we rely on the VRPLIB package ([9]) to compute distances and durations, and we provide helper functions to scale and then round or truncate them before converting to integers. This way, we support various conventions, including the one-decimal precision used in the DIMACS VRPTW challenge and the CVRPLIB benchmark repository.[1]

3. Related Projects

As many algorithms developed in the literature have not been open sourced, the primary goal of PyVRP is to open-source a state-of-the-art VRP solver that is easy to use and customize. We are aware of the following related projects:

HGS-CVRP ([17]) is a simple, specialized solver for the CVRP implemented in C++ with state-of-the-art performance. Although a Python interface, PyHygese ([7]), is available on the Python package index, it does not come with precompiled binaries and thus requires that users have a compiler toolchain already installed. Beyond setting the parameters, all types of customization require changes of the C++ source code. HGS-CVRP is open to contributions from the community and has a permissive MIT license.

LKH-3 ([4]) is a heuristic that supports a wide variety of VRP variants. It solves these by transforming them into a symmetric traveling salesman problem and applying the Lin-Kernighan-Helsgaun local search heuristic. Although it provides good solutions for many problem variants, the solver is hard to customize, as it requires modifying its C source code. Furthermore, it is only available under an academic and noncommercial license, and it is unclear whether community contributions are welcomed.

VROOM ([3]), the Vehicle Routing Open-source Optimization Machine, is an open-source solver that aims to provide good solutions to real-life VRPs. In particular, it integrates well with open-source routing software to solve real-life VRPs within limited computation time. It implements many constructive heuristics and a local search algorithm in C++ and can handle different types of VRPs. However, it is unable to compete with state-of-the-art algorithms and lacks documentation to customize its underlying solver.

OR-Tools ([11]) is a general modeling and optimization toolkit for solving operations research problems, developed and maintained by Google. It is written in C++ but can be used from Python, Java, or C#. OR-Tools is extensively documented and can be installed directly from the Python package index. Internally, it uses a constraint programming approach specialized to solve a large variety of routing problems. Although this approach allows it to model and solve many problem variants, its performance is far from the state of the art.

VRPSolver ([12]) is an exact state-of-the-art VRP solver that supports different problem variants through a generic model. The solver has a C++, Julia, and Python interface, the latter of which can be installed directly from the Python package index. VRPSolver can find optimal solutions and prove optimality for VRP solutions of modest size, but it is does not scale to instances with more than a few hundred customers. Moreover, the solver's license limits the use of its most powerful components to academic users.

"A VRP Solver" is a rich VRP heuristic solver of [2], written in Rust and made available under an Apache 2.0 license. The project supports many VRP variants, using a custom data format based on JavaScript Object Notation. The project is well tested, and a user manual is available that includes examples, but it appears to be lacking a detailed documentation of the available functional endpoints. Furthermore, it is unclear how well the solver performs in general, as results on standard benchmark instances are lacking.

Whereas each of these projects has their own merit, PyVRP has a unique combination of scope, performance, flexibility, and ease-of-use, making it a useful addition to this set of projects.

4. Technical Implementation

PyVRP implements a variant of the HGS algorithm of [18]. At its core, our implementation consists of a genetic algorithm, a population, and a local search improvement method. We explain these in the following sections, but refer to our documentation[2] for a full overview of the class and function descriptions and other helper classes and methods we do not describe here.

4.1. Overview of HGS

HGS is a hybrid algorithm that combines a genetic algorithm with a local search algorithm. It maintains a population with feasible and infeasible solutions. Initially, solutions are created by randomly assigning customers to routes (feasibility is not required), which ensures diversity in the search. Then, in every iteration, two parents are selected from the population and combined using a crossover operator to create a new offspring solution. We provide an efficient C++ implementation of the selective route exchange (SREX) crossover operator ([10]) by default, but this can easily be replaced by another crossover operator.

In each iteration, the new offspring solution is improved using local search, which considers time windows and capacities as soft constraints by penalizing violations. This way, the local search considers a smoothed version of the problem, which helps the genetic algorithm to converge toward promising regions of the solution space. The penalty weights are automatically adjusted such that a target percentage of the local search runs result in a feasible solution. After the local search, the offspring is inserted into the population. Once the population exceeds a certain size, a survivor selection mechanism removes solutions that contribute the least to the overall quality and diversity of the population.

4.2. Genetic Algorithm

The genetic algorithm is implemented in Python and defines the main search loop. In every iteration of the search loop, the genetic algorithm selects two (feasible or infeasible) parent solutions from the population. A crossover operator takes the two parent solutions and uses those to generate an offspring solution that inherits features from both parents.

After crossover completes, the offspring solution is improved using local search and then added to the population. If this improved offspring solution is feasible and better than our current best solution, it becomes the new best observed solution. Finally, after the main search loop completes, the genetic algorithm returns a result object that contains the best observed solution and detailed runtime statistics.

4.3. Local Search

We provide an efficient local search implementation to improve a new offspring solution. This improvement procedure is typically the most expensive part of the HGS algorithm. Software profiling suggests that, in PyVRP, it accounts for 80%–90% of the runtime, which is why the local search is implemented in C++. The implementation explores a granular neighborhood ([13]) in a very efficient manner using user-provided operators. These operators evaluate moves in different neighborhoods, and the local search algorithm applies the move as soon as it yields a direct improvement in the objective value of the solution. The search is repeated until no more improvements can be made. We distinguish node operators and route operators. Node operators are applied to pairs of customers and evaluate local moves around these customers. Node operators may also be applied to a customer and an unassigned vehicle: this evaluates moves placing a customer into an empty route. To limit the number of vehicles used, these moves are evaluated only once all moves involving pairs of customer have been exhausted. Route operators are applied to pairs of nonempty routes and evaluate more expensive moves that intensify the search.

Users are free to supply their own node and route operators, but for convenience, we already provide a large set of efficient operators, which we describe next.

4.3.1. Node Operators.

Node operators each evaluate (and possibly apply) a move between two customers u and v, with the restriction that v is in the granular neighborhood <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi mathvariant="script">N</mi><mo stretchy="false">(</mo><mi>u</mi><mo stretchy="false">)</mo></mrow></math> of u. We provide a default granular neighborhood of size k for each customer, which takes into account both spatial and temporal aspects of the problem instance. This default implementation reduces the neighborhood size from <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>O</mi><mo stretchy="false">(</mo><msup><mrow><mi>n</mi></mrow><mn>2</mn></msup><mo stretchy="false">)</mo></mrow></math> to O(kn), but a user can fully customize the neighborhood structure or replace it altogether with their own.

PyVRP currently implements the following node operators:

(N, M)-exchange

This operator considers exchanging a consecutive route segment of n > 0 nodes starting at u (inclusive) with a segment of <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mn>0</mn><mo>&#8804;</mo><mi>M</mi><mo>&#8804;</mo><mi>N</mi></mrow></math> nodes starting at v (inclusive). These segments must not overlap in the same route and not contain the depot. When M = 0, this operator evaluates relocate moves inserting u (and possible subsequent nodes) after v. When M > 0, the operator evaluates swap moves exchanging the route segments of one or more nodes starting at nodes u and v. This exchange generalizes the implementations of [17]. We implement (N, M)-exchange using C++'s template mechanism, which after compilation results in efficient, specialized operator implementations for any N and M.

MoveTwoClientsReversed

This operator considers a (2, 0)-exchange where u and its immediate successor are reversed before inserting them after v.

2-OPT

The 2-OPT operator represents the routes of u and v as (directed) line graphs, where an arc <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>u</mi><mo>&#8594;</mo><mi>x</mi></mrow></math> indicates x is visited directly after u. 2-OPT replaces the arcs <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>u</mi><mo>&#8594;</mo><mi>x</mi></mrow></math> and <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>v</mi><mo>&#8594;</mo><mi>y</mi></mrow></math> by <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>u</mi><mo>&#8594;</mo><mi>y</mi></mrow></math> and <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>v</mi><mo>&#8594;</mo><mi>x</mi></mrow></math> , effectively recombining the starts and ends of the two routes if we split them at u and v. When u and v are within the same route, and u precedes v, this operator replaces <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>u</mi><mo>&#8594;</mo><mi>x</mi></mrow></math> and <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>v</mi><mo>&#8594;</mo><mi>y</mi></mrow></math> by <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>u</mi><mo>&#8594;</mo><mi>v</mi></mrow></math> and <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>x</mi><mo>&#8594;</mo><mi>y</mi></mrow></math> , thus reversing the route segment from x to v.

4.3.2. Route Operators.

Route operators consider moves between route pairs, avoiding the granularity restrictions imposed on the node operators. This enables the evaluation of much larger neighborhoods, whereas additional caching opportunities ensure these evaluations remain fast. PyVRP provides two route operators by default:

RELOCATE*

The RELOCATE* operator finds and applies the best (1, 0)-exchange move between two routes. RELOCATE* uses the (N, M)-exchange node operator (with n = 1 and M = 0) to evaluate each move between the two routes.

SWAP*

The SWAP* operator of [17] considers the best swap move between two routes but does not require that the swapped customers are inserted in each other's place. Instead, each is inserted into the best location in the other route. We enhance the implementation of [17] with time window support, further caching, and earlier stopping when evaluating "known-bad" moves.

4.4. Population Management

The population is implemented in Python, using feasible and infeasible subpopulations that are implemented in C++ for performance. New solutions can be added to the population, and parent solutions can be requested from it for crossover. These parents are selected by a k-way tournament on the relative fitness of each parent ([8]). By default, k = 2, which results in a binary tournament.

The population is initialized with a minimal set of random solutions. New solutions obtained by the genetic algorithm are added to it as they are generated. Once a subpopulation reaches its maximal size, survivor selection is performed that reduces the subpopulation to its minimal size. This survivor selection is done by first removing duplicate solutions and then by removing those solutions that have the worst fitness based on the biased fitness criterion of [17]. This fitness criterion balances solution quality based on the solution's objective value and diversity w.r.t. to other solutions in the subpopulation, evaluated using a diversity measure supplied to the population. We implement a directed variant of the broken pairs distance, but a user can also supply their own diversity measure.

5. The PyVRP Package

The PyVRP package is developed in a GitHub repository.[3] The repository contains the C++ and Python source code, including unit and integration tests, as well as documentation and examples introducing new users to PyVRP. Additionally, the repository uses automated workflows that build PyVRP for different platforms (currently Linux, Windows, and MacOS) such that a user can install PyVRP directly from the Python package index using "pip install pyvrp" without having to compile the C++ extensions themselves.

5.1. Package Structure

The top-level pyvrp namespace contains some of the components of Section 4 and important additional classes. These include the Model modeling interface, the GeneticAlgorithm and Population, along with a read function that can be used to read benchmark instances in various formats (through the VRPLIB Python package). Crossover operators that can be used together with the GeneticAlgorithm are provided in pyvrp.crossover. Further, the pyvrp.diversity namespace contains diversity measures that can be used with the Population. The pyvrp.search namespace contains the LocalSearch class, the operators, and the compute_neighbours function that computes a granular neighborhood. Stopping criteria for the genetic algorithm are provided by pyvrp.stop. These include stopping criteria based on a maximum number of iterations or runtime and also variants that stop after a number of iterations without improvement. Finally, pyvrp.plotting provides utilities for plotting and analyzing solutions.

5.2. Example Use

We present two examples for different audiences. The first example, Listing 1 in Figure 1, shows the modeling interface of PyVRP and how that can be used to define and solve a CVRP instance. This interface is particularly convenient for practitioners interested in solving VRPs using PyVRP. The second example, in Listing 2 of Figure 2, shows the different components in PyVRP and how they can be used to solve a VRPTW instance. This example is helpful for understanding how PyVRP's implementation of HGS works and can be used as a basis to customize the solution algorithm.

Graph: Figure 1. (Color online) Listing 1: Using PyVRP's Modeling Interface to Solve a CVRP Instance

Graph: Figure 2. (Color online) Listing 2: PyVRP Example Usage

We will first present the modeling interface in Listing 1 of Figure 1.

The modeling interface is available as Model and can be used to define all relevant instance attributes: the depot, clients, vehicle types, and the edges connecting all locations. After defining an instance, it can be solved by calling the solve method on the model. Once solving finishes, a result object res is returned. This object contains the best-found solution (res. best) and statistics about the solver run. The result object can be printed to display the solution and some relevant statistics. Additionally, the results can be plotted, which we will show how to do in Listing 2 in Figure 2.

In Listing 2 of Figure 2, we solve the 1,000-customer RC2_10_5 instance of the Homberger and Gehring VRPTW set of benchmarks. Rather than using the modeling interface's high-level solve method, here, we set everything up explicitly. The code assumes that the RC2_10_5 instance is available locally.

Listing 2 of Figure 2 first reads a benchmark instance in standard format and constructs a random number generator with fixed seed. It then defines the local search method. We use the default granular neighborhood computed by compute_neighbours, but this can easily be customized by providing an alternative neighborhood definition. Then, we add all node and route operators described in Section 4.3 to the local search object. This is not required: any subset of these operators is also allowed and might even improve the solver performance in specific cases. Finally, the penalty manager and population are initialized. These track, respectively, the weights of constraint violation penalties and the feasible and infeasible solution subpopulations. An initial population should also be provided to the genetic algorithm: here, we generate 25 random solutions. A user may wish to apply alternative population generation methods here. Finally, the genetic algorithm is initialized and run until a stopping criterion is met; in this case, the stopping criterion is 60 seconds of runtime. We plot the solver trajectory and best observed solution in Figure 3.

Graph: Figure 3. Detailed Statistics Collected from a Single Run of Listing 2Notes. (a) Average diversity of the feasible and infeasible subpopulations. It is clear from this figure that periodic survivor selection improves diversity. (b) The best and average objectives of both subpopulations, which improve over time as the search progresses. (c) Iteration runtimes (in seconds), including a trendline. (d) The best observed solution.

5.3. Extending PyVRP

Before writing new code for PyVRP, a few things must be decided about the new constraint. Hard constraints might require changes to PyVRP data structures. Soft constraints typically require modifications to the cost evaluation functions. Additionally, the new constraint likely requires additional data attributes that must be added to PyVRP's data instance object and solution representation. Once that new data are available, the search method can be updated to compute the correct cost deltas of each available move. Some of the cost delta evaluation may need to be cached to ensure an efficient implementation—this is particularly the case for time-related costs, which PyVRP already supports. Entirely new problem aspects might need to develop such caching as part of the extension.

Because we have developed several extensions to PyVRP already, there are some examples available of previous work. We have summarized guidelines for extending PyVRP in our online documentation.[4]

6. Experiments

In this section, we present PyVRP's performance on widely used CVRP and VRPTW benchmark instances. We compare PyVRP's performance with both the best known solutions (BKSs) and with results from the literature, accounting for CPU differences by adjusting the time limits based on the PassMark score. PyVRP is benchmarked on an AMD EPYC 7H12 CPU with a PassMark single-thread performance of 2014. We benchmark PyVRP version 0.5.0, which is available as a static archive on the IJOC GitHub repository ([19]). The BKSs were obtained from the CVRPLIB repository on February 28, 2023.

6.1. CVRP

We evaluate our solver for CVRP on the X benchmark instances of [15]. This set includes 100 instances and covers diverse problem characteristics, such as customer geography, demand distributions, and route lengths. We follow the convention to minimize the total distance. The distances are computed by taking the Euclidean distances rounded to the nearest integer. The parameter settings used in our experiments are shown in Table 1. We solve each instance with 10 different seeds and present the average total distance rounded to one decimal. We compare our solver with the results of state-of-the-art CVRP solvers HGS-2012 ([18]) and HGS-CVRP ([17]). We use the time limits of [17]: each instance is solved for <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mrow><mi>T</mi></mrow><mrow><mtext>max</mtext></mrow></msub><mo>=</mo><mi>n</mi><mo>&#215;</mo><mn>240</mn><mo>/</mo><mn>100</mn></mrow></math> seconds, where n denotes the number of customers in the instance. The smallest instance of 100 customers is thus solved for 4 minutes, and the largest instance with 1,000 customers is solved for 40 minutes. The experiments from [17] were run on a single core of an Intel Gold 6148 CPU with PassMark single-thread performance of 2,183. We normalize the time limit by multiplying <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mrow><mi>T</mi></mrow><mrow><mtext>max</mtext></mrow></msub></mrow></math> with 2,183/2,014 to compensate for the CPU differences.

Table 1. Parameters Values for CVRP and VRPTW

<table><thead valign="bottom"><tr><th align="left" rowspan="1" colspan="1">Category</th><th align="center" rowspan="1" colspan="1">Parameter</th><th align="center" rowspan="1" colspan="1">CVRP</th><th align="center" rowspan="1" colspan="1">VRPTW</th></tr></thead><tbody valign="top"><tr><td align="left" rowspan="1" colspan="1" /><td rowspan="1" colspan="1">Repair probability</td><td align="center" rowspan="1" colspan="1">50%</td><td align="center" rowspan="1" colspan="1">80%</td></tr><tr><td rowspan="1" colspan="1">Genetic algorithm</td><td rowspan="1" colspan="1">Number of nonimproving iterations before restart</td><td align="center" rowspan="1" colspan="1">20,000</td><td align="center" rowspan="1" colspan="1">20,000</td></tr><tr><td align="left" rowspan="6" colspan="1">Population</td><td rowspan="1" colspan="1">Minimum population size</td><td align="center" rowspan="1" colspan="1">25</td><td align="center" rowspan="1" colspan="1">25</td></tr><tr><td rowspan="1" colspan="1">Population generation size</td><td align="center" rowspan="1" colspan="1">40</td><td align="center" rowspan="1" colspan="1">40</td></tr><tr><td rowspan="1" colspan="1">Number of elite solutions</td><td align="center" rowspan="1" colspan="1">4</td><td align="center" rowspan="1" colspan="1">4</td></tr><tr><td rowspan="1" colspan="1">Number of close solutions</td><td align="center" rowspan="1" colspan="1">5</td><td align="center" rowspan="1" colspan="1">5</td></tr><tr><td rowspan="1" colspan="1">Lower bound diversity</td><td align="center" rowspan="1" colspan="1">0.1</td><td align="center" rowspan="1" colspan="1">0.1</td></tr><tr><td rowspan="1" colspan="1">Upper bound diversity</td><td align="center" rowspan="1" colspan="1">0.5</td><td align="center" rowspan="1" colspan="1">0.5</td></tr><tr><td align="left" rowspan="7" colspan="1">Penalty manager</td><td rowspan="1" colspan="1">Initial capacity penalty</td><td align="center" rowspan="1" colspan="1">20</td><td align="center" rowspan="1" colspan="1">20</td></tr><tr><td rowspan="1" colspan="1">Initial time warp penalty</td><td align="center" rowspan="1" colspan="1">&#8212;</td><td align="center" rowspan="1" colspan="1">6</td></tr><tr><td rowspan="1" colspan="1">Repair booster</td><td align="center" rowspan="1" colspan="1">12</td><td align="center" rowspan="1" colspan="1">12</td></tr><tr><td rowspan="1" colspan="1">Number of registrations between penalty updates</td><td align="center" rowspan="1" colspan="1">100</td><td align="center" rowspan="1" colspan="1">50</td></tr><tr><td rowspan="1" colspan="1">Penalty increase factor</td><td align="center" rowspan="1" colspan="1">1.25</td><td align="center" rowspan="1" colspan="1">1.34</td></tr><tr><td rowspan="1" colspan="1">Penalty decrease</td><td align="center" rowspan="1" colspan="1">0.85</td><td align="center" rowspan="1" colspan="1">0.32</td></tr><tr><td rowspan="1" colspan="1">Target feasible</td><td align="center" rowspan="1" colspan="1">0.43</td><td align="center" rowspan="1" colspan="1">0.43</td></tr><tr><td align="left" rowspan="10" colspan="1">Local search</td><td rowspan="1" colspan="1">Number of neighbors</td><td align="center" rowspan="1" colspan="1">20</td><td align="center" rowspan="1" colspan="1">40</td></tr><tr><td rowspan="1" colspan="1">Weight waiting time</td><td align="center" rowspan="1" colspan="1">&#8212;</td><td align="center" rowspan="1" colspan="1">0.2</td></tr><tr><td rowspan="1" colspan="1">Weight time warp</td><td align="center" rowspan="1" colspan="1">&#8212;</td><td align="center" rowspan="1" colspan="1">1.0</td></tr><tr><td rowspan="1" colspan="1">Symmetric proximity</td><td align="center" rowspan="1" colspan="1">True</td><td align="center" rowspan="1" colspan="1">True</td></tr><tr><td rowspan="1" colspan="1">Symmetric neighbors</td><td align="center" rowspan="1" colspan="1">True</td><td align="center" rowspan="1" colspan="1">False</td></tr><tr><td rowspan="1" colspan="1">Relocate operators ((1, 0)-exchange, (2, 0)-exchange, (3, 0)-exchange, MoveTwoClientsReversed)</td><td align="center" rowspan="1" colspan="1">True</td><td align="center" rowspan="1" colspan="1">True</td></tr><tr><td rowspan="1" colspan="1">Swap operators ((1, 1)-exchange, (2, 1)-exchange, (2, 2)-exchange, (3, 2)-exchange, (3, 3)-exchange)</td><td align="center" rowspan="1" colspan="1">True</td><td align="center" rowspan="1" colspan="1">True</td></tr><tr><td rowspan="1" colspan="1">Include 2-OPT operator</td><td align="center" rowspan="1" colspan="1">True</td><td align="center" rowspan="1" colspan="1">True</td></tr><tr><td rowspan="1" colspan="1">Include RELOCATE* operator</td><td align="center" rowspan="1" colspan="1">True</td><td align="center" rowspan="1" colspan="1">True</td></tr><tr><td rowspan="1" colspan="1">Include SWAP* operator</td><td align="center" rowspan="1" colspan="1">True</td><td align="center" rowspan="1" colspan="1">True</td></tr></tbody></table>

1 Note. The values are slightly adapted from those of [17] for CVRP and [6] for VRPTW.

Table 2 presents the summarized results for CVRP. We report both the mean gap <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mfrac><mn>1</mn><mi>n</mi></mfrac><mstyle displaystyle="false"><msub><mo>&#8721;</mo><mi>i</mi></msub><mrow><mrow><mo>(</mo><msub><mrow><mi>c</mi></mrow><mi>i</mi></msub></mrow><mo>/</mo><mrow><msub><mrow><mtext>BKS</mtext></mrow><mi>i</mi></msub></mrow><mo>)</mo></mrow></mstyle><mo>&#8722;</mo><mn>1</mn></mrow></math> , as well as the gap of the mean <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mrow><mo>(</mo><mstyle displaystyle="false"><msub><mo>&#8721;</mo><mi>i</mi></msub><mrow><msub><mrow><mi>c</mi></mrow><mi>i</mi></msub><mo>)</mo></mrow></mstyle></mrow><mo>/</mo><mrow><mo>(</mo><mstyle displaystyle="false"><msub><mo>&#8721;</mo><mi>i</mi></msub><mrow><msub><mrow><mtext>BKS</mtext></mrow><mi>i</mi></msub><mo>)</mo></mrow></mstyle></mrow><mo>&#8722;</mo><mn>1</mn></mrow></math> . Here, i represents a single instance, c<subs>i</subs> denotes the objective value of the solver's solution, and <math display="inline" overflow="scroll" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mrow><mtext>BKS</mtext></mrow><mi>i</mi></msub></mrow></math> is the best known solution value. The gaps are expressed as percentages. PyVRP obtains a mean gap of 0.22% and a gap of the mean of 0.27% on the solved instances. Despite the fact that PyVRP has not been specifically designed for the CVRP, these gaps are only slightly higher than the gaps of specialized CVRP solvers like HGS-2012 (mean gap, 0.21%, and gap of mean, 0.28%) and HGS-CVRP (mean gap, 0.11%, and gap of mean, 0.16%). The complete results for each instance can be found in Table 3.

Table 2. Benchmark Results for CVRP on X Instances of [15]

<table><thead valign="bottom"><tr><th align="left" rowspan="1" colspan="1" /><th align="center" rowspan="1" colspan="1">Mean cost</th><th align="center" rowspan="1" colspan="1">Mean gap (%)</th><th align="center" rowspan="1" colspan="1">Gap of mean (%)</th></tr></thead><tbody valign="top"><tr><td rowspan="1" colspan="1">PyVRP</td><td align="center" rowspan="1" colspan="1">63,275.5</td><td align="center" rowspan="1" colspan="1">0.22</td><td align="center" rowspan="1" colspan="1">0.27</td></tr><tr><td rowspan="1" colspan="1">HGS-2012</td><td align="center" rowspan="1" colspan="1">63,285.8</td><td align="center" rowspan="1" colspan="1">0.21</td><td align="center" rowspan="1" colspan="1">0.28</td></tr><tr><td rowspan="1" colspan="1">HGS-CVRP</td><td align="center" rowspan="1" colspan="1">63,206.1</td><td align="center" rowspan="1" colspan="1">0.11</td><td align="center" rowspan="1" colspan="1">0.16</td></tr><tr><td rowspan="1" colspan="1">BKS</td><td align="center" rowspan="1" colspan="1">63,106.7</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">0.00</td></tr></tbody></table>

Table 3. Benchmark Results for CVRP on X Instances

<p> <ephtml> <table><thead valign="bottom"><tr><th align="left" rowspan="1" colspan="1" /><th align="center" colspan="2" rowspan="1">PyVRP</th><th align="center" colspan="2" rowspan="1">HGS-2012</th><th align="center" colspan="2" rowspan="1">HGS-CVRP</th><th align="center" rowspan="1" colspan="1">BKS</th></tr><tr><th align="left" rowspan="1" colspan="1">Instance</th><th align="center" rowspan="1" colspan="1">Cost</th><th align="center" rowspan="1" colspan="1">Gap</th><th align="center" rowspan="1" colspan="1">Cost</th><th align="center" rowspan="1" colspan="1">Gap</th><th align="center" rowspan="1" colspan="1">Cost</th><th align="center" rowspan="1" colspan="1">Gap</th><th align="center" rowspan="1" colspan="1">Cost</th></tr></thead><tbody valign="top"><tr><td rowspan="1" colspan="1">X-n101-k25</td><td align="center" rowspan="1" colspan="1">27,591.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">27,591.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">27,591.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">27,591</td></tr><tr><td rowspan="1" colspan="1">X-n106-k14</td><td align="center" rowspan="1" colspan="1">26,376.0</td><td align="center" rowspan="1" colspan="1">0.05</td><td align="center" rowspan="1" colspan="1">26,408.8</td><td align="center" rowspan="1" colspan="1">0.18</td><td align="center" rowspan="1" colspan="1">26,381.4</td><td align="center" rowspan="1" colspan="1">0.07</td><td align="center" rowspan="1" colspan="1">26,362</td></tr><tr><td rowspan="1" colspan="1">X-n110-k13</td><td align="center" rowspan="1" colspan="1">14,971.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">14,971.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">14,971.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">14,971</td></tr><tr><td rowspan="1" colspan="1">X-n115-k10</td><td align="center" rowspan="1" colspan="1">12,747.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">12,747.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">12,747.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">12,747</td></tr><tr><td rowspan="1" colspan="1">X-n120-k6</td><td align="center" rowspan="1" colspan="1">13,332.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">13,332.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">13,332.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">13,332</td></tr><tr><td rowspan="1" colspan="1">X-n125-k30</td><td align="center" rowspan="1" colspan="1">55,541.9</td><td align="center" rowspan="1" colspan="1">0.01</td><td align="center" rowspan="1" colspan="1">55,539.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">55,539.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">55,539</td></tr><tr><td rowspan="1" colspan="1">X-n129-k18</td><td align="center" rowspan="1" colspan="1">28,940.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">28,940.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">28,940.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">28,940</td></tr><tr><td rowspan="1" colspan="1">X-n134-k13</td><td align="center" rowspan="1" colspan="1">10,916.2</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">10,916.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">10,916.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">10,916</td></tr><tr><td rowspan="1" colspan="1">X-n139-k10</td><td align="center" rowspan="1" colspan="1">13,590.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">13,590.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">13,590.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">13,590</td></tr><tr><td rowspan="1" colspan="1">X-n143-k7</td><td align="center" rowspan="1" colspan="1">15,719.2</td><td align="center" rowspan="1" colspan="1">0.12</td><td align="center" rowspan="1" colspan="1">15,700.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">15,700.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">15,700</td></tr><tr><td rowspan="1" colspan="1">X-n148-k46</td><td align="center" rowspan="1" colspan="1">43,448.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">43,448.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">43,448.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">43,448</td></tr><tr><td rowspan="1" colspan="1">X-n153-k22</td><td align="center" rowspan="1" colspan="1">21,220.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">21,223.5</td><td align="center" rowspan="1" colspan="1">0.02</td><td align="center" rowspan="1" colspan="1">21,225.0</td><td align="center" rowspan="1" colspan="1">0.02</td><td align="center" rowspan="1" colspan="1">21,220</td></tr><tr><td rowspan="1" colspan="1">X-n157-k13</td><td align="center" rowspan="1" colspan="1">16,876.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,876.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,876.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,876</td></tr><tr><td rowspan="1" colspan="1">X-n162-k11</td><td align="center" rowspan="1" colspan="1">14,138.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">14,138.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">14,138.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">14,138</td></tr><tr><td rowspan="1" colspan="1">X-n167-k10</td><td align="center" rowspan="1" colspan="1">20,557.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">20,557.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">20,557.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">20,557</td></tr><tr><td rowspan="1" colspan="1">X-n172-k51</td><td align="center" rowspan="1" colspan="1">45,607.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">45,607.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">45,607.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">45,607</td></tr><tr><td rowspan="1" colspan="1">X-n176-k26</td><td align="center" rowspan="1" colspan="1">47,817.0</td><td align="center" rowspan="1" colspan="1">0.01</td><td align="center" rowspan="1" colspan="1">47,812.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">47,812.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">47,812</td></tr><tr><td rowspan="1" colspan="1">X-n181-k23</td><td align="center" rowspan="1" colspan="1">25,569.4</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">25,570.2</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">25,569.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">25,569</td></tr><tr><td rowspan="1" colspan="1">X-n186-k15</td><td align="center" rowspan="1" colspan="1">24,149.6</td><td align="center" rowspan="1" colspan="1">0.02</td><td align="center" rowspan="1" colspan="1">24,145.2</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">24,145.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">24,145</td></tr><tr><td rowspan="1" colspan="1">X-n190-k8</td><td align="center" rowspan="1" colspan="1">16,996.2</td><td align="center" rowspan="1" colspan="1">0.10</td><td align="center" rowspan="1" colspan="1">16,992.4</td><td align="center" rowspan="1" colspan="1">0.07</td><td align="center" rowspan="1" colspan="1">16,983.3</td><td align="center" rowspan="1" colspan="1">0.02</td><td align="center" rowspan="1" colspan="1">16,980</td></tr><tr><td rowspan="1" colspan="1">X-n195-k51</td><td align="center" rowspan="1" colspan="1">44,236.1</td><td align="center" rowspan="1" colspan="1">0.03</td><td align="center" rowspan="1" colspan="1">44,225.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">44,225.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">44,225</td></tr><tr><td rowspan="1" colspan="1">X-n200-k36</td><td align="center" rowspan="1" colspan="1">58,583.2</td><td align="center" rowspan="1" colspan="1">0.01</td><td align="center" rowspan="1" colspan="1">58,589.6</td><td align="center" rowspan="1" colspan="1">0.02</td><td align="center" rowspan="1" colspan="1">58,578.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">58,578</td></tr><tr><td rowspan="1" colspan="1">X-n204-k19</td><td align="center" rowspan="1" colspan="1">19,568.5</td><td align="center" rowspan="1" colspan="1">0.02</td><td align="center" rowspan="1" colspan="1">19,565.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">19,565.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">19,565</td></tr><tr><td rowspan="1" colspan="1">X-n209-k16</td><td align="center" rowspan="1" colspan="1">30,672.6</td><td align="center" rowspan="1" colspan="1">0.05</td><td align="center" rowspan="1" colspan="1">30,658.7</td><td align="center" rowspan="1" colspan="1">0.01</td><td align="center" rowspan="1" colspan="1">30,656.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">30,656</td></tr><tr><td rowspan="1" colspan="1">X-n214-k11</td><td align="center" rowspan="1" colspan="1">10,874.6</td><td align="center" rowspan="1" colspan="1">0.17</td><td align="center" rowspan="1" colspan="1">10,877.0</td><td align="center" rowspan="1" colspan="1">0.19</td><td align="center" rowspan="1" colspan="1">10,860.5</td><td align="center" rowspan="1" colspan="1">0.04</td><td align="center" rowspan="1" colspan="1">10,856</td></tr><tr><td rowspan="1" colspan="1">X-n219-k73</td><td align="center" rowspan="1" colspan="1">117,602.3</td><td align="center" rowspan="1" colspan="1">0.01</td><td align="center" rowspan="1" colspan="1">117,601.7</td><td align="center" rowspan="1" colspan="1">0.01</td><td align="center" rowspan="1" colspan="1">117,596.1</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">117,595</td></tr><tr><td rowspan="1" colspan="1">X-n223-k34</td><td align="center" rowspan="1" colspan="1">40,486.3</td><td align="center" rowspan="1" colspan="1">0.12</td><td align="center" rowspan="1" colspan="1">40,455.3</td><td align="center" rowspan="1" colspan="1">0.05</td><td align="center" rowspan="1" colspan="1">40,437.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">40,437</td></tr><tr><td rowspan="1" colspan="1">X-n228-k23</td><td align="center" rowspan="1" colspan="1">25,752.4</td><td align="center" rowspan="1" colspan="1">0.04</td><td align="center" rowspan="1" colspan="1">25,742.7</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">25,742.8</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">25,742</td></tr><tr><td rowspan="1" colspan="1">X-n233-k16</td><td align="center" rowspan="1" colspan="1">19,238.4</td><td align="center" rowspan="1" colspan="1">0.04</td><td align="center" rowspan="1" colspan="1">19,233.1</td><td align="center" rowspan="1" colspan="1">0.02</td><td align="center" rowspan="1" colspan="1">19,230.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">19,230</td></tr><tr><td rowspan="1" colspan="1">X-n237-k14</td><td align="center" rowspan="1" colspan="1">27,049.9</td><td align="center" rowspan="1" colspan="1">0.03</td><td align="center" rowspan="1" colspan="1">27,049.4</td><td align="center" rowspan="1" colspan="1">0.03</td><td align="center" rowspan="1" colspan="1">27,042.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">27,042</td></tr><tr><td rowspan="1" colspan="1">X-n242-k48</td><td align="center" rowspan="1" colspan="1">82,875.4</td><td align="center" rowspan="1" colspan="1">0.15</td><td align="center" rowspan="1" colspan="1">82,826.5</td><td align="center" rowspan="1" colspan="1">0.09</td><td align="center" rowspan="1" colspan="1">82,806.0</td><td align="center" rowspan="1" colspan="1">0.07</td><td align="center" rowspan="1" colspan="1">82,751</td></tr><tr><td rowspan="1" colspan="1">X-n247-k50</td><td align="center" rowspan="1" colspan="1">37,285.0</td><td align="center" rowspan="1" colspan="1">0.03</td><td align="center" rowspan="1" colspan="1">37,295.0</td><td align="center" rowspan="1" colspan="1">0.06</td><td align="center" rowspan="1" colspan="1">37,277.1</td><td align="center" rowspan="1" colspan="1">0.01</td><td align="center" rowspan="1" colspan="1">37,274</td></tr><tr><td rowspan="1" colspan="1">X-n251-k28</td><td align="center" rowspan="1" colspan="1">38,769.4</td><td align="center" rowspan="1" colspan="1">0.22</td><td align="center" rowspan="1" colspan="1">38,735.9</td><td align="center" rowspan="1" colspan="1">0.13</td><td align="center" rowspan="1" colspan="1">38,689.9</td><td align="center" rowspan="1" colspan="1">0.02</td><td align="center" rowspan="1" colspan="1">38,684</td></tr><tr><td rowspan="1" colspan="1">X-n256-k16</td><td align="center" rowspan="1" colspan="1">18,880.0</td><td align="center" rowspan="1" colspan="1">0.22</td><td align="center" rowspan="1" colspan="1">18,880.0</td><td align="center" rowspan="1" colspan="1">0.22</td><td align="center" rowspan="1" colspan="1">18,839.6</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">18,839</td></tr><tr><td rowspan="1" colspan="1">X-n261-k13</td><td align="center" rowspan="1" colspan="1">26,604.5</td><td align="center" rowspan="1" colspan="1">0.18</td><td align="center" rowspan="1" colspan="1">26,594.0</td><td align="center" rowspan="1" colspan="1">0.14</td><td align="center" rowspan="1" colspan="1">26,558.2</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">26,558</td></tr><tr><td rowspan="1" colspan="1">X-n266-k58</td><td align="center" rowspan="1" colspan="1">75,620.7</td><td align="center" rowspan="1" colspan="1">0.19</td><td align="center" rowspan="1" colspan="1">75,646.8</td><td align="center" rowspan="1" colspan="1">0.22</td><td align="center" rowspan="1" colspan="1">75,564.7</td><td align="center" rowspan="1" colspan="1">0.11</td><td align="center" rowspan="1" colspan="1">75,478</td></tr><tr><td rowspan="1" colspan="1">X-n270-k35</td><td align="center" rowspan="1" colspan="1">35,315.2</td><td align="center" rowspan="1" colspan="1">0.07</td><td align="center" rowspan="1" colspan="1">35,306.4</td><td align="center" rowspan="1" colspan="1">0.04</td><td align="center" rowspan="1" colspan="1">35,303.0</td><td align="center" rowspan="1" colspan="1">0.03</td><td align="center" rowspan="1" colspan="1">35,291</td></tr><tr><td rowspan="1" colspan="1">X-n275-k28</td><td align="center" rowspan="1" colspan="1">21,245.8</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">21,247.8</td><td align="center" rowspan="1" colspan="1">0.01</td><td align="center" rowspan="1" colspan="1">21,245.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">21,245</td></tr><tr><td rowspan="1" colspan="1">X-n280-k17</td><td align="center" rowspan="1" colspan="1">33,592.6</td><td align="center" rowspan="1" colspan="1">0.27</td><td align="center" rowspan="1" colspan="1">33,573.0</td><td align="center" rowspan="1" colspan="1">0.21</td><td align="center" rowspan="1" colspan="1">33,543.2</td><td align="center" rowspan="1" colspan="1">0.12</td><td align="center" rowspan="1" colspan="1">33,503</td></tr><tr><td rowspan="1" colspan="1">X-n284-k15</td><td align="center" rowspan="1" colspan="1">20,304.1</td><td align="center" rowspan="1" colspan="1">0.44</td><td align="center" rowspan="1" colspan="1">20,248.0</td><td align="center" rowspan="1" colspan="1">0.16</td><td align="center" rowspan="1" colspan="1">20,245.5</td><td align="center" rowspan="1" colspan="1">0.15</td><td align="center" rowspan="1" colspan="1">20,215</td></tr><tr><td rowspan="1" colspan="1">X-n289-k60</td><td align="center" rowspan="1" colspan="1">95,304.3</td><td align="center" rowspan="1" colspan="1">0.16</td><td align="center" rowspan="1" colspan="1">95,350.4</td><td align="center" rowspan="1" colspan="1">0.21</td><td align="center" rowspan="1" colspan="1">95,300.9</td><td align="center" rowspan="1" colspan="1">0.16</td><td align="center" rowspan="1" colspan="1">95,151</td></tr><tr><td rowspan="1" colspan="1">X-n294-k50</td><td align="center" rowspan="1" colspan="1">47,214.0</td><td align="center" rowspan="1" colspan="1">0.11</td><td align="center" rowspan="1" colspan="1">47,217.8</td><td align="center" rowspan="1" colspan="1">0.12</td><td align="center" rowspan="1" colspan="1">47,184.1</td><td align="center" rowspan="1" colspan="1">0.05</td><td align="center" rowspan="1" colspan="1">47,161</td></tr><tr><td rowspan="1" colspan="1">X-n298-k31</td><td align="center" rowspan="1" colspan="1">34,250.5</td><td align="center" rowspan="1" colspan="1">0.06</td><td align="center" rowspan="1" colspan="1">34,235.9</td><td align="center" rowspan="1" colspan="1">0.01</td><td align="center" rowspan="1" colspan="1">34,234.8</td><td align="center" rowspan="1" colspan="1">0.01</td><td align="center" rowspan="1" colspan="1">34,231</td></tr><tr><td rowspan="1" colspan="1">X-n303-k21</td><td align="center" rowspan="1" colspan="1">21,862.0</td><td align="center" rowspan="1" colspan="1">0.58</td><td align="center" rowspan="1" colspan="1">21,763.4</td><td align="center" rowspan="1" colspan="1">0.13</td><td align="center" rowspan="1" colspan="1">21,748.5</td><td align="center" rowspan="1" colspan="1">0.06</td><td align="center" rowspan="1" colspan="1">21,736</td></tr><tr><td rowspan="1" colspan="1">X-n308-k13</td><td align="center" rowspan="1" colspan="1">25,895.4</td><td align="center" rowspan="1" colspan="1">0.14</td><td align="center" rowspan="1" colspan="1">25,879.8</td><td align="center" rowspan="1" colspan="1">0.08</td><td align="center" rowspan="1" colspan="1">25,870.8</td><td align="center" rowspan="1" colspan="1">0.05</td><td align="center" rowspan="1" colspan="1">25,859</td></tr><tr><td rowspan="1" colspan="1">X-n313-k71</td><td align="center" rowspan="1" colspan="1">94,244.0</td><td align="center" rowspan="1" colspan="1">0.21</td><td align="center" rowspan="1" colspan="1">94,127.7</td><td align="center" rowspan="1" colspan="1">0.09</td><td align="center" rowspan="1" colspan="1">94,112.2</td><td align="center" rowspan="1" colspan="1">0.07</td><td align="center" rowspan="1" colspan="1">94,043</td></tr><tr><td rowspan="1" colspan="1">X-n317-k53</td><td align="center" rowspan="1" colspan="1">78,360.8</td><td align="center" rowspan="1" colspan="1">0.01</td><td align="center" rowspan="1" colspan="1">78,374.8</td><td align="center" rowspan="1" colspan="1">0.03</td><td align="center" rowspan="1" colspan="1">78,355.4</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">78,355</td></tr><tr><td rowspan="1" colspan="1">X-n322-k28</td><td align="center" rowspan="1" colspan="1">29,885.6</td><td align="center" rowspan="1" colspan="1">0.17</td><td align="center" rowspan="1" colspan="1">29,887.5</td><td align="center" rowspan="1" colspan="1">0.18</td><td align="center" rowspan="1" colspan="1">29,848.7</td><td align="center" rowspan="1" colspan="1">0.05</td><td align="center" rowspan="1" colspan="1">29,834</td></tr><tr><td rowspan="1" colspan="1">X-n327-k20</td><td align="center" rowspan="1" colspan="1">27,620.3</td><td align="center" rowspan="1" colspan="1">0.32</td><td align="center" rowspan="1" colspan="1">27,580.4</td><td align="center" rowspan="1" colspan="1">0.18</td><td align="center" rowspan="1" colspan="1">27,540.8</td><td align="center" rowspan="1" colspan="1">0.03</td><td align="center" rowspan="1" colspan="1">27,532</td></tr><tr><td rowspan="1" colspan="1">X-n331-k15</td><td align="center" rowspan="1" colspan="1">31,147.8</td><td align="center" rowspan="1" colspan="1">0.15</td><td align="center" rowspan="1" colspan="1">31,114.0</td><td align="center" rowspan="1" colspan="1">0.04</td><td align="center" rowspan="1" colspan="1">31,103.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">31,102</td></tr><tr><td rowspan="1" colspan="1">X-n336-k84</td><td align="center" rowspan="1" colspan="1">139,627.1</td><td align="center" rowspan="1" colspan="1">0.37</td><td align="center" rowspan="1" colspan="1">139,437.1</td><td align="center" rowspan="1" colspan="1">0.23</td><td align="center" rowspan="1" colspan="1">139,273.5</td><td align="center" rowspan="1" colspan="1">0.12</td><td align="center" rowspan="1" colspan="1">139,111</td></tr><tr><td rowspan="1" colspan="1">X-n344-k43</td><td align="center" rowspan="1" colspan="1">42,136.8</td><td align="center" rowspan="1" colspan="1">0.21</td><td align="center" rowspan="1" colspan="1">42,086.0</td><td align="center" rowspan="1" colspan="1">0.09</td><td align="center" rowspan="1" colspan="1">42,075.6</td><td align="center" rowspan="1" colspan="1">0.06</td><td align="center" rowspan="1" colspan="1">42,050</td></tr><tr><td rowspan="1" colspan="1">X-n351-k40</td><td align="center" rowspan="1" colspan="1">25,998.8</td><td align="center" rowspan="1" colspan="1">0.40</td><td align="center" rowspan="1" colspan="1">25,972.8</td><td align="center" rowspan="1" colspan="1">0.30</td><td align="center" rowspan="1" colspan="1">25,943.6</td><td align="center" rowspan="1" colspan="1">0.18</td><td align="center" rowspan="1" colspan="1">25,896</td></tr><tr><td rowspan="1" colspan="1">X-n359-k29</td><td align="center" rowspan="1" colspan="1">51,674.7</td><td align="center" rowspan="1" colspan="1">0.33</td><td align="center" rowspan="1" colspan="1">51,653.8</td><td align="center" rowspan="1" colspan="1">0.29</td><td align="center" rowspan="1" colspan="1">51,620.0</td><td align="center" rowspan="1" colspan="1">0.22</td><td align="center" rowspan="1" colspan="1">51,505</td></tr><tr><td rowspan="1" colspan="1">X-n367-k17</td><td align="center" rowspan="1" colspan="1">22,827.2</td><td align="center" rowspan="1" colspan="1">0.06</td><td align="center" rowspan="1" colspan="1">22,814.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">22,814.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">22,814</td></tr><tr><td rowspan="1" colspan="1">X-n376-k94</td><td align="center" rowspan="1" colspan="1">147,729.4</td><td align="center" rowspan="1" colspan="1">0.01</td><td align="center" rowspan="1" colspan="1">147,719.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">147,714.5</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">147,713</td></tr><tr><td rowspan="1" colspan="1">X-n384-k52</td><td align="center" rowspan="1" colspan="1">66,155.7</td><td align="center" rowspan="1" colspan="1">0.35</td><td align="center" rowspan="1" colspan="1">66,163.7</td><td align="center" rowspan="1" colspan="1">0.36</td><td align="center" rowspan="1" colspan="1">66,049.1</td><td align="center" rowspan="1" colspan="1">0.18</td><td align="center" rowspan="1" colspan="1">65,928</td></tr><tr><td rowspan="1" colspan="1">X-n393-k38</td><td align="center" rowspan="1" colspan="1">38,310.4</td><td align="center" rowspan="1" colspan="1">0.13</td><td align="center" rowspan="1" colspan="1">38,281.4</td><td align="center" rowspan="1" colspan="1">0.06</td><td align="center" rowspan="1" colspan="1">38,260.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">38,260</td></tr><tr><td rowspan="1" colspan="1">X-n401-k29</td><td align="center" rowspan="1" colspan="1">66,264.0</td><td align="center" rowspan="1" colspan="1">0.17</td><td align="center" rowspan="1" colspan="1">66,305.3</td><td align="center" rowspan="1" colspan="1">0.23</td><td align="center" rowspan="1" colspan="1">66,252.5</td><td align="center" rowspan="1" colspan="1">0.15</td><td align="center" rowspan="1" colspan="1">66,154</td></tr><tr><td rowspan="1" colspan="1">X-n411-k19</td><td align="center" rowspan="1" colspan="1">19,735.6</td><td align="center" rowspan="1" colspan="1">0.12</td><td align="center" rowspan="1" colspan="1">19,723.8</td><td align="center" rowspan="1" colspan="1">0.06</td><td align="center" rowspan="1" colspan="1">19,720.3</td><td align="center" rowspan="1" colspan="1">0.04</td><td align="center" rowspan="1" colspan="1">19,712</td></tr><tr><td rowspan="1" colspan="1">X-n420-k130</td><td align="center" rowspan="1" colspan="1">107,903.6</td><td align="center" rowspan="1" colspan="1">0.10</td><td align="center" rowspan="1" colspan="1">107,843.3</td><td align="center" rowspan="1" colspan="1">0.04</td><td align="center" rowspan="1" colspan="1">107,839.8</td><td align="center" rowspan="1" colspan="1">0.04</td><td align="center" rowspan="1" colspan="1">107,798</td></tr><tr><td rowspan="1" colspan="1">X-n429-k61</td><td align="center" rowspan="1" colspan="1">65,556.2</td><td align="center" rowspan="1" colspan="1">0.16</td><td align="center" rowspan="1" colspan="1">65,565.4</td><td align="center" rowspan="1" colspan="1">0.18</td><td align="center" rowspan="1" colspan="1">65,502.7</td><td align="center" rowspan="1" colspan="1">0.08</td><td align="center" rowspan="1" colspan="1">65,449</td></tr><tr><td rowspan="1" colspan="1">X-n439-k37</td><td align="center" rowspan="1" colspan="1">36,422.6</td><td align="center" rowspan="1" colspan="1">0.09</td><td align="center" rowspan="1" colspan="1">36,426.4</td><td align="center" rowspan="1" colspan="1">0.10</td><td align="center" rowspan="1" colspan="1">36,395.5</td><td align="center" rowspan="1" colspan="1">0.01</td><td align="center" rowspan="1" colspan="1">36,391</td></tr><tr><td rowspan="1" colspan="1">X-n449-k29</td><td align="center" rowspan="1" colspan="1">55,596.2</td><td align="center" rowspan="1" colspan="1">0.66</td><td align="center" rowspan="1" colspan="1">55,598.1</td><td align="center" rowspan="1" colspan="1">0.66</td><td align="center" rowspan="1" colspan="1">55,368.5</td><td align="center" rowspan="1" colspan="1">0.25</td><td align="center" rowspan="1" colspan="1">55,233</td></tr><tr><td rowspan="1" colspan="1">X-n459-k26</td><td align="center" rowspan="1" colspan="1">24,191.1</td><td align="center" rowspan="1" colspan="1">0.22</td><td align="center" rowspan="1" colspan="1">24,199.3</td><td align="center" rowspan="1" colspan="1">0.25</td><td align="center" rowspan="1" colspan="1">24,163.8</td><td align="center" rowspan="1" colspan="1">0.10</td><td align="center" rowspan="1" colspan="1">24,139</td></tr><tr><td rowspan="1" colspan="1">X-n469-k138</td><td align="center" rowspan="1" colspan="1">222,327.0</td><td align="center" rowspan="1" colspan="1">0.23</td><td align="center" rowspan="1" colspan="1">222,364.3</td><td align="center" rowspan="1" colspan="1">0.24</td><td align="center" rowspan="1" colspan="1">222,170.1</td><td align="center" rowspan="1" colspan="1">0.16</td><td align="center" rowspan="1" colspan="1">221,824</td></tr><tr><td rowspan="1" colspan="1">X-n480-k70</td><td align="center" rowspan="1" colspan="1">89,600.2</td><td align="center" rowspan="1" colspan="1">0.17</td><td align="center" rowspan="1" colspan="1">89,665.0</td><td align="center" rowspan="1" colspan="1">0.24</td><td align="center" rowspan="1" colspan="1">89,524.4</td><td align="center" rowspan="1" colspan="1">0.08</td><td align="center" rowspan="1" colspan="1">89,449</td></tr><tr><td rowspan="1" colspan="1">X-n491-k59</td><td align="center" rowspan="1" colspan="1">66,751.4</td><td align="center" rowspan="1" colspan="1">0.40</td><td align="center" rowspan="1" colspan="1">66,723.7</td><td align="center" rowspan="1" colspan="1">0.36</td><td align="center" rowspan="1" colspan="1">66,641.5</td><td align="center" rowspan="1" colspan="1">0.24</td><td align="center" rowspan="1" colspan="1">66,483</td></tr><tr><td rowspan="1" colspan="1">X-n502-k39</td><td align="center" rowspan="1" colspan="1">69,252.4</td><td align="center" rowspan="1" colspan="1">0.04</td><td align="center" rowspan="1" colspan="1">69,300.8</td><td align="center" rowspan="1" colspan="1">0.11</td><td align="center" rowspan="1" colspan="1">69,239.5</td><td align="center" rowspan="1" colspan="1">0.02</td><td align="center" rowspan="1" colspan="1">69,226</td></tr><tr><td rowspan="1" colspan="1">X-n513-k21</td><td align="center" rowspan="1" colspan="1">24,263.4</td><td align="center" rowspan="1" colspan="1">0.26</td><td align="center" rowspan="1" colspan="1">24,206.5</td><td align="center" rowspan="1" colspan="1">0.02</td><td align="center" rowspan="1" colspan="1">24,201.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">24,201</td></tr><tr><td rowspan="1" colspan="1">X-n524-k153</td><td align="center" rowspan="1" colspan="1">154,881.0</td><td align="center" rowspan="1" colspan="1">0.19</td><td align="center" rowspan="1" colspan="1">154,890.1</td><td align="center" rowspan="1" colspan="1">0.19</td><td align="center" rowspan="1" colspan="1">154,747.6</td><td align="center" rowspan="1" colspan="1">0.10</td><td align="center" rowspan="1" colspan="1">154,593</td></tr><tr><td rowspan="1" colspan="1">X-n536-k96</td><td align="center" rowspan="1" colspan="1">95,173.6</td><td align="center" rowspan="1" colspan="1">0.35</td><td align="center" rowspan="1" colspan="1">95,205.1</td><td align="center" rowspan="1" colspan="1">0.38</td><td align="center" rowspan="1" colspan="1">95,091.9</td><td align="center" rowspan="1" colspan="1">0.26</td><td align="center" rowspan="1" colspan="1">94,846</td></tr><tr><td rowspan="1" colspan="1">X-n548-k50</td><td align="center" rowspan="1" colspan="1">86,855.6</td><td align="center" rowspan="1" colspan="1">0.18</td><td align="center" rowspan="1" colspan="1">86,970.8</td><td align="center" rowspan="1" colspan="1">0.31</td><td align="center" rowspan="1" colspan="1">86,778.4</td><td align="center" rowspan="1" colspan="1">0.09</td><td align="center" rowspan="1" colspan="1">86,700</td></tr><tr><td rowspan="1" colspan="1">X-n561-k42</td><td align="center" rowspan="1" colspan="1">42,834.2</td><td align="center" rowspan="1" colspan="1">0.27</td><td align="center" rowspan="1" colspan="1">42,783.9</td><td align="center" rowspan="1" colspan="1">0.16</td><td align="center" rowspan="1" colspan="1">42,742.7</td><td align="center" rowspan="1" colspan="1">0.06</td><td align="center" rowspan="1" colspan="1">42,717</td></tr><tr><td rowspan="1" colspan="1">X-n573-k30</td><td align="center" rowspan="1" colspan="1">50,925.0</td><td align="center" rowspan="1" colspan="1">0.50</td><td align="center" rowspan="1" colspan="1">50,861.2</td><td align="center" rowspan="1" colspan="1">0.37</td><td align="center" rowspan="1" colspan="1">50,813.0</td><td align="center" rowspan="1" colspan="1">0.28</td><td align="center" rowspan="1" colspan="1">50,673</td></tr><tr><td rowspan="1" colspan="1">X-n586-k159</td><td align="center" rowspan="1" colspan="1">190,643.4</td><td align="center" rowspan="1" colspan="1">0.17</td><td align="center" rowspan="1" colspan="1">190,759.3</td><td align="center" rowspan="1" colspan="1">0.23</td><td align="center" rowspan="1" colspan="1">190,588.1</td><td align="center" rowspan="1" colspan="1">0.14</td><td align="center" rowspan="1" colspan="1">190,316</td></tr><tr><td rowspan="1" colspan="1">X-n599-k92</td><td align="center" rowspan="1" colspan="1">108,813.2</td><td align="center" rowspan="1" colspan="1">0.33</td><td align="center" rowspan="1" colspan="1">108,872.3</td><td align="center" rowspan="1" colspan="1">0.39</td><td align="center" rowspan="1" colspan="1">108,656.0</td><td align="center" rowspan="1" colspan="1">0.19</td><td align="center" rowspan="1" colspan="1">108,451</td></tr><tr><td rowspan="1" colspan="1">X-n613-k62</td><td align="center" rowspan="1" colspan="1">59,795.0</td><td align="center" rowspan="1" colspan="1">0.44</td><td align="center" rowspan="1" colspan="1">59,801.0</td><td align="center" rowspan="1" colspan="1">0.45</td><td align="center" rowspan="1" colspan="1">59,696.3</td><td align="center" rowspan="1" colspan="1">0.27</td><td align="center" rowspan="1" colspan="1">59,535</td></tr><tr><td rowspan="1" colspan="1">X-n627-k43</td><td align="center" rowspan="1" colspan="1">62,439.1</td><td align="center" rowspan="1" colspan="1">0.44</td><td align="center" rowspan="1" colspan="1">62,558.7</td><td align="center" rowspan="1" colspan="1">0.63</td><td align="center" rowspan="1" colspan="1">62,371.6</td><td align="center" rowspan="1" colspan="1">0.33</td><td align="center" rowspan="1" colspan="1">62,164</td></tr><tr><td rowspan="1" colspan="1">X-n641-k35</td><td align="center" rowspan="1" colspan="1">63,993.0</td><td align="center" rowspan="1" colspan="1">0.49</td><td align="center" rowspan="1" colspan="1">64,086.0</td><td align="center" rowspan="1" colspan="1">0.63</td><td align="center" rowspan="1" colspan="1">63,874.2</td><td align="center" rowspan="1" colspan="1">0.30</td><td align="center" rowspan="1" colspan="1">63,682</td></tr><tr><td rowspan="1" colspan="1">X-n655-k131</td><td align="center" rowspan="1" colspan="1">106,851.9</td><td align="center" rowspan="1" colspan="1">0.07</td><td align="center" rowspan="1" colspan="1">106,865.4</td><td align="center" rowspan="1" colspan="1">0.08</td><td align="center" rowspan="1" colspan="1">106,808.8</td><td align="center" rowspan="1" colspan="1">0.03</td><td align="center" rowspan="1" colspan="1">106,780</td></tr><tr><td rowspan="1" colspan="1">X-n670-k130</td><td align="center" rowspan="1" colspan="1">146,893.7</td><td align="center" rowspan="1" colspan="1">0.38</td><td align="center" rowspan="1" colspan="1">147,319.0</td><td align="center" rowspan="1" colspan="1">0.67</td><td align="center" rowspan="1" colspan="1">146,777.7</td><td align="center" rowspan="1" colspan="1">0.30</td><td align="center" rowspan="1" colspan="1">146,332</td></tr><tr><td rowspan="1" colspan="1">X-n685-k75</td><td align="center" rowspan="1" colspan="1">68,532.3</td><td align="center" rowspan="1" colspan="1">0.48</td><td align="center" rowspan="1" colspan="1">68,498.0</td><td align="center" rowspan="1" colspan="1">0.43</td><td align="center" rowspan="1" colspan="1">68,343.1</td><td align="center" rowspan="1" colspan="1">0.20</td><td align="center" rowspan="1" colspan="1">68,205</td></tr><tr><td rowspan="1" colspan="1">X-n701-k44</td><td align="center" rowspan="1" colspan="1">82,462.8</td><td align="center" rowspan="1" colspan="1">0.66</td><td align="center" rowspan="1" colspan="1">82,457.9</td><td align="center" rowspan="1" colspan="1">0.65</td><td align="center" rowspan="1" colspan="1">82,237.3</td><td align="center" rowspan="1" colspan="1">0.38</td><td align="center" rowspan="1" colspan="1">81,923</td></tr><tr><td rowspan="1" colspan="1">X-n716-k35</td><td align="center" rowspan="1" colspan="1">43,616.9</td><td align="center" rowspan="1" colspan="1">0.56</td><td align="center" rowspan="1" colspan="1">43,615.1</td><td align="center" rowspan="1" colspan="1">0.56</td><td align="center" rowspan="1" colspan="1">43,505.8</td><td align="center" rowspan="1" colspan="1">0.31</td><td align="center" rowspan="1" colspan="1">43,373</td></tr><tr><td rowspan="1" colspan="1">X-n733-k159</td><td align="center" rowspan="1" colspan="1">136,526.4</td><td align="center" rowspan="1" colspan="1">0.25</td><td align="center" rowspan="1" colspan="1">136,512.5</td><td align="center" rowspan="1" colspan="1">0.24</td><td align="center" rowspan="1" colspan="1">136,426.9</td><td align="center" rowspan="1" colspan="1">0.18</td><td align="center" rowspan="1" colspan="1">136,187</td></tr><tr><td rowspan="1" colspan="1">X-n749-k98</td><td align="center" rowspan="1" colspan="1">77,801.3</td><td align="center" rowspan="1" colspan="1">0.69</td><td align="center" rowspan="1" colspan="1">77,783.0</td><td align="center" rowspan="1" colspan="1">0.67</td><td align="center" rowspan="1" colspan="1">77,655.4</td><td align="center" rowspan="1" colspan="1">0.50</td><td align="center" rowspan="1" colspan="1">77,269</td></tr><tr><td rowspan="1" colspan="1">X-n766-k71</td><td align="center" rowspan="1" colspan="1">115,135.3</td><td align="center" rowspan="1" colspan="1">0.63</td><td align="center" rowspan="1" colspan="1">114,894.6</td><td align="center" rowspan="1" colspan="1">0.42</td><td align="center" rowspan="1" colspan="1">114,764.5</td><td align="center" rowspan="1" colspan="1">0.30</td><td align="center" rowspan="1" colspan="1">114,417</td></tr><tr><td rowspan="1" colspan="1">X-n783-k48</td><td align="center" rowspan="1" colspan="1">72,915.8</td><td align="center" rowspan="1" colspan="1">0.73</td><td align="center" rowspan="1" colspan="1">73,027.6</td><td align="center" rowspan="1" colspan="1">0.89</td><td align="center" rowspan="1" colspan="1">72,790.7</td><td align="center" rowspan="1" colspan="1">0.56</td><td align="center" rowspan="1" colspan="1">72,386</td></tr><tr><td rowspan="1" colspan="1">X-n801-k40</td><td align="center" rowspan="1" colspan="1">73,655.2</td><td align="center" rowspan="1" colspan="1">0.48</td><td align="center" rowspan="1" colspan="1">73,803.3</td><td align="center" rowspan="1" colspan="1">0.68</td><td align="center" rowspan="1" colspan="1">73,500.4</td><td align="center" rowspan="1" colspan="1">0.27</td><td align="center" rowspan="1" colspan="1">73,305</td></tr><tr><td rowspan="1" colspan="1">X-n819-k171</td><td align="center" rowspan="1" colspan="1">158,745.0</td><td align="center" rowspan="1" colspan="1">0.39</td><td align="center" rowspan="1" colspan="1">158,756.1</td><td align="center" rowspan="1" colspan="1">0.40</td><td align="center" rowspan="1" colspan="1">158,511.6</td><td align="center" rowspan="1" colspan="1">0.25</td><td align="center" rowspan="1" colspan="1">158,121</td></tr><tr><td rowspan="1" colspan="1">X-n837-k142</td><td align="center" rowspan="1" colspan="1">194,291.2</td><td align="center" rowspan="1" colspan="1">0.29</td><td align="center" rowspan="1" colspan="1">194,636.5</td><td align="center" rowspan="1" colspan="1">0.46</td><td align="center" rowspan="1" colspan="1">194,231.3</td><td align="center" rowspan="1" colspan="1">0.26</td><td align="center" rowspan="1" colspan="1">193,737</td></tr><tr><td rowspan="1" colspan="1">X-n856-k95</td><td align="center" rowspan="1" colspan="1">89,129.8</td><td align="center" rowspan="1" colspan="1">0.19</td><td align="center" rowspan="1" colspan="1">89,216.1</td><td align="center" rowspan="1" colspan="1">0.28</td><td align="center" rowspan="1" colspan="1">89,037.5</td><td align="center" rowspan="1" colspan="1">0.08</td><td align="center" rowspan="1" colspan="1">88,965</td></tr><tr><td rowspan="1" colspan="1">X-n876-k59</td><td align="center" rowspan="1" colspan="1">99,824.3</td><td align="center" rowspan="1" colspan="1">0.53</td><td align="center" rowspan="1" colspan="1">99,889.4</td><td align="center" rowspan="1" colspan="1">0.59</td><td align="center" rowspan="1" colspan="1">99,682.7</td><td align="center" rowspan="1" colspan="1">0.39</td><td align="center" rowspan="1" colspan="1">99,299</td></tr><tr><td rowspan="1" colspan="1">X-n895-k37</td><td align="center" rowspan="1" colspan="1">54,281.0</td><td align="center" rowspan="1" colspan="1">0.78</td><td align="center" rowspan="1" colspan="1">54,255.9</td><td align="center" rowspan="1" colspan="1">0.74</td><td align="center" rowspan="1" colspan="1">54,070.6</td><td align="center" rowspan="1" colspan="1">0.39</td><td align="center" rowspan="1" colspan="1">53,860</td></tr><tr><td rowspan="1" colspan="1">X-n916-k207</td><td align="center" rowspan="1" colspan="1">329,935.4</td><td align="center" rowspan="1" colspan="1">0.23</td><td align="center" rowspan="1" colspan="1">330,234.0</td><td align="center" rowspan="1" colspan="1">0.32</td><td align="center" rowspan="1" colspan="1">329,852.0</td><td align="center" rowspan="1" colspan="1">0.20</td><td align="center" rowspan="1" colspan="1">329,179</td></tr><tr><td rowspan="1" colspan="1">X-n936-k151</td><td align="center" rowspan="1" colspan="1">133,365.1</td><td align="center" rowspan="1" colspan="1">0.49</td><td align="center" rowspan="1" colspan="1">133,613.7</td><td align="center" rowspan="1" colspan="1">0.68</td><td align="center" rowspan="1" colspan="1">133,369.9</td><td align="center" rowspan="1" colspan="1">0.49</td><td align="center" rowspan="1" colspan="1">132,715</td></tr><tr><td rowspan="1" colspan="1">X-n957-k87</td><td align="center" rowspan="1" colspan="1">85,678.0</td><td align="center" rowspan="1" colspan="1">0.25</td><td align="center" rowspan="1" colspan="1">85,823.3</td><td align="center" rowspan="1" colspan="1">0.42</td><td align="center" rowspan="1" colspan="1">85,550.1</td><td align="center" rowspan="1" colspan="1">0.10</td><td align="center" rowspan="1" colspan="1">85,465</td></tr><tr><td rowspan="1" colspan="1">X-n979-k58</td><td align="center" rowspan="1" colspan="1">119,781.8</td><td align="center" rowspan="1" colspan="1">0.68</td><td align="center" rowspan="1" colspan="1">119,502.3</td><td align="center" rowspan="1" colspan="1">0.44</td><td align="center" rowspan="1" colspan="1">119,247.5</td><td align="center" rowspan="1" colspan="1">0.23</td><td align="center" rowspan="1" colspan="1">118,976</td></tr><tr><td rowspan="1" colspan="1">X-n1001-k43</td><td align="center" rowspan="1" colspan="1">73,001.0</td><td align="center" rowspan="1" colspan="1">0.89</td><td align="center" rowspan="1" colspan="1">73,051.4</td><td align="center" rowspan="1" colspan="1">0.96</td><td align="center" rowspan="1" colspan="1">72,748.8</td><td align="center" rowspan="1" colspan="1">0.54</td><td align="center" rowspan="1" colspan="1">72,355</td></tr><tr><td rowspan="1" colspan="1">Mean</td><td align="center" rowspan="1" colspan="1">63,275.5</td><td align="center" rowspan="1" colspan="1">0.22</td><td align="center" rowspan="1" colspan="1">63,285.8</td><td align="center" rowspan="1" colspan="1">0.21</td><td align="center" rowspan="1" colspan="1">63,206.1</td><td align="center" rowspan="1" colspan="1">0.11</td><td align="center" rowspan="1" colspan="1">63,106.7</td></tr><tr><td rowspan="1" colspan="1">Gap of mean</td><td align="center" rowspan="1" colspan="1" /><td align="center" rowspan="1" colspan="1">0.27</td><td align="center" rowspan="1" colspan="1" /><td align="center" rowspan="1" colspan="1">0.28</td><td align="center" rowspan="1" colspan="1" /><td align="center" rowspan="1" colspan="1">0.16</td><td align="center" rowspan="1" colspan="1" /></tr></tbody></table> </ephtml> </p>

6.2. VRPTW

<p>We evaluate our solver on the well-known Homberger and Gehring VRPTW instance set ([5]). The set includes five categories of instance sizes with 200, 400, 600, 800, and 1,000 customers. For brevity, we only presents results here for the 1,000 customer instances. The relative performance differences on smaller instances are similar to the results on the 1,000 customer instances. Following the DIMACS competition convention, we minimize the total travel distance and set a time limit of two hours for 1,000 customer instances on a CPU with reference PassMark score of 2,000. We normalize the time limits for our choice of CPU, so we multiply the time limits by 2,000/2,014 in our numerical experiments. We solve each instance with 10 different seeds and present the average total distance rounded to one decimal. The parameter settings of our solver are shown in Table 1 and largely follow the parameter values used by [6] and [16]. We compare PyVRP with the solutions found by [6], denoted as HGS-DIMACS. Since the original DIMACS results were reported as gaps to a reference solution provided by the DIMACS organization, we also include the gaps between these reference solutions and the reference BKSs.</p> <p>Table 4 summarizes the results for VRPTW. The complete results for each instance can be found in Table 5. We again report both the mean gap and the gap of the mean. PyVRP achieves a mean gap of 0.40% and gap of mean of 0.46% on the VRPTW benchmark instances, which is slightly higher than that of HGS-DIMACS (mean gap of 0.32% and gap of mean of 0.37%). The difference in performance can be explained by the simplified implementation of PyVRP. As a result of this simplification, PyVRP would have ended up in second place in the DIMACS VRPTW competition. Furthermore, during extended runs, PyVRP managed to improve 27 of the 300 best known solutions of the complete Homberger and Gehring instances.</p> <p>Table 4. Benchmark Results for VRPTW on 1,000-Customer Instances of [5]</p> <p> <ephtml> <table><thead valign="bottom"><tr><th align="left" rowspan="1" colspan="1" /><th align="center" rowspan="1" colspan="1">Mean cost</th><th align="center" rowspan="1" colspan="1">Mean gap</th><th align="center" rowspan="1" colspan="1">Gap of mean</th></tr></thead><tbody valign="top"><tr><td rowspan="1" colspan="1">PyVRP</td><td align="center" rowspan="1" colspan="1">33,296.4</td><td align="center" rowspan="1" colspan="1">0.40</td><td align="center" rowspan="1" colspan="1">0.46</td></tr><tr><td rowspan="1" colspan="1">HGS-DIMACS</td><td align="center" rowspan="1" colspan="1">33,265.5</td><td align="center" rowspan="1" colspan="1">0.32</td><td align="center" rowspan="1" colspan="1">0.37</td></tr><tr><td rowspan="1" colspan="1">DIMACS reference</td><td align="center" rowspan="1" colspan="1">33,245.1</td><td align="center" rowspan="1" colspan="1">0.29</td><td align="center" rowspan="1" colspan="1">0.31</td></tr><tr><td rowspan="1" colspan="1">BKS</td><td align="center" rowspan="1" colspan="1">33,143.8</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">0.00</td></tr></tbody></table> </ephtml> </p> <p>Table 5. Benchmark Results for VRPTW on 1,000-Customer Homberger and Gehring Instances</p> <p> <ephtml> <table><thead valign="bottom"><tr><th align="left" rowspan="1" colspan="1" /><th align="center" colspan="2" rowspan="1">PyVRP</th><th align="center" colspan="2" rowspan="1">HGS-DIMACS</th><th align="center" colspan="2" rowspan="1">DIMACS</th><th align="center" rowspan="1" colspan="1">BKS</th></tr><tr><th align="left" rowspan="1" colspan="1">Instance</th><th align="center" rowspan="1" colspan="1">Cost</th><th align="center" rowspan="1" colspan="1">Gap</th><th align="center" rowspan="1" colspan="1">Cost</th><th align="center" rowspan="1" colspan="1">Gap</th><th align="center" rowspan="1" colspan="1">Cost</th><th align="center" rowspan="1" colspan="1">Gap</th><th align="center" rowspan="1" colspan="1">Cost</th></tr></thead><tbody valign="top"><tr><td rowspan="1" colspan="1">C1&#95;10&#95;1</td><td align="center" rowspan="1" colspan="1">42,444.8</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">42,444.8</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">42,444.8</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">42,444.8</td></tr><tr><td rowspan="1" colspan="1">C1&#95;10&#95;2</td><td align="center" rowspan="1" colspan="1">41,391.0</td><td align="center" rowspan="1" colspan="1">0.13</td><td align="center" rowspan="1" colspan="1">41,386.4</td><td align="center" rowspan="1" colspan="1">0.12</td><td align="center" rowspan="1" colspan="1">41,392.7</td><td align="center" rowspan="1" colspan="1">0.13</td><td align="center" rowspan="1" colspan="1">41,337.8</td></tr><tr><td rowspan="1" colspan="1">C1&#95;10&#95;3</td><td align="center" rowspan="1" colspan="1">40,205.4</td><td align="center" rowspan="1" colspan="1">0.35</td><td align="center" rowspan="1" colspan="1">40,216.4</td><td align="center" rowspan="1" colspan="1">0.38</td><td align="center" rowspan="1" colspan="1">40,146.2</td><td align="center" rowspan="1" colspan="1">0.20</td><td align="center" rowspan="1" colspan="1">40,064.4</td></tr><tr><td rowspan="1" colspan="1">C1&#95;10&#95;4</td><td align="center" rowspan="1" colspan="1">39,544.2</td><td align="center" rowspan="1" colspan="1">0.28</td><td align="center" rowspan="1" colspan="1">39,524.6</td><td align="center" rowspan="1" colspan="1">0.23</td><td align="center" rowspan="1" colspan="1">39,490.9</td><td align="center" rowspan="1" colspan="1">0.14</td><td align="center" rowspan="1" colspan="1">39,434.1</td></tr><tr><td rowspan="1" colspan="1">C1&#95;10&#95;5</td><td align="center" rowspan="1" colspan="1">42,434.8</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">42,434.8</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">42,434.8</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">42,434.8</td></tr><tr><td rowspan="1" colspan="1">C1&#95;10&#95;6</td><td align="center" rowspan="1" colspan="1">42,437.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">42,437.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">42,437.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">42,437.0</td></tr><tr><td rowspan="1" colspan="1">C1&#95;10&#95;7</td><td align="center" rowspan="1" colspan="1">42,420.5</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">42,420.4</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">42,420.4</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">42,420.4</td></tr><tr><td rowspan="1" colspan="1">C1&#95;10&#95;8</td><td align="center" rowspan="1" colspan="1">41,870.3</td><td align="center" rowspan="1" colspan="1">0.52</td><td align="center" rowspan="1" colspan="1">41,902.5</td><td align="center" rowspan="1" colspan="1">0.60</td><td align="center" rowspan="1" colspan="1">41,837.8</td><td align="center" rowspan="1" colspan="1">0.45</td><td align="center" rowspan="1" colspan="1">41,652.1</td></tr><tr><td rowspan="1" colspan="1">C1&#95;10&#95;9</td><td align="center" rowspan="1" colspan="1">40,520.8</td><td align="center" rowspan="1" colspan="1">0.58</td><td align="center" rowspan="1" colspan="1">40,425.2</td><td align="center" rowspan="1" colspan="1">0.34</td><td align="center" rowspan="1" colspan="1">40,366.7</td><td align="center" rowspan="1" colspan="1">0.19</td><td align="center" rowspan="1" colspan="1">40,288.4</td></tr><tr><td rowspan="1" colspan="1">C1&#95;10&#95;10</td><td align="center" rowspan="1" colspan="1">40,134.9</td><td align="center" rowspan="1" colspan="1">0.80</td><td align="center" rowspan="1" colspan="1">40,149.5</td><td align="center" rowspan="1" colspan="1">0.84</td><td align="center" rowspan="1" colspan="1">39,874.5</td><td align="center" rowspan="1" colspan="1">0.14</td><td align="center" rowspan="1" colspan="1">39,816.8</td></tr><tr><td rowspan="1" colspan="1">C2&#95;10&#95;1</td><td align="center" rowspan="1" colspan="1">16,841.1</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,841.1</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,841.1</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,841.1</td></tr><tr><td rowspan="1" colspan="1">C2&#95;10&#95;2</td><td align="center" rowspan="1" colspan="1">16,464.8</td><td align="center" rowspan="1" colspan="1">0.01</td><td align="center" rowspan="1" colspan="1">16,462.6</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,462.6</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,462.6</td></tr><tr><td rowspan="1" colspan="1">C2&#95;10&#95;3</td><td align="center" rowspan="1" colspan="1">16,041.7</td><td align="center" rowspan="1" colspan="1">0.03</td><td align="center" rowspan="1" colspan="1">16,036.5</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,036.5</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,036.5</td></tr><tr><td rowspan="1" colspan="1">C2&#95;10&#95;4</td><td align="center" rowspan="1" colspan="1">15,484.2</td><td align="center" rowspan="1" colspan="1">0.16</td><td align="center" rowspan="1" colspan="1">15,463.6</td><td align="center" rowspan="1" colspan="1">0.03</td><td align="center" rowspan="1" colspan="1">15,482.9</td><td align="center" rowspan="1" colspan="1">0.15</td><td align="center" rowspan="1" colspan="1">15,459.5</td></tr><tr><td rowspan="1" colspan="1">C2&#95;10&#95;5</td><td align="center" rowspan="1" colspan="1">16,522.0</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,521.3</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,521.3</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,521.3</td></tr><tr><td rowspan="1" colspan="1">C2&#95;10&#95;6</td><td align="center" rowspan="1" colspan="1">16,296.1</td><td align="center" rowspan="1" colspan="1">0.03</td><td align="center" rowspan="1" colspan="1">16,290.7</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,290.7</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,290.7</td></tr><tr><td rowspan="1" colspan="1">C2&#95;10&#95;7</td><td align="center" rowspan="1" colspan="1">16,378.9</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,378.4</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,378.4</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,378.4</td></tr><tr><td rowspan="1" colspan="1">C2&#95;10&#95;8</td><td align="center" rowspan="1" colspan="1">16,035.5</td><td align="center" rowspan="1" colspan="1">0.04</td><td align="center" rowspan="1" colspan="1">16,029.8</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,029.1</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,029.1</td></tr><tr><td rowspan="1" colspan="1">C2&#95;10&#95;9</td><td align="center" rowspan="1" colspan="1">16,089.1</td><td align="center" rowspan="1" colspan="1">0.09</td><td align="center" rowspan="1" colspan="1">16,075.6</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">16,077.0</td><td align="center" rowspan="1" colspan="1">0.01</td><td align="center" rowspan="1" colspan="1">16,075.4</td></tr><tr><td rowspan="1" colspan="1">C2&#95;10&#95;10</td><td align="center" rowspan="1" colspan="1">15,741.0</td><td align="center" rowspan="1" colspan="1">0.08</td><td align="center" rowspan="1" colspan="1">15,728.6</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">15,728.6</td><td align="center" rowspan="1" colspan="1">0.00</td><td align="center" rowspan="1" colspan="1">15,728.6</td></tr><tr><td rowspan="1" colspan="1">R1&#95;10&#95;1</td><td align="center" rowspan="1" colspan="1">53,378.9</td><td align="center" rowspan="1" colspan="1">0.63</td><td align="center" rowspan="1" colspan="1">53,341.7</td><td align="center" rowspan="1" colspan="1">0.56</td><td align="center" rowspan="1" colspan="1">53,233.9</td><td align="center" rowspan="1" colspan="1">0.35</td><td align="center" rowspan="1" colspan="1">53,046.5</td></tr><tr><td rowspan="1" colspan="1">R1&#95;10&#95;2</td><td align="center" rowspan="1" colspan="1">48,684.4</td><td align="center" rowspan="1" colspan="1">0.87</td><td align="center" rowspan="1" colspan="1">48,513.0</td><td align="center" rowspan="1" colspan="1">0.52</td><td align="center" rowspan="1" colspan="1">48,369.1</td><td align="center" rowspan="1" colspan="1">0.22</td><td align="center" rowspan="1" colspan="1">48,263.1</td></tr><tr><td rowspan="1" colspan="1">R1&#95;10&#95;3</td><td align="center" rowspan="1" colspan="1">45,057.2</td><td align="center" rowspan="1" colspan="1">0.85</td><td align="center" rowspan="1" colspan="1">44,999.1</td><td align="center" rowspan="1" colspan="1">0.72</td><td align="center" rowspan="1" colspan="1">44,862.4</td><td align="center" rowspan="1" colspan="1">0.41</td><td align="center" rowspan="1" colspan="1">44,677.1</td></tr><tr><td rowspan="1" colspan="1">R1&#95;10&#95;4</td><td align="center" rowspan="1" colspan="1">42,839.8</td><td align="center" rowspan="1" colspan="1">0.94</td><td align="center" rowspan="1" colspan="1">42,625.9</td><td align="center" rowspan="1" colspan="1">0.44</td><td align="center" rowspan="1" colspan="1">42,577.9</td><td align="center" rowspan="1" colspan="1">0.32</td><td align="center" rowspan="1" colspan="1">42,440.7</td></tr><tr><td rowspan="1" colspan="1">R1&#95;10&#95;5</td><td align="center" rowspan="1" colspan="1">50,572.4</td><td align="center" rowspan="1" colspan="1">0.33</td><td align="center" rowspan="1" colspan="1">50,596.5</td><td align="center" rowspan="1" colspan="1">0.38</td><td align="center" rowspan="1" colspan="1">50,487.8</td><td align="center" rowspan="1" colspan="1">0.16</td><td align="center" rowspan="1" colspan="1">50,406.7</td></tr><tr><td rowspan="1" colspan="1">R1&#95;10&#95;6</td><td align="center" rowspan="1" colspan="1">47,312.8</td><td align="center" rowspan="1" colspan="1">0.82</td><td align="center" rowspan="1" colspan="1">47,276.2</td><td align="center" rowspan="1" colspan="1">0.74</td><td align="center" rowspan="1" colspan="1">47,145.8</td><td align="center" rowspan="1" colspan="1">0.46</td><td align="center" rowspan="1" colspan="1">46,930.3</td></tr><tr><td rowspan="1" colspan="1">R1&#95;10&#95;7</td><td align="center" rowspan="1" colspan="1">44,342.7</td><td align="center" rowspan="1" colspan="1">0.78</td><td align="center" rowspan="1" colspan="1">44,174.8</td><td align="center" rowspan="1" colspan="1">0.40</td><td align="center" rowspan="1" colspan="1">44,231.4</td><td align="center" rowspan="1" colspan="1">0.53</td><td align="center" rowspan="1" colspan="1">43,997.4</td></tr><tr><td rowspan="1" colspan="1">R1&#95;10&#95;8</td><td align="center" rowspan="1" colspan="1">42,611.3</td><td align="center" rowspan="1" colspan="1">0.79</td><td align="center" rowspan="1" colspan="1">42,451.6</td><td align="center" rowspan="1" colspan="1">0.41</td><td align="center" rowspan="1" colspan="1">42,435.9</td><td align="center" rowspan="1" colspan="1">0.37</td><td align="center" rowspan="1" colspan="1">42,279.3</td></tr><tr><td rowspan="1" colspan="1">R1&#95;10&#95;9</td><td align="center" rowspan="1" colspan="1">49,387.7</td><td align="center" rowspan="1" colspan="1">0.46</td><td align="center" rowspan="1" colspan="1">49,417.9</td><td align="center" rowspan="1" colspan="1">0.52</td><td align="center" rowspan="1" colspan="1">49,334.3</td><td align="center" rowspan="1" colspan="1">0.35</td><td align="center" rowspan="1" colspan="1">49,162.8</td></tr><tr><td rowspan="1" colspan="1">R1&#95;10&#95;10</td><td align="center" rowspan="1" colspan="1">47,705.7</td><td align="center" rowspan="1" colspan="1">0.72</td><td align="center" rowspan="1" colspan="1">47,690.5</td><td align="center" rowspan="1" colspan="1">0.69</td><td align="center" rowspan="1" colspan="1">47,570.6</td><td align="center" rowspan="1" colspan="1">0.43</td><td align="center" rowspan="1" colspan="1">47,364.6</td></tr><tr><td rowspan="1" colspan="1">R2&#95;10&#95;1</td><td align="center" rowspan="1" colspan="1">36,932.0</td><td align="center" rowspan="1" colspan="1">0.14</td><td align="center" rowspan="1" colspan="1">36,891.3</td><td align="center" rowspan="1" colspan="1">0.03</td><td align="center" rowspan="1" colspan="1">36,899.4</td><td align="center" rowspan="1" colspan="1">0.05</td><td align="center" rowspan="1" colspan="1">36,881.0</td></tr><tr><td rowspan="1" colspan="1">R2&#95;10&#95;2</td><td align="center" rowspan="1" colspan="1">31,349.5</td><td align="center" rowspan="1" colspan="1">0.34</td><td align="center" rowspan="1" colspan="1">31,384.7</td><td align="center" rowspan="1" colspan="1">0.46</td><td align="center" rowspan="1" colspan="1">31,296.2</td><td align="center" rowspan="1" colspan="1">0.17</td><td align="center" rowspan="1" colspan="1">31,241.9</td></tr><tr><td rowspan="1" colspan="1">R2&#95;10&#95;3</td><td align="center" rowspan="1" colspan="1">24,469.2</td><td align="center" rowspan="1" colspan="1">0.29</td><td align="center" rowspan="1" colspan="1">24,429.7</td><td align="center" rowspan="1" colspan="1">0.13</td><td align="center" rowspan="1" colspan="1">24,422.1</td><td align="center" rowspan="1" colspan="1">0.09</td><td align="center" rowspan="1" colspan="1">24,399.0</td></tr><tr><td rowspan="1" colspan="1">R2&#95;10&#95;4</td><td align="center" rowspan="1" colspan="1">17,926.3</td><td align="center" rowspan="1" colspan="1">0.64</td><td align="center" rowspan="1" colspan="1">17,870.1</td><td align="center" rowspan="1" colspan="1">0.33</td><td align="center" rowspan="1" colspan="1">17,968.1</td><td align="center" rowspan="1" colspan="1">0.88</td><td align="center" rowspan="1" colspan="1">17,811.5</td></tr><tr><td rowspan="1" colspan="1">R2&#95;10&#95;5</td><td align="center" rowspan="1" colspan="1">34,181.1</td><td align="center" rowspan="1" colspan="1">0.14</td><td align="center" rowspan="1" colspan="1">34,195.3</td><td align="center" rowspan="1" colspan="1">0.18</td><td align="center" rowspan="1" colspan="1">34,233.0</td><td align="center" rowspan="1" colspan="1">0.29</td><td align="center" rowspan="1" colspan="1">34,132.8</td></tr><tr><td rowspan="1" colspan="1">R2&#95;10&#95;6</td><td align="center" rowspan="1" colspan="1">29,239.6</td><td align="center" rowspan="1" colspan="1">0.39</td><td align="center" rowspan="1" colspan="1">29,179.4</td><td align="center" rowspan="1" colspan="1">0.19</td><td align="center" rowspan="1" colspan="1">29,215.3</td><td align="center" rowspan="1" colspan="1">0.31</td><td align="center" rowspan="1" colspan="1">29,124.7</td></tr><tr><td rowspan="1" colspan="1">R2&#95;10&#95;7</td><td align="center" rowspan="1" colspan="1">23,237.3</td><td align="center" rowspan="1" colspan="1">0.58</td><td align="center" rowspan="1" colspan="1">23,305.2</td><td align="center" rowspan="1" colspan="1">0.88</td><td align="center" rowspan="1" colspan="1">23,243.8</td><td align="center" rowspan="1" colspan="1">0.61</td><td align="center" rowspan="1" colspan="1">23,102.2</td></tr><tr><td rowspan="1" colspan="1">R2&#95;10&#95;8</td><td align="center" rowspan="1" colspan="1">17,505.4</td><td align="center" rowspan="1" colspan="1">0.58</td><td align="center" rowspan="1" colspan="1">17,463.3</td><td align="center" rowspan="1" colspan="1">0.34</td><td align="center" rowspan="1" colspan="1">17,512.7</td><td align="center" rowspan="1" colspan="1">0.63</td><td align="center" rowspan="1" colspan="1">17,403.8</td></tr><tr><td rowspan="1" colspan="1">R2&#95;10&#95;9</td><td align="center" rowspan="1" colspan="1">32,089.8</td><td align="center" rowspan="1" colspan="1">0.31</td><td align="center" rowspan="1" colspan="1">32,058.0</td><td align="center" rowspan="1" colspan="1">0.21</td><td align="center" rowspan="1" colspan="1">32,104.9</td><td align="center" rowspan="1" colspan="1">0.36</td><td align="center" rowspan="1" colspan="1">31,990.6</td></tr><tr><td rowspan="1" colspan="1">R2&#95;10&#95;10</td><td align="center" rowspan="1" colspan="1">29,934.0</td><td align="center" rowspan="1" colspan="1">0.31</td><td align="center" rowspan="1" colspan="1">29,882.3</td><td align="center" rowspan="1" colspan="1">0.14</td><td align="center" rowspan="1" colspan="1">29,956.9</td><td align="center" rowspan="1" colspan="1">0.39</td><td align="center" rowspan="1" colspan="1">29,840.5</td></tr><tr><td rowspan="1" colspan="1">RC1&#95;10&#95;1</td><td align="center" rowspan="1" colspan="1">46,018.1</td><td align="center" rowspan="1" colspan="1">0.50</td><td align="center" rowspan="1" colspan="1">46,047.3</td><td align="center" rowspan="1" colspan="1">0.56</td><td align="center" rowspan="1" colspan="1">45,948.5</td><td align="center" rowspan="1" colspan="1">0.34</td><td align="center" rowspan="1" colspan="1">45,790.8</td></tr><tr><td rowspan="1" colspan="1">RC1&#95;10&#95;2</td><td align="center" rowspan="1" colspan="1">44,078.7</td><td align="center" rowspan="1" colspan="1">0.92</td><td align="center" rowspan="1" colspan="1">43,892.6</td><td align="center" rowspan="1" colspan="1">0.49</td><td align="center" rowspan="1" colspan="1">43,870.6</td><td align="center" rowspan="1" colspan="1">0.44</td><td align="center" rowspan="1" colspan="1">43,678.3</td></tr><tr><td rowspan="1" colspan="1">RC1&#95;10&#95;3</td><td align="center" rowspan="1" colspan="1">42,537.9</td><td align="center" rowspan="1" colspan="1">0.99</td><td align="center" rowspan="1" colspan="1">42,311.1</td><td align="center" rowspan="1" colspan="1">0.45</td><td align="center" rowspan="1" colspan="1">42,338.0</td><td align="center" rowspan="1" colspan="1">0.51</td><td align="center" rowspan="1" colspan="1">42,122.0</td></tr><tr><td rowspan="1" colspan="1">RC1&#95;10&#95;4</td><td align="center" rowspan="1" colspan="1">41,669.5</td><td align="center" rowspan="1" colspan="1">0.75</td><td align="center" rowspan="1" colspan="1">41,577.1</td><td align="center" rowspan="1" colspan="1">0.53</td><td align="center" rowspan="1" colspan="1">41,469.2</td><td align="center" rowspan="1" colspan="1">0.27</td><td align="center" rowspan="1" colspan="1">41,357.4</td></tr><tr><td rowspan="1" colspan="1">RC1&#95;10&#95;5</td><td align="center" rowspan="1" colspan="1">45,333.7</td><td align="center" rowspan="1" colspan="1">0.68</td><td align="center" rowspan="1" colspan="1">45,349.6</td><td align="center" rowspan="1" colspan="1">0.71</td><td align="center" rowspan="1" colspan="1">45,235.5</td><td align="center" rowspan="1" colspan="1">0.46</td><td align="center" rowspan="1" colspan="1">45,028.1</td></tr><tr><td rowspan="1" colspan="1">RC1&#95;10&#95;6</td><td align="center" rowspan="1" colspan="1">45,176.9</td><td align="center" rowspan="1" colspan="1">0.61</td><td align="center" rowspan="1" colspan="1">45,359.9</td><td align="center" rowspan="1" colspan="1">1.02</td><td align="center" rowspan="1" colspan="1">45,144.0</td><td align="center" rowspan="1" colspan="1">0.54</td><td align="center" rowspan="1" colspan="1">44,903.6</td></tr><tr><td rowspan="1" colspan="1">RC1&#95;10&#95;7</td><td align="center" rowspan="1" colspan="1">44,742.2</td><td align="center" rowspan="1" colspan="1">0.73</td><td align="center" rowspan="1" colspan="1">44,657.9</td><td align="center" rowspan="1" colspan="1">0.54</td><td align="center" rowspan="1" colspan="1">44,686.2</td><td align="center" rowspan="1" colspan="1">0.61</td><td align="center" rowspan="1" colspan="1">44,417.1</td></tr><tr><td rowspan="1" colspan="1">RC1&#95;10&#95;8</td><td align="center" rowspan="1" colspan="1">44,221.9</td><td align="center" rowspan="1" colspan="1">0.70</td><td align="center" rowspan="1" colspan="1">44,145.6</td><td align="center" rowspan="1" colspan="1">0.52</td><td align="center" rowspan="1" colspan="1">44,130.8</td><td align="center" rowspan="1" colspan="1">0.49</td><td align="center" rowspan="1" colspan="1">43,916.5</td></tr><tr><td rowspan="1" colspan="1">RC1&#95;10&#95;9</td><td align="center" rowspan="1" colspan="1">44,153.4</td><td align="center" rowspan="1" colspan="1">0.67</td><td align="center" rowspan="1" colspan="1">44,087.3</td><td align="center" rowspan="1" colspan="1">0.52</td><td align="center" rowspan="1" colspan="1">44,072.4</td><td align="center" rowspan="1" colspan="1">0.49</td><td align="center" rowspan="1" colspan="1">43,858.1</td></tr><tr><td rowspan="1" colspan="1">RC1&#95;10&#95;10</td><td align="center" rowspan="1" colspan="1">43,815.9</td><td align="center" rowspan="1" colspan="1">0.65</td><td align="center" rowspan="1" colspan="1">43,635.1</td><td align="center" rowspan="1" colspan="1">0.23</td><td align="center" rowspan="1" colspan="1">43,745.6</td><td align="center" rowspan="1" colspan="1">0.49</td><td align="center" rowspan="1" colspan="1">43,533.7</td></tr><tr><td rowspan="1" colspan="1">RC2&#95;10&#95;1</td><td align="center" rowspan="1" colspan="1">28,168.0</td><td align="center" rowspan="1" colspan="1">0.16</td><td align="center" rowspan="1" colspan="1">28,192.1</td><td align="center" rowspan="1" colspan="1">0.25</td><td align="center" rowspan="1" colspan="1">28,190.8</td><td align="center" rowspan="1" colspan="1">0.24</td><td align="center" rowspan="1" colspan="1">28,122.6</td></tr><tr><td rowspan="1" colspan="1">RC2&#95;10&#95;2</td><td align="center" rowspan="1" colspan="1">24,276.0</td><td align="center" rowspan="1" colspan="1">0.11</td><td align="center" rowspan="1" colspan="1">24,268.6</td><td align="center" rowspan="1" colspan="1">0.08</td><td align="center" rowspan="1" colspan="1">24,271.7</td><td align="center" rowspan="1" colspan="1">0.10</td><td align="center" rowspan="1" colspan="1">24,248.6</td></tr><tr><td rowspan="1" colspan="1">RC2&#95;10&#95;3</td><td align="center" rowspan="1" colspan="1">19,673.1</td><td align="center" rowspan="1" colspan="1">0.28</td><td align="center" rowspan="1" colspan="1">19,665.6</td><td align="center" rowspan="1" colspan="1">0.24</td><td align="center" rowspan="1" colspan="1">19,747.9</td><td align="center" rowspan="1" colspan="1">0.66</td><td align="center" rowspan="1" colspan="1">19,618.1</td></tr><tr><td rowspan="1" colspan="1">RC2&#95;10&#95;4</td><td align="center" rowspan="1" colspan="1">15,744.6</td><td align="center" rowspan="1" colspan="1">0.56</td><td align="center" rowspan="1" colspan="1">15,716.2</td><td align="center" rowspan="1" colspan="1">0.38</td><td align="center" rowspan="1" colspan="1">15,804.9</td><td align="center" rowspan="1" colspan="1">0.94</td><td align="center" rowspan="1" colspan="1">15,657.0</td></tr><tr><td rowspan="1" colspan="1">RC2&#95;10&#95;5</td><td align="center" rowspan="1" colspan="1">25,851.7</td><td align="center" rowspan="1" colspan="1">0.21</td><td align="center" rowspan="1" colspan="1">25,862.2</td><td align="center" rowspan="1" colspan="1">0.25</td><td align="center" rowspan="1" colspan="1">25,892.3</td><td align="center" rowspan="1" colspan="1">0.37</td><td align="center" rowspan="1" colspan="1">25,797.5</td></tr><tr><td rowspan="1" colspan="1">RC2&#95;10&#95;6</td><td align="center" rowspan="1" colspan="1">25,854.3</td><td align="center" rowspan="1" colspan="1">0.28</td><td align="center" rowspan="1" colspan="1">25,823.0</td><td align="center" rowspan="1" colspan="1">0.16</td><td align="center" rowspan="1" colspan="1">25,871.0</td><td align="center" rowspan="1" colspan="1">0.34</td><td align="center" rowspan="1" colspan="1">25,782.5</td></tr><tr><td rowspan="1" colspan="1">RC2&#95;10&#95;7</td><td align="center" rowspan="1" colspan="1">24,458.4</td><td align="center" rowspan="1" colspan="1">0.26</td><td align="center" rowspan="1" colspan="1">24,456.6</td><td align="center" rowspan="1" colspan="1">0.25</td><td align="center" rowspan="1" colspan="1">24,451.7</td><td align="center" rowspan="1" colspan="1">0.23</td><td align="center" rowspan="1" colspan="1">24,395.8</td></tr><tr><td rowspan="1" colspan="1">RC2&#95;10&#95;8</td><td align="center" rowspan="1" colspan="1">23,331.9</td><td align="center" rowspan="1" colspan="1">0.22</td><td align="center" rowspan="1" colspan="1">23,307.9</td><td align="center" rowspan="1" colspan="1">0.12</td><td align="center" rowspan="1" colspan="1">23,332.3</td><td align="center" rowspan="1" colspan="1">0.22</td><td align="center" rowspan="1" colspan="1">23,280.2</td></tr><tr><td rowspan="1" colspan="1">RC2&#95;10&#95;9</td><td align="center" rowspan="1" colspan="1">22,784.8</td><td align="center" rowspan="1" colspan="1">0.23</td><td align="center" rowspan="1" colspan="1">22,796.2</td><td align="center" rowspan="1" colspan="1">0.28</td><td align="center" rowspan="1" colspan="1">22,859.3</td><td align="center" rowspan="1" colspan="1">0.56</td><td align="center" rowspan="1" colspan="1">22,731.6</td></tr><tr><td rowspan="1" colspan="1">RC2&#95;10&#95;10</td><td align="center" rowspan="1" colspan="1">21,838.2</td><td align="center" rowspan="1" colspan="1">0.47</td><td align="center" rowspan="1" colspan="1">21,862.3</td><td align="center" rowspan="1" colspan="1">0.58</td><td align="center" rowspan="1" colspan="1">21,848.3</td><td align="center" rowspan="1" colspan="1">0.52</td><td align="center" rowspan="1" colspan="1">21,736.1</td></tr><tr><td rowspan="1" colspan="1">Mean</td><td align="center" rowspan="1" colspan="1">33,296.4</td><td align="center" rowspan="1" colspan="1">0.40</td><td align="center" rowspan="1" colspan="1">33,265.5</td><td align="center" rowspan="1" colspan="1">0.32</td><td align="center" rowspan="1" colspan="1">33,245.1</td><td align="center" rowspan="1" colspan="1">0.29</td><td align="center" rowspan="1" colspan="1">33,143.8</td></tr><tr><td rowspan="1" colspan="1">Gap of mean</td><td align="center" rowspan="1" colspan="1" /><td align="center" rowspan="1" colspan="1">0.46</td><td align="center" rowspan="1" colspan="1" /><td align="center" rowspan="1" colspan="1">0.37</td><td align="center" rowspan="1" colspan="1" /><td align="center" rowspan="1" colspan="1">0.31</td><td align="center" rowspan="1" colspan="1" /></tr></tbody></table> </ephtml> </p>

7. Conclusion

<p>We introduce PyVRP, an open-source Python package for solving the vehicle routing problem with time windows and show numerically that PyVRP achieves excellent performance on this problem variant. The package has minimal dependencies and can easily be installed in precompiled format from the Python package index. The package's implementation is flexible and can easily be extended with new solution techniques and vehicle routing problem variants. Our hope is that PyVRP facilitates furthering the state of the art in VRP solving by enabling researchers and practitioners to easily and quickly build on a state-of-the-art solver.</p>

Acknowledgments

<p>The authors are grateful to Penghui Guo for transferring the "PyVRP" name on the Python package index to them. Leon Lan would like to thank TKI Dinalog, Topsector Logistics, and the Dutch Ministry of Economic Affairs and Climate Policy for funding this project.</p>

Footnotes

<p class="blist"> 1 See http://vrp.galgos.inf.puc-rio.br/. </p> <p class="blist"> 2 See https://pyvrp.org/. </p> <p class="blist"> 3 See https://github.com/PyVRP/PyVRP. </p> <p class="blist"> 4 See https://pyvrp.org/dev/new_vrp_variants.html. </p> <p class="blist"> 5 Corresponding author </p>

References

<p class="blist"> Accorsi L, Lodi A, Vigo D (2022). Guidelines for the computational testing of machine learning approaches to vehicle routing problems. Oper. Res. Lett. 50 (2): 229–234. </p> <p class="blist"> Builuk I (2023). A new solver for rich vehicle routing problem. http://dx.doi.org/10.5281/zenodo.4624037, https://github.com/reinterpretcat/vrp/tree/v1.22.1. </p> <p class="blist"> Coupey J, Nicod JM, Varnier C (2023). VROOM v1.13, vehicle routing open-source optimization machine. Accessed August 17, 2023, http://vroom-project.org/. </p> <p class="blist"> Helsgaun K (2017). An extension of the Lin-Kernighan-Helsgaun TSP solver for constrained traveling salesman and vehicle routing problems. Technical report, Roskilde University, Roskilde, Denmark. </p> <p class="blist"> Homberger J, Gehring H (1999). Two evolutionary metaheuristics for the vehicle routing problem with time windows. INFOR Inform. Systems Oper. Res. 37 (3): 297–318. </p> <p class="blist"> 6 Kool W, Juninck JO, Roos E, Cornelissen K, Agterberg P, van Hoorn J, Visser T (2022). Hybrid genetic search for the vehicle routing problem with time windows: A high-performance implementation. Technical report. https://wouterkool.github.io/pdf/paper-kool-hgs-vrptw.pdf. </p> <p class="blist"> 7 Kwon C (2022). PyHygese. https://github.com/chkwon/PyHygese. </p> <p class="blist"> 8 Kwon YD, Choo J, Bae D, Kim J, Hottung A (2022). Cost shaping via reinforcement learning for vehicle routing problems. Technical report. https://github.com/ortec/euro-neurips-vrp-2022-quickstart/raw/main/papers/Team_SB.pdf. </p> <p class="blist"> 9 Lan L (2023). VRPLIB. https://github.com/leonlan/VRPLIB. </p> <p class="blist"> Nagata Y, Kobayashi S (2010). A memetic algorithm for the pickup and delivery problem with time windows using selective route exchange crossover. Internat. Conf. Parallel Problem Solving Nature (Springer Nature Switzerland, Cham, Switzerland), 536–545. </p> <p class="blist"> Perron L, Furnon V (2022). OR-Tools. https://developers.google.com/optimization/. </p> <p class="blist"> Pessoa A, Sadykov R, Uchoa E, Vanderbeck F (2020). A generic exact solver for vehicle routing and related problems. Math. Programming 183 : 483–523. </p> <p class="blist"> Toth P, Vigo D (2003). The granular tabu search and its application to the vehicle-routing problem. INFORMS J. Comput. 15 (4): 333–346. </p> <p class="blist"> Toth P, Vigo D, eds. (2014). Vehicle Routing: Problems, Methods, and Applications, 2nd ed. (Society for Industrial and Applied Mathematics, Philadelphia). </p> <p class="blist"> Uchoa E, Pecin D, Pessoa A, Poggi M, Vidal T, Subramanian A (2017). New benchmark instances for the capacitated vehicle routing problem. Eur. J. Oper. Res. 257 (3): 845–858. </p> <p class="blist"> Van Doorn J, Lan L, Pentinga L, Wouda NA (2022). Solving a static and dynamic VRP with time windows using hybrid genetic search and simulation. Technical report. https://github.com/ortec/euro-neurips-vrp-2022-quickstart/raw/main/papers/OptiML.pdf. </p> <p class="blist"> Vidal T (2022). Hybrid genetic search for the CVRP: Open-source implementation and SWAP* neighborhood. Comput. Oper. Res. 140 : 105643. </p> <p class="blist"> Vidal T, Crainic TG, Gendreau M, Prins C (2013). A hybrid genetic algorithm with adaptive diversity management for a large class of vehicle routing problems with time-windows. Comput. Oper. Res. 40 (1): 475–489. </p> <p class="blist"> Wouda NA, Lan L, Kool W (2023). PyVRP: A high-performance VRP solver package. https://dx.doi.org/10.1287/ijoc.2023.0055.cd, https://github.com/INFORMSJoC/2023.0055. </p>
<p class="aug"> <p>By Niels A. Wouda; Leon Lan and Wouter Kool</p> <p>Reported by Author; Author; Author</p> </p>