[{"data":1,"prerenderedAt":2225},["ShallowReactive",2],{"navigation":3,"\u002Falgorithms\u002Ftransport\u002Ftutorials\u002Foptimal-transport":174,"\u002Falgorithms\u002Ftransport\u002Ftutorials\u002Foptimal-transport-surround":2220},[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":2214,"extension":2215,"links":177,"meta":2216,"navigation":2217,"path":91,"seo":2218,"stem":92,"__hash__":2219},"docs\u002F2.algorithms\u002F2.transport\u002F7.tutorials\u002F1.optimal-transport.md","What Is Optimal Transport?",null,{"type":179,"value":180,"toc":2205},"minimark",[181,186,190,193,196,200,212,542,545,549,569,585,595,605,963,974,978,997,1001,1007,1015,1018,1666,1669,1673,1676,2160,2171,2175,2201],[182,183,185],"h2",{"id":184},"moving-mass-at-minimum-cost","Moving mass at minimum cost",[187,188,189],"p",{},"Optimal transport (OT) answers a simple question: given two probability distributions, what is the cheapest way to rearrange the mass of one to match the other?",[187,191,192],{},"The canonical image is a pile of sand. Flatten it into the shape of a source distribution, then imagine rearranging the grains into the shape of a target distribution. Each grain travels some distance; OT finds the rearrangement that minimises the total work done.",[187,194,195],{},"The same idea applies to any pair of discrete distributions — histograms, point clouds, or probability vectors. Two sensors with different noise profiles, two images with different pixel distributions, two sets of detections at different time steps: OT gives a geometrically meaningful measure of how far apart they are.",[182,197,199],{"id":198},"two-histograms","Two histograms",[187,201,202,203,207,208,211],{},"Start with a concrete 1-D example. Suppose mass is concentrated on the left (source ",[204,205,206],"code",{},"a",") and needs to move right (target ",[204,209,210],{},"b","):",[213,214,219],"pre",{"className":215,"code":216,"language":217,"meta":218,"style":218},"language-python shiki shiki-themes material-theme-lighter github-light github-dark","import numpy as np\nimport torch\nimport torchmatch\n\nN_BINS = 8\ngrid = np.arange(N_BINS, dtype=np.float32)\n\n# Source: mass on the left.\na = np.array([0.30, 0.25, 0.20, 0.15, 0.05, 0.03, 0.01, 0.01], dtype=np.float32)\n# Target: mass on the right.\nb = np.array([0.01, 0.01, 0.03, 0.05, 0.15, 0.20, 0.25, 0.30], dtype=np.float32)\n\n# Cost matrix: squared Euclidean distance between grid positions.\n# C[i, j] = (i - j)^2\nC = (grid[:, None] - grid[None, :]) ** 2   # (8, 8)\n","python","",[204,220,221,240,248,256,263,278,325,330,337,407,413,475,480,486,492],{"__ignoreMap":218},[222,223,226,230,234,237],"span",{"class":224,"line":225},"line",1,[222,227,229],{"class":228},"sVHd0","import",[222,231,233],{"class":232},"su5hD"," numpy ",[222,235,236],{"class":228},"as",[222,238,239],{"class":232}," np\n",[222,241,243,245],{"class":224,"line":242},2,[222,244,229],{"class":228},[222,246,247],{"class":232}," torch\n",[222,249,251,253],{"class":224,"line":250},3,[222,252,229],{"class":228},[222,254,255],{"class":232}," torchmatch\n",[222,257,259],{"class":224,"line":258},4,[222,260,262],{"emptyLinePlaceholder":261},true,"\n",[222,264,266,270,274],{"class":224,"line":265},5,[222,267,269],{"class":268},"s_hVV","N_BINS",[222,271,273],{"class":272},"smGrS"," =",[222,275,277],{"class":276},"srdBf"," 8\n",[222,279,281,284,287,290,294,298,301,304,307,311,313,316,318,322],{"class":224,"line":280},6,[222,282,283],{"class":232},"grid ",[222,285,286],{"class":272},"=",[222,288,289],{"class":232}," np",[222,291,293],{"class":292},"sP7_E",".",[222,295,297],{"class":296},"slqww","arange",[222,299,300],{"class":292},"(",[222,302,269],{"class":303},"sptTA",[222,305,306],{"class":292},",",[222,308,310],{"class":309},"s99_P"," dtype",[222,312,286],{"class":272},[222,314,315],{"class":296},"np",[222,317,293],{"class":292},[222,319,321],{"class":320},"skxfh","float32",[222,323,324],{"class":292},")\n",[222,326,328],{"class":224,"line":327},7,[222,329,262],{"emptyLinePlaceholder":261},[222,331,333],{"class":224,"line":332},8,[222,334,336],{"class":335},"sutJx","# Source: mass on the left.\n",[222,338,340,343,345,347,349,352,355,358,360,363,365,368,370,373,375,378,380,383,385,388,390,392,395,397,399,401,403,405],{"class":224,"line":339},9,[222,341,342],{"class":232},"a ",[222,344,286],{"class":272},[222,346,289],{"class":232},[222,348,293],{"class":292},[222,350,351],{"class":296},"array",[222,353,354],{"class":292},"([",[222,356,357],{"class":276},"0.30",[222,359,306],{"class":292},[222,361,362],{"class":276}," 0.25",[222,364,306],{"class":292},[222,366,367],{"class":276}," 0.20",[222,369,306],{"class":292},[222,371,372],{"class":276}," 0.15",[222,374,306],{"class":292},[222,376,377],{"class":276}," 0.05",[222,379,306],{"class":292},[222,381,382],{"class":276}," 0.03",[222,384,306],{"class":292},[222,386,387],{"class":276}," 0.01",[222,389,306],{"class":292},[222,391,387],{"class":276},[222,393,394],{"class":292},"],",[222,396,310],{"class":309},[222,398,286],{"class":272},[222,400,315],{"class":296},[222,402,293],{"class":292},[222,404,321],{"class":320},[222,406,324],{"class":292},[222,408,410],{"class":224,"line":409},10,[222,411,412],{"class":335},"# Target: mass on the right.\n",[222,414,416,419,421,423,425,427,429,432,434,436,438,440,442,444,446,448,450,452,454,456,458,461,463,465,467,469,471,473],{"class":224,"line":415},11,[222,417,418],{"class":232},"b ",[222,420,286],{"class":272},[222,422,289],{"class":232},[222,424,293],{"class":292},[222,426,351],{"class":296},[222,428,354],{"class":292},[222,430,431],{"class":276},"0.01",[222,433,306],{"class":292},[222,435,387],{"class":276},[222,437,306],{"class":292},[222,439,382],{"class":276},[222,441,306],{"class":292},[222,443,377],{"class":276},[222,445,306],{"class":292},[222,447,372],{"class":276},[222,449,306],{"class":292},[222,451,367],{"class":276},[222,453,306],{"class":292},[222,455,362],{"class":276},[222,457,306],{"class":292},[222,459,460],{"class":276}," 0.30",[222,462,394],{"class":292},[222,464,310],{"class":309},[222,466,286],{"class":272},[222,468,315],{"class":296},[222,470,293],{"class":292},[222,472,321],{"class":320},[222,474,324],{"class":292},[222,476,478],{"class":224,"line":477},12,[222,479,262],{"emptyLinePlaceholder":261},[222,481,483],{"class":224,"line":482},13,[222,484,485],{"class":335},"# Cost matrix: squared Euclidean distance between grid positions.\n",[222,487,489],{"class":224,"line":488},14,[222,490,491],{"class":335},"# C[i, j] = (i - j)^2\n",[222,493,495,498,500,503,506,509,513,516,519,522,525,528,530,533,536,539],{"class":224,"line":494},15,[222,496,497],{"class":232},"C ",[222,499,286],{"class":272},[222,501,502],{"class":292}," (",[222,504,505],{"class":232},"grid",[222,507,508],{"class":292},"[:,",[222,510,512],{"class":511},"s39Yj"," None",[222,514,515],{"class":292},"]",[222,517,518],{"class":272}," -",[222,520,521],{"class":232}," grid",[222,523,524],{"class":292},"[",[222,526,527],{"class":511},"None",[222,529,306],{"class":292},[222,531,532],{"class":292}," :])",[222,534,535],{"class":272}," **",[222,537,538],{"class":276}," 2",[222,540,541],{"class":335},"   # (8, 8)\n",[187,543,544],{},"The cost matrix encodes the price of moving mass between any pair of bins. Moving between adjacent bins is cheap; moving across the histogram is expensive.",[182,546,548],{"id":547},"the-transport-plan","The transport plan",[187,550,551,552,556,557,560,561,564,565,568],{},"A ",[553,554,555],"strong",{},"transport plan"," P is an N×M matrix where ",[204,558,559],{},"P[i, j]"," is the amount of mass moved from source bin ",[204,562,563],{},"i"," to target bin ",[204,566,567],{},"j",". Two constraints must hold:",[570,571,572,579],"ul",{},[573,574,575,576],"li",{},"Row sums equal the source weights: ",[204,577,578],{},"P.sum(axis=1) == a",[573,580,581,582],{},"Column sums equal the target weights: ",[204,583,584],{},"P.sum(axis=0) == b",[187,586,587,588,591,592,293],{},"These are the ",[553,589,590],{},"marginal constraints",". Any P satisfying them is a valid transport plan; the optimal plan minimises the total cost ",[204,593,594],{},"⟨P, C⟩ = ∑_ij P[i,j] · C[i,j]",[187,596,597,600,601,604],{},[204,598,599],{},"torchmatch.transport.matrix.solve"," finds this plan. It expects a 3-D input ",[204,602,603],{},"(B, N, M)"," to support batches; add an unsqueeze for single problems:",[213,606,608],{"className":215,"code":607,"language":217,"meta":218,"style":218},"cost_t = torch.tensor(C).unsqueeze(0)    # (1, 8, 8)\na_t    = torch.tensor(a).unsqueeze(0)    # (1, 8)\nb_t    = torch.tensor(b).unsqueeze(0)    # (1, 8)\n\nlog_plan = torchmatch.transport.matrix.solve(\n    cost_t, a=a_t, b=b_t, reg=0.01, n_iter=500\n)\nP = log_plan.exp().squeeze(0).numpy()    # (8, 8)\n\nprint(f\"Row sums ≈ a: {P.sum(axis=1).round(3)}\")\nprint(f\"Col sums ≈ b: {P.sum(axis=0).round(3)}\")\nprint(f\"Transport cost: {(P * C).sum():.4f}\")\n",[204,609,610,647,677,706,710,738,782,786,822,826,882,925],{"__ignoreMap":218},[222,611,612,615,617,620,622,625,627,630,633,636,638,641,644],{"class":224,"line":225},[222,613,614],{"class":232},"cost_t ",[222,616,286],{"class":272},[222,618,619],{"class":232}," torch",[222,621,293],{"class":292},[222,623,624],{"class":296},"tensor",[222,626,300],{"class":292},[222,628,629],{"class":296},"C",[222,631,632],{"class":292},").",[222,634,635],{"class":296},"unsqueeze",[222,637,300],{"class":292},[222,639,640],{"class":276},"0",[222,642,643],{"class":292},")",[222,645,646],{"class":335},"    # (1, 8, 8)\n",[222,648,649,652,654,656,658,660,662,664,666,668,670,672,674],{"class":224,"line":242},[222,650,651],{"class":232},"a_t    ",[222,653,286],{"class":272},[222,655,619],{"class":232},[222,657,293],{"class":292},[222,659,624],{"class":296},[222,661,300],{"class":292},[222,663,206],{"class":296},[222,665,632],{"class":292},[222,667,635],{"class":296},[222,669,300],{"class":292},[222,671,640],{"class":276},[222,673,643],{"class":292},[222,675,676],{"class":335},"    # (1, 8)\n",[222,678,679,682,684,686,688,690,692,694,696,698,700,702,704],{"class":224,"line":250},[222,680,681],{"class":232},"b_t    ",[222,683,286],{"class":272},[222,685,619],{"class":232},[222,687,293],{"class":292},[222,689,624],{"class":296},[222,691,300],{"class":292},[222,693,210],{"class":296},[222,695,632],{"class":292},[222,697,635],{"class":296},[222,699,300],{"class":292},[222,701,640],{"class":276},[222,703,643],{"class":292},[222,705,676],{"class":335},[222,707,708],{"class":224,"line":258},[222,709,262],{"emptyLinePlaceholder":261},[222,711,712,715,717,720,722,725,727,730,732,735],{"class":224,"line":265},[222,713,714],{"class":232},"log_plan ",[222,716,286],{"class":272},[222,718,719],{"class":232}," torchmatch",[222,721,293],{"class":292},[222,723,724],{"class":320},"transport",[222,726,293],{"class":292},[222,728,729],{"class":320},"matrix",[222,731,293],{"class":292},[222,733,734],{"class":296},"solve",[222,736,737],{"class":292},"(\n",[222,739,740,743,745,748,750,753,755,758,760,763,765,768,770,772,774,777,779],{"class":224,"line":280},[222,741,742],{"class":296},"    cost_t",[222,744,306],{"class":292},[222,746,747],{"class":309}," a",[222,749,286],{"class":272},[222,751,752],{"class":296},"a_t",[222,754,306],{"class":292},[222,756,757],{"class":309}," b",[222,759,286],{"class":272},[222,761,762],{"class":296},"b_t",[222,764,306],{"class":292},[222,766,767],{"class":309}," reg",[222,769,286],{"class":272},[222,771,431],{"class":276},[222,773,306],{"class":292},[222,775,776],{"class":309}," n_iter",[222,778,286],{"class":272},[222,780,781],{"class":276},"500\n",[222,783,784],{"class":224,"line":327},[222,785,324],{"class":292},[222,787,788,791,793,796,798,801,804,807,809,811,813,816,819],{"class":224,"line":332},[222,789,790],{"class":232},"P ",[222,792,286],{"class":272},[222,794,795],{"class":232}," log_plan",[222,797,293],{"class":292},[222,799,800],{"class":296},"exp",[222,802,803],{"class":292},"().",[222,805,806],{"class":296},"squeeze",[222,808,300],{"class":292},[222,810,640],{"class":276},[222,812,632],{"class":292},[222,814,815],{"class":296},"numpy",[222,817,818],{"class":292},"()",[222,820,821],{"class":335},"    # (8, 8)\n",[222,823,824],{"class":224,"line":339},[222,825,262],{"emptyLinePlaceholder":261},[222,827,828,831,833,837,841,844,847,849,852,854,857,859,862,864,867,869,872,874,877,880],{"class":224,"line":409},[222,829,830],{"class":303},"print",[222,832,300],{"class":292},[222,834,836],{"class":835},"sbsja","f",[222,838,840],{"class":839},"s_sjI","\"Row sums ≈ a: ",[222,842,843],{"class":276},"{",[222,845,846],{"class":296},"P",[222,848,293],{"class":292},[222,850,851],{"class":296},"sum",[222,853,300],{"class":292},[222,855,856],{"class":309},"axis",[222,858,286],{"class":272},[222,860,861],{"class":276},"1",[222,863,632],{"class":292},[222,865,866],{"class":296},"round",[222,868,300],{"class":292},[222,870,871],{"class":276},"3",[222,873,643],{"class":292},[222,875,876],{"class":276},"}",[222,878,879],{"class":839},"\"",[222,881,324],{"class":292},[222,883,884,886,888,890,893,895,897,899,901,903,905,907,909,911,913,915,917,919,921,923],{"class":224,"line":415},[222,885,830],{"class":303},[222,887,300],{"class":292},[222,889,836],{"class":835},[222,891,892],{"class":839},"\"Col sums ≈ b: ",[222,894,843],{"class":276},[222,896,846],{"class":296},[222,898,293],{"class":292},[222,900,851],{"class":296},[222,902,300],{"class":292},[222,904,856],{"class":309},[222,906,286],{"class":272},[222,908,640],{"class":276},[222,910,632],{"class":292},[222,912,866],{"class":296},[222,914,300],{"class":292},[222,916,871],{"class":276},[222,918,643],{"class":292},[222,920,876],{"class":276},[222,922,879],{"class":839},[222,924,324],{"class":292},[222,926,927,929,931,933,936,938,940,942,945,948,950,952,954,957,959,961],{"class":224,"line":477},[222,928,830],{"class":303},[222,930,300],{"class":292},[222,932,836],{"class":835},[222,934,935],{"class":839},"\"Transport cost: ",[222,937,843],{"class":276},[222,939,300],{"class":292},[222,941,790],{"class":296},[222,943,944],{"class":272},"*",[222,946,947],{"class":296}," C",[222,949,632],{"class":292},[222,951,851],{"class":296},[222,953,818],{"class":292},[222,955,956],{"class":835},":.4f",[222,958,876],{"class":276},[222,960,879],{"class":839},[222,962,324],{"class":292},[187,964,965,966,969,970,973],{},"The plan is returned in log space (",[204,967,968],{},"log_plan",") for numerical stability. Call ",[204,971,972],{},".exp()"," to recover probabilities. The diagonal-dominant structure of P reflects the nature of the problem: nearby bins exchange the most mass, distant bins exchange very little.",[182,975,977],{"id":976},"why-log-space","Why log space?",[187,979,980,981,984,985,988,989,992,993,996],{},"With small regularisation (e.g. ",[204,982,983],{},"reg=0.01","), many entries of P are extremely small — values like 1e-200 that underflow to zero in float32. Working in log space avoids this: ",[204,986,987],{},"log_plan[b, i, j]"," stores ",[204,990,991],{},"log P[i, j]",", which stays in a numerically stable range even when P",[222,994,995],{},"i, j"," itself would vanish.",[182,998,1000],{"id":999},"wasserstein-distance","Wasserstein distance",[187,1002,1003,1004,1006],{},"The ",[553,1005,1000],{}," (or earth-mover distance) between two distributions is the minimum total transport cost over all valid plans:",[213,1008,1013],{"className":1009,"code":1011,"language":1012},[1010],"language-text","W(a, b) = min_P ⟨P, C⟩   subject to marginal constraints\n","text",[204,1014,1011],{"__ignoreMap":218},[187,1016,1017],{},"It is not a raw per-element comparison. Two distributions with identical histograms shifted by one bin have a small Wasserstein distance; two distributions with the same mean but swapped peaks have a larger one. The geometry of the underlying space enters the computation through C.",[213,1019,1021],{"className":215,"code":1020,"language":217,"meta":218,"style":218},"import numpy as np\nimport torch\nimport torchmatch\n\ndef make_gaussian_hist(mean, std, n=8):\n    grid = np.arange(n, dtype=np.float32)\n    w = np.exp(-0.5 * ((grid - mean) \u002F std) ** 2)\n    return (w \u002F w.sum()).astype(np.float32)\n\nN_BINS = 8\nC = (np.arange(N_BINS, dtype=np.float32)[:, None] -\n     np.arange(N_BINS, dtype=np.float32)[None, :]) ** 2\n\npairs = [\n    (make_gaussian_hist(3.0, 0.8), make_gaussian_hist(4.0, 0.8), \"nearby\"),\n    (make_gaussian_hist(1.5, 0.8), make_gaussian_hist(6.5, 0.8), \"far apart\"),\n]\ncost_t = torch.tensor(C).unsqueeze(0)\n\nfor a_i, b_i, label in pairs:\n    log_p = torchmatch.transport.matrix.solve(\n        cost_t,\n        a=torch.tensor(a_i).unsqueeze(0),\n        b=torch.tensor(b_i).unsqueeze(0),\n        reg=0.02, n_iter=300,\n    )\n    P_i = log_p.exp().squeeze(0).numpy()\n    w = (P_i * C).sum()\n    print(f\"{label:12s}  W = {w:.4f}\")\n",[204,1022,1023,1033,1039,1045,1049,1082,1114,1163,1199,1203,1211,1251,1290,1294,1304,1350,1390,1396,1423,1428,1456,1480,1489,1519,1548,1570,1576,1606,1628],{"__ignoreMap":218},[222,1024,1025,1027,1029,1031],{"class":224,"line":225},[222,1026,229],{"class":228},[222,1028,233],{"class":232},[222,1030,236],{"class":228},[222,1032,239],{"class":232},[222,1034,1035,1037],{"class":224,"line":242},[222,1036,229],{"class":228},[222,1038,247],{"class":232},[222,1040,1041,1043],{"class":224,"line":250},[222,1042,229],{"class":228},[222,1044,255],{"class":232},[222,1046,1047],{"class":224,"line":258},[222,1048,262],{"emptyLinePlaceholder":261},[222,1050,1051,1054,1058,1060,1064,1066,1069,1071,1074,1076,1079],{"class":224,"line":265},[222,1052,1053],{"class":835},"def",[222,1055,1057],{"class":1056},"sGLFI"," make_gaussian_hist",[222,1059,300],{"class":292},[222,1061,1063],{"class":1062},"sFwrP","mean",[222,1065,306],{"class":292},[222,1067,1068],{"class":1062}," std",[222,1070,306],{"class":292},[222,1072,1073],{"class":1062}," n",[222,1075,286],{"class":272},[222,1077,1078],{"class":276},"8",[222,1080,1081],{"class":292},"):\n",[222,1083,1084,1087,1089,1091,1093,1095,1097,1100,1102,1104,1106,1108,1110,1112],{"class":224,"line":280},[222,1085,1086],{"class":232},"    grid ",[222,1088,286],{"class":272},[222,1090,289],{"class":232},[222,1092,293],{"class":292},[222,1094,297],{"class":296},[222,1096,300],{"class":292},[222,1098,1099],{"class":296},"n",[222,1101,306],{"class":292},[222,1103,310],{"class":309},[222,1105,286],{"class":272},[222,1107,315],{"class":296},[222,1109,293],{"class":292},[222,1111,321],{"class":320},[222,1113,324],{"class":292},[222,1115,1116,1119,1121,1123,1125,1127,1129,1132,1135,1138,1141,1143,1145,1148,1150,1153,1155,1157,1159,1161],{"class":224,"line":327},[222,1117,1118],{"class":232},"    w ",[222,1120,286],{"class":272},[222,1122,289],{"class":232},[222,1124,293],{"class":292},[222,1126,800],{"class":296},[222,1128,300],{"class":292},[222,1130,1131],{"class":272},"-",[222,1133,1134],{"class":276},"0.5",[222,1136,1137],{"class":272}," *",[222,1139,1140],{"class":292}," ((",[222,1142,283],{"class":296},[222,1144,1131],{"class":272},[222,1146,1147],{"class":296}," mean",[222,1149,643],{"class":292},[222,1151,1152],{"class":272}," \u002F",[222,1154,1068],{"class":296},[222,1156,643],{"class":292},[222,1158,535],{"class":272},[222,1160,538],{"class":276},[222,1162,324],{"class":292},[222,1164,1165,1168,1170,1173,1176,1179,1181,1183,1186,1189,1191,1193,1195,1197],{"class":224,"line":332},[222,1166,1167],{"class":228},"    return",[222,1169,502],{"class":292},[222,1171,1172],{"class":232},"w ",[222,1174,1175],{"class":272},"\u002F",[222,1177,1178],{"class":232}," w",[222,1180,293],{"class":292},[222,1182,851],{"class":296},[222,1184,1185],{"class":292},"()).",[222,1187,1188],{"class":296},"astype",[222,1190,300],{"class":292},[222,1192,315],{"class":296},[222,1194,293],{"class":292},[222,1196,321],{"class":320},[222,1198,324],{"class":292},[222,1200,1201],{"class":224,"line":339},[222,1202,262],{"emptyLinePlaceholder":261},[222,1204,1205,1207,1209],{"class":224,"line":409},[222,1206,269],{"class":268},[222,1208,273],{"class":272},[222,1210,277],{"class":276},[222,1212,1213,1215,1217,1219,1221,1223,1225,1227,1229,1231,1233,1235,1237,1239,1241,1244,1246,1248],{"class":224,"line":415},[222,1214,497],{"class":232},[222,1216,286],{"class":272},[222,1218,502],{"class":292},[222,1220,315],{"class":232},[222,1222,293],{"class":292},[222,1224,297],{"class":296},[222,1226,300],{"class":292},[222,1228,269],{"class":303},[222,1230,306],{"class":292},[222,1232,310],{"class":309},[222,1234,286],{"class":272},[222,1236,315],{"class":296},[222,1238,293],{"class":292},[222,1240,321],{"class":320},[222,1242,1243],{"class":292},")[:,",[222,1245,512],{"class":511},[222,1247,515],{"class":292},[222,1249,1250],{"class":272}," -\n",[222,1252,1253,1256,1258,1260,1262,1264,1266,1268,1270,1272,1274,1276,1279,1281,1283,1285,1287],{"class":224,"line":477},[222,1254,1255],{"class":232},"     np",[222,1257,293],{"class":292},[222,1259,297],{"class":296},[222,1261,300],{"class":292},[222,1263,269],{"class":303},[222,1265,306],{"class":292},[222,1267,310],{"class":309},[222,1269,286],{"class":272},[222,1271,315],{"class":296},[222,1273,293],{"class":292},[222,1275,321],{"class":320},[222,1277,1278],{"class":292},")[",[222,1280,527],{"class":511},[222,1282,306],{"class":292},[222,1284,532],{"class":292},[222,1286,535],{"class":272},[222,1288,1289],{"class":276}," 2\n",[222,1291,1292],{"class":224,"line":482},[222,1293,262],{"emptyLinePlaceholder":261},[222,1295,1296,1299,1301],{"class":224,"line":488},[222,1297,1298],{"class":232},"pairs ",[222,1300,286],{"class":272},[222,1302,1303],{"class":292}," [\n",[222,1305,1306,1309,1312,1314,1317,1319,1322,1325,1327,1329,1332,1334,1336,1338,1342,1345,1347],{"class":224,"line":494},[222,1307,1308],{"class":292},"    (",[222,1310,1311],{"class":296},"make_gaussian_hist",[222,1313,300],{"class":292},[222,1315,1316],{"class":276},"3.0",[222,1318,306],{"class":292},[222,1320,1321],{"class":276}," 0.8",[222,1323,1324],{"class":292},"),",[222,1326,1057],{"class":296},[222,1328,300],{"class":292},[222,1330,1331],{"class":276},"4.0",[222,1333,306],{"class":292},[222,1335,1321],{"class":276},[222,1337,1324],{"class":292},[222,1339,1341],{"class":1340},"sjJ54"," \"",[222,1343,1344],{"class":839},"nearby",[222,1346,879],{"class":1340},[222,1348,1349],{"class":292},"),\n",[222,1351,1353,1355,1357,1359,1362,1364,1366,1368,1370,1372,1375,1377,1379,1381,1383,1386,1388],{"class":224,"line":1352},16,[222,1354,1308],{"class":292},[222,1356,1311],{"class":296},[222,1358,300],{"class":292},[222,1360,1361],{"class":276},"1.5",[222,1363,306],{"class":292},[222,1365,1321],{"class":276},[222,1367,1324],{"class":292},[222,1369,1057],{"class":296},[222,1371,300],{"class":292},[222,1373,1374],{"class":276},"6.5",[222,1376,306],{"class":292},[222,1378,1321],{"class":276},[222,1380,1324],{"class":292},[222,1382,1341],{"class":1340},[222,1384,1385],{"class":839},"far apart",[222,1387,879],{"class":1340},[222,1389,1349],{"class":292},[222,1391,1393],{"class":224,"line":1392},17,[222,1394,1395],{"class":292},"]\n",[222,1397,1399,1401,1403,1405,1407,1409,1411,1413,1415,1417,1419,1421],{"class":224,"line":1398},18,[222,1400,614],{"class":232},[222,1402,286],{"class":272},[222,1404,619],{"class":232},[222,1406,293],{"class":292},[222,1408,624],{"class":296},[222,1410,300],{"class":292},[222,1412,629],{"class":296},[222,1414,632],{"class":292},[222,1416,635],{"class":296},[222,1418,300],{"class":292},[222,1420,640],{"class":276},[222,1422,324],{"class":292},[222,1424,1426],{"class":224,"line":1425},19,[222,1427,262],{"emptyLinePlaceholder":261},[222,1429,1431,1434,1437,1439,1442,1444,1447,1450,1453],{"class":224,"line":1430},20,[222,1432,1433],{"class":228},"for",[222,1435,1436],{"class":232}," a_i",[222,1438,306],{"class":292},[222,1440,1441],{"class":232}," b_i",[222,1443,306],{"class":292},[222,1445,1446],{"class":232}," label ",[222,1448,1449],{"class":228},"in",[222,1451,1452],{"class":232}," pairs",[222,1454,1455],{"class":292},":\n",[222,1457,1459,1462,1464,1466,1468,1470,1472,1474,1476,1478],{"class":224,"line":1458},21,[222,1460,1461],{"class":232},"    log_p ",[222,1463,286],{"class":272},[222,1465,719],{"class":232},[222,1467,293],{"class":292},[222,1469,724],{"class":320},[222,1471,293],{"class":292},[222,1473,729],{"class":320},[222,1475,293],{"class":292},[222,1477,734],{"class":296},[222,1479,737],{"class":292},[222,1481,1483,1486],{"class":224,"line":1482},22,[222,1484,1485],{"class":296},"        cost_t",[222,1487,1488],{"class":292},",\n",[222,1490,1492,1495,1497,1500,1502,1504,1506,1509,1511,1513,1515,1517],{"class":224,"line":1491},23,[222,1493,1494],{"class":309},"        a",[222,1496,286],{"class":272},[222,1498,1499],{"class":296},"torch",[222,1501,293],{"class":292},[222,1503,624],{"class":296},[222,1505,300],{"class":292},[222,1507,1508],{"class":296},"a_i",[222,1510,632],{"class":292},[222,1512,635],{"class":296},[222,1514,300],{"class":292},[222,1516,640],{"class":276},[222,1518,1349],{"class":292},[222,1520,1522,1525,1527,1529,1531,1533,1535,1538,1540,1542,1544,1546],{"class":224,"line":1521},24,[222,1523,1524],{"class":309},"        b",[222,1526,286],{"class":272},[222,1528,1499],{"class":296},[222,1530,293],{"class":292},[222,1532,624],{"class":296},[222,1534,300],{"class":292},[222,1536,1537],{"class":296},"b_i",[222,1539,632],{"class":292},[222,1541,635],{"class":296},[222,1543,300],{"class":292},[222,1545,640],{"class":276},[222,1547,1349],{"class":292},[222,1549,1551,1554,1556,1559,1561,1563,1565,1568],{"class":224,"line":1550},25,[222,1552,1553],{"class":309},"        reg",[222,1555,286],{"class":272},[222,1557,1558],{"class":276},"0.02",[222,1560,306],{"class":292},[222,1562,776],{"class":309},[222,1564,286],{"class":272},[222,1566,1567],{"class":276},"300",[222,1569,1488],{"class":292},[222,1571,1573],{"class":224,"line":1572},26,[222,1574,1575],{"class":292},"    )\n",[222,1577,1579,1582,1584,1587,1589,1591,1593,1595,1597,1599,1601,1603],{"class":224,"line":1578},27,[222,1580,1581],{"class":232},"    P_i ",[222,1583,286],{"class":272},[222,1585,1586],{"class":232}," log_p",[222,1588,293],{"class":292},[222,1590,800],{"class":296},[222,1592,803],{"class":292},[222,1594,806],{"class":296},[222,1596,300],{"class":292},[222,1598,640],{"class":276},[222,1600,632],{"class":292},[222,1602,815],{"class":296},[222,1604,1605],{"class":292},"()\n",[222,1607,1609,1611,1613,1615,1618,1620,1622,1624,1626],{"class":224,"line":1608},28,[222,1610,1118],{"class":232},[222,1612,286],{"class":272},[222,1614,502],{"class":292},[222,1616,1617],{"class":232},"P_i ",[222,1619,944],{"class":272},[222,1621,947],{"class":232},[222,1623,632],{"class":292},[222,1625,851],{"class":296},[222,1627,1605],{"class":292},[222,1629,1631,1634,1636,1638,1640,1642,1645,1648,1650,1653,1655,1658,1660,1662,1664],{"class":224,"line":1630},29,[222,1632,1633],{"class":303},"    print",[222,1635,300],{"class":292},[222,1637,836],{"class":835},[222,1639,879],{"class":839},[222,1641,843],{"class":276},[222,1643,1644],{"class":296},"label",[222,1646,1647],{"class":835},":12s",[222,1649,876],{"class":276},[222,1651,1652],{"class":839},"  W = ",[222,1654,843],{"class":276},[222,1656,1657],{"class":296},"w",[222,1659,956],{"class":835},[222,1661,876],{"class":276},[222,1663,879],{"class":839},[222,1665,324],{"class":292},[187,1667,1668],{},"The \"far apart\" pair has a larger Wasserstein distance — the mass must travel further. Unlike, say, cross-entropy or L2, Wasserstein distance gives a meaningful answer even when the distributions have non-overlapping support.",[182,1670,1672],{"id":1671},"connection-to-the-assignment-problem","Connection to the assignment problem",[187,1674,1675],{},"When both distributions are uniform over N points, the optimal transport plan is a permutation matrix — exactly the output of an assignment solver. OT is a continuous generalisation of the linear assignment problem (LAP): it handles arbitrary distributions, not just unit-mass matchings.",[213,1677,1679],{"className":215,"code":1678,"language":217,"meta":218,"style":218},"import numpy as np\nimport torch\nimport torchmatch\n\nrng = np.random.default_rng(42)\nN = 5\na_unif = np.ones(N, dtype=np.float32) \u002F N\nb_unif = np.ones(N, dtype=np.float32) \u002F N\nC_lap  = rng.random((N, N)).astype(np.float32)\n\nlog_plan_unif = torchmatch.transport.matrix.solve(\n    torch.tensor(C_lap).unsqueeze(0),\n    a=torch.tensor(a_unif).unsqueeze(0),\n    b=torch.tensor(b_unif).unsqueeze(0),\n    reg=0.001, n_iter=1000,\n)\nP_unif = log_plan_unif.exp().squeeze(0)\n\n# With very small regularisation, P ≈ a permutation matrix.\n# The assignment solver gives the same optimal cost.\nassignment = torchmatch.assignment.solve(torch.tensor(C_lap))\nlap_cost  = C_lap[np.arange(N), assignment.numpy()].sum()\not_cost   = (P_unif.numpy() * C_lap).sum()\nprint(f\"LAP cost: {lap_cost:.4f}   OT cost: {ot_cost:.4f}\")\n",[204,1680,1681,1691,1697,1703,1707,1733,1743,1781,1816,1855,1859,1882,1906,1934,1962,1983,1987,2011,2015,2020,2025,2058,2096,2124],{"__ignoreMap":218},[222,1682,1683,1685,1687,1689],{"class":224,"line":225},[222,1684,229],{"class":228},[222,1686,233],{"class":232},[222,1688,236],{"class":228},[222,1690,239],{"class":232},[222,1692,1693,1695],{"class":224,"line":242},[222,1694,229],{"class":228},[222,1696,247],{"class":232},[222,1698,1699,1701],{"class":224,"line":250},[222,1700,229],{"class":228},[222,1702,255],{"class":232},[222,1704,1705],{"class":224,"line":258},[222,1706,262],{"emptyLinePlaceholder":261},[222,1708,1709,1712,1714,1716,1718,1721,1723,1726,1728,1731],{"class":224,"line":265},[222,1710,1711],{"class":232},"rng ",[222,1713,286],{"class":272},[222,1715,289],{"class":232},[222,1717,293],{"class":292},[222,1719,1720],{"class":320},"random",[222,1722,293],{"class":292},[222,1724,1725],{"class":296},"default_rng",[222,1727,300],{"class":292},[222,1729,1730],{"class":276},"42",[222,1732,324],{"class":292},[222,1734,1735,1738,1740],{"class":224,"line":280},[222,1736,1737],{"class":232},"N ",[222,1739,286],{"class":272},[222,1741,1742],{"class":276}," 5\n",[222,1744,1745,1748,1750,1752,1754,1757,1759,1762,1764,1766,1768,1770,1772,1774,1776,1778],{"class":224,"line":327},[222,1746,1747],{"class":232},"a_unif ",[222,1749,286],{"class":272},[222,1751,289],{"class":232},[222,1753,293],{"class":292},[222,1755,1756],{"class":296},"ones",[222,1758,300],{"class":292},[222,1760,1761],{"class":296},"N",[222,1763,306],{"class":292},[222,1765,310],{"class":309},[222,1767,286],{"class":272},[222,1769,315],{"class":296},[222,1771,293],{"class":292},[222,1773,321],{"class":320},[222,1775,643],{"class":292},[222,1777,1152],{"class":272},[222,1779,1780],{"class":232}," N\n",[222,1782,1783,1786,1788,1790,1792,1794,1796,1798,1800,1802,1804,1806,1808,1810,1812,1814],{"class":224,"line":332},[222,1784,1785],{"class":232},"b_unif ",[222,1787,286],{"class":272},[222,1789,289],{"class":232},[222,1791,293],{"class":292},[222,1793,1756],{"class":296},[222,1795,300],{"class":292},[222,1797,1761],{"class":296},[222,1799,306],{"class":292},[222,1801,310],{"class":309},[222,1803,286],{"class":272},[222,1805,315],{"class":296},[222,1807,293],{"class":292},[222,1809,321],{"class":320},[222,1811,643],{"class":292},[222,1813,1152],{"class":272},[222,1815,1780],{"class":232},[222,1817,1818,1821,1823,1826,1828,1830,1833,1835,1837,1840,1843,1845,1847,1849,1851,1853],{"class":224,"line":339},[222,1819,1820],{"class":232},"C_lap  ",[222,1822,286],{"class":272},[222,1824,1825],{"class":232}," rng",[222,1827,293],{"class":292},[222,1829,1720],{"class":296},[222,1831,1832],{"class":292},"((",[222,1834,1761],{"class":296},[222,1836,306],{"class":292},[222,1838,1839],{"class":296}," N",[222,1841,1842],{"class":292},")).",[222,1844,1188],{"class":296},[222,1846,300],{"class":292},[222,1848,315],{"class":296},[222,1850,293],{"class":292},[222,1852,321],{"class":320},[222,1854,324],{"class":292},[222,1856,1857],{"class":224,"line":409},[222,1858,262],{"emptyLinePlaceholder":261},[222,1860,1861,1864,1866,1868,1870,1872,1874,1876,1878,1880],{"class":224,"line":415},[222,1862,1863],{"class":232},"log_plan_unif ",[222,1865,286],{"class":272},[222,1867,719],{"class":232},[222,1869,293],{"class":292},[222,1871,724],{"class":320},[222,1873,293],{"class":292},[222,1875,729],{"class":320},[222,1877,293],{"class":292},[222,1879,734],{"class":296},[222,1881,737],{"class":292},[222,1883,1884,1887,1889,1891,1893,1896,1898,1900,1902,1904],{"class":224,"line":477},[222,1885,1886],{"class":296},"    torch",[222,1888,293],{"class":292},[222,1890,624],{"class":296},[222,1892,300],{"class":292},[222,1894,1895],{"class":296},"C_lap",[222,1897,632],{"class":292},[222,1899,635],{"class":296},[222,1901,300],{"class":292},[222,1903,640],{"class":276},[222,1905,1349],{"class":292},[222,1907,1908,1911,1913,1915,1917,1919,1921,1924,1926,1928,1930,1932],{"class":224,"line":482},[222,1909,1910],{"class":309},"    a",[222,1912,286],{"class":272},[222,1914,1499],{"class":296},[222,1916,293],{"class":292},[222,1918,624],{"class":296},[222,1920,300],{"class":292},[222,1922,1923],{"class":296},"a_unif",[222,1925,632],{"class":292},[222,1927,635],{"class":296},[222,1929,300],{"class":292},[222,1931,640],{"class":276},[222,1933,1349],{"class":292},[222,1935,1936,1939,1941,1943,1945,1947,1949,1952,1954,1956,1958,1960],{"class":224,"line":488},[222,1937,1938],{"class":309},"    b",[222,1940,286],{"class":272},[222,1942,1499],{"class":296},[222,1944,293],{"class":292},[222,1946,624],{"class":296},[222,1948,300],{"class":292},[222,1950,1951],{"class":296},"b_unif",[222,1953,632],{"class":292},[222,1955,635],{"class":296},[222,1957,300],{"class":292},[222,1959,640],{"class":276},[222,1961,1349],{"class":292},[222,1963,1964,1967,1969,1972,1974,1976,1978,1981],{"class":224,"line":494},[222,1965,1966],{"class":309},"    reg",[222,1968,286],{"class":272},[222,1970,1971],{"class":276},"0.001",[222,1973,306],{"class":292},[222,1975,776],{"class":309},[222,1977,286],{"class":272},[222,1979,1980],{"class":276},"1000",[222,1982,1488],{"class":292},[222,1984,1985],{"class":224,"line":1352},[222,1986,324],{"class":292},[222,1988,1989,1992,1994,1997,1999,2001,2003,2005,2007,2009],{"class":224,"line":1392},[222,1990,1991],{"class":232},"P_unif ",[222,1993,286],{"class":272},[222,1995,1996],{"class":232}," log_plan_unif",[222,1998,293],{"class":292},[222,2000,800],{"class":296},[222,2002,803],{"class":292},[222,2004,806],{"class":296},[222,2006,300],{"class":292},[222,2008,640],{"class":276},[222,2010,324],{"class":292},[222,2012,2013],{"class":224,"line":1398},[222,2014,262],{"emptyLinePlaceholder":261},[222,2016,2017],{"class":224,"line":1425},[222,2018,2019],{"class":335},"# With very small regularisation, P ≈ a permutation matrix.\n",[222,2021,2022],{"class":224,"line":1430},[222,2023,2024],{"class":335},"# The assignment solver gives the same optimal cost.\n",[222,2026,2027,2030,2032,2034,2036,2039,2041,2043,2045,2047,2049,2051,2053,2055],{"class":224,"line":1458},[222,2028,2029],{"class":232},"assignment ",[222,2031,286],{"class":272},[222,2033,719],{"class":232},[222,2035,293],{"class":292},[222,2037,2038],{"class":320},"assignment",[222,2040,293],{"class":292},[222,2042,734],{"class":296},[222,2044,300],{"class":292},[222,2046,1499],{"class":296},[222,2048,293],{"class":292},[222,2050,624],{"class":296},[222,2052,300],{"class":292},[222,2054,1895],{"class":296},[222,2056,2057],{"class":292},"))\n",[222,2059,2060,2063,2065,2068,2070,2072,2074,2076,2078,2080,2082,2085,2087,2089,2092,2094],{"class":224,"line":1482},[222,2061,2062],{"class":232},"lap_cost  ",[222,2064,286],{"class":272},[222,2066,2067],{"class":232}," C_lap",[222,2069,524],{"class":292},[222,2071,315],{"class":232},[222,2073,293],{"class":292},[222,2075,297],{"class":296},[222,2077,300],{"class":292},[222,2079,1761],{"class":296},[222,2081,1324],{"class":292},[222,2083,2084],{"class":232}," assignment",[222,2086,293],{"class":292},[222,2088,815],{"class":296},[222,2090,2091],{"class":292},"()].",[222,2093,851],{"class":296},[222,2095,1605],{"class":292},[222,2097,2098,2101,2103,2105,2108,2110,2112,2114,2116,2118,2120,2122],{"class":224,"line":1491},[222,2099,2100],{"class":232},"ot_cost   ",[222,2102,286],{"class":272},[222,2104,502],{"class":292},[222,2106,2107],{"class":232},"P_unif",[222,2109,293],{"class":292},[222,2111,815],{"class":296},[222,2113,818],{"class":292},[222,2115,1137],{"class":272},[222,2117,2067],{"class":232},[222,2119,632],{"class":292},[222,2121,851],{"class":296},[222,2123,1605],{"class":292},[222,2125,2126,2128,2130,2132,2135,2137,2140,2142,2144,2147,2149,2152,2154,2156,2158],{"class":224,"line":1521},[222,2127,830],{"class":303},[222,2129,300],{"class":292},[222,2131,836],{"class":835},[222,2133,2134],{"class":839},"\"LAP cost: ",[222,2136,843],{"class":276},[222,2138,2139],{"class":296},"lap_cost",[222,2141,956],{"class":835},[222,2143,876],{"class":276},[222,2145,2146],{"class":839},"   OT cost: ",[222,2148,843],{"class":276},[222,2150,2151],{"class":296},"ot_cost",[222,2153,956],{"class":835},[222,2155,876],{"class":276},[222,2157,879],{"class":839},[222,2159,324],{"class":292},[187,2161,2162,2163,2166,2167,2170],{},"With ",[204,2164,2165],{},"reg=0.001"," the regularised OT cost closely tracks the exact LAP cost. Increasing ",[204,2168,2169],{},"reg"," smears the plan and raises the cost — this tradeoff is the subject of the next tutorial.",[182,2172,2174],{"id":2173},"see-also","See also",[570,2176,2177,2190,2196],{},[573,2178,2179,2181,2182,2185,2186,2189],{},[206,2180,22],{"href":65},": ",[204,2183,2184],{},"matrix.solve"," and ",[204,2187,2188],{},"samples.loss"," in one page.",[573,2191,2192,2195],{},[206,2193,2194],{"href":95},"Sinkhorn algorithm",": why regularisation is necessary and how Sinkhorn iteration works.",[573,2197,2198,2200],{},[206,2199,9],{"href":72},": the full derivation of the OT problem and solver families.",[2202,2203,2204],"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 .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}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 .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 pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--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 .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--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 .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}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 .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":218,"searchDepth":250,"depth":250,"links":2206},[2207,2208,2209,2210,2211,2212,2213],{"id":184,"depth":242,"text":185},{"id":198,"depth":242,"text":199},{"id":547,"depth":242,"text":548},{"id":976,"depth":242,"text":977},{"id":999,"depth":242,"text":1000},{"id":1671,"depth":242,"text":1672},{"id":2173,"depth":242,"text":2174},"Earth-mover intuition, transport plans, marginal constraints, and Wasserstein distance — from scratch using torchmatch.transport.matrix.solve.","md",{},{"title":90},{"title":176,"description":2214},"W8E4c1I_1CdLZzTh-7dg7NQF4kz9zQPOPdM4suyIxwM",[2221,2223],{"title":41,"path":85,"stem":86,"description":2222,"children":-1},"Hands-on Jupyter notebooks covering optimal transport — from earth-mover intuition through Sinkhorn and point-cloud Wasserstein losses.",{"title":94,"path":95,"stem":96,"description":2224,"children":-1},"Why exact OT is expensive, how entropic regularisation fixes it, what the regularisation parameter controls, and when to use Sinkhorn divergence instead of raw Sinkhorn loss.",1785218169374]