Skip to main content

Move Types

Move types drive the evaluation of neighbor states when using the local search solver.

An assignment of objects to containers defines a state. The initial state is the initial assignment, which the user provides and which generally represents the current state of the world. The search runs in iterations. In each step, the constraint and objective functions are evaluated on a set of neighboring states (the exact set is defined by the move types in use). The best neighbor---the one that minimizes the objective without breaking constraints---is selected and carried into the next step. When no neighbor improves the objective, the search has reached a local minimum and stops; it also stops when a timeout is reached. The state in the last step is returned as the final assignment.

Each move type defines a set of neighbors to evaluate. For example, the Single move type evaluates every state reachable by moving exactly one object to a different container, while Swap exchanges two objects. Multiple move types can be combined, and they are applied in order: the first is used until it finds no improvement, then the second, and so on.

Common logic

The local search solver orders all containers from hot to cold, by how much each contributes to the overall objective. Moves out of the hottest container are evaluated first; if the best of them improves the objective, it is applied and the search moves on. Otherwise the next-hottest container is considered, and so on. Move types therefore do not control the order in which source containers are selected.

function find_best_neighbor(state):
for source_container in sort_from_hot_to_cold(all_containers):
for move_type in move_types:
best_move = move_type.get_best_move_from(source_container)
new_state = apply(state, best_move)
if evaluate_objective(new_state) < evaluate_objective(state):
return new_state
return null

function get_final_assignment(initial_assignment):
state = initial_assignment
while timeout not exceeded:
best_neighbor = find_best_neighbor(state)
if best_neighbor == null:
break
state = best_neighbor
return state

Every move type implements get_best_move_from(source_container), with the guarantee that it evaluates all the moves of that type which take some object out of source_container and returns the best one.

Move types available

Each move type is implemented by a class that inherits from MoveType. The summary below lists the move types; dedicated pages for each will be linked from this table.

NameDescription
SingleTries moving every object in the source container to every possible destination container.
Single FastLike Single, but stops after fully exploring the first object that improves the objective, so it may not explore all objects in the source container.
Single GreedyTries moving every object to every possible destination, prioritizing destinations by how hot they are, and stops as soon as an improving move is found. Single threaded.
Single Random BatchesLike Single Greedy, but processes multiple containers at a time to benefit from multi-threading, stopping as soon as an improving move is found.
SwapTries swapping each object in the source container with every other object in every possible destination container.
Swap Full ContainersTries exchanging all objects in the source container with all objects in every possible destination container.
Swap Full With Empty ContainersTries moving all objects in the source container to every possible empty destination container.
Swap SampledLike Swap, but evaluates only a sampled subset of all possible swaps, controlled by parameters.
Triple LoopTries moving every triplet of objects in a cycle, where one object is from the source container and the other two are from different destination containers.
KL SearchInspired by the Kernighan–Lin algorithm: sequentially picks the move (in either direction) with the best objective change regardless of improvement, then keeps the point with the minimum objective.
Single ChainTries all pairs of moves where an object leaves the hot container and a second object from another container takes its place. Prefer Single End Chain.
Single End ChainTries all pairs of moves where an object moves from the hot container to a destination, and a second object from that destination moves to another destination.
Single Chain FastLike Single Chain, but evaluates all moves in parallel and returns as soon as an improving move is found.
Single Random Object StratifiedEvaluates moving a sample of objects to a pre-defined container.
Single Random StratifiedTries moving every object in the source container to a random sample of destination containers drawn evenly from similarity classes.
Single Coldest StratifiedLike Single Random Stratified, but picks the coldest containers within each similarity class instead of a random sample.
Group Move With Hint StrategiesMoves a related set of objects together, guided by hint strategies.
Group RoutingRoutes groups of objects together between scope items.
Greedy Group To Scope ItemGreedily moves a group's objects into a scope item.
Colocate GroupsTries moving a related set of objects in a scope item to every possible combination of containers in every different scope item.
Replica DropDrops replicas of an object when moving it.
Fixed DestTries moving every object in the source container to a specified destination container.
Fixed SourceTries moving every object out of one or more specified source containers.
Fixed Dest Multi MoveTries moving every set of related objects from the hot container to a specified destination container.
Fixed Source Multi MoveTries moving every set of related objects from a specified source container to the hot container.
Fixed Dest Swap Multi MoveTries swapping every set of related objects between the hot container and a specified destination container, supporting uneven 1:k swaps.