Munkres
Optimally pair up two sets (workers to jobs, drivers to riders, bids to items) to minimize total cost.
Given a cost matrix where matrix[y][x] is the cost of pairing item y with item x, munkres returns the one-to-one assignment with the lowest possible total cost. It’s a fast, dependency-free implementation of the Munkres (Hungarian) algorithm.
Reach for it whenever you have a table of pairing costs (or profits) and need the optimal matching rather than a greedy guess.
Features
- Flexible:
numberorbigintcosts; square (NxN) or rectangular (MxN) matrices; anyMatrixLikeinput (arrays, typed arrays, custom indexables). - Fast: O(M²N) time when M ≤ N (O(MN²) otherwise) and only O(M + N) extra memory. Benchmarks below.
- Typed & dependency-free: first-class TypeScript types, zero runtime dependencies, ships both ESM and CommonJS.
- Robust: force an assignment with
-Infinityor avoid one withInfinity; built-in helpers for building and transforming matrices.
Install
npm install munkres
yarn add munkres
pnpm add munkres
jsr add @munkres/munkresUsage
import { munkres } from "munkres";
// matrix[y][x] = cost of assigning worker y to job x
const costMatrix = [
[1, 2, 3],
[2, 4, 6],
[3, 6, 9],
];
const assignments = munkres(costMatrix);
// → [[0, 2], [1, 1], [2, 0]] (worker 0 → job 2, worker 1 → job 1, worker 2 → job 0)Each result is a [y, x] pair (row, then column). The result has min(rows, cols) pairs; if there are more workers than jobs (or vice versa), the unmatched ones are simply absent.
Maximizing instead of minimizing? Convert your profit matrix to a cost matrix first:
import { munkres, copyMatrix, invertMatrix } from "munkres";
const profitMatrix = [
[9, 8, 7],
[8, 6, 4],
[7, 4, 1],
];
const costMatrix = copyMatrix(profitMatrix);
invertMatrix(costMatrix); // flip profits into costs
const assignments = munkres(costMatrix);
// → [[0, 2], [1, 1], [2, 0]]API
munkres(costMatrix, options?)
Runs the algorithm and returns a set of optimal [y, x] assignment pairs. If several optimal assignments exist, one is returned.
costMatrix: aMatrixLike<number>orMatrixLike<bigint>wherecostMatrix[y][x]is the cost of assigning workeryto jobx. Costs are minimized, so use-Infinityto force an assignment (chosen whenever possible) andInfinityto avoid one (used only as a last resort, when no finite alternative exists).options.finite(boolean, defaultfalse): promise the matrix is all-finite and in-range, skipping input validation for a small speedup on large matrices. If the promise is broken, the result is undefined (it won’t throw). SeeMunkresOptions.
Returns Pair<number>[], an array of [y, x] pairs, length min(rows, cols).
Throws
TypeError: anumbermatrix containsNaN. (UseInfinityto avoid an assignment instead.)RangeError: anumbermatrix’s value range (max - min) exceedsNumber.MAX_VALUE / 2and could overflow. Scale the matrix down, or usebigint.
Precision: the
numberpath uses 64-bit floats. For integer costs that need an exact optimum (especially near or beyondNumber.MAX_SAFE_INTEGER), use abigintmatrix for arbitrary precision.
Types
Matrix<T>: a 2D matrix,T[][].MatrixLike<T>: a read-only 2D matrix accepting anyArrayLike(arrays, typed arrays, custom indexables).Pair<A, B = A>: a[A, B]tuple.MunkresOptions: the options object formunkres().
Helpers
Utilities for building and transforming cost matrices:
| Helper | Description |
|---|---|
copyMatrix(matrix) |
Copy a matrix. |
createMatrix(workers, jobs, callbackFn) |
Build a matrix from worker/job lists and a cost function. |
genMatrix(numRows, numCols, callbackFn) |
Build a matrix from dimensions and a callback. |
getMatrixMax(matrix) / getMatrixMin(matrix) |
Find the max / min value. |
invertMatrix(matrix, bigVal?) |
Invert values (max → min); converts between minimizing and maximizing. Uses the matrix max if bigVal is omitted. |
negateMatrix(matrix) |
Negate all values; another way to swap minimizing and maximizing. |
Benchmarks
Performance is tracked automatically on every release and every commit to main:
- Release-over-release trend →: how performance changes across published versions.
- Per-commit history →: fine-grained regression tracking.
- Run it in your browser →: try it on your own inputs.
- Run locally →: See the contributing guide.
As a ballpark (Apple M2, v2.1.1):
| Matrix Size | number |
bigint |
|---|---|---|
| 64x64 | ~0.07ms | ~0.17ms |
| 256x256 | ~1.2ms | ~3.7ms |
| 1024x1024 | ~26ms | ~110ms |
| 4096x4096 | ~0.73s | ~3.8s |
Contributing
Contributions are welcome. See the contributing guide for local setup, tests, and the style guide.
- Questions / discussion: GitHub Discussions
- Bugs: Issue tracker
- Feature requests: open an issue describing the feature and its benefit.