Education

The pyvrp.educate module contains classes and methods responsible for educating (improving) a newly created offspring solution. This happens just after pyvrp.crossover is performed by the GeneticAlgorithm.

class LocalSearch(data: ProblemData, penalty_manager: PenaltyManager, rng: XorShift128, neighbours: List[List[int]])

LocalSearch educator. This educator is able to explore a granular neighbourhood in a very efficient manner using user-provided node and route operators. This quickly results in much improved (‘educated’) solutions.

Parameters:
data

Data object describing the problem to be solved.

penalty_manager

Penalty manager to use.

rng

Random number generator.

neighbours

List of lists that defines the local search neighbourhood.

Methods

add_node_operator(op)

Adds a node operator to this local search object.

add_route_operator(op)

Adds a route operator to this local search object.

get_neighbours()

Returns the granular neighbourhood currently used by the local search.

intensify(individual[, ...])

This method uses the intensifying route operators on this local search object to improve the given individual.

run(individual, should_intensify)

This method uses the search() and intensify() methods to iteratively improve the given individual.

search(individual)

This method uses the node operators on this local search object to improve the given individual.

set_neighbours(neighbours)

Convenience method to replace the current granular neighbourhood used by the local search object.

add_node_operator(op)

Adds a node operator to this local search object. The node operator will be used by search() to improve an individual.

Parameters:
op

The node operator to add to this local search object.

add_route_operator(op)

Adds a route operator to this local search object. The route operator will be used by intensify() to improve an individual using more expensive route operators.

Parameters:
op

The route operator to add to this local search object.

get_neighbours() List[List[int]]

Returns the granular neighbourhood currently used by the local search.

Returns:
list

The current granular neighbourhood.

intensify(individual: Individual, overlap_tolerance_degrees: int = 0) Individual

This method uses the intensifying route operators on this local search object to improve the given individual. To limit the computation demands of intensification, the overlap_tolerance_degrees argument can be used to limit the number of route pairs that are evaluated.

Parameters:
individual

The individual to improve.

overlap_tolerance_degrees

This method evaluates improving moves between route pairs. To limit computational efforts, by default not all route pairs are considered: only those route pairs that share some overlap when considering their center’s angle from the depot are evaluted. This parameter controls the amount of overlap needed before two routes are evaluated.

Returns:
Individual

The improved individual. This is not the same object as the individual that was passed in.

Raises:
RuntimeError

When this method is called before registering route operators. Operators can be registered using add_route_operator().

run(individual: Individual, should_intensify: bool) Individual

This method uses the search() and intensify() methods to iteratively improve the given individual. First, search() is applied. Thereafter, if should_intensify is true, intensify() is applied. This process repeats until no further improvements are found. Finally, the improved solution is returned.

Parameters:
individual

The individual to improve through local search.

should_intensify

Whether to apply intensify(). Intensification can provide much better solutions, but is computationally demanding. By default intensification is applied.

Returns:
Individual

The improved individual. This is not the same object as the individual that was passed in.

search(individual: Individual) Individual

This method uses the node operators on this local search object to improve the given individual.

Parameters:
individual

The individual to improve.

Returns:
Individual

The improved individual. This is not the same object as the individual that was passed in.

Raises:
RuntimeError

When this method is called before registering node operators. Operators can be registered using add_node_operator().

set_neighbours(neighbours: List[List[int]])

Convenience method to replace the current granular neighbourhood used by the local search object.

Parameters:
neighbours

A new granular neighbourhood.

class NeighbourhoodParams(weight_wait_time: float = 0.2, weight_time_warp: float = 1.0, nb_granular: int = 40, symmetric_proximity: bool = True, symmetric_neighbours: bool = False)

Configuration for calculating a granular neighbourhood.

Raises:
ValueError

When nb_granular is non-positive.

Attributes:
weight_wait_time

TODO

weight_time_warp

TODO

nb_granular

Number of other clients that are in each client’s granular neighbourhood. This parameter determines the size of the overall neighbourhood.

symmetric_proximity

TODO

symmetric_neighbours

TODO

compute_neighbours(data: ProblemData, params: NeighbourhoodParams = NeighbourhoodParams(weight_wait_time=0.2, weight_time_warp=1.0, nb_granular=40, symmetric_proximity=True, symmetric_neighbours=False)) List[List[int]]

Computes neighbours defining the neighbourhood for a problem instance.

Parameters:
data

ProblemData for which to compute the neighbourhood.

params

NeighbourhoodParams that define how the neighbourhood is computed.

Returns:
Neighbours

A list of list of integers representing the neighbours for each client. The first element represents the depot and is an empty list.

Node operators

Instances of these operators can be added to the LocalSearch object via the add_node_operator() method. As a convenience, the pyvrp.educate module makes all these operators available as NODE_OPERATORS:

from pyvrp.educate import NODE_OPERATORS
class Exchange10(data: pyvrp.ProblemData, penalty_manager: pyvrp.PenaltyManager)
class Exchange20(data: pyvrp.ProblemData, penalty_manager: pyvrp.PenaltyManager)
class Exchange30(data: pyvrp.ProblemData, penalty_manager: pyvrp.PenaltyManager)
class Exchange11(data: pyvrp.ProblemData, penalty_manager: pyvrp.PenaltyManager)
class Exchange21(data: pyvrp.ProblemData, penalty_manager: pyvrp.PenaltyManager)
class Exchange31(data: pyvrp.ProblemData, penalty_manager: pyvrp.PenaltyManager)
class Exchange22(data: pyvrp.ProblemData, penalty_manager: pyvrp.PenaltyManager)
class Exchange32(data: pyvrp.ProblemData, penalty_manager: pyvrp.PenaltyManager)
class Exchange33(data: pyvrp.ProblemData, penalty_manager: pyvrp.PenaltyManager)
class MoveTwoClientsReversed(data: pyvrp.ProblemData, penalty_manager: pyvrp.PenaltyManager)
class TwoOpt(data: pyvrp.ProblemData, penalty_manager: pyvrp.PenaltyManager)

Route operators

Instances of these operators can be added to the LocalSearch object via the add_route_operator() method. As a convenience, the pyvrp.educate module makes all these operators available as ROUTE_OPERATORS:

from pyvrp.educate import ROUTE_OPERATORS
class RelocateStar(data: pyvrp.ProblemData, penalty_manager: pyvrp.PenaltyManager)
class SwapStar(data: pyvrp.ProblemData, penalty_manager: pyvrp.PenaltyManager)