[{"data":1,"prerenderedAt":555},["ShallowReactive",2],{"navigation":3,"\u002Falgorithms\u002Fassignment":174,"\u002Falgorithms\u002Fassignment-surround":550},[4,8,101,165,170],{"title":5,"path":6,"stem":7},"Getting started","\u002Fgetting-started","1.getting-started",{"title":9,"path":10,"stem":11,"children":12},"Algorithms","\u002Falgorithms","2.algorithms",[13,15,58],{"title":9,"path":10,"stem":14},"2.algorithms\u002Findex",{"title":16,"path":17,"stem":18,"children":19},"Assignment","\u002Falgorithms\u002Fassignment","2.algorithms\u002F1.assignment\u002Findex",[20,21,25,29,32,36,40],{"title":16,"path":17,"stem":18},{"title":22,"path":23,"stem":24},"Quickstart","\u002Falgorithms\u002Fassignment\u002Fquickstart","2.algorithms\u002F1.assignment\u002F1.quickstart",{"title":26,"path":27,"stem":28},"Tracking","\u002Falgorithms\u002Fassignment\u002Ftracking","2.algorithms\u002F1.assignment\u002F2.tracking",{"title":9,"path":30,"stem":31},"\u002Falgorithms\u002Fassignment\u002Falgorithms","2.algorithms\u002F1.assignment\u002F3.algorithms",{"title":33,"path":34,"stem":35},"Reference","\u002Falgorithms\u002Fassignment\u002Freference","2.algorithms\u002F1.assignment\u002F4.reference",{"title":37,"path":38,"stem":39},"Choosing","\u002Falgorithms\u002Fassignment\u002Fchoosing","2.algorithms\u002F1.assignment\u002F5.choosing",{"title":41,"path":42,"stem":43,"children":44},"Tutorials","\u002Falgorithms\u002Fassignment\u002Ftutorials","2.algorithms\u002F1.assignment\u002F6.tutorials\u002Findex",[45,46,50,54],{"title":41,"path":42,"stem":43},{"title":47,"path":48,"stem":49},"Fundamentals","\u002Falgorithms\u002Fassignment\u002Ftutorials\u002Ffundamentals","2.algorithms\u002F1.assignment\u002F6.tutorials\u002F1.fundamentals",{"title":51,"path":52,"stem":53},"Backends","\u002Falgorithms\u002Fassignment\u002Ftutorials\u002Fbackends","2.algorithms\u002F1.assignment\u002F6.tutorials\u002F2.backends",{"title":55,"path":56,"stem":57},"Object tracking","\u002Falgorithms\u002Fassignment\u002Ftutorials\u002Ftracking","2.algorithms\u002F1.assignment\u002F6.tutorials\u002F3.tracking",{"title":59,"path":60,"stem":61,"children":62},"Transport","\u002Falgorithms\u002Ftransport","2.algorithms\u002F2.transport\u002Findex",[63,64,67,71,74,77,80,84],{"title":59,"path":60,"stem":61},{"title":22,"path":65,"stem":66},"\u002Falgorithms\u002Ftransport\u002Fquickstart","2.algorithms\u002F2.transport\u002F1.quickstart",{"title":68,"path":69,"stem":70},"Point-cloud tutorial","\u002Falgorithms\u002Ftransport\u002Fpoint-clouds","2.algorithms\u002F2.transport\u002F2.point-clouds",{"title":9,"path":72,"stem":73},"\u002Falgorithms\u002Ftransport\u002Falgorithms","2.algorithms\u002F2.transport\u002F3.algorithms",{"title":33,"path":75,"stem":76},"\u002Falgorithms\u002Ftransport\u002Freference","2.algorithms\u002F2.transport\u002F4.reference",{"title":37,"path":78,"stem":79},"\u002Falgorithms\u002Ftransport\u002Fchoosing","2.algorithms\u002F2.transport\u002F5.choosing",{"title":81,"path":82,"stem":83},"Building","\u002Falgorithms\u002Ftransport\u002Fbuilding","2.algorithms\u002F2.transport\u002F6.building",{"title":41,"path":85,"stem":86,"children":87},"\u002Falgorithms\u002Ftransport\u002Ftutorials","2.algorithms\u002F2.transport\u002F7.tutorials\u002Findex",[88,89,93,97],{"title":41,"path":85,"stem":86},{"title":90,"path":91,"stem":92},"Optimal transport","\u002Falgorithms\u002Ftransport\u002Ftutorials\u002Foptimal-transport","2.algorithms\u002F2.transport\u002F7.tutorials\u002F1.optimal-transport",{"title":94,"path":95,"stem":96},"Sinkhorn","\u002Falgorithms\u002Ftransport\u002Ftutorials\u002Fsinkhorn","2.algorithms\u002F2.transport\u002F7.tutorials\u002F2.sinkhorn",{"title":98,"path":99,"stem":100},"Point clouds","\u002Falgorithms\u002Ftransport\u002Ftutorials\u002Fpoint-clouds","2.algorithms\u002F2.transport\u002F7.tutorials\u002F3.point-clouds",{"title":102,"path":103,"stem":104,"children":105},"Resources","\u002Fresources","3.resources",[106,108,147,151,155],{"title":102,"path":103,"stem":107},"3.resources\u002Findex",{"title":41,"path":109,"stem":110,"children":111},"\u002Fresources\u002Ftutorials","3.resources\u002F1.tutorials\u002Findex",[112,113,131],{"title":41,"path":109,"stem":110},{"title":16,"path":114,"stem":115,"children":116,"page":130},"\u002Fresources\u002Ftutorials\u002Fassignment","3.resources\u002F1.tutorials\u002Fassignment",[117,122,126],{"title":118,"path":119,"stem":120,"icon":121},"Tutorial 1 — The Assignment Problem","\u002Fresources\u002Ftutorials\u002Fassignment\u002F01_the_assignment_problem","3.resources\u002F1.tutorials\u002Fassignment\u002F01_the_assignment_problem","i-lucide-notebook",{"title":123,"path":124,"stem":125,"icon":121},"Tutorial 2 — Backends and Batching","\u002Fresources\u002Ftutorials\u002Fassignment\u002F02_backends_and_batching","3.resources\u002F1.tutorials\u002Fassignment\u002F02_backends_and_batching",{"title":127,"path":128,"stem":129,"icon":121},"Tutorial 3 — Object Tracking with the Assignment Problem","\u002Fresources\u002Ftutorials\u002Fassignment\u002F03_object_tracking","3.resources\u002F1.tutorials\u002Fassignment\u002F03_object_tracking",false,{"title":59,"path":132,"stem":133,"children":134,"page":130},"\u002Fresources\u002Ftutorials\u002Ftransport","3.resources\u002F1.tutorials\u002Ftransport",[135,139,143],{"title":136,"path":137,"stem":138,"icon":121},"Tutorial 1 — What Is Optimal Transport?","\u002Fresources\u002Ftutorials\u002Ftransport\u002F01_optimal_transport","3.resources\u002F1.tutorials\u002Ftransport\u002F01_optimal_transport",{"title":140,"path":141,"stem":142,"icon":121},"Tutorial 2 — The Sinkhorn Algorithm","\u002Fresources\u002Ftutorials\u002Ftransport\u002F02_sinkhorn_algorithm","3.resources\u002F1.tutorials\u002Ftransport\u002F02_sinkhorn_algorithm",{"title":144,"path":145,"stem":146,"icon":121},"Tutorial 3 — Point-Cloud OT and Shape Learning","\u002Fresources\u002Ftutorials\u002Ftransport\u002F03_point_clouds","3.resources\u002F1.tutorials\u002Ftransport\u002F03_point_clouds",{"title":148,"path":149,"stem":150},"Assignment applications","\u002Fresources\u002Fassignment-applications","3.resources\u002F2.assignment-applications",{"title":152,"path":153,"stem":154},"Transport applications","\u002Fresources\u002Ftransport-applications","3.resources\u002F3.transport-applications",{"title":156,"path":157,"stem":158,"children":159},"Benchmarks","\u002Fresources\u002Fbenchmarks","3.resources\u002F4.benchmarks\u002Findex",[160,161],{"title":156,"path":157,"stem":158},{"title":162,"path":163,"stem":164},"Contributing benchmarks","\u002Fresources\u002Fbenchmarks\u002Fcontributing","3.resources\u002F4.benchmarks\u002Fcontributing",{"title":166,"path":167,"stem":168,"icon":169},"API Reference","\u002Fapi","4.api","i-lucide-package",{"title":171,"path":172,"stem":173},"References","\u002Freferences","5.references",{"id":175,"title":16,"api":176,"body":177,"description":544,"extension":545,"links":176,"meta":546,"navigation":547,"path":17,"seo":548,"stem":18,"__hash__":549},"docs\u002F2.algorithms\u002F1.assignment\u002Findex.md",null,{"type":178,"value":179,"toc":539},"minimark",[180,202,205,315,326,331,338,373,380,384,466,481,489,493,528,535],[181,182,183,184,188,189,192,193,197,198,201],"p",{},"The ",[185,186,187],"strong",{},"assignment"," family solves the ",[185,190,191],{},"linear assignment problem (LAP)",": given a cost matrix\n",[194,195,196],"code",{},"C"," of shape ",[194,199,200],{},"(N, M)",", find the one-to-one mapping from rows to columns that minimises the\ntotal cost. The problem is also called bipartite matching — pairing items from one set (rows)\nwith items from another set (columns) so each item appears in at most one pair — or the\nweighted assignment problem.",[181,203,204],{},"torchmatch exposes the assignment solvers through a single dispatcher:",[206,207,212],"pre",{"className":208,"code":209,"language":210,"meta":211,"style":211},"language-python shiki shiki-themes material-theme-lighter github-light github-dark","import torchmatch\n\n# 2-D cost: single problem, CPU or CUDA\nrow_to_col = torchmatch.assignment.solve(cost)\n\n# 3-D cost: batch of problems, CPU or CUDA\nrow_to_col = torchmatch.assignment.solve(costs)   # shape (B, N)\n","python","",[194,213,214,227,234,241,276,281,287],{"__ignoreMap":211},[215,216,219,223],"span",{"class":217,"line":218},"line",1,[215,220,222],{"class":221},"sVHd0","import",[215,224,226],{"class":225},"su5hD"," torchmatch\n",[215,228,230],{"class":217,"line":229},2,[215,231,233],{"emptyLinePlaceholder":232},true,"\n",[215,235,237],{"class":217,"line":236},3,[215,238,240],{"class":239},"sutJx","# 2-D cost: single problem, CPU or CUDA\n",[215,242,244,247,251,254,258,261,263,267,270,273],{"class":217,"line":243},4,[215,245,246],{"class":225},"row_to_col ",[215,248,250],{"class":249},"smGrS","=",[215,252,253],{"class":225}," torchmatch",[215,255,257],{"class":256},"sP7_E",".",[215,259,187],{"class":260},"skxfh",[215,262,257],{"class":256},[215,264,266],{"class":265},"slqww","solve",[215,268,269],{"class":256},"(",[215,271,272],{"class":265},"cost",[215,274,275],{"class":256},")\n",[215,277,279],{"class":217,"line":278},5,[215,280,233],{"emptyLinePlaceholder":232},[215,282,284],{"class":217,"line":283},6,[215,285,286],{"class":239},"# 3-D cost: batch of problems, CPU or CUDA\n",[215,288,290,292,294,296,298,300,302,304,306,309,312],{"class":217,"line":289},7,[215,291,246],{"class":225},[215,293,250],{"class":249},[215,295,253],{"class":225},[215,297,257],{"class":256},[215,299,187],{"class":260},[215,301,257],{"class":256},[215,303,266],{"class":265},[215,305,269],{"class":256},[215,307,308],{"class":265},"costs",[215,310,311],{"class":256},")",[215,313,314],{"class":239},"   # shape (B, N)\n",[181,316,317,318,321,322,325],{},"The dispatcher (",[194,319,320],{},"Backend.AUTO",") picks the fastest registered op for the device, shape, and\ncost structure. Direct op handles (e.g., ",[194,323,324],{},"torchmatch.assignment.ops.jonker_dense",") are also\navailable when you need to fix a particular algorithm — for benchmarking or to avoid the\nauto-selection overhead.",[327,328,330],"h2",{"id":329},"when-assignment-is-the-right-tool","When assignment is the right tool",[181,332,333,334,337],{},"Use assignment when you need a ",[185,335,336],{},"hard, one-to-one matching"," between two sets of items of\nknown, finite size. Common situations:",[339,340,341,347,353,359],"ul",{},[342,343,344,346],"li",{},[185,345,55],{},": match each detected bounding box this frame to one track from the\nprevious frame.",[342,348,349,352],{},[185,350,351],{},"Set-prediction losses",": match each model prediction to one ground-truth target so you can\ncompute a per-pair loss — as used in transformer-based object detectors like DETR.",[342,354,355,358],{},[185,356,357],{},"Cluster evaluation",": when two clustering algorithms assign different integer labels to the\nsame groups, find the label mapping that maximises the overlap before comparing them.",[342,360,361,364,365,368,369,372],{},[185,362,363],{},"Replacing SciPy",": ",[194,366,367],{},"torchmatch.assignment.solve"," is a drop-in replacement for\n",[194,370,371],{},"scipy.optimize.linear_sum_assignment"," that accepts and returns PyTorch tensors directly,\nwithout leaving the GPU or converting to NumPy arrays.",[181,374,375,376,379],{},"If you are comparing probability distributions, working with point clouds, or want a fractional\n(probabilistic) rather than hard one-to-one matching, look at ",[377,378,59],"a",{"href":60}," instead.",[327,381,383],{"id":382},"three-solver-families","Three solver families",[385,386,387,403],"table",{},[388,389,390],"thead",{},[391,392,393,397,400],"tr",{},[394,395,396],"th",{},"Family",[394,398,399],{},"Ops",[394,401,402],{},"Hardware",[404,405,406,431,450],"tbody",{},[391,407,408,412,425],{},[409,410,411],"td",{},"Jonker-Volgenant (successive-shortest-path)",[409,413,414,417,418,417,421,424],{},[194,415,416],{},"jonker_scalar",", ",[194,419,420],{},"jonker_dense",[194,422,423],{},"jonker_compact"," and their batched variants",[409,426,427,428],{},"CPU (AVX2 SIMD); CUDA for ",[194,429,430],{},"jonker_dense_batch",[391,432,433,436,447],{},[409,434,435],{},"Hungarian algorithm family",[409,437,438,417,441,417,444],{},[194,439,440],{},"munkres",[194,442,443],{},"lawler",[194,445,446],{},"hybrid",[409,448,449],{},"CUDA only",[391,451,452,455,463],{},[409,453,454],{},"Pure-Python heuristics",[409,456,457,417,460],{},[194,458,459],{},"greedy",[194,461,462],{},"auction_assignment",[409,464,465],{},"CPU and CUDA (no compiled extension)",[181,467,468,470,471,474,475,477,478,480],{},[194,469,462],{}," (Bertsekas' auction algorithm) returns a\n",[194,472,473],{},"(matches, unmatched_rows, unmatched_cols)"," triple and is not wired into\n",[194,476,266],{},". Use it when you need an optimal or near-optimal match without the\ncompiled extension. ",[194,479,459],{}," is a single-pass O(N²) heuristic suited for\nwarm-starts or profiling.",[181,482,183,483,485,486,488],{},[377,484,9],{"href":30}," page explains the mathematical differences. The\n",[377,487,37],{"href":38}," guide maps problem characteristics to the right op.",[327,490,492],{"id":491},"in-this-section","In this section",[339,494,495,500,508,513,518,523],{},[342,496,497,499],{},[377,498,22],{"href":23}," — install, import, and run your first assignment",[342,501,502,505,506],{},[377,503,504],{"href":27},"Tracking tutorial"," — end-to-end batched tracking with ",[194,507,430],{},[342,509,510,512],{},[377,511,9],{"href":30}," — how Jonker-Volgenant, Munkres, and Lawler work and how they differ",[342,514,515,517],{},[377,516,33],{"href":34}," — full signature for every op",[342,519,520,522],{},[377,521,37],{"href":38}," — benchmark-backed decision tree",[342,524,525,527],{},[377,526,41],{"href":42}," — deeper notebook-based walkthroughs, from first\nprinciples through object tracking",[181,529,530,531,534],{},"See also the ",[377,532,533],{"href":149},"history of applications"," — tracking, DETR losses, cluster evaluation, and more.",[536,537,538],"style",{},"html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .slqww, html code.shiki .slqww{--shiki-light:#6182B8;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":211,"searchDepth":236,"depth":236,"links":540},[541,542,543],{"id":329,"depth":229,"text":330},{"id":382,"depth":229,"text":383},{"id":491,"depth":229,"text":492},"Linear assignment problem solvers — Jonker-Volgenant, Hungarian (Munkres, Lawler), and Greedy — registered as PyTorch custom ops.","md",{},{"title":16},{"title":16,"description":544},"etSvLN0Qdp-cIpNdFB2VfXABEBw46NdL4t1lGuoDuxE",[551,553],{"title":9,"path":10,"stem":14,"description":552,"children":-1},"The two solver families torchmatch provides — linear assignment (one-to-one matching) and optimal transport (soft, many-to-many matching) — each with quickstarts, algorithm notes, and a full op reference.",{"title":22,"path":23,"stem":24,"description":554,"children":-1},"Solve one cost matrix on CPU with each JV variant, covering square, rectangular, forbidden-edge, NaN, and empty inputs.",1785218159644]