[{"data":1,"prerenderedAt":2569},["ShallowReactive",2],{"navigation":3,"\u002Falgorithms\u002Fassignment\u002Ftracking":174,"\u002Falgorithms\u002Fassignment\u002Ftracking-surround":2564},[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":176,"api":177,"body":178,"description":2558,"extension":2559,"links":177,"meta":2560,"navigation":2561,"path":27,"seo":2562,"stem":28,"__hash__":2563},"docs\u002F2.algorithms\u002F1.assignment\u002F2.tracking.md","Batched tracking workflow",null,{"type":179,"value":180,"toc":2549},"minimark",[181,185,188,206,211,949,953,963,1204,1214,1218,1511,1515,1522,2064,2070,2074,2081,2303,2320,2324,2330,2504,2525,2529,2545],[182,183,184],"p",{},"A multi-object-tracking scenario: for each frame in a batch, match the\ncurrent set of detected objects (detections, e.g., bounding boxes from a\ndetector) to the objects the tracker is already following (tracks). The\ngoal is to decide which detection corresponds to which track — assigning\neach detection to at most one track at minimum cost.",[182,186,187],{},"This tutorial covers three steps:",[189,190,191,195,198],"ol",{},[192,193,194],"li",{},"Build batched IoU costs on the chosen device.",[192,196,197],{},"Pick the right batched op for the data shape.",[192,199,200,201,205],{},"Recover ",[202,203,204],"code",{},"(matches, unmatched_rows, unmatched_cols)"," in one pass.",[207,208,210],"h2",{"id":209},"synthesizing-realistic-costs","Synthesizing realistic costs",[212,213,218],"pre",{"className":214,"code":215,"language":216,"meta":217,"style":217},"language-python shiki shiki-themes material-theme-lighter github-light github-dark","import torch\nimport torchmatch                          # extensions load eagerly at import\n\n\ndef boxes(n, device, generator):\n    \"\"\"Random axis-aligned boxes in [0, 1]² with side length ~ U(0.1, 0.4).\"\"\"\n    xy = torch.rand(n, 2, generator=generator, device=device)\n    wh = torch.rand(n, 2, generator=generator, device=device) * 0.3 + 0.1\n    return torch.cat([xy, xy + wh], dim=1)   # (n, 4) = x1, y1, x2, y2\n\n\ndef iou_cost(boxes_a, boxes_b):\n    \"\"\"Pairwise (1 - IoU) cost matrix.\"\"\"\n    lo = torch.maximum(boxes_a[:, None, :2], boxes_b[None, :, :2])\n    hi = torch.minimum(boxes_a[:, None, 2:], boxes_b[None, :, 2:])\n    inter = (hi - lo).clamp_min(0).prod(-1)\n    area_a = (boxes_a[:, 2:] - boxes_a[:, :2]).prod(-1)[:, None]\n    area_b = (boxes_b[:, 2:] - boxes_b[:, :2]).prod(-1)[None, :]\n    iou = inter \u002F (area_a + area_b - inter + 1e-9)\n    return 1.0 - iou\n\n\ndef build_batch(B, N, device):\n    g = torch.Generator(device=device).manual_seed(0)\n    return torch.stack([\n        iou_cost(boxes(N, device, g), boxes(N, device, g))\n        for _ in range(B)\n    ]).contiguous()\n","python","",[202,219,220,233,245,252,257,290,304,356,409,455,460,465,485,495,551,596,640,690,739,774,787,792,797,821,855,870,915,937],{"__ignoreMap":217},[221,222,225,229],"span",{"class":223,"line":224},"line",1,[221,226,228],{"class":227},"sVHd0","import",[221,230,232],{"class":231},"su5hD"," torch\n",[221,234,236,238,241],{"class":223,"line":235},2,[221,237,228],{"class":227},[221,239,240],{"class":231}," torchmatch                          ",[221,242,244],{"class":243},"sutJx","# extensions load eagerly at import\n",[221,246,248],{"class":223,"line":247},3,[221,249,251],{"emptyLinePlaceholder":250},true,"\n",[221,253,255],{"class":223,"line":254},4,[221,256,251],{"emptyLinePlaceholder":250},[221,258,260,264,268,272,276,279,282,284,287],{"class":223,"line":259},5,[221,261,263],{"class":262},"sbsja","def",[221,265,267],{"class":266},"sGLFI"," boxes",[221,269,271],{"class":270},"sP7_E","(",[221,273,275],{"class":274},"sFwrP","n",[221,277,278],{"class":270},",",[221,280,281],{"class":274}," device",[221,283,278],{"class":270},[221,285,286],{"class":274}," generator",[221,288,289],{"class":270},"):\n",[221,291,293,297,301],{"class":223,"line":292},6,[221,294,296],{"class":295},"s2W-s","    \"\"\"",[221,298,300],{"class":299},"sithA","Random axis-aligned boxes in [0, 1]² with side length ~ U(0.1, 0.4).",[221,302,303],{"class":295},"\"\"\"\n",[221,305,307,310,314,317,320,324,326,328,330,334,336,339,341,344,346,348,350,353],{"class":223,"line":306},7,[221,308,309],{"class":231},"    xy ",[221,311,313],{"class":312},"smGrS","=",[221,315,316],{"class":231}," torch",[221,318,319],{"class":270},".",[221,321,323],{"class":322},"slqww","rand",[221,325,271],{"class":270},[221,327,275],{"class":322},[221,329,278],{"class":270},[221,331,333],{"class":332},"srdBf"," 2",[221,335,278],{"class":270},[221,337,286],{"class":338},"s99_P",[221,340,313],{"class":312},[221,342,343],{"class":322},"generator",[221,345,278],{"class":270},[221,347,281],{"class":338},[221,349,313],{"class":312},[221,351,352],{"class":322},"device",[221,354,355],{"class":270},")\n",[221,357,359,362,364,366,368,370,372,374,376,378,380,382,384,386,388,390,392,394,397,400,403,406],{"class":223,"line":358},8,[221,360,361],{"class":231},"    wh ",[221,363,313],{"class":312},[221,365,316],{"class":231},[221,367,319],{"class":270},[221,369,323],{"class":322},[221,371,271],{"class":270},[221,373,275],{"class":322},[221,375,278],{"class":270},[221,377,333],{"class":332},[221,379,278],{"class":270},[221,381,286],{"class":338},[221,383,313],{"class":312},[221,385,343],{"class":322},[221,387,278],{"class":270},[221,389,281],{"class":338},[221,391,313],{"class":312},[221,393,352],{"class":322},[221,395,396],{"class":270},")",[221,398,399],{"class":312}," *",[221,401,402],{"class":332}," 0.3",[221,404,405],{"class":312}," +",[221,407,408],{"class":332}," 0.1\n",[221,410,412,415,417,419,422,425,428,430,433,436,439,442,445,447,450,452],{"class":223,"line":411},9,[221,413,414],{"class":227},"    return",[221,416,316],{"class":231},[221,418,319],{"class":270},[221,420,421],{"class":322},"cat",[221,423,424],{"class":270},"([",[221,426,427],{"class":322},"xy",[221,429,278],{"class":270},[221,431,432],{"class":322}," xy ",[221,434,435],{"class":312},"+",[221,437,438],{"class":322}," wh",[221,440,441],{"class":270},"],",[221,443,444],{"class":338}," dim",[221,446,313],{"class":312},[221,448,449],{"class":332},"1",[221,451,396],{"class":270},[221,453,454],{"class":243},"   # (n, 4) = x1, y1, x2, y2\n",[221,456,458],{"class":223,"line":457},10,[221,459,251],{"emptyLinePlaceholder":250},[221,461,463],{"class":223,"line":462},11,[221,464,251],{"emptyLinePlaceholder":250},[221,466,468,470,473,475,478,480,483],{"class":223,"line":467},12,[221,469,263],{"class":262},[221,471,472],{"class":266}," iou_cost",[221,474,271],{"class":270},[221,476,477],{"class":274},"boxes_a",[221,479,278],{"class":270},[221,481,482],{"class":274}," boxes_b",[221,484,289],{"class":270},[221,486,488,490,493],{"class":223,"line":487},13,[221,489,296],{"class":295},[221,491,492],{"class":299},"Pairwise (1 - IoU) cost matrix.",[221,494,303],{"class":295},[221,496,498,501,503,505,507,510,512,514,517,521,523,526,529,531,533,536,539,541,544,546,548],{"class":223,"line":497},14,[221,499,500],{"class":231},"    lo ",[221,502,313],{"class":312},[221,504,316],{"class":231},[221,506,319],{"class":270},[221,508,509],{"class":322},"maximum",[221,511,271],{"class":270},[221,513,477],{"class":322},[221,515,516],{"class":270},"[:,",[221,518,520],{"class":519},"s39Yj"," None",[221,522,278],{"class":270},[221,524,525],{"class":270}," :",[221,527,528],{"class":332},"2",[221,530,441],{"class":270},[221,532,482],{"class":322},[221,534,535],{"class":270},"[",[221,537,538],{"class":519},"None",[221,540,278],{"class":270},[221,542,543],{"class":270}," :,",[221,545,525],{"class":270},[221,547,528],{"class":332},[221,549,550],{"class":270},"])\n",[221,552,554,557,559,561,563,566,568,570,572,574,576,578,581,583,585,587,589,591,593],{"class":223,"line":553},15,[221,555,556],{"class":231},"    hi ",[221,558,313],{"class":312},[221,560,316],{"class":231},[221,562,319],{"class":270},[221,564,565],{"class":322},"minimum",[221,567,271],{"class":270},[221,569,477],{"class":322},[221,571,516],{"class":270},[221,573,520],{"class":519},[221,575,278],{"class":270},[221,577,333],{"class":332},[221,579,580],{"class":270},":],",[221,582,482],{"class":322},[221,584,535],{"class":270},[221,586,538],{"class":519},[221,588,278],{"class":270},[221,590,543],{"class":270},[221,592,333],{"class":332},[221,594,595],{"class":270},":])\n",[221,597,599,602,604,607,610,613,616,619,622,624,627,629,632,634,636,638],{"class":223,"line":598},16,[221,600,601],{"class":231},"    inter ",[221,603,313],{"class":312},[221,605,606],{"class":270}," (",[221,608,609],{"class":231},"hi ",[221,611,612],{"class":312},"-",[221,614,615],{"class":231}," lo",[221,617,618],{"class":270},").",[221,620,621],{"class":322},"clamp_min",[221,623,271],{"class":270},[221,625,626],{"class":332},"0",[221,628,618],{"class":270},[221,630,631],{"class":322},"prod",[221,633,271],{"class":270},[221,635,612],{"class":312},[221,637,449],{"class":332},[221,639,355],{"class":270},[221,641,643,646,648,650,652,654,656,659,662,665,667,669,671,674,676,678,680,682,685,687],{"class":223,"line":642},17,[221,644,645],{"class":231},"    area_a ",[221,647,313],{"class":312},[221,649,606],{"class":270},[221,651,477],{"class":231},[221,653,516],{"class":270},[221,655,333],{"class":332},[221,657,658],{"class":270},":]",[221,660,661],{"class":312}," -",[221,663,664],{"class":231}," boxes_a",[221,666,516],{"class":270},[221,668,525],{"class":270},[221,670,528],{"class":332},[221,672,673],{"class":270},"]).",[221,675,631],{"class":322},[221,677,271],{"class":270},[221,679,612],{"class":312},[221,681,449],{"class":332},[221,683,684],{"class":270},")[:,",[221,686,520],{"class":519},[221,688,689],{"class":270},"]\n",[221,691,693,696,698,700,703,705,707,709,711,713,715,717,719,721,723,725,727,729,732,734,736],{"class":223,"line":692},18,[221,694,695],{"class":231},"    area_b ",[221,697,313],{"class":312},[221,699,606],{"class":270},[221,701,702],{"class":231},"boxes_b",[221,704,516],{"class":270},[221,706,333],{"class":332},[221,708,658],{"class":270},[221,710,661],{"class":312},[221,712,482],{"class":231},[221,714,516],{"class":270},[221,716,525],{"class":270},[221,718,528],{"class":332},[221,720,673],{"class":270},[221,722,631],{"class":322},[221,724,271],{"class":270},[221,726,612],{"class":312},[221,728,449],{"class":332},[221,730,731],{"class":270},")[",[221,733,538],{"class":519},[221,735,278],{"class":270},[221,737,738],{"class":270}," :]\n",[221,740,742,745,747,750,753,755,758,760,763,765,767,769,772],{"class":223,"line":741},19,[221,743,744],{"class":231},"    iou ",[221,746,313],{"class":312},[221,748,749],{"class":231}," inter ",[221,751,752],{"class":312},"\u002F",[221,754,606],{"class":270},[221,756,757],{"class":231},"area_a ",[221,759,435],{"class":312},[221,761,762],{"class":231}," area_b ",[221,764,612],{"class":312},[221,766,749],{"class":231},[221,768,435],{"class":312},[221,770,771],{"class":332}," 1e-9",[221,773,355],{"class":270},[221,775,777,779,782,784],{"class":223,"line":776},20,[221,778,414],{"class":227},[221,780,781],{"class":332}," 1.0",[221,783,661],{"class":312},[221,785,786],{"class":231}," iou\n",[221,788,790],{"class":223,"line":789},21,[221,791,251],{"emptyLinePlaceholder":250},[221,793,795],{"class":223,"line":794},22,[221,796,251],{"emptyLinePlaceholder":250},[221,798,800,802,805,807,810,812,815,817,819],{"class":223,"line":799},23,[221,801,263],{"class":262},[221,803,804],{"class":266}," build_batch",[221,806,271],{"class":270},[221,808,809],{"class":274},"B",[221,811,278],{"class":270},[221,813,814],{"class":274}," N",[221,816,278],{"class":270},[221,818,281],{"class":274},[221,820,289],{"class":270},[221,822,824,827,829,831,833,836,838,840,842,844,846,849,851,853],{"class":223,"line":823},24,[221,825,826],{"class":231},"    g ",[221,828,313],{"class":312},[221,830,316],{"class":231},[221,832,319],{"class":270},[221,834,835],{"class":322},"Generator",[221,837,271],{"class":270},[221,839,352],{"class":338},[221,841,313],{"class":312},[221,843,352],{"class":322},[221,845,618],{"class":270},[221,847,848],{"class":322},"manual_seed",[221,850,271],{"class":270},[221,852,626],{"class":332},[221,854,355],{"class":270},[221,856,858,860,862,864,867],{"class":223,"line":857},25,[221,859,414],{"class":227},[221,861,316],{"class":231},[221,863,319],{"class":270},[221,865,866],{"class":322},"stack",[221,868,869],{"class":270},"([\n",[221,871,873,876,878,881,883,886,888,890,892,895,898,900,902,904,906,908,910,912],{"class":223,"line":872},26,[221,874,875],{"class":322},"        iou_cost",[221,877,271],{"class":270},[221,879,880],{"class":322},"boxes",[221,882,271],{"class":270},[221,884,885],{"class":322},"N",[221,887,278],{"class":270},[221,889,281],{"class":322},[221,891,278],{"class":270},[221,893,894],{"class":322}," g",[221,896,897],{"class":270},"),",[221,899,267],{"class":322},[221,901,271],{"class":270},[221,903,885],{"class":322},[221,905,278],{"class":270},[221,907,281],{"class":322},[221,909,278],{"class":270},[221,911,894],{"class":322},[221,913,914],{"class":270},"))\n",[221,916,918,921,924,927,931,933,935],{"class":223,"line":917},27,[221,919,920],{"class":227},"        for",[221,922,923],{"class":322}," _ ",[221,925,926],{"class":227},"in",[221,928,930],{"class":929},"sptTA"," range",[221,932,271],{"class":270},[221,934,809],{"class":322},[221,936,355],{"class":270},[221,938,940,943,946],{"class":223,"line":939},28,[221,941,942],{"class":270},"    ]).",[221,944,945],{"class":322},"contiguous",[221,947,948],{"class":270},"()\n",[207,950,952],{"id":951},"picking-the-right-batched-op","Picking the right batched op",[182,954,955,956,958,959,962],{},"There are only a few batched solver functions to choose from. For a batch\nof ",[202,957,809],{}," problems of size ",[202,960,961],{},"N×N",":",[212,964,966],{"className":214,"code":965,"language":216,"meta":217,"style":217},"def solve_batch(costs: torch.Tensor) -> torch.Tensor:\n    \"\"\"Dispatch to the fastest backend for this batch shape.\"\"\"\n    B, N, _ = costs.shape\n\n    if costs.is_cuda and N \u003C= 64:\n        # CUDA tiled backend is CUDA-graph-safe; pick it when it applies.\n        return torchmatch.assignment.ops.jonker_dense_batch(costs)\n\n    if costs.is_cuda:\n        # Tiled CUDA kernel rejects K > 64, so route oversized problems via CPU.\n        out_cpu = torchmatch.assignment.ops.jonker_dense_batch(costs.cpu())\n        return out_cpu.to(costs.device)\n\n    return torchmatch.assignment.ops.jonker_dense_batch(costs)\n",[202,967,968,1004,1013,1036,1040,1066,1071,1100,1104,1116,1121,1154,1176,1180],{"__ignoreMap":217},[221,969,970,972,975,977,980,982,984,986,990,992,995,997,999,1001],{"class":223,"line":224},[221,971,263],{"class":262},[221,973,974],{"class":266}," solve_batch",[221,976,271],{"class":270},[221,978,979],{"class":274},"costs",[221,981,962],{"class":270},[221,983,316],{"class":231},[221,985,319],{"class":270},[221,987,989],{"class":988},"skxfh","Tensor",[221,991,396],{"class":270},[221,993,994],{"class":270}," ->",[221,996,316],{"class":231},[221,998,319],{"class":270},[221,1000,989],{"class":988},[221,1002,1003],{"class":270},":\n",[221,1005,1006,1008,1011],{"class":223,"line":235},[221,1007,296],{"class":295},[221,1009,1010],{"class":299},"Dispatch to the fastest backend for this batch shape.",[221,1012,303],{"class":295},[221,1014,1015,1018,1020,1022,1024,1026,1028,1031,1033],{"class":223,"line":247},[221,1016,1017],{"class":231},"    B",[221,1019,278],{"class":270},[221,1021,814],{"class":231},[221,1023,278],{"class":270},[221,1025,923],{"class":231},[221,1027,313],{"class":312},[221,1029,1030],{"class":231}," costs",[221,1032,319],{"class":270},[221,1034,1035],{"class":988},"shape\n",[221,1037,1038],{"class":223,"line":254},[221,1039,251],{"emptyLinePlaceholder":250},[221,1041,1042,1045,1047,1049,1052,1055,1058,1061,1064],{"class":223,"line":259},[221,1043,1044],{"class":227},"    if",[221,1046,1030],{"class":231},[221,1048,319],{"class":270},[221,1050,1051],{"class":988},"is_cuda",[221,1053,1054],{"class":312}," and",[221,1056,1057],{"class":231}," N ",[221,1059,1060],{"class":312},"\u003C=",[221,1062,1063],{"class":332}," 64",[221,1065,1003],{"class":270},[221,1067,1068],{"class":223,"line":292},[221,1069,1070],{"class":243},"        # CUDA tiled backend is CUDA-graph-safe; pick it when it applies.\n",[221,1072,1073,1076,1079,1081,1084,1086,1089,1091,1094,1096,1098],{"class":223,"line":306},[221,1074,1075],{"class":227},"        return",[221,1077,1078],{"class":231}," torchmatch",[221,1080,319],{"class":270},[221,1082,1083],{"class":988},"assignment",[221,1085,319],{"class":270},[221,1087,1088],{"class":988},"ops",[221,1090,319],{"class":270},[221,1092,1093],{"class":322},"jonker_dense_batch",[221,1095,271],{"class":270},[221,1097,979],{"class":322},[221,1099,355],{"class":270},[221,1101,1102],{"class":223,"line":358},[221,1103,251],{"emptyLinePlaceholder":250},[221,1105,1106,1108,1110,1112,1114],{"class":223,"line":411},[221,1107,1044],{"class":227},[221,1109,1030],{"class":231},[221,1111,319],{"class":270},[221,1113,1051],{"class":988},[221,1115,1003],{"class":270},[221,1117,1118],{"class":223,"line":457},[221,1119,1120],{"class":243},"        # Tiled CUDA kernel rejects K > 64, so route oversized problems via CPU.\n",[221,1122,1123,1126,1128,1130,1132,1134,1136,1138,1140,1142,1144,1146,1148,1151],{"class":223,"line":462},[221,1124,1125],{"class":231},"        out_cpu ",[221,1127,313],{"class":312},[221,1129,1078],{"class":231},[221,1131,319],{"class":270},[221,1133,1083],{"class":988},[221,1135,319],{"class":270},[221,1137,1088],{"class":988},[221,1139,319],{"class":270},[221,1141,1093],{"class":322},[221,1143,271],{"class":270},[221,1145,979],{"class":322},[221,1147,319],{"class":270},[221,1149,1150],{"class":322},"cpu",[221,1152,1153],{"class":270},"())\n",[221,1155,1156,1158,1161,1163,1166,1168,1170,1172,1174],{"class":223,"line":467},[221,1157,1075],{"class":227},[221,1159,1160],{"class":231}," out_cpu",[221,1162,319],{"class":270},[221,1164,1165],{"class":322},"to",[221,1167,271],{"class":270},[221,1169,979],{"class":322},[221,1171,319],{"class":270},[221,1173,352],{"class":988},[221,1175,355],{"class":270},[221,1177,1178],{"class":223,"line":487},[221,1179,251],{"emptyLinePlaceholder":250},[221,1181,1182,1184,1186,1188,1190,1192,1194,1196,1198,1200,1202],{"class":223,"line":497},[221,1183,414],{"class":227},[221,1185,1078],{"class":231},[221,1187,319],{"class":270},[221,1189,1083],{"class":988},[221,1191,319],{"class":270},[221,1193,1088],{"class":988},[221,1195,319],{"class":270},[221,1197,1093],{"class":322},[221,1199,271],{"class":270},[221,1201,979],{"class":322},[221,1203,355],{"class":270},[182,1205,1206,1207,1210,1211,1213],{},"The CUDA tiled kernel is fastest for typical tracking costs when ",[202,1208,1209],{},"N ≤ 64",".\nFor larger ",[202,1212,885],{},", routing through CPU is faster because the CPU op distributes\neach problem to a separate thread in parallel — CUDA's advantage diminishes\nwhen each problem is too large to fit in on-chip shared memory.",[207,1215,1217],{"id":1216},"running-it","Running it",[212,1219,1221],{"className":214,"code":1220,"language":216,"meta":217,"style":217},"device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\n# B=16 frames, N=32 boxes per frame\ncosts = build_batch(B=16, N=32, device=device)\n\nrow_to_col = solve_batch(costs)\nprint(row_to_col.shape)\n# (16, 32). For each frame, the row→col mapping.\n\n# Total cost across the batch\nbatch_idx = torch.arange(16, device=device)[:, None]\nrow_idx = torch.arange(32, device=device)[None, :]\nmatched = row_to_col >= 0\ntotals = (costs[batch_idx, row_idx, row_to_col.clamp_min(0)] * matched).sum(-1)\nprint(totals)\n",[202,1222,1223,1268,1272,1277,1314,1318,1333,1350,1355,1359,1364,1396,1429,1445,1500],{"__ignoreMap":217},[221,1224,1225,1228,1230,1234,1238,1241,1244,1246,1248,1250,1252,1255,1258,1261,1263,1265],{"class":223,"line":224},[221,1226,1227],{"class":231},"device ",[221,1229,313],{"class":312},[221,1231,1233],{"class":1232},"sjJ54"," \"",[221,1235,1237],{"class":1236},"s_sjI","cuda",[221,1239,1240],{"class":1232},"\"",[221,1242,1243],{"class":227}," if",[221,1245,316],{"class":231},[221,1247,319],{"class":270},[221,1249,1237],{"class":988},[221,1251,319],{"class":270},[221,1253,1254],{"class":322},"is_available",[221,1256,1257],{"class":270},"()",[221,1259,1260],{"class":227}," else",[221,1262,1233],{"class":1232},[221,1264,1150],{"class":1236},[221,1266,1267],{"class":1232},"\"\n",[221,1269,1270],{"class":223,"line":235},[221,1271,251],{"emptyLinePlaceholder":250},[221,1273,1274],{"class":223,"line":247},[221,1275,1276],{"class":243},"# B=16 frames, N=32 boxes per frame\n",[221,1278,1279,1282,1284,1286,1288,1290,1292,1295,1297,1299,1301,1304,1306,1308,1310,1312],{"class":223,"line":254},[221,1280,1281],{"class":231},"costs ",[221,1283,313],{"class":312},[221,1285,804],{"class":322},[221,1287,271],{"class":270},[221,1289,809],{"class":338},[221,1291,313],{"class":312},[221,1293,1294],{"class":332},"16",[221,1296,278],{"class":270},[221,1298,814],{"class":338},[221,1300,313],{"class":312},[221,1302,1303],{"class":332},"32",[221,1305,278],{"class":270},[221,1307,281],{"class":338},[221,1309,313],{"class":312},[221,1311,352],{"class":322},[221,1313,355],{"class":270},[221,1315,1316],{"class":223,"line":259},[221,1317,251],{"emptyLinePlaceholder":250},[221,1319,1320,1323,1325,1327,1329,1331],{"class":223,"line":292},[221,1321,1322],{"class":231},"row_to_col ",[221,1324,313],{"class":312},[221,1326,974],{"class":322},[221,1328,271],{"class":270},[221,1330,979],{"class":322},[221,1332,355],{"class":270},[221,1334,1335,1338,1340,1343,1345,1348],{"class":223,"line":306},[221,1336,1337],{"class":929},"print",[221,1339,271],{"class":270},[221,1341,1342],{"class":322},"row_to_col",[221,1344,319],{"class":270},[221,1346,1347],{"class":988},"shape",[221,1349,355],{"class":270},[221,1351,1352],{"class":223,"line":358},[221,1353,1354],{"class":243},"# (16, 32). For each frame, the row→col mapping.\n",[221,1356,1357],{"class":223,"line":411},[221,1358,251],{"emptyLinePlaceholder":250},[221,1360,1361],{"class":223,"line":457},[221,1362,1363],{"class":243},"# Total cost across the batch\n",[221,1365,1366,1369,1371,1373,1375,1378,1380,1382,1384,1386,1388,1390,1392,1394],{"class":223,"line":462},[221,1367,1368],{"class":231},"batch_idx ",[221,1370,313],{"class":312},[221,1372,316],{"class":231},[221,1374,319],{"class":270},[221,1376,1377],{"class":322},"arange",[221,1379,271],{"class":270},[221,1381,1294],{"class":332},[221,1383,278],{"class":270},[221,1385,281],{"class":338},[221,1387,313],{"class":312},[221,1389,352],{"class":322},[221,1391,684],{"class":270},[221,1393,520],{"class":519},[221,1395,689],{"class":270},[221,1397,1398,1401,1403,1405,1407,1409,1411,1413,1415,1417,1419,1421,1423,1425,1427],{"class":223,"line":467},[221,1399,1400],{"class":231},"row_idx ",[221,1402,313],{"class":312},[221,1404,316],{"class":231},[221,1406,319],{"class":270},[221,1408,1377],{"class":322},[221,1410,271],{"class":270},[221,1412,1303],{"class":332},[221,1414,278],{"class":270},[221,1416,281],{"class":338},[221,1418,313],{"class":312},[221,1420,352],{"class":322},[221,1422,731],{"class":270},[221,1424,538],{"class":519},[221,1426,278],{"class":270},[221,1428,738],{"class":270},[221,1430,1431,1434,1436,1439,1442],{"class":223,"line":487},[221,1432,1433],{"class":231},"matched ",[221,1435,313],{"class":312},[221,1437,1438],{"class":231}," row_to_col ",[221,1440,1441],{"class":312},">=",[221,1443,1444],{"class":332}," 0\n",[221,1446,1447,1450,1452,1454,1456,1458,1461,1463,1466,1468,1471,1473,1475,1477,1479,1482,1484,1487,1489,1492,1494,1496,1498],{"class":223,"line":497},[221,1448,1449],{"class":231},"totals ",[221,1451,313],{"class":312},[221,1453,606],{"class":270},[221,1455,979],{"class":231},[221,1457,535],{"class":270},[221,1459,1460],{"class":231},"batch_idx",[221,1462,278],{"class":270},[221,1464,1465],{"class":231}," row_idx",[221,1467,278],{"class":270},[221,1469,1470],{"class":231}," row_to_col",[221,1472,319],{"class":270},[221,1474,621],{"class":322},[221,1476,271],{"class":270},[221,1478,626],{"class":332},[221,1480,1481],{"class":270},")]",[221,1483,399],{"class":312},[221,1485,1486],{"class":231}," matched",[221,1488,618],{"class":270},[221,1490,1491],{"class":322},"sum",[221,1493,271],{"class":270},[221,1495,612],{"class":312},[221,1497,449],{"class":332},[221,1499,355],{"class":270},[221,1501,1502,1504,1506,1509],{"class":223,"line":553},[221,1503,1337],{"class":929},[221,1505,271],{"class":270},[221,1507,1508],{"class":322},"totals",[221,1510,355],{"class":270},[207,1512,1514],{"id":1513},"getting-the-unmatched-sets-in-one-pass","Getting the unmatched sets in one pass",[182,1516,1517,1518,1521],{},"When you need to separately access the matched pairs and the unmatched\ndetections or tracks, the ",[202,1519,1520],{},"_unpacked"," variants return those as three tensors\ndirectly. Without them, you would have to loop over the row-to-column index\ntensor in Python and compute the unmatched sets yourself.",[1523,1524,1527,1812],"code-tabs",{"default":1525,"direct-label":1526},"solve","jonker_dense_batch_unpacked",[1528,1529,1530],"template",{"v-slot:solve":217},[212,1531,1533],{"className":214,"code":1532,"language":216,"meta":217,"style":217},"costs_cpu = costs.cpu()\nmatches, ur, uc, n_matched = torchmatch.assignment.solve(\n    costs_cpu, unpack=True,\n)\n\n# Tensor shapes:\n#   matches[b, k]    = (row, col) of the k-th match in problem b. Padded with -1.\n#   ur[b, k]         = index of the k-th unmatched row in problem b. Padded.\n#   uc[b, k]         = index of the k-th unmatched column. Padded.\n#   n_matched[b]     = actual number of matches in problem b.\n\n# Per-problem unpack:\nfor b in range(matches.shape[0]):\n    nm = int(n_matched[b].item())\n    real_matches = matches[b, :nm]\n    real_unmatched_rows = ur[b, :int(costs_cpu.size(1) - nm)]\n    real_unmatched_cols = uc[b, :int(costs_cpu.size(2) - nm)]\n    # ... use them\n",[202,1534,1535,1550,1585,1603,1607,1611,1616,1621,1626,1631,1636,1640,1645,1672,1701,1724,1768,1807],{"__ignoreMap":217},[221,1536,1537,1540,1542,1544,1546,1548],{"class":223,"line":224},[221,1538,1539],{"class":231},"costs_cpu ",[221,1541,313],{"class":312},[221,1543,1030],{"class":231},[221,1545,319],{"class":270},[221,1547,1150],{"class":322},[221,1549,948],{"class":270},[221,1551,1552,1555,1557,1560,1562,1565,1567,1570,1572,1574,1576,1578,1580,1582],{"class":223,"line":235},[221,1553,1554],{"class":231},"matches",[221,1556,278],{"class":270},[221,1558,1559],{"class":231}," ur",[221,1561,278],{"class":270},[221,1563,1564],{"class":231}," uc",[221,1566,278],{"class":270},[221,1568,1569],{"class":231}," n_matched ",[221,1571,313],{"class":312},[221,1573,1078],{"class":231},[221,1575,319],{"class":270},[221,1577,1083],{"class":988},[221,1579,319],{"class":270},[221,1581,1525],{"class":322},[221,1583,1584],{"class":270},"(\n",[221,1586,1587,1590,1592,1595,1597,1600],{"class":223,"line":247},[221,1588,1589],{"class":322},"    costs_cpu",[221,1591,278],{"class":270},[221,1593,1594],{"class":338}," unpack",[221,1596,313],{"class":312},[221,1598,1599],{"class":519},"True",[221,1601,1602],{"class":270},",\n",[221,1604,1605],{"class":223,"line":254},[221,1606,355],{"class":270},[221,1608,1609],{"class":223,"line":259},[221,1610,251],{"emptyLinePlaceholder":250},[221,1612,1613],{"class":223,"line":292},[221,1614,1615],{"class":243},"# Tensor shapes:\n",[221,1617,1618],{"class":223,"line":306},[221,1619,1620],{"class":243},"#   matches[b, k]    = (row, col) of the k-th match in problem b. Padded with -1.\n",[221,1622,1623],{"class":223,"line":358},[221,1624,1625],{"class":243},"#   ur[b, k]         = index of the k-th unmatched row in problem b. Padded.\n",[221,1627,1628],{"class":223,"line":411},[221,1629,1630],{"class":243},"#   uc[b, k]         = index of the k-th unmatched column. Padded.\n",[221,1632,1633],{"class":223,"line":457},[221,1634,1635],{"class":243},"#   n_matched[b]     = actual number of matches in problem b.\n",[221,1637,1638],{"class":223,"line":462},[221,1639,251],{"emptyLinePlaceholder":250},[221,1641,1642],{"class":223,"line":467},[221,1643,1644],{"class":243},"# Per-problem unpack:\n",[221,1646,1647,1650,1653,1655,1657,1659,1661,1663,1665,1667,1669],{"class":223,"line":487},[221,1648,1649],{"class":227},"for",[221,1651,1652],{"class":231}," b ",[221,1654,926],{"class":227},[221,1656,930],{"class":929},[221,1658,271],{"class":270},[221,1660,1554],{"class":322},[221,1662,319],{"class":270},[221,1664,1347],{"class":988},[221,1666,535],{"class":270},[221,1668,626],{"class":332},[221,1670,1671],{"class":270},"]):\n",[221,1673,1674,1677,1679,1683,1685,1688,1690,1693,1696,1699],{"class":223,"line":497},[221,1675,1676],{"class":231},"    nm ",[221,1678,313],{"class":312},[221,1680,1682],{"class":1681},"sZMiF"," int",[221,1684,271],{"class":270},[221,1686,1687],{"class":322},"n_matched",[221,1689,535],{"class":270},[221,1691,1692],{"class":322},"b",[221,1694,1695],{"class":270},"].",[221,1697,1698],{"class":322},"item",[221,1700,1153],{"class":270},[221,1702,1703,1706,1708,1711,1713,1715,1717,1719,1722],{"class":223,"line":553},[221,1704,1705],{"class":231},"    real_matches ",[221,1707,313],{"class":312},[221,1709,1710],{"class":231}," matches",[221,1712,535],{"class":270},[221,1714,1692],{"class":231},[221,1716,278],{"class":270},[221,1718,525],{"class":270},[221,1720,1721],{"class":231},"nm",[221,1723,689],{"class":270},[221,1725,1726,1729,1731,1733,1735,1737,1739,1741,1744,1746,1749,1751,1754,1756,1758,1760,1762,1765],{"class":223,"line":598},[221,1727,1728],{"class":231},"    real_unmatched_rows ",[221,1730,313],{"class":312},[221,1732,1559],{"class":231},[221,1734,535],{"class":270},[221,1736,1692],{"class":231},[221,1738,278],{"class":270},[221,1740,525],{"class":270},[221,1742,1743],{"class":1681},"int",[221,1745,271],{"class":270},[221,1747,1748],{"class":322},"costs_cpu",[221,1750,319],{"class":270},[221,1752,1753],{"class":322},"size",[221,1755,271],{"class":270},[221,1757,449],{"class":332},[221,1759,396],{"class":270},[221,1761,661],{"class":312},[221,1763,1764],{"class":322}," nm",[221,1766,1767],{"class":270},")]\n",[221,1769,1770,1773,1775,1777,1779,1781,1783,1785,1787,1789,1791,1793,1795,1797,1799,1801,1803,1805],{"class":223,"line":642},[221,1771,1772],{"class":231},"    real_unmatched_cols ",[221,1774,313],{"class":312},[221,1776,1564],{"class":231},[221,1778,535],{"class":270},[221,1780,1692],{"class":231},[221,1782,278],{"class":270},[221,1784,525],{"class":270},[221,1786,1743],{"class":1681},[221,1788,271],{"class":270},[221,1790,1748],{"class":322},[221,1792,319],{"class":270},[221,1794,1753],{"class":322},[221,1796,271],{"class":270},[221,1798,528],{"class":332},[221,1800,396],{"class":270},[221,1802,661],{"class":312},[221,1804,1764],{"class":322},[221,1806,1767],{"class":270},[221,1808,1809],{"class":223,"line":692},[221,1810,1811],{"class":243},"    # ... use them\n",[1528,1813,1814],{"v-slot:direct":217},[212,1815,1817],{"className":214,"code":1816,"language":216,"meta":217,"style":217},"# AUTO would route to jonker_dense_batch_unpacked here; calling it\n# directly lets you pick jonker_compact_batch_unpacked instead for\n# square problems with smooth costs.\ncosts_cpu = costs.cpu()\nmatches, ur, uc, n_matched = torchmatch.assignment.ops.jonker_dense_batch_unpacked(costs_cpu)\n\n# Tensor shapes:\n#   matches[b, k]    = (row, col) of the k-th match in problem b. Padded with -1.\n#   ur[b, k]         = index of the k-th unmatched row in problem b. Padded.\n#   uc[b, k]         = index of the k-th unmatched column. Padded.\n#   n_matched[b]     = actual number of matches in problem b.\n\n# Per-problem unpack:\nfor b in range(matches.shape[0]):\n    nm = int(n_matched[b].item())\n    real_matches = matches[b, :nm]\n    real_unmatched_rows = ur[b, :int(costs_cpu.size(1) - nm)]\n    real_unmatched_cols = uc[b, :int(costs_cpu.size(2) - nm)]\n    # ... use them\n",[202,1818,1819,1824,1829,1834,1848,1886,1890,1894,1898,1902,1906,1910,1914,1918,1942,1964,1984,2022,2060],{"__ignoreMap":217},[221,1820,1821],{"class":223,"line":224},[221,1822,1823],{"class":243},"# AUTO would route to jonker_dense_batch_unpacked here; calling it\n",[221,1825,1826],{"class":223,"line":235},[221,1827,1828],{"class":243},"# directly lets you pick jonker_compact_batch_unpacked instead for\n",[221,1830,1831],{"class":223,"line":247},[221,1832,1833],{"class":243},"# square problems with smooth costs.\n",[221,1835,1836,1838,1840,1842,1844,1846],{"class":223,"line":254},[221,1837,1539],{"class":231},[221,1839,313],{"class":312},[221,1841,1030],{"class":231},[221,1843,319],{"class":270},[221,1845,1150],{"class":322},[221,1847,948],{"class":270},[221,1849,1850,1852,1854,1856,1858,1860,1862,1864,1866,1868,1870,1872,1874,1876,1878,1880,1882,1884],{"class":223,"line":259},[221,1851,1554],{"class":231},[221,1853,278],{"class":270},[221,1855,1559],{"class":231},[221,1857,278],{"class":270},[221,1859,1564],{"class":231},[221,1861,278],{"class":270},[221,1863,1569],{"class":231},[221,1865,313],{"class":312},[221,1867,1078],{"class":231},[221,1869,319],{"class":270},[221,1871,1083],{"class":988},[221,1873,319],{"class":270},[221,1875,1088],{"class":988},[221,1877,319],{"class":270},[221,1879,1526],{"class":322},[221,1881,271],{"class":270},[221,1883,1748],{"class":322},[221,1885,355],{"class":270},[221,1887,1888],{"class":223,"line":292},[221,1889,251],{"emptyLinePlaceholder":250},[221,1891,1892],{"class":223,"line":306},[221,1893,1615],{"class":243},[221,1895,1896],{"class":223,"line":358},[221,1897,1620],{"class":243},[221,1899,1900],{"class":223,"line":411},[221,1901,1625],{"class":243},[221,1903,1904],{"class":223,"line":457},[221,1905,1630],{"class":243},[221,1907,1908],{"class":223,"line":462},[221,1909,1635],{"class":243},[221,1911,1912],{"class":223,"line":467},[221,1913,251],{"emptyLinePlaceholder":250},[221,1915,1916],{"class":223,"line":487},[221,1917,1644],{"class":243},[221,1919,1920,1922,1924,1926,1928,1930,1932,1934,1936,1938,1940],{"class":223,"line":497},[221,1921,1649],{"class":227},[221,1923,1652],{"class":231},[221,1925,926],{"class":227},[221,1927,930],{"class":929},[221,1929,271],{"class":270},[221,1931,1554],{"class":322},[221,1933,319],{"class":270},[221,1935,1347],{"class":988},[221,1937,535],{"class":270},[221,1939,626],{"class":332},[221,1941,1671],{"class":270},[221,1943,1944,1946,1948,1950,1952,1954,1956,1958,1960,1962],{"class":223,"line":553},[221,1945,1676],{"class":231},[221,1947,313],{"class":312},[221,1949,1682],{"class":1681},[221,1951,271],{"class":270},[221,1953,1687],{"class":322},[221,1955,535],{"class":270},[221,1957,1692],{"class":322},[221,1959,1695],{"class":270},[221,1961,1698],{"class":322},[221,1963,1153],{"class":270},[221,1965,1966,1968,1970,1972,1974,1976,1978,1980,1982],{"class":223,"line":598},[221,1967,1705],{"class":231},[221,1969,313],{"class":312},[221,1971,1710],{"class":231},[221,1973,535],{"class":270},[221,1975,1692],{"class":231},[221,1977,278],{"class":270},[221,1979,525],{"class":270},[221,1981,1721],{"class":231},[221,1983,689],{"class":270},[221,1985,1986,1988,1990,1992,1994,1996,1998,2000,2002,2004,2006,2008,2010,2012,2014,2016,2018,2020],{"class":223,"line":642},[221,1987,1728],{"class":231},[221,1989,313],{"class":312},[221,1991,1559],{"class":231},[221,1993,535],{"class":270},[221,1995,1692],{"class":231},[221,1997,278],{"class":270},[221,1999,525],{"class":270},[221,2001,1743],{"class":1681},[221,2003,271],{"class":270},[221,2005,1748],{"class":322},[221,2007,319],{"class":270},[221,2009,1753],{"class":322},[221,2011,271],{"class":270},[221,2013,449],{"class":332},[221,2015,396],{"class":270},[221,2017,661],{"class":312},[221,2019,1764],{"class":322},[221,2021,1767],{"class":270},[221,2023,2024,2026,2028,2030,2032,2034,2036,2038,2040,2042,2044,2046,2048,2050,2052,2054,2056,2058],{"class":223,"line":692},[221,2025,1772],{"class":231},[221,2027,313],{"class":312},[221,2029,1564],{"class":231},[221,2031,535],{"class":270},[221,2033,1692],{"class":231},[221,2035,278],{"class":270},[221,2037,525],{"class":270},[221,2039,1743],{"class":1681},[221,2041,271],{"class":270},[221,2043,1748],{"class":322},[221,2045,319],{"class":270},[221,2047,1753],{"class":322},[221,2049,271],{"class":270},[221,2051,528],{"class":332},[221,2053,396],{"class":270},[221,2055,661],{"class":312},[221,2057,1764],{"class":322},[221,2059,1767],{"class":270},[221,2061,2062],{"class":223,"line":741},[221,2063,1811],{"class":243},[182,2065,2066,2067,2069],{},"The ",[202,2068,1520],{}," variants cost about the same as the packed ones (within\nabout 5 %). When the unpacked output is what you need, use them instead\nof a post-hoc Python loop.",[207,2071,2073],{"id":2072},"adding-feasibility-gating-inf-edges","Adding feasibility gating (+inf edges)",[182,2075,2076,2077,2080],{},"Real trackers exclude implausible pairs before solving: any detection–track\npair whose center-point distance exceeds a threshold is forbidden by setting\nits cost to ",[202,2078,2079],{},"+inf",". This prevents the solver from ever matching a detection\nto a track that is too far away.",[212,2082,2084],{"className":214,"code":2083,"language":216,"meta":217,"style":217},"def gated_iou_cost(boxes_a, boxes_b, gate=0.3):\n    \"\"\"IoU cost with centroid-distance gating.\"\"\"\n    cost = iou_cost(boxes_a, boxes_b)\n    centers_a = (boxes_a[:, None, :2] + boxes_a[:, None, 2:]) \u002F 2\n    centers_b = (boxes_b[None, :, :2] + boxes_b[None, :, 2:]) \u002F 2\n    dist = (centers_a - centers_b).norm(dim=-1)\n    return cost.masked_fill(dist > gate, float(\"inf\"))\n",[202,2085,2086,2113,2122,2141,2186,2231,2265],{"__ignoreMap":217},[221,2087,2088,2090,2093,2095,2097,2099,2101,2103,2106,2108,2111],{"class":223,"line":224},[221,2089,263],{"class":262},[221,2091,2092],{"class":266}," gated_iou_cost",[221,2094,271],{"class":270},[221,2096,477],{"class":274},[221,2098,278],{"class":270},[221,2100,482],{"class":274},[221,2102,278],{"class":270},[221,2104,2105],{"class":274}," gate",[221,2107,313],{"class":312},[221,2109,2110],{"class":332},"0.3",[221,2112,289],{"class":270},[221,2114,2115,2117,2120],{"class":223,"line":235},[221,2116,296],{"class":295},[221,2118,2119],{"class":299},"IoU cost with centroid-distance gating.",[221,2121,303],{"class":295},[221,2123,2124,2127,2129,2131,2133,2135,2137,2139],{"class":223,"line":247},[221,2125,2126],{"class":231},"    cost ",[221,2128,313],{"class":312},[221,2130,472],{"class":322},[221,2132,271],{"class":270},[221,2134,477],{"class":322},[221,2136,278],{"class":270},[221,2138,482],{"class":322},[221,2140,355],{"class":270},[221,2142,2143,2146,2148,2150,2152,2154,2156,2158,2160,2162,2165,2167,2169,2171,2173,2175,2177,2180,2183],{"class":223,"line":254},[221,2144,2145],{"class":231},"    centers_a ",[221,2147,313],{"class":312},[221,2149,606],{"class":270},[221,2151,477],{"class":231},[221,2153,516],{"class":270},[221,2155,520],{"class":519},[221,2157,278],{"class":270},[221,2159,525],{"class":270},[221,2161,528],{"class":332},[221,2163,2164],{"class":270},"]",[221,2166,405],{"class":312},[221,2168,664],{"class":231},[221,2170,516],{"class":270},[221,2172,520],{"class":519},[221,2174,278],{"class":270},[221,2176,333],{"class":332},[221,2178,2179],{"class":270},":])",[221,2181,2182],{"class":312}," \u002F",[221,2184,2185],{"class":332}," 2\n",[221,2187,2188,2191,2193,2195,2197,2199,2201,2203,2205,2207,2209,2211,2213,2215,2217,2219,2221,2223,2225,2227,2229],{"class":223,"line":259},[221,2189,2190],{"class":231},"    centers_b ",[221,2192,313],{"class":312},[221,2194,606],{"class":270},[221,2196,702],{"class":231},[221,2198,535],{"class":270},[221,2200,538],{"class":519},[221,2202,278],{"class":270},[221,2204,543],{"class":270},[221,2206,525],{"class":270},[221,2208,528],{"class":332},[221,2210,2164],{"class":270},[221,2212,405],{"class":312},[221,2214,482],{"class":231},[221,2216,535],{"class":270},[221,2218,538],{"class":519},[221,2220,278],{"class":270},[221,2222,543],{"class":270},[221,2224,333],{"class":332},[221,2226,2179],{"class":270},[221,2228,2182],{"class":312},[221,2230,2185],{"class":332},[221,2232,2233,2236,2238,2240,2243,2245,2248,2250,2253,2255,2258,2261,2263],{"class":223,"line":292},[221,2234,2235],{"class":231},"    dist ",[221,2237,313],{"class":312},[221,2239,606],{"class":270},[221,2241,2242],{"class":231},"centers_a ",[221,2244,612],{"class":312},[221,2246,2247],{"class":231}," centers_b",[221,2249,618],{"class":270},[221,2251,2252],{"class":322},"norm",[221,2254,271],{"class":270},[221,2256,2257],{"class":338},"dim",[221,2259,2260],{"class":312},"=-",[221,2262,449],{"class":332},[221,2264,355],{"class":270},[221,2266,2267,2269,2272,2274,2277,2279,2282,2285,2287,2289,2292,2294,2296,2299,2301],{"class":223,"line":306},[221,2268,414],{"class":227},[221,2270,2271],{"class":231}," cost",[221,2273,319],{"class":270},[221,2275,2276],{"class":322},"masked_fill",[221,2278,271],{"class":270},[221,2280,2281],{"class":322},"dist ",[221,2283,2284],{"class":312},">",[221,2286,2105],{"class":322},[221,2288,278],{"class":270},[221,2290,2291],{"class":1681}," float",[221,2293,271],{"class":270},[221,2295,1240],{"class":1232},[221,2297,2298],{"class":1236},"inf",[221,2300,1240],{"class":1232},[221,2302,914],{"class":270},[182,2304,2305,2306,2309,2310,2312,2313,2315,2316,2319],{},"Use it the same way; ",[202,2307,2308],{},"solve_batch(costs)"," handles the ",[202,2311,2079],{}," entries\ninternally. The Jonker-Volgenant (JV) solvers handle this automatically:\nthey replace ",[202,2314,2079],{}," internally with a large finite value (a sentinel) so\nthe underlying algorithm never sees infinity, but the forbidden-pair\nconstraint is still respected. Leave at least one feasible matching per\nproblem after gating; the JV ops mark unmatchable rows with ",[202,2317,2318],{},"-1"," rather\nthan failing.",[207,2321,2323],{"id":2322},"when-to-use-a-cuda-graph","When to use a CUDA graph",[182,2325,2326,2327,2329],{},"The CUDA backend of ",[202,2328,1093],{}," is the only assignment solver that\nworks inside a CUDA graph. A CUDA graph records a sequence of GPU operations\nonce and can replay them repeatedly with minimal CPU overhead — useful when\nthe same solver call runs on every frame of an inference loop:",[212,2331,2333],{"className":214,"code":2332,"language":216,"meta":217,"style":217},"g = torch.cuda.CUDAGraph()\ncosts_in = torch.empty(16, 32, 32, device=\"cuda\")\nwith torch.cuda.graph(g):\n    out = torchmatch.assignment.ops.jonker_dense_batch(costs_in)\n\n# Per-frame:\ncosts_in.copy_(new_costs)\ng.replay()\ntorch.cuda.synchronize()\n# out is now populated\n",[202,2334,2335,2355,2396,2419,2447,2451,2456,2472,2483,2499],{"__ignoreMap":217},[221,2336,2337,2340,2342,2344,2346,2348,2350,2353],{"class":223,"line":224},[221,2338,2339],{"class":231},"g ",[221,2341,313],{"class":312},[221,2343,316],{"class":231},[221,2345,319],{"class":270},[221,2347,1237],{"class":988},[221,2349,319],{"class":270},[221,2351,2352],{"class":322},"CUDAGraph",[221,2354,948],{"class":270},[221,2356,2357,2360,2362,2364,2366,2369,2371,2373,2375,2378,2380,2382,2384,2386,2388,2390,2392,2394],{"class":223,"line":235},[221,2358,2359],{"class":231},"costs_in ",[221,2361,313],{"class":312},[221,2363,316],{"class":231},[221,2365,319],{"class":270},[221,2367,2368],{"class":322},"empty",[221,2370,271],{"class":270},[221,2372,1294],{"class":332},[221,2374,278],{"class":270},[221,2376,2377],{"class":332}," 32",[221,2379,278],{"class":270},[221,2381,2377],{"class":332},[221,2383,278],{"class":270},[221,2385,281],{"class":338},[221,2387,313],{"class":312},[221,2389,1240],{"class":1232},[221,2391,1237],{"class":1236},[221,2393,1240],{"class":1232},[221,2395,355],{"class":270},[221,2397,2398,2401,2403,2405,2407,2409,2412,2414,2417],{"class":223,"line":247},[221,2399,2400],{"class":227},"with",[221,2402,316],{"class":231},[221,2404,319],{"class":270},[221,2406,1237],{"class":988},[221,2408,319],{"class":270},[221,2410,2411],{"class":322},"graph",[221,2413,271],{"class":270},[221,2415,2416],{"class":322},"g",[221,2418,289],{"class":270},[221,2420,2421,2424,2426,2428,2430,2432,2434,2436,2438,2440,2442,2445],{"class":223,"line":254},[221,2422,2423],{"class":231},"    out ",[221,2425,313],{"class":312},[221,2427,1078],{"class":231},[221,2429,319],{"class":270},[221,2431,1083],{"class":988},[221,2433,319],{"class":270},[221,2435,1088],{"class":988},[221,2437,319],{"class":270},[221,2439,1093],{"class":322},[221,2441,271],{"class":270},[221,2443,2444],{"class":322},"costs_in",[221,2446,355],{"class":270},[221,2448,2449],{"class":223,"line":259},[221,2450,251],{"emptyLinePlaceholder":250},[221,2452,2453],{"class":223,"line":292},[221,2454,2455],{"class":243},"# Per-frame:\n",[221,2457,2458,2460,2462,2465,2467,2470],{"class":223,"line":306},[221,2459,2444],{"class":231},[221,2461,319],{"class":270},[221,2463,2464],{"class":322},"copy_",[221,2466,271],{"class":270},[221,2468,2469],{"class":322},"new_costs",[221,2471,355],{"class":270},[221,2473,2474,2476,2478,2481],{"class":223,"line":358},[221,2475,2416],{"class":231},[221,2477,319],{"class":270},[221,2479,2480],{"class":322},"replay",[221,2482,948],{"class":270},[221,2484,2485,2488,2490,2492,2494,2497],{"class":223,"line":411},[221,2486,2487],{"class":231},"torch",[221,2489,319],{"class":270},[221,2491,1237],{"class":988},[221,2493,319],{"class":270},[221,2495,2496],{"class":322},"synchronize",[221,2498,948],{"class":270},[221,2500,2501],{"class":223,"line":457},[221,2502,2503],{"class":243},"# out is now populated\n",[182,2505,2506,2507,2510,2511,2510,2514,2517,2518,2521,2522,2524],{},"The other CUDA solvers (",[202,2508,2509],{},"munkres",", ",[202,2512,2513],{},"hybrid",[202,2515,2516],{},"lawler",") cannot be recorded\ninto a CUDA graph — they synchronize with the CPU mid-execution, which\nbreaks graph capture. Do not use them inside a ",[202,2519,2520],{},"torch.cuda.graph"," block.\nUnlike the other CUDA solvers, ",[202,2523,1093],{}," never pauses to\ncommunicate with the CPU during execution, so it can be captured into a\nCUDA graph without restriction.",[207,2526,2528],{"id":2527},"whats-next","What's next",[2530,2531,2532,2539],"ul",{},[192,2533,2534,2538],{},[2535,2536,2537],"a",{"href":38},"Choosing the right op",": when to pick which variant.",[192,2540,2541,2544],{},[2535,2542,2543],{"href":34},"Operations reference",": exact constraints and\noutput shapes.",[2546,2547,2548],"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 .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sFwrP, html code.shiki .sFwrP{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#24292E;--shiki-default-font-style:inherit;--shiki-dark:#E1E4E8;--shiki-dark-font-style:inherit}html pre.shiki code .s2W-s, html code.shiki .s2W-s{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#032F62;--shiki-default-font-style:inherit;--shiki-dark:#9ECBFF;--shiki-dark-font-style:inherit}html pre.shiki code .sithA, html code.shiki .sithA{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#032F62;--shiki-default-font-style:inherit;--shiki-dark:#9ECBFF;--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 .slqww, html code.shiki .slqww{--shiki-light:#6182B8;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}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);}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":217,"searchDepth":247,"depth":247,"links":2550},[2551,2552,2553,2554,2555,2556,2557],{"id":209,"depth":235,"text":210},{"id":951,"depth":235,"text":952},{"id":1216,"depth":235,"text":1217},{"id":1513,"depth":235,"text":1514},{"id":2072,"depth":235,"text":2073},{"id":2322,"depth":235,"text":2323},{"id":2527,"depth":235,"text":2528},"Detection-to-track association on a batch of frames using IoU costs, with CPU and CUDA backends and one-pass unpacking.","md",{},{"title":26},{"title":176,"description":2558},"X3CLgLl0ewLt4G0hAYMkZKOgHALvXgrrOj8y2Fi8ULk",[2565,2567],{"title":22,"path":23,"stem":24,"description":2566,"children":-1},"Solve one cost matrix on CPU with each JV variant, covering square, rectangular, forbidden-edge, NaN, and empty inputs.",{"title":9,"path":30,"stem":31,"description":2568,"children":-1},"The linear assignment problem, the Hungarian primal-dual method, and the three implementations torchmatch ships (Munkres, Lawler, Jonker-Volgenant).",1785218159644]