[{"data":1,"prerenderedAt":1425},["ShallowReactive",2],{"navigation":3,"\u002Falgorithms\u002Ftransport\u002Fquickstart":174,"\u002Falgorithms\u002Ftransport\u002Fquickstart-surround":1420},[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":1414,"extension":1415,"links":177,"meta":1416,"navigation":1417,"path":65,"seo":1418,"stem":66,"__hash__":1419},"docs\u002F2.algorithms\u002F2.transport\u002F1.quickstart.md","Transport quickstart",null,{"type":179,"value":180,"toc":1404},"minimark",[181,201,206,221,450,460,465,478,589,593,604,725,729,739,948,961,1010,1017,1061,1065,1076,1261,1269,1273,1278,1356,1362,1366,1400],[182,183,184,188,189,192,193,196,197,200],"p",{},[185,186,187],"code",{},"import torchmatch"," also loads ",[185,190,191],{},"torchmatch.transport",". Both sub-packages\n(",[185,194,195],{},"transport.matrix"," and ",[185,198,199],{},"transport.samples",") are ready as soon as the import returns;\nno separate install is required.",[202,203,205],"h2",{"id":204},"your-first-matrix-solve","Your first matrix solve",[182,207,208,211,212,216,217,220],{},[185,209,210],{},"torchmatch.transport.matrix.solve"," takes a cost matrix and returns a transport plan — a\nmatrix P where P",[213,214,215],"span",{},"i,j"," is the fraction of the total weight assigned from source row i to\ntarget column j, with entropic regularisation added to make the solution unique and\ndifferentiable. By default, the plan is computed using the log-domain Sinkhorn algorithm\n(see ",[218,219,9],"a",{"href":72}," for details).",[222,223,228],"pre",{"className":224,"code":225,"language":226,"meta":227,"style":227},"language-python shiki shiki-themes material-theme-lighter github-light github-dark","import torch\nimport torchmatch\n\n# Cost matrix: element (i, j) = cost of moving mass (probability weight, point density,\n# or any quantity being redistributed) from source i to target j.\n# Shape: (N, M) for a single problem; (B, N, M) for a batch.\ncost = torch.rand(8, 12)\n\n# Returns a log-plan of the same shape: (8, 12).\nlog_plan = torchmatch.transport.matrix.solve(cost)\n\n# Exponentiate to get the transport plan in [0, 1].\nplan = log_plan.exp()\nprint(plan.sum(dim=-1))   # ≈ uniform, each row sums to 1\u002FN\nprint(plan.sum(dim=-2))   # ≈ uniform, each column sums to 1\u002FM\n","python","",[185,229,230,242,250,257,264,270,276,313,318,324,358,363,369,388,423],{"__ignoreMap":227},[213,231,234,238],{"class":232,"line":233},"line",1,[213,235,237],{"class":236},"sVHd0","import",[213,239,241],{"class":240},"su5hD"," torch\n",[213,243,245,247],{"class":232,"line":244},2,[213,246,237],{"class":236},[213,248,249],{"class":240}," torchmatch\n",[213,251,253],{"class":232,"line":252},3,[213,254,256],{"emptyLinePlaceholder":255},true,"\n",[213,258,260],{"class":232,"line":259},4,[213,261,263],{"class":262},"sutJx","# Cost matrix: element (i, j) = cost of moving mass (probability weight, point density,\n",[213,265,267],{"class":232,"line":266},5,[213,268,269],{"class":262},"# or any quantity being redistributed) from source i to target j.\n",[213,271,273],{"class":232,"line":272},6,[213,274,275],{"class":262},"# Shape: (N, M) for a single problem; (B, N, M) for a batch.\n",[213,277,279,282,286,289,293,297,300,304,307,310],{"class":232,"line":278},7,[213,280,281],{"class":240},"cost ",[213,283,285],{"class":284},"smGrS","=",[213,287,288],{"class":240}," torch",[213,290,292],{"class":291},"sP7_E",".",[213,294,296],{"class":295},"slqww","rand",[213,298,299],{"class":291},"(",[213,301,303],{"class":302},"srdBf","8",[213,305,306],{"class":291},",",[213,308,309],{"class":302}," 12",[213,311,312],{"class":291},")\n",[213,314,316],{"class":232,"line":315},8,[213,317,256],{"emptyLinePlaceholder":255},[213,319,321],{"class":232,"line":320},9,[213,322,323],{"class":262},"# Returns a log-plan of the same shape: (8, 12).\n",[213,325,327,330,332,335,337,341,343,346,348,351,353,356],{"class":232,"line":326},10,[213,328,329],{"class":240},"log_plan ",[213,331,285],{"class":284},[213,333,334],{"class":240}," torchmatch",[213,336,292],{"class":291},[213,338,340],{"class":339},"skxfh","transport",[213,342,292],{"class":291},[213,344,345],{"class":339},"matrix",[213,347,292],{"class":291},[213,349,350],{"class":295},"solve",[213,352,299],{"class":291},[213,354,355],{"class":295},"cost",[213,357,312],{"class":291},[213,359,361],{"class":232,"line":360},11,[213,362,256],{"emptyLinePlaceholder":255},[213,364,366],{"class":232,"line":365},12,[213,367,368],{"class":262},"# Exponentiate to get the transport plan in [0, 1].\n",[213,370,372,375,377,380,382,385],{"class":232,"line":371},13,[213,373,374],{"class":240},"plan ",[213,376,285],{"class":284},[213,378,379],{"class":240}," log_plan",[213,381,292],{"class":291},[213,383,384],{"class":295},"exp",[213,386,387],{"class":291},"()\n",[213,389,391,395,397,400,402,405,407,411,414,417,420],{"class":232,"line":390},14,[213,392,394],{"class":393},"sptTA","print",[213,396,299],{"class":291},[213,398,399],{"class":295},"plan",[213,401,292],{"class":291},[213,403,404],{"class":295},"sum",[213,406,299],{"class":291},[213,408,410],{"class":409},"s99_P","dim",[213,412,413],{"class":284},"=-",[213,415,416],{"class":302},"1",[213,418,419],{"class":291},"))",[213,421,422],{"class":262},"   # ≈ uniform, each row sums to 1\u002FN\n",[213,424,426,428,430,432,434,436,438,440,442,445,447],{"class":232,"line":425},15,[213,427,394],{"class":393},[213,429,299],{"class":291},[213,431,399],{"class":295},[213,433,292],{"class":291},[213,435,404],{"class":295},[213,437,299],{"class":291},[213,439,410],{"class":409},[213,441,413],{"class":284},[213,443,444],{"class":302},"2",[213,446,419],{"class":291},[213,448,449],{"class":262},"   # ≈ uniform, each column sums to 1\u002FM\n",[182,451,452,453,456,457,459],{},"The plan is fully differentiable: gradients flow back through ",[185,454,455],{},"log_plan.exp()"," and\n",[185,458,210],{}," to the cost matrix and, optionally, to the source and\ntarget weight vectors (marginals).",[461,462,464],"h3",{"id":463},"regularisation","Regularisation",[182,466,467,468,471,472,474,475,477],{},"The ",[185,469,470],{},"reg"," parameter controls the entropic regularisation strength. Entropic regularisation\nadds a smoothness penalty that makes the plan unique and differentiable; larger ",[185,473,470],{},"\nspreads mass more evenly across all entries, while smaller ",[185,476,470],{}," concentrates it on the\nlowest-cost assignments (approaching the unregularised optimum).",[222,479,481],{"className":224,"code":480,"language":226,"meta":227,"style":227},"# Sharp plan: closer to exact OT but slower to converge.\nlog_plan_sharp = torchmatch.transport.matrix.solve(cost, reg=0.01, n_iter=500)\n\n# Soft plan: converges in few iterations; acts as a soft attention matrix.\nlog_plan_soft = torchmatch.transport.matrix.solve(cost, reg=1.0, n_iter=50)\n",[185,482,483,488,535,539,544],{"__ignoreMap":227},[213,484,485],{"class":232,"line":233},[213,486,487],{"class":262},"# Sharp plan: closer to exact OT but slower to converge.\n",[213,489,490,493,495,497,499,501,503,505,507,509,511,513,515,518,520,523,525,528,530,533],{"class":232,"line":244},[213,491,492],{"class":240},"log_plan_sharp ",[213,494,285],{"class":284},[213,496,334],{"class":240},[213,498,292],{"class":291},[213,500,340],{"class":339},[213,502,292],{"class":291},[213,504,345],{"class":339},[213,506,292],{"class":291},[213,508,350],{"class":295},[213,510,299],{"class":291},[213,512,355],{"class":295},[213,514,306],{"class":291},[213,516,517],{"class":409}," reg",[213,519,285],{"class":284},[213,521,522],{"class":302},"0.01",[213,524,306],{"class":291},[213,526,527],{"class":409}," n_iter",[213,529,285],{"class":284},[213,531,532],{"class":302},"500",[213,534,312],{"class":291},[213,536,537],{"class":232,"line":252},[213,538,256],{"emptyLinePlaceholder":255},[213,540,541],{"class":232,"line":259},[213,542,543],{"class":262},"# Soft plan: converges in few iterations; acts as a soft attention matrix.\n",[213,545,546,549,551,553,555,557,559,561,563,565,567,569,571,573,575,578,580,582,584,587],{"class":232,"line":266},[213,547,548],{"class":240},"log_plan_soft ",[213,550,285],{"class":284},[213,552,334],{"class":240},[213,554,292],{"class":291},[213,556,340],{"class":339},[213,558,292],{"class":291},[213,560,345],{"class":339},[213,562,292],{"class":291},[213,564,350],{"class":295},[213,566,299],{"class":291},[213,568,355],{"class":295},[213,570,306],{"class":291},[213,572,517],{"class":409},[213,574,285],{"class":284},[213,576,577],{"class":302},"1.0",[213,579,306],{"class":291},[213,581,527],{"class":409},[213,583,285],{"class":284},[213,585,586],{"class":302},"50",[213,588,312],{"class":291},[461,590,592],{"id":591},"sinkhorn-divergence-debiased-scalar-loss","Sinkhorn divergence (debiased scalar loss)",[182,594,595,596,599,600,603],{},"When you need a single scalar that measures how different two distributions are — rather\nthan a full transport plan — use ",[185,597,598],{},"SINKHORN_DIVERGENCE",". It removes a systematic bias\npresent in the plain Sinkhorn loss, so the result is zero only when the two inputs are\nidentical. It returns a scalar (or ",[185,601,602],{},"(B,)"," tensor for batches).",[222,605,607],{"className":224,"code":606,"language":226,"meta":227,"style":227},"from torchmatch.transport.matrix import Backend\n\ndivergence = torchmatch.transport.matrix.solve(\n    cost,\n    backend=Backend.SINKHORN_DIVERGENCE,\n    reg=0.1,\n)\nprint(divergence)   # scalar ≥ 0; equals 0 when source == target\ndivergence.backward()\n",[185,608,609,630,634,658,666,683,695,699,714],{"__ignoreMap":227},[213,610,611,614,616,618,620,622,625,627],{"class":232,"line":233},[213,612,613],{"class":236},"from",[213,615,334],{"class":240},[213,617,292],{"class":291},[213,619,340],{"class":240},[213,621,292],{"class":291},[213,623,624],{"class":240},"matrix ",[213,626,237],{"class":236},[213,628,629],{"class":240}," Backend\n",[213,631,632],{"class":232,"line":244},[213,633,256],{"emptyLinePlaceholder":255},[213,635,636,639,641,643,645,647,649,651,653,655],{"class":232,"line":252},[213,637,638],{"class":240},"divergence ",[213,640,285],{"class":284},[213,642,334],{"class":240},[213,644,292],{"class":291},[213,646,340],{"class":339},[213,648,292],{"class":291},[213,650,345],{"class":339},[213,652,292],{"class":291},[213,654,350],{"class":295},[213,656,657],{"class":291},"(\n",[213,659,660,663],{"class":232,"line":259},[213,661,662],{"class":295},"    cost",[213,664,665],{"class":291},",\n",[213,667,668,671,673,676,678,681],{"class":232,"line":266},[213,669,670],{"class":409},"    backend",[213,672,285],{"class":284},[213,674,675],{"class":295},"Backend",[213,677,292],{"class":291},[213,679,598],{"class":680},"swQdS",[213,682,665],{"class":291},[213,684,685,688,690,693],{"class":232,"line":272},[213,686,687],{"class":409},"    reg",[213,689,285],{"class":284},[213,691,692],{"class":302},"0.1",[213,694,665],{"class":291},[213,696,697],{"class":232,"line":278},[213,698,312],{"class":291},[213,700,701,703,705,708,711],{"class":232,"line":315},[213,702,394],{"class":393},[213,704,299],{"class":291},[213,706,707],{"class":295},"divergence",[213,709,710],{"class":291},")",[213,712,713],{"class":262},"   # scalar ≥ 0; equals 0 when source == target\n",[213,715,716,718,720,723],{"class":232,"line":320},[213,717,707],{"class":240},[213,719,292],{"class":291},[213,721,722],{"class":295},"backward",[213,724,387],{"class":291},[202,726,728],{"id":727},"your-first-point-cloud-loss","Your first point-cloud loss",[182,730,731,734,735],{},[185,732,733],{},"torchmatch.transport.samples.loss"," takes two sets of points and returns a scalar that\nmeasures the optimal-transport distance between them. The pairwise distances are computed\nwithout materialising the full N×M cost matrix in memory, keeping peak memory low.\n",[736,737,738],"strong",{},"CUDA only.",[222,740,742],{"className":224,"code":741,"language":226,"meta":227,"style":227},"import torch\nimport torchmatch\n\nx = torch.randn(512, 3, device='cuda', requires_grad=True)   # source: (N, D)\ny = torch.randn(512, 3, device='cuda')                       # target: (M, D)\n\nloss = torchmatch.transport.samples.loss(x, y)\nprint(loss)         # scalar ≥ 0\n\nloss.backward()     # gradients flow through x (and y if requires_grad)\nprint(x.grad.shape) # (512, 3)\n",[185,743,744,750,756,760,817,855,859,894,907,911,925],{"__ignoreMap":227},[213,745,746,748],{"class":232,"line":233},[213,747,237],{"class":236},[213,749,241],{"class":240},[213,751,752,754],{"class":232,"line":244},[213,753,237],{"class":236},[213,755,249],{"class":240},[213,757,758],{"class":232,"line":252},[213,759,256],{"emptyLinePlaceholder":255},[213,761,762,765,767,769,771,774,776,779,781,784,786,789,791,795,799,801,803,806,808,812,814],{"class":232,"line":259},[213,763,764],{"class":240},"x ",[213,766,285],{"class":284},[213,768,288],{"class":240},[213,770,292],{"class":291},[213,772,773],{"class":295},"randn",[213,775,299],{"class":291},[213,777,778],{"class":302},"512",[213,780,306],{"class":291},[213,782,783],{"class":302}," 3",[213,785,306],{"class":291},[213,787,788],{"class":409}," device",[213,790,285],{"class":284},[213,792,794],{"class":793},"sjJ54","'",[213,796,798],{"class":797},"s_sjI","cuda",[213,800,794],{"class":793},[213,802,306],{"class":291},[213,804,805],{"class":409}," requires_grad",[213,807,285],{"class":284},[213,809,811],{"class":810},"s39Yj","True",[213,813,710],{"class":291},[213,815,816],{"class":262},"   # source: (N, D)\n",[213,818,819,822,824,826,828,830,832,834,836,838,840,842,844,846,848,850,852],{"class":232,"line":266},[213,820,821],{"class":240},"y ",[213,823,285],{"class":284},[213,825,288],{"class":240},[213,827,292],{"class":291},[213,829,773],{"class":295},[213,831,299],{"class":291},[213,833,778],{"class":302},[213,835,306],{"class":291},[213,837,783],{"class":302},[213,839,306],{"class":291},[213,841,788],{"class":409},[213,843,285],{"class":284},[213,845,794],{"class":793},[213,847,798],{"class":797},[213,849,794],{"class":793},[213,851,710],{"class":291},[213,853,854],{"class":262},"                       # target: (M, D)\n",[213,856,857],{"class":232,"line":272},[213,858,256],{"emptyLinePlaceholder":255},[213,860,861,864,866,868,870,872,874,877,879,882,884,887,889,892],{"class":232,"line":278},[213,862,863],{"class":240},"loss ",[213,865,285],{"class":284},[213,867,334],{"class":240},[213,869,292],{"class":291},[213,871,340],{"class":339},[213,873,292],{"class":291},[213,875,876],{"class":339},"samples",[213,878,292],{"class":291},[213,880,881],{"class":295},"loss",[213,883,299],{"class":291},[213,885,886],{"class":295},"x",[213,888,306],{"class":291},[213,890,891],{"class":295}," y",[213,893,312],{"class":291},[213,895,896,898,900,902,904],{"class":232,"line":315},[213,897,394],{"class":393},[213,899,299],{"class":291},[213,901,881],{"class":295},[213,903,710],{"class":291},[213,905,906],{"class":262},"         # scalar ≥ 0\n",[213,908,909],{"class":232,"line":320},[213,910,256],{"emptyLinePlaceholder":255},[213,912,913,915,917,919,922],{"class":232,"line":326},[213,914,881],{"class":240},[213,916,292],{"class":291},[213,918,722],{"class":295},[213,920,921],{"class":291},"()",[213,923,924],{"class":262},"     # gradients flow through x (and y if requires_grad)\n",[213,926,927,929,931,933,935,938,940,943,945],{"class":232,"line":360},[213,928,394],{"class":393},[213,930,299],{"class":291},[213,932,886],{"class":295},[213,934,292],{"class":291},[213,936,937],{"class":339},"grad",[213,939,292],{"class":291},[213,941,942],{"class":339},"shape",[213,944,710],{"class":291},[213,946,947],{"class":262}," # (512, 3)\n",[182,949,950,953,954,956,957,960],{},[185,951,952],{},"blur"," controls how spread out the matching is (analogous to the ",[185,955,470],{}," parameter in\n",[185,958,959],{},"matrix.solve","): lower values produce sharper, more concentrated matchings; higher values\nproduce smoother ones.",[222,962,964],{"className":224,"code":963,"language":226,"meta":227,"style":227},"# Lower blur → sharper matching; higher blur → smoother\u002Ffaster\nloss = torchmatch.transport.samples.loss(x, y, blur=0.01)\n",[185,965,966,971],{"__ignoreMap":227},[213,967,968],{"class":232,"line":233},[213,969,970],{"class":262},"# Lower blur → sharper matching; higher blur → smoother\u002Ffaster\n",[213,972,973,975,977,979,981,983,985,987,989,991,993,995,997,999,1001,1004,1006,1008],{"class":232,"line":244},[213,974,863],{"class":240},[213,976,285],{"class":284},[213,978,334],{"class":240},[213,980,292],{"class":291},[213,982,340],{"class":339},[213,984,292],{"class":291},[213,986,876],{"class":339},[213,988,292],{"class":291},[213,990,881],{"class":295},[213,992,299],{"class":291},[213,994,886],{"class":295},[213,996,306],{"class":291},[213,998,891],{"class":295},[213,1000,306],{"class":291},[213,1002,1003],{"class":409}," blur",[213,1005,285],{"class":284},[213,1007,522],{"class":302},[213,1009,312],{"class":291},[182,1011,1012,1013,1016],{},"Pass ",[185,1014,1015],{},"debias=True"," to compute the Sinkhorn divergence (a symmetric, bias-corrected scalar\ndistance) instead of the raw loss:",[222,1018,1020],{"className":224,"code":1019,"language":226,"meta":227,"style":227},"loss = torchmatch.transport.samples.loss(x, y, debias=True)\n",[185,1021,1022],{"__ignoreMap":227},[213,1023,1024,1026,1028,1030,1032,1034,1036,1038,1040,1042,1044,1046,1048,1050,1052,1055,1057,1059],{"class":232,"line":233},[213,1025,863],{"class":240},[213,1027,285],{"class":284},[213,1029,334],{"class":240},[213,1031,292],{"class":291},[213,1033,340],{"class":339},[213,1035,292],{"class":291},[213,1037,876],{"class":339},[213,1039,292],{"class":291},[213,1041,881],{"class":295},[213,1043,299],{"class":291},[213,1045,886],{"class":295},[213,1047,306],{"class":291},[213,1049,891],{"class":295},[213,1051,306],{"class":291},[213,1053,1054],{"class":409}," debias",[213,1056,285],{"class":284},[213,1058,811],{"class":810},[213,1060,312],{"class":291},[202,1062,1064],{"id":1063},"calling-an-op-directly","Calling an op directly",[182,1066,1067,1068,1071,1072,1075],{},"The individual ops are exported at ",[185,1069,1070],{},"torchmatch.transport.matrix.ops.*"," and at\n",[185,1073,1074],{},"torch.ops.transport.*",":",[222,1077,1079],{"className":224,"code":1078,"language":226,"meta":227,"style":227},"from torchmatch.transport.matrix.ops import log_sinkhorn, sinkhorn_divergence\n\na = torch.full((1, 8), 1.0 \u002F 8)    # source marginal\nb = torch.full((1, 12), 1.0 \u002F 12)  # target marginal\ncost_3d = cost.unsqueeze(0)         # (1, 8, 12)\n\nlog_plan = log_sinkhorn(cost_3d, 0.1, 200, a, b, None, None)\n",[185,1080,1081,1110,1114,1154,1188,1213,1217],{"__ignoreMap":227},[213,1082,1083,1085,1087,1089,1091,1093,1095,1097,1100,1102,1105,1107],{"class":232,"line":233},[213,1084,613],{"class":236},[213,1086,334],{"class":240},[213,1088,292],{"class":291},[213,1090,340],{"class":240},[213,1092,292],{"class":291},[213,1094,345],{"class":240},[213,1096,292],{"class":291},[213,1098,1099],{"class":240},"ops ",[213,1101,237],{"class":236},[213,1103,1104],{"class":240}," log_sinkhorn",[213,1106,306],{"class":291},[213,1108,1109],{"class":240}," sinkhorn_divergence\n",[213,1111,1112],{"class":232,"line":244},[213,1113,256],{"emptyLinePlaceholder":255},[213,1115,1116,1119,1121,1123,1125,1128,1131,1133,1135,1138,1141,1144,1147,1149,1151],{"class":232,"line":252},[213,1117,1118],{"class":240},"a ",[213,1120,285],{"class":284},[213,1122,288],{"class":240},[213,1124,292],{"class":291},[213,1126,1127],{"class":295},"full",[213,1129,1130],{"class":291},"((",[213,1132,416],{"class":302},[213,1134,306],{"class":291},[213,1136,1137],{"class":302}," 8",[213,1139,1140],{"class":291},"),",[213,1142,1143],{"class":302}," 1.0",[213,1145,1146],{"class":284}," \u002F",[213,1148,1137],{"class":302},[213,1150,710],{"class":291},[213,1152,1153],{"class":262},"    # source marginal\n",[213,1155,1156,1159,1161,1163,1165,1167,1169,1171,1173,1175,1177,1179,1181,1183,1185],{"class":232,"line":259},[213,1157,1158],{"class":240},"b ",[213,1160,285],{"class":284},[213,1162,288],{"class":240},[213,1164,292],{"class":291},[213,1166,1127],{"class":295},[213,1168,1130],{"class":291},[213,1170,416],{"class":302},[213,1172,306],{"class":291},[213,1174,309],{"class":302},[213,1176,1140],{"class":291},[213,1178,1143],{"class":302},[213,1180,1146],{"class":284},[213,1182,309],{"class":302},[213,1184,710],{"class":291},[213,1186,1187],{"class":262},"  # target marginal\n",[213,1189,1190,1193,1195,1198,1200,1203,1205,1208,1210],{"class":232,"line":266},[213,1191,1192],{"class":240},"cost_3d ",[213,1194,285],{"class":284},[213,1196,1197],{"class":240}," cost",[213,1199,292],{"class":291},[213,1201,1202],{"class":295},"unsqueeze",[213,1204,299],{"class":291},[213,1206,1207],{"class":302},"0",[213,1209,710],{"class":291},[213,1211,1212],{"class":262},"         # (1, 8, 12)\n",[213,1214,1215],{"class":232,"line":272},[213,1216,256],{"emptyLinePlaceholder":255},[213,1218,1219,1221,1223,1225,1227,1230,1232,1235,1237,1240,1242,1245,1247,1250,1252,1255,1257,1259],{"class":232,"line":278},[213,1220,329],{"class":240},[213,1222,285],{"class":284},[213,1224,1104],{"class":295},[213,1226,299],{"class":291},[213,1228,1229],{"class":295},"cost_3d",[213,1231,306],{"class":291},[213,1233,1234],{"class":302}," 0.1",[213,1236,306],{"class":291},[213,1238,1239],{"class":302}," 200",[213,1241,306],{"class":291},[213,1243,1244],{"class":295}," a",[213,1246,306],{"class":291},[213,1248,1249],{"class":295}," b",[213,1251,306],{"class":291},[213,1253,1254],{"class":810}," None",[213,1256,306],{"class":291},[213,1258,1254],{"class":810},[213,1260,312],{"class":291},[182,1262,1263,1266,1267,292],{},[185,1264,1265],{},"torchmatch.transport.matrix.ops.log_sinkhorn is torch.ops.transport.log_sinkhorn","\nevaluates to ",[185,1268,811],{},[202,1270,1272],{"id":1271},"torchcompile","torch.compile",[182,1274,1275,1276,1075],{},"Both the matrix API and the samples API work under ",[185,1277,1272],{},[222,1279,1281],{"className":224,"code":1280,"language":226,"meta":227,"style":227},"@torch.compile\ndef compute_loss(x, y):\n    return torchmatch.transport.samples.loss(x, y, debias=True)\n",[185,1282,1283,1298,1319],{"__ignoreMap":227},[213,1284,1285,1289,1293,1295],{"class":232,"line":233},[213,1286,1288],{"class":1287},"stp6e","@",[213,1290,1292],{"class":1291},"sGLFI","torch",[213,1294,292],{"class":1287},[213,1296,1297],{"class":1291},"compile\n",[213,1299,1300,1304,1307,1309,1312,1314,1316],{"class":232,"line":244},[213,1301,1303],{"class":1302},"sbsja","def",[213,1305,1306],{"class":1291}," compute_loss",[213,1308,299],{"class":291},[213,1310,886],{"class":1311},"sFwrP",[213,1313,306],{"class":291},[213,1315,891],{"class":1311},[213,1317,1318],{"class":291},"):\n",[213,1320,1321,1324,1326,1328,1330,1332,1334,1336,1338,1340,1342,1344,1346,1348,1350,1352,1354],{"class":232,"line":252},[213,1322,1323],{"class":236},"    return",[213,1325,334],{"class":240},[213,1327,292],{"class":291},[213,1329,340],{"class":339},[213,1331,292],{"class":291},[213,1333,876],{"class":339},[213,1335,292],{"class":291},[213,1337,881],{"class":295},[213,1339,299],{"class":291},[213,1341,886],{"class":295},[213,1343,306],{"class":291},[213,1345,891],{"class":295},[213,1347,306],{"class":291},[213,1349,1054],{"class":409},[213,1351,285],{"class":284},[213,1353,811],{"class":810},[213,1355,312],{"class":291},[182,1357,1358,1359,1361],{},"The backward pass is registered so that ",[185,1360,1272],{}," can fuse the forward and gradient\ncomputation into a single optimised graph.",[202,1363,1365],{"id":1364},"next-steps","Next steps",[1367,1368,1369,1375,1380,1390,1395],"ul",{},[1370,1371,1372,1374],"li",{},[218,1373,68],{"href":69},": end-to-end shape-generation training.",[1370,1376,1377,1379],{},[218,1378,9],{"href":72},": how Sinkhorn works, debiasing, and unbalanced OT.",[1370,1381,1382,1384,1385,196,1387,292],{},[218,1383,33],{"href":75},": full API signatures for ",[185,1386,959],{},[185,1388,1389],{},"samples.loss",[1370,1391,1392,1394],{},[218,1393,37],{"href":78},": which backend to use for your problem.",[1370,1396,1397,1399],{},[218,1398,16],{"href":17},": if you need a hard, integer-valued, one-to-one matching rather\nthan a soft plan, the assignment family is the right tool.",[1401,1402,1403],"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 .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 .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--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 .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 .swQdS, html code.shiki .swQdS{--shiki-light:#E53935;--shiki-default:#005CC5;--shiki-dark:#79B8FF}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 .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .stp6e, html code.shiki .stp6e{--shiki-light:#39ADB5;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}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}",{"title":227,"searchDepth":252,"depth":252,"links":1405},[1406,1410,1411,1412,1413],{"id":204,"depth":244,"text":205,"children":1407},[1408,1409],{"id":463,"depth":252,"text":464},{"id":591,"depth":252,"text":592},{"id":727,"depth":244,"text":728},{"id":1063,"depth":244,"text":1064},{"id":1271,"depth":244,"text":1272},{"id":1364,"depth":244,"text":1365},"First use of transport.matrix.solve and transport.samples.loss — install, import, and compute your first OT plan.","md",{},{"title":22},{"title":176,"description":1414},"joLVoJNXVyJAgpO2z8vdp6vWJ_C6F8dvQd_g_2iiR1s",[1421,1423],{"title":59,"path":60,"stem":61,"description":1422,"children":-1},"Optimal transport solvers — Sinkhorn, Sinkhorn divergence, unbalanced OT, and exact EMD — registered as PyTorch custom ops.",{"title":68,"path":69,"stem":70,"description":1424,"children":-1},"End-to-end tutorial — computing and differentiating a Wasserstein loss between two 3D point clouds using transport.samples.loss.",1785218164270]