Skip to content

pymetaheuristics

Metaheuristics for optimization problems in plain Python, with no dependencies. You describe the problem: how to make a solution, how to score it, which solutions are allowed, and whether to minimize or maximize. Then you hand it to a heuristic, which returns the best solution it found.

Metaheuristics are a good fit when the search space is too large to enumerate and no exact solver suits the problem: combinatorial problems (routing, packing, scheduling, assignment) or black-box objectives. They give good solutions quickly, but they don't prove those solutions are optimal.

The library ships with:

  • Genetic Algorithm: genetic_algorithm(), a population-based search with pluggable selection, crossover and mutation.
  • Simulated Annealing: simulated_annealing(), a single-trajectory search with pluggable neighborhoods and cooling schedules.
  • A benchmark suite of Knapsack, TSP and continuous problems with known optima.

Every heuristic is a plain function with the same shape, so you can swap algorithms without touching the problem. This documentation describes the API as of 0.2.

Install

Requires Python 3.12+.

pip install pymetaheuristics
uv add pymetaheuristics

Quickstart

Find a short closed tour through five points:

import math
from pymetaheuristics.core import Problem, max_iterations
from pymetaheuristics.simulated_annealing import simulated_annealing

cities = [(0, 0), (0, 2), (3, 2), (3, 0), (1, 1)]


def tour_length(tour):
    return sum(math.dist(cities[tour[i - 1]], cities[tour[i]])
               for i in range(len(tour)))


problem = Problem(
    generate=lambda rng: rng.sample(range(len(cities)), len(cities)),
    evaluate=tour_length,
)  # direction defaults to Direction.MINIMIZE

result = simulated_annealing(problem, stop=max_iterations(500), rng=0)
print(result.best_solution, round(result.best_value, 3))

Switching heuristics changes only the call:

result = simulated_annealing(problem, stop=max_iterations(500), rng=0)
from pymetaheuristics.genetic_algorithm import genetic_algorithm
from pymetaheuristics.genetic_algorithm.steps.crossovers import (
    pmx_single_point)

result = genetic_algorithm(problem, stop=max_iterations(50), rng=0,
                           crossover=pmx_single_point)
from pymetaheuristics.artificial_bee_colony import artificial_bee_colony

result = artificial_bee_colony(problem, stop=max_iterations(50), rng=0)

How well does it work?

Every heuristic against random search on the benchmark suite, with the same budget of 2000 evaluations over 20 seeds (details):

Gap closed versus random search Time per run

On TSP all three heuristics find the optimum on every seed and on the sphere the GA and SA close over 99.7% of random search's gap, while random search stays far off. Rastrigin is hard for all of them with this budget. A full run takes about 10-30 ms.

What can I do?

I want to... Go to
describe my problem, minimizing or maximizing Problem and direction
forbid invalid solutions (reject, repair, penalty) Constraints
stop by iterations, evaluations, time or target value Stopping
use a built-in neighborhood, selection, crossover or mutation Operators
search with a population Genetic Algorithm
search with one moving solution Simulated Annealing
read the best solution and plot convergence Results and history
get the same run twice Reproducibility
see complete programs Worked examples
write my own operator, stop or heuristic Extending
test against problems with known optima Benchmark suite
look up a function Reference

Where next