FastHungarian 1.0.0

dotnet add package FastHungarian --version 1.0.0
                    
NuGet\Install-Package FastHungarian -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FastHungarian" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FastHungarian" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="FastHungarian" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add FastHungarian --version 1.0.0
                    
#r "nuget: FastHungarian, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package FastHungarian@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=FastHungarian&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=FastHungarian&version=1.0.0
                    
Install as a Cake Tool

FastHungarian

FastHungarian

Fast assignment problem solver based on modified Kwok's algorithm for maximum weight matching on bipartite graphs. Supports anything from .NET Standard 2.0 to modern .NET 10+ with no dependencies. Solves both minimum cost assignment (Hungarian algorithm) and maximum weight matching problems. ~12-20× faster than classical Hungarian algorithm implementations while maintaining optimal solutions. Extensively tested with comprehensive fuzz testing across thousands of matrix configurations.

Getting Started

Install the package via NuGet:

dotnet add package FastHungarian

Solve assignment problems:

using FastHungarian;

// Cost matrix: assign workers to tasks minimizing total cost
int[,] costs = new int[,]
{
    { 10, 25, 15, 20 },  // Worker 0 costs for tasks 0-3
    { 15, 30, 5,  15 },  // Worker 1 costs for tasks 0-3
    { 20, 5,  10, 25 },  // Worker 2 costs for tasks 0-3
    { 25, 20, 15, 10 }   // Worker 3 costs for tasks 0-3
};

int[] assignments = FastHungarian.FindAssignments(costs);
// assignments[i] = task assigned to worker i
// Result: [2, 2, 1, 3] means Worker 0→Task 2, Worker 1→Task 2, etc.

That's it! The algorithm automatically handles:

  • Non-square matrices (different number of workers and tasks)
  • Transposition for optimal performance
  • Edge retention optimization for large graphs

Advanced Usage

Get Total Cost

Matching result = FastHungarian.FindAssignmentsWithWeight(costs);
Console.WriteLine($"Optimal cost: {result.WeightSum}");
Console.WriteLine($"Assignments: {string.Join(", ", result.LeftPairs)}");

Maximum Weight Matching (Adjacency List API)

For sparse graphs or when you want to maximize weights instead of minimize costs:

// Bipartite graph: L = {0, 1, 2}, R = {0, 1, 2, 3}
// Each list contains (vertex, weight) pairs
var adjacencyList = new List<List<(int vertex, int weight)>>
{
    [(0, 10), (1, 5), (2, 3)],     // Vertex 0 edges
    [(1, 8), (2, 7), (3, 9)],      // Vertex 1 edges
    [(0, 4), (2, 12), (3, 6)]      // Vertex 2 edges
};

Matching result = FastHungarian.MaximumWeightMatching(
    leftCount: 3, 
    rightCount: 4, 
    adjacencyList
);

Console.WriteLine($"Maximum weight: {result.WeightSum}");
// result.LeftPairs[i] = matched right vertex for left vertex i
// result.RightPairs[j] = matched left vertex for right vertex j

Handling Non-Square Matrices

// More workers than tasks: some workers won't be assigned
int[,] costs = new int[5, 3];  // 5 workers, 3 tasks
int[] assignments = FastHungarian.FindAssignments(costs);
// assignments.Length == 5
// assignments[i] == -1 if worker i is not assigned

// More tasks than workers: all workers assigned, some tasks unassigned
int[,] costs2 = new int[3, 5];  // 3 workers, 5 tasks
int[] assignments2 = FastHungarian.FindAssignments(costs2);
// assignments2.Length == 3
// All assignments2[i] >= 0

Algorithm Details

FastHungarian implements modified Kwok's 2025 algorithm for maximum weight matching with several optimizations:

  1. Flat adjacency list - Better cache locality vs nested lists
  2. Edge retention (Theorem 4.2.1) - Reduces edges to O(|L|) per vertex using QuickSelect
  3. Pre-computed labels - Eliminates redundant scans
  4. Incremental slack tracking - Avoids repeated minimum calculations
  5. Ring buffer BFS - Reduces queue overhead
  6. Span<T> bounds check elimination (.NET 8+) - Zero-overhead array access
  7. Branchless operations - Better CPU pipelining

Complexity

  • Time: O(|L| × |R| × min(|L|, |R|)) worst case, typically much faster in practice
  • Space: O(|L| × min(|L|, |R|)) due to edge retention
  • Classical Hungarian: O(|L|³) or O(|L|² × |R|)

Performance

Benchmark results on Intel Core i7-8700 (Coffee Lake), baseline is available here:

Method Mean Error StdDev Ratio RatioSD Gen0 Gen1 Gen2 Allocated Alloc Ratio
FastHungarian_Large_100x100 402.468 us 6.9906 us 10.0257 us 0.06 0.00 19.5313 6.3477 - 122.93 KB 0.96
Baseline_Large_100x100 6,444.749 us 97.8914 us 81.7438 us 1.00 0.02 15.6250 - - 127.72 KB 1.00
FastHungarian_Large_150x150 791.253 us 9.7217 us 8.1180 us 0.03 0.00 84.9609 84.9609 84.9609 272.08 KB 0.95
Baseline_Large_150x150 27,457.877 us 519.1077 us 710.5605 us 1.00 0.04 62.5000 62.5000 62.5000 286.72 KB 1.00
FastHungarian_Medium_50x50 97.723 us 1.9213 us 3.5132 us 0.14 0.01 5.2490 0.3662 - 32.41 KB 1.01
Baseline_Medium_50x50 698.737 us 13.2450 us 12.3894 us 1.00 0.02 4.8828 - - 32.22 KB 1.00
FastHungarian_Rect_100x50 105.358 us 1.2996 us 1.1521 us 0.10 0.00 10.2539 0.9766 - 63.81 KB 0.76
Baseline_Rect_100x50 1,106.895 us 21.9947 us 33.5883 us 1.00 0.04 11.7188 - - 83.98 KB 1.00
FastHungarian_Rect_50x100 86.426 us 1.4426 us 1.3494 us 0.17 0.00 7.0801 0.9766 - 43.83 KB 0.68
Baseline_Rect_50x100 522.193 us 6.3832 us 5.3303 us 1.00 0.01 9.7656 - - 64 KB 1.00
FastHungarian_Small_10x10 1.784 us 0.0189 us 0.0158 us 0.38 0.01 0.3529 - - 2.17 KB 1.43
Baseline_Small_10x10 4.696 us 0.0895 us 0.0793 us 1.00 0.02 0.2441 - - 1.52 KB 1.00
FastHungarian_Sparse_100x100 89.620 us 1.6555 us 1.4675 us 0.01 0.00 19.8975 6.5918 - 122.93 KB 0.96
Baseline_Sparse_100x100 7,049.420 us 138.4074 us 129.4664 us 1.00 0.03 15.6250 - - 127.72 KB 1.00
FastHungarian_WideRange_100x100 382.472 us 6.5613 us 6.1374 us 0.05 0.00 19.5313 6.3477 - 122.93 KB 0.96
Baseline_WideRange_100x100 8,283.841 us 151.0171 us 211.7049 us 1.00 0.04 15.6250 - - 127.72 KB 1.00

Memory usage: ~5% less allocation than Baseline Hungarian algorithm.

Sparse matrices (90% high cost, 10% low cost): 60× faster than vanilla for 100×100.

Full benchmark results and reproduction available in the benchmark project.

Testing

FastHungarian is thoroughly tested with 11 comprehensive fuzz test suites covering:

  • ✅ Square matrices (2×2 to 200×200)
  • ✅ Non-square matrices (all aspect ratios)
  • ✅ Extreme shapes (1×N, N×1, 10:1 ratios)
  • ✅ Edge case patterns (diagonal, sparse, bimodal, outliers)
  • ✅ Degenerate cases (1×1, single row/column, near-overflow)
  • Total: 350+ test iterations, thousands of matrix configurations

All tests verify correctness against the proven Hungarian algorithm implementation from the HungarianAlgorithm NuGet package.

Limitations

  • Integer weights: Currently supports int weights. For floating-point weights, scale to integers.

The algorithm handles:

  • ✅ Non-square matrices (automatic transposition)
  • ✅ Unbalanced assignments (more workers than tasks or vice versa)
  • ✅ Zero costs and identical values
  • ✅ Large cost ranges (tested up to int.MaxValue / 2)

Contributing

If you are looking to add new functionality, please open an issue first to verify your intent is aligned with the scope of the project. The library is covered by comprehensive fuzz tests with over 350 test iterations. Please run them against your work before proposing changes:

dotnet test

When reporting issues, providing a minimal reproduction with the specific cost matrix that fails greatly reduces turnaround time.

References

License

This library is licensed under the MIT license. 💜

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.
  • net10.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 265 11/15/2025