Skip to main content

KAYROS

PyPI SWH

KAYROS is an exact & anytime solver for duration-minimization time-dependent vehicle routing problems, TDVRPTW (with time windows) and TDVRP, benchmarked on the canonical MAMUT-routing TD instance families.

The name is a nod to Kairos, the ancient Greek notion of the right, opportune moment, fitting for a time-dependent solver where when each route departs is itself a decision. It is also a recursive acronym: Kayros Anytime-Yielding Routing Optimization Solver.

Status: beta (v1.6.1), developed as part of a PhD. Two solving modes on one exact time-dependent engine: an anytime time-dependent iterated local search that produced the large majority of the MAMUT store's best-known solutions (minimizing Duration or, since 1.2.0, FleetCostDuration — a fleet fixed cost plus duration, as priced by the Blauth2024 family; since 1.3.0 a fleet-descent route-elimination phase contests the fleet size itself, the mechanism behind the first best-known solutions beaten on that family; since 1.4.0 the first solution is published within a fraction of a second at every instance size, where it used to take minutes at n = 1000; since 1.5.0 the search starts from a deliberately over-provisioned fleet and shrinks it, which is worth double-digit percentages where waiting dominates; 1.6.0 adds an opt-in penalty-tolerant time-window squeeze and a K-capped confined search, the campaign tools behind the warm-started refresh that leaves all thirty Blauth2024 records kayros-held), and an audited exact branch-price-and-cut component (kayros.lera) whose multi-gate certification protocol stands behind the store's proven-optimal solutions (704 as of 2026-08-08: one certificate was retracted after a checker-valid counterexample and the pricing defect behind it repaired in 1.5.1, the 2026-08-06 re-certification re-derived 466 of 468 earlier stamps four-way bit-exactly on the repaired build with one withdrawn on a protocol disagreement, and the Poryos2026 families received their first 238 certificates). Every run ends with an honest verdict (optimum, time limit, or resource limit), never a silent kill.

Install

pip install kayros    # or: uv add kayros / uv pip install kayros

This pulls everything, including the benchmark loaders and the reference checker (mamut-routing-lib). Version 1.6.1 requires mamut-routing-lib>=0.6.0,<0.12: KAYROS implements the historical td-fold/1 contract, while checker 0.12 introduced td-fold/2. A mixed environment can fail the final objective-equality check even when the values differ by only a final floating-point bit. Upgrade existing environments with python -m pip install --upgrade kayros, or pin mamut-routing-lib==0.11.0 when retaining an older KAYROS release. Newer checker versions will be admitted after numerical compatibility is validated. For development:

git clone https://github.com/0nyr/kayros && cd kayros
pip install -e . --group dev    # pip >= 25.1 (or: uv pip install -e . --group dev)

Requirements: Python ≥ 3.11. Building from source (sdist or checkout) additionally needs a C++23 compiler, CMake ≥ 3.26 (fetched automatically by the build backend when missing) and Boost.Graph headers+library; the HiGHS LP solver is fetched and built statically by CMake when no install is found.

Usage

Anytime heuristic solve: iterated local search over granular candidate lists, streaming every new incumbent:

import kayros

# Any MAMUT-routing TD instance (.vrp.json with its .atf.json sidecar next to it)
instance_path = "benchmarks/TDVRPTW/Dabia2013/n=25/C101.vrp.json"
solution = kayros.solve(instance_path, time_limit=10.0, seed=42)
print(solution.duration, solution.num_routes, solution.status)

# Anytime: react to every new incumbent while the solve keeps running
def on_incumbent(incumbent, routes):
    print(f"[{incumbent.seconds:7.2f}s] {incumbent.value:.6f} ({incumbent.origin})")

solution = kayros.solve(instance_path, time_limit=60.0, on_incumbent=on_incumbent)

Instances are loaded without re-verifying their artifact digests, because materialization is deterministic and the check costs minutes and gigabytes of peak memory at n = 1000. Pass verify=True (to kayros.solve on a path, or to kayros.io.load_instance) on test runs and on the first run over data you have not used before: it re-derives the sidecar digests and the ATF digest and pins them against what the instance file declares, which is what catches a truncated download or a mismatched sidecar. Without it those failures are silent.

The default strategy is "ils" (single-trajectory iterated local search), picked over the alternatives in a 20,808-run head-to-head across five TD families at n=10..1000, with the margin growing with instance size. A MAX-MIN TD ant colony remains available as Params(strategy="aco"), and Params(num_neighbours=0) restores exhaustive (non-granular) local-search enumeration; both are alternatives for experimentation, not defaults.

Families that price vehicles (a normative fleet_fixed_cost field on the instance, e.g. Blauth2024) can be solved under the FleetCostDuration objective: the same canonical duration fold plus fleet_fixed_cost × num_routes, priced bitwise by the reference checker. The fleet term is part of solution.duration; the local search then trades route dissolves against duration, helped by a route-dissolve perturbation kick.

params = kayros.Params(objective="fleet_cost_duration")
solution = kayros.solve(instance_path, params, time_limit=10.0, seed=42)
print(solution.duration, solution.num_routes)  # cost includes the fleet term

Exact solve: branch-price-and-cut with checker-exact certificates, optionally warm-started from a known solution (the fast path when certifying near-optimal solutions, e.g. stored best-known ones):

from mamut_routing_lib.td import load_td_instance
from kayros.lera import solve_duration

loaded = load_td_instance(instance_path)
result = solve_duration(loaded, time_limit_s=600.0,
                        initial_routes=[list(r) for r in solution.routes])
print(result["exact_log"]["status"], result["value"])
# status == "Optimum" with routes == [] means: the warm-start solution itself
# is proven optimal. On a time limit, result["exact_log"]["best_bound"] is a
# valid global lower bound when the root relaxation finished (absent otherwise).

solution.duration and result["value"] are always values computed by the reference checker (mamut_routing_lib.td.check_td_solution), never an internal approximation.

Resource limits are verdicts, not crashes: besides the hard time-limit deadline, the exact solve carries a memory self-guard: an RSS watermark polled at the same interruption points as the deadline. When pricing would outgrow the machine (full-horizon TDVRP labeling can exceed any node's RAM), the solve unwinds cleanly with exact_log.status == "MemoryLimitReached", honest bounds, and no certificate. The default limit is resolved from the machine (own RSS + ~80% of available memory, capped by the cgroup limit); solve_duration(memory_limit_mb=...) overrides it, 0 disables.

Design

KAYROS is two solving modes on one exact time-dependent engine:

  • The engine (cpp/pwlf, cpp/core) represents arrival times as non-decreasing continuous piecewise-linear functions (NDCPWLF) and evaluates routes by exact function composition: a bit-identical C++ port of the reference checker's arithmetic (gated by an equivalence suite over the full benchmark set).
  • The anytime stack (kayros.solve): greedy construction and a single-trajectory TD iterated local search (granular ruin-and-recreate kicks, late-acceptance hill climbing, restart-to-best), with a TD ant colony as an alternative strategy, over one time-dependent local-search layer using LCA-BST move evaluation (Blauth et al. 2024) with granular candidate lists: tree-ranked relocate/swap/2-opt* where every accepted move is repriced by the checker-identical fold before it counts.
  • The exact component (kayros.lera): the branch-price-and-cut solver of Lera-Romero, Miranda Bront & Soulignac (2020), vendored under cpp/lera/ (see its NOTICE.md) on the open-source HiGHS LP backend, extended with deadline-compliant anytime behavior, warm starts through columns, TDVRP support, honest time-limit gap reporting, and the memory self-guard. Every column entering the master problem is repriced in the checker's arithmetic, so reported values (and optimality certificates) are checker-exact: optimal under checker-exact route costs and standard LP/pricing tolerances, completeness modulo the search engine's epsilon dominance. On stepwise (value-jump) travel-time functions the labeling switches automatically to an exact value-jump path: the steps' verticals travel through the piecewise-linear machinery as tagged first-class objects (jump vs departure-choice verticals, attained values preserved) instead of being smoothed into steep bridges, so pricing stays complete and stepwise certificates are single-run checker-exact certificates like any other. This path was promoted after a validation ladder ending in a 1444-run four-solve re-certification campaign that re-confirmed 93 stored certificates at their exact stored values with zero checker-infeasible priced columns (cpp/lera/NOTICE.md item 9 records the full history). Turning the LP dual bounds themselves into rigorous certificates (safe bounding) is future work.

Core principles

  • The checker is the referee. Every solution and every certificate is priced by the reference checker of mamut-routing-lib; the checker's value is the value.
  • Exact arithmetic. Plain IEEE-754 doubles, no epsilon comparisons in the engine, no FMA contraction (-ffp-contract=off); results are bit-reproducible across machines.
  • Anytime first. Time budgets are hard deadlines honored by every component (heuristics and exact search alike), and incumbents stream out as they are found; a solver that only answers at the end is not a solver you can interrupt.
  • Honest verdicts. A run ends with an answer: optimum, time limit, or resource limit, with valid bounds where they exist. The solver is never OOM-killed mid-certificate, and it never claims more than its arithmetic supports.
  • One-command install, no proprietary dependency. The default build, including the exact component, is pure open source; HiGHS is built statically into the wheels. The faster CPLEX backend for the BPC remains strictly a source-build opt-in (-DLERA_LP_BACKEND=cplex) and never ships in wheels.
  • One run is one thread. No intra-run parallelism; parallelism belongs to the experiment layer above.
  • POD core. The fresh C++ is plain structs, flat arrays and free functions: optimization-kernel style, no framework (the vendored BPC keeps its upstream style, contained under cpp/lera/).

Archival and reproducibility

kayros is archived by Software Heritage; the badge above tracks the archive status of the GitHub origin (archived origin, archival visits). For academic referencing, prefer Software Heritage identifiers (SWHIDs) of the exact archived revision or release tag over the moving repository origin; when reporting computational results, cite both the kayros release used and the MAMUT-routing benchmark artifacts it was run on.

Branches

Development happens on main. One long-lived branch is deliberately not merged: td-time-warp prototypes penalised exploration of the time-infeasible region (time-warp moves in the local search). A controlled head-to-head found it a no-go for the default solver (parity at best, worse on several families at equal time budgets), so it is kept reachable behind Params for reproducibility rather than merged; the negative result is written up in full as a thesis appendix.

Provenance

KAYROS is developed by Florian Rascoussier (Onyr) as part of a PhD in Informatics and Operations Research (IMT Atlantique / INSA Lyon), under the supervision of Romain Billot, Christine Solnon and Lina Fahed. The NDCPWLF composition engine follows Visser & Spliet (2020)'s move-evaluation theorems; the local-search move evaluation follows Blauth et al. (2024); the exact component vendors the branch-price-and-cut solver of Lera-Romero, Miranda Bront & Soulignac (2020, MIT-licensed; provenance and local modifications documented in cpp/lera/NOTICE.md); the TD-ACO is a rewrite of the author's heuristic layer originally built on that same solver. MIT license.

References

  • Gonzalo Lera-Romero, Juan J. Miranda Bront, Francisco J. Soulignac. Linear edge costs and labeling algorithms: The case of the time-dependent vehicle routing problem with time windows. Networks 76(1):24–53, 2020. doi:10.1002/net.21937. Companion code: gleraromero/networks2020 by Gonzalo Lera-Romero, the solver vendored under cpp/lera/. As of 2026-07-18 its only GitHub star is ours: sadly little recognition for such an important project in the time-dependent routing world. Go give it a second one.
  • Thomas R. Visser, Remy Spliet. Efficient move evaluations for time-dependent vehicle routing problems. Transportation Science 54(4):1091–1112, 2020. doi:10.1287/trsc.2019.0938
  • Jannis Blauth, Stephan Held, Dirk Müller, Niklas Schlomberg, Vera Traub, Thorben Tröbst, Jens Vygen. Vehicle routing with time-dependent travel times: Theory, practice, and benchmarks. Discrete Optimization 53:100848, 2024. doi:10.1016/j.disopt.2024.100848

Acknowledgements

Full authorship, supervision, and contributor policy: AUTHORS.md.

  • Romain Billot, Christine Solnon and Lina Fahed, who supervise the PhD this solver is built for. A special mention to Christine for her guidance and for her decade-long involvement around Time-Dependent routing problems that goes as far back as the PhD of Pénélope Aguiar Melgarejo (more info on Christine's page).
  • Adrien Pichon, Marc Sevaux and Alexandru-Liviu Olteanu as members of the ANR-MAMUT project and its MAMUT-routing benchmark catalog.
  • Romain Fontaine, for his help with Grid'5000, where every KAYROS validation and certification campaign runs. This PhD is a multi-vehicle follow-up to his TDTSPTW thesis and his dynamic-programming solver, tdtsptw-ejor23.
  • Gonzalo Lera-Romero, who made his branch-price-and-cut solver open source: a major milestone on the road to this thesis and the direct inspiration for KAYROS's exact component.
  • Leon Lan, Niels Wouda, Wouter Kool and other contributors to PyVRP who made and kept open-source the PyVRP framework, which is another major inspiration for Kayros's anytime heuristic layer, in 3 aspects: the realization that a single-trajectory iterated local search (ILS) is a strong, simple and scalable anytime metaheuristic for vehicle routing (away from Thibaut Vidal's HGS), for the overall C++/Python architecture, and for the additional competitive drive of the day I read this post by Niels. At that time, I was already on this research stream for a year and realized I was not alone on this problem which was very motivating.
  • Thibaut Vidal, who initiated the movement of open-source vehicle routing solvers and whose HGS-CVRP is a reference anytime metaheuristic for vehicle routing. I have learned a lot from his work, and I am grateful for the open-source spirit he has fostered in the community.

Funding

This work is funded by the French National Research Agency (ANR) as part of the MAMUT project, ANR-22-CE22-0016 "Machine learning et matheuristiques pour le transport urbain" (Machine learning And Matheuristics algorithms for Urban Transportation).

Metadata

Release files for kayros 1.6.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for kayros 1.6.1
File Size Uploaded
kayros-1.6.1.tar.gz 467.0 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for kayros 1.6.1
File
kayros-1.6.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.14 CPython 3.14 Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 Details
kayros-1.6.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details
kayros-1.6.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details
kayros-1.6.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 Details

Total release size: 90.4 MB

Release files / kayros-1.6.1.tar.gz

Download URL kayros-1.6.1.tar.gz
Size 467.0 kB
Tags Source
SHA-256 checksum
How to use checksums
0c7ccfff94c0e8f96589dabb4f53294543555393498f9c63338ab180e123fa62
BLAKE2b-256 checksum
How to use checksums
dfdcd43d50ce1e7df437df24e155bbe75a883928181daf53a611595276c28937
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / kayros-1.6.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL kayros-1.6.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 22.5 MB
Tags CPython 3.14 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
ac878d957e80f6a7ae6d050097040570b4cd08ac48924cc3e61e9278fb362f6d
BLAKE2b-256 checksum
How to use checksums
823d4dd04797f5145fbadb2e708aca6e99ab8da447744dec737d530734af2ac8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / kayros-1.6.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL kayros-1.6.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 22.5 MB
Tags CPython 3.13 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
8e423f76717b8d4166d6c71eb23cf5d038846844848a6b8786018a00da837461
BLAKE2b-256 checksum
How to use checksums
e1741efb91473dccdc8c3c7e70e15a32b8b2e5795730404cad89d55dd91f060c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / kayros-1.6.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL kayros-1.6.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 22.5 MB
Tags CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
93254457610758165f00dd66dddfc3b04997026f86029042af1b4b9b30faec4f
BLAKE2b-256 checksum
How to use checksums
6fb1c64aaadb4a75f47733f3399cad6ea077336cfb59e8263252edfee3924098
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / kayros-1.6.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL kayros-1.6.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 22.5 MB
Tags CPython 3.11 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
112a4d428f8acc1e4c44ef76766e245e35b978eeba9d3dd25e39baf75929b4ec
BLAKE2b-256 checksum
How to use checksums
91197c3e1092fd1f3637db5c454f9eefe2e59ceaf91af9d44e21a72dc79e5124
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.6.1 This release

5 release files

1.6.0

5 release files

1.5.2

5 release files

1.5.1

5 release files

1.5.0

5 release files

1.4.0

5 release files

1.3.0

5 release files

1.2.1

5 release files

1.2.0

5 release files

1.1.3

4 release files

1.1.2

4 release files

1.1.1

4 release files

1.1.0

4 release files

1.0.0

4 release files

0.5.0

4 release files

0.4.0

4 release files

0.3.0

4 release files

0.2.0

4 release files

0.1.0

4 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page