Skip to content
This repository was archived by the owner on Dec 4, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,66 @@ target/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# Virtual Environment
venv/
env/
ENV/

# IDE specific files
.vscode/
*.swp
*.swo

# Jupyter Notebook
.ipynb_checkpoints
*/.ipynb_checkpoints/*

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytest
.pytest_cache/
.coverage
htmlcov/

# Environment variables
.env
.venv
env/
venv/
ENV/

# Distribution / packaging
.Python
build/
*.pyc

.ruff_cache
1 change: 0 additions & 1 deletion .python-version

This file was deleted.

97 changes: 97 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ name = "fastlap"
crate-type = ["cdylib"]

[dependencies]
pyo3 = "0.25.0"
pyo3 = { version = "0.25.0", features = ["extension-module", "anyhow", "auto-initialize"] }
numpy = "0.25"
46 changes: 45 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,46 @@

# fastlap
Python's LAP library written in Rust.

**Python’s LAP (Linear Assignment Problem) solver — written in Rust for performance.**

`fastlap` provides a blazing-fast implementation of common assignment algorithms such as:

- Jonker-Volgenant (LAPJV)
- Hungarian (a.k.a. Munkres)

Built with [Rust](https://www.rust-lang.org/) and exposed to Python via [PyO3](https://pyo3.rs), this library offers performance and interoperability in one package.


## ✨ Features

- ✅ Fast and memory-safe implementation in Rust
- ✅ Python bindings via PyO3
- ✅ Supports both `lapjv` and `hungarian` algorithms
- ✅ Can be used in native Rust projects or as a Python package


## 📖 Algorithms

* **LAPJV** – Efficient dual-based shortest augmenting path algorithm (Jonker & Volgenant, 1987)
* **Hungarian** – Classic method with row/column reduction and assignment phases

## Roadmap

- [ ] Release first version
- [ ] Add more algorithms
- [ ] Add more features
- [ ] Add more examples
- [ ] Add more tests
- [ ] Add more benchmarks


## 📚 References

* Jonker, R., & Volgenant, A. (1987). *A shortest augmenting path algorithm for dense and sparse linear assignment problems*. Computing, 38(4), 325–340.
* Munkres, J. (1957). *Algorithms for the Assignment and Transportation Problems*. Journal of the Society for Industrial and Applied Mathematics.


## 📃 License

MIT License © 2025

7 changes: 7 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,12 @@ classifiers = [
"Programming Language :: Python :: Implementation :: PyPy",
]
dynamic = ["version"]
dependencies = [
"lap>=0.4.0",
"maturin>=1.8.7",
"numpy>=1.20,<2.0",
"pytest>=7.0",
"scipy>=1.8",
]
[tool.maturin]
features = ["pyo3/extension-module"]
52 changes: 52 additions & 0 deletions python/fastlaps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import time
import fastlap
import numpy as np
from scipy.optimize import linear_sum_assignment
import lap


if __name__ == "__main__":
# Quick example for a 3x3 matrix
matrix = np.random.rand(4, 5)
for algo in ["lapjv", "hungarian"]:
print(f"\nAlgorithm: {algo}")
start = time.time()
fastlap_cost, fastlap_rows, fastlap_cols = fastlap.solve_lap(matrix, algo)
fastlap_end = time.time()
print(f"fastlap.{algo}: Time={fastlap_end - start:.8f}s")
print(
f"fastlap.{algo}: Cost={fastlap_cost}, Rows={fastlap_rows}, Cols={fastlap_cols}"
)
if algo == "hungarian":
start = time.time()
scipy_rows, scipy_cols = linear_sum_assignment(matrix)
scipy_cost = matrix[scipy_rows, scipy_cols].sum()
scipy_end = time.time()
print(
f"scipy.optimize.linear_sum_assignment: Time={scipy_end - start:.8f}s"
)
print(
f"scipy.optimize.linear_sum_assignment: Cost={scipy_cost}, Rows={list(scipy_rows)}, Cols={list(scipy_cols)}"
)
if algo == "lapjv":
start = time.time()
lap_cost, lap_rows, lap_cols = lap.lapjv(matrix, extend_cost=True)
lap_end = time.time()
print(f"lap.lapjv: Time={lap_end - start:.8f}s")
print(f"lap.lapjv: Cost={lap_cost}, Rows={lap_rows}, Cols={lap_cols}")

"""
First release:

Algorithm: lapjv
fastlap.lapjv: Time=0.00017548s
fastlap.lapjv: Cost=inf, Rows=[2, 0, 1, 4, 3], Cols=[1, 2, 0, 4, 3]
lap.lapjv: Time=0.00013208s
lap.lapjv: Cost=0.6229432588732741, Rows=[2 0 1 4], Cols=[ 1 2 0 -1 3]

Algorithm: hungarian
fastlap.hungarian: Time=0.00000453s
fastlap.hungarian: Cost=0.7465856501551806, Rows=[2, 0, 1, 3], Cols=[1, 2, 0, 3, 18446744073709551615]
scipy.optimize.linear_sum_assignment: Time=0.00001287s
scipy.optimize.linear_sum_assignment: Cost=0.6229432588732741, Rows=[0, 1, 2, 3], Cols=[2, 0, 1, 4]
"""
4 changes: 0 additions & 4 deletions python/init_test.py

This file was deleted.

12 changes: 12 additions & 0 deletions python/lapjv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import lap
import numpy as np
import time


if __name__ == "__main__":
array = np.random.rand(4, 5)
start = time.time()
result = lap.lapjv(array, extend_cost=True)
end = time.time()
print(f"lapjv: Time={end - start:.8f}s")
print(result)
Loading
Loading