[{"data":1,"prerenderedAt":2696},["ShallowReactive",2],{"navigation":3,"\u002Falgorithms\u002Ftransport\u002Ftutorials\u002Fsinkhorn":174,"\u002Falgorithms\u002Ftransport\u002Ftutorials\u002Fsinkhorn-surround":2691},[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":2685,"extension":2686,"links":177,"meta":2687,"navigation":2688,"path":95,"seo":2689,"stem":96,"__hash__":2690},"docs\u002F2.algorithms\u002F2.transport\u002F7.tutorials\u002F2.sinkhorn.md","The Sinkhorn Algorithm",null,{"type":179,"value":180,"toc":2674},"minimark",[181,186,199,206,210,213,223,238,242,245,251,262,986,989,993,1024,1444,1452,1456,1459,1480,1691,1697,1701,1707,2070,2081,2085,2099,2104,2110,2116,2565,2581,2585,2643,2647,2670],[182,183,185],"h2",{"id":184},"the-cost-of-exact-ot","The cost of exact OT",[187,188,189,190,194,195,198],"p",{},"The network simplex finds the exact optimal transport plan in ",[191,192,193],"code",{},"O((N+M)^3 log(N+M))"," time. For two histograms with 1000 bins each, that is roughly 8 billion operations per solve. In a training loop that calls ",[191,196,197],{},"solve"," thousands of times per epoch, exact OT is not practical.",[187,200,201,202,205],{},"Entropic regularisation cuts this to roughly ",[191,203,204],{},"O(N·M·T)"," — linear in the number of cells and the number of iterations — by solving a slightly different problem. The solution is no longer exactly optimal, but it is close, and the regularised version is differentiable, which exact OT is not.",[182,207,209],{"id":208},"adding-an-entropy-term","Adding an entropy term",[187,211,212],{},"The regularised OT objective adds a penalty on the entropy of the plan:",[214,215,220],"pre",{"className":216,"code":218,"language":219},[217],"language-text","OT_ε(a, b) = min_P  ⟨P, C⟩ − ε · H(P)\n","text",[191,221,218],{"__ignoreMap":222},"",[187,224,225,226,229,230,233,234,237],{},"where ",[191,227,228],{},"H(P) = −∑_ij P[i,j] log P[i,j]"," is the entropy of P and ",[191,231,232],{},"ε > 0"," is the regularisation strength. Maximising entropy pushes P toward a uniform distribution; the cost term pulls it toward the sparse, diagonal plan. The parameter ",[191,235,236],{},"ε"," controls the balance.",[182,239,241],{"id":240},"sinkhorn-iteration","Sinkhorn iteration",[187,243,244],{},"The unique minimiser of the regularised objective has a factored form:",[214,246,249],{"className":247,"code":248,"language":219},[217],"P_ε = diag(u) · K · diag(v)     where K[i,j] = exp(−C[i,j] \u002F ε)\n",[191,250,248],{"__ignoreMap":222},[187,252,253,254,257,258,261],{},"The vectors ",[191,255,256],{},"u"," and ",[191,259,260],{},"v"," are found by alternating row and column normalisations — this is the Sinkhorn algorithm:",[214,263,267],{"className":264,"code":265,"language":266,"meta":222,"style":222},"language-python shiki shiki-themes material-theme-lighter github-light github-dark","import numpy as np\n\ndef sinkhorn_numpy(C, a, b, reg, n_iter=200):\n    K = np.exp(-C \u002F reg)\n    v = np.ones(len(b), dtype=np.float64)\n\n    for _ in range(n_iter):\n        u = a \u002F (K @ v + 1e-300)\n        v = b \u002F (K.T @ u + 1e-300)\n\n    P = np.diag(u) @ K @ np.diag(v)\n    return P\n\nN = 16\ngrid = np.linspace(0, 1, N, dtype=np.float64)\na = np.exp(-0.5 * ((grid - 0.3) \u002F 0.15) ** 2)\nb = np.exp(-0.5 * ((grid - 0.7) \u002F 0.15) ** 2)\na \u002F= a.sum(); b \u002F= b.sum()\nC = ((grid[:, None] - grid[None, :]) ** 2).astype(np.float64)\n\nP = sinkhorn_numpy(C, a, b, reg=0.05)\nprint(f\"Row error: {np.abs(P.sum(axis=1) - a).max():.2e}\")\nprint(f\"Col error: {np.abs(P.sum(axis=0) - b).max():.2e}\")\n","python",[191,268,269,288,295,346,380,426,431,453,486,521,526,567,576,581,592,636,688,733,765,824,829,862,930],{"__ignoreMap":222},[270,271,274,278,282,285],"span",{"class":272,"line":273},"line",1,[270,275,277],{"class":276},"sVHd0","import",[270,279,281],{"class":280},"su5hD"," numpy ",[270,283,284],{"class":276},"as",[270,286,287],{"class":280}," np\n",[270,289,291],{"class":272,"line":290},2,[270,292,294],{"emptyLinePlaceholder":293},true,"\n",[270,296,298,302,306,310,314,317,320,322,325,327,330,332,335,339,343],{"class":272,"line":297},3,[270,299,301],{"class":300},"sbsja","def",[270,303,305],{"class":304},"sGLFI"," sinkhorn_numpy",[270,307,309],{"class":308},"sP7_E","(",[270,311,313],{"class":312},"sFwrP","C",[270,315,316],{"class":308},",",[270,318,319],{"class":312}," a",[270,321,316],{"class":308},[270,323,324],{"class":312}," b",[270,326,316],{"class":308},[270,328,329],{"class":312}," reg",[270,331,316],{"class":308},[270,333,334],{"class":312}," n_iter",[270,336,338],{"class":337},"smGrS","=",[270,340,342],{"class":341},"srdBf","200",[270,344,345],{"class":308},"):\n",[270,347,349,352,354,357,360,364,366,369,372,375,377],{"class":272,"line":348},4,[270,350,351],{"class":280},"    K ",[270,353,338],{"class":337},[270,355,356],{"class":280}," np",[270,358,359],{"class":308},".",[270,361,363],{"class":362},"slqww","exp",[270,365,309],{"class":308},[270,367,368],{"class":337},"-",[270,370,371],{"class":362},"C ",[270,373,374],{"class":337},"\u002F",[270,376,329],{"class":362},[270,378,379],{"class":308},")\n",[270,381,383,386,388,390,392,395,397,401,403,406,409,413,415,418,420,424],{"class":272,"line":382},5,[270,384,385],{"class":280},"    v ",[270,387,338],{"class":337},[270,389,356],{"class":280},[270,391,359],{"class":308},[270,393,394],{"class":362},"ones",[270,396,309],{"class":308},[270,398,400],{"class":399},"sptTA","len",[270,402,309],{"class":308},[270,404,405],{"class":362},"b",[270,407,408],{"class":308},"),",[270,410,412],{"class":411},"s99_P"," dtype",[270,414,338],{"class":337},[270,416,417],{"class":362},"np",[270,419,359],{"class":308},[270,421,423],{"class":422},"skxfh","float64",[270,425,379],{"class":308},[270,427,429],{"class":272,"line":428},6,[270,430,294],{"emptyLinePlaceholder":293},[270,432,434,437,440,443,446,448,451],{"class":272,"line":433},7,[270,435,436],{"class":276},"    for",[270,438,439],{"class":280}," _ ",[270,441,442],{"class":276},"in",[270,444,445],{"class":399}," range",[270,447,309],{"class":308},[270,449,450],{"class":362},"n_iter",[270,452,345],{"class":308},[270,454,456,459,461,464,466,469,472,475,478,481,484],{"class":272,"line":455},8,[270,457,458],{"class":280},"        u ",[270,460,338],{"class":337},[270,462,463],{"class":280}," a ",[270,465,374],{"class":337},[270,467,468],{"class":308}," (",[270,470,471],{"class":280},"K ",[270,473,474],{"class":337},"@",[270,476,477],{"class":280}," v ",[270,479,480],{"class":337},"+",[270,482,483],{"class":341}," 1e-300",[270,485,379],{"class":308},[270,487,489,492,494,497,499,501,504,506,509,512,515,517,519],{"class":272,"line":488},9,[270,490,491],{"class":280},"        v ",[270,493,338],{"class":337},[270,495,496],{"class":280}," b ",[270,498,374],{"class":337},[270,500,468],{"class":308},[270,502,503],{"class":280},"K",[270,505,359],{"class":308},[270,507,508],{"class":422},"T",[270,510,511],{"class":337}," @",[270,513,514],{"class":280}," u ",[270,516,480],{"class":337},[270,518,483],{"class":341},[270,520,379],{"class":308},[270,522,524],{"class":272,"line":523},10,[270,525,294],{"emptyLinePlaceholder":293},[270,527,529,532,534,536,538,541,543,545,548,550,553,555,557,559,561,563,565],{"class":272,"line":528},11,[270,530,531],{"class":280},"    P ",[270,533,338],{"class":337},[270,535,356],{"class":280},[270,537,359],{"class":308},[270,539,540],{"class":362},"diag",[270,542,309],{"class":308},[270,544,256],{"class":362},[270,546,547],{"class":308},")",[270,549,511],{"class":337},[270,551,552],{"class":280}," K ",[270,554,474],{"class":337},[270,556,356],{"class":280},[270,558,359],{"class":308},[270,560,540],{"class":362},[270,562,309],{"class":308},[270,564,260],{"class":362},[270,566,379],{"class":308},[270,568,570,573],{"class":272,"line":569},12,[270,571,572],{"class":276},"    return",[270,574,575],{"class":280}," P\n",[270,577,579],{"class":272,"line":578},13,[270,580,294],{"emptyLinePlaceholder":293},[270,582,584,587,589],{"class":272,"line":583},14,[270,585,586],{"class":280},"N ",[270,588,338],{"class":337},[270,590,591],{"class":341}," 16\n",[270,593,595,598,600,602,604,607,609,612,614,617,619,622,624,626,628,630,632,634],{"class":272,"line":594},15,[270,596,597],{"class":280},"grid ",[270,599,338],{"class":337},[270,601,356],{"class":280},[270,603,359],{"class":308},[270,605,606],{"class":362},"linspace",[270,608,309],{"class":308},[270,610,611],{"class":341},"0",[270,613,316],{"class":308},[270,615,616],{"class":341}," 1",[270,618,316],{"class":308},[270,620,621],{"class":362}," N",[270,623,316],{"class":308},[270,625,412],{"class":411},[270,627,338],{"class":337},[270,629,417],{"class":362},[270,631,359],{"class":308},[270,633,423],{"class":422},[270,635,379],{"class":308},[270,637,639,642,644,646,648,650,652,654,657,660,663,665,667,670,672,675,678,680,683,686],{"class":272,"line":638},16,[270,640,641],{"class":280},"a ",[270,643,338],{"class":337},[270,645,356],{"class":280},[270,647,359],{"class":308},[270,649,363],{"class":362},[270,651,309],{"class":308},[270,653,368],{"class":337},[270,655,656],{"class":341},"0.5",[270,658,659],{"class":337}," *",[270,661,662],{"class":308}," ((",[270,664,597],{"class":362},[270,666,368],{"class":337},[270,668,669],{"class":341}," 0.3",[270,671,547],{"class":308},[270,673,674],{"class":337}," \u002F",[270,676,677],{"class":341}," 0.15",[270,679,547],{"class":308},[270,681,682],{"class":337}," **",[270,684,685],{"class":341}," 2",[270,687,379],{"class":308},[270,689,691,694,696,698,700,702,704,706,708,710,712,714,716,719,721,723,725,727,729,731],{"class":272,"line":690},17,[270,692,693],{"class":280},"b ",[270,695,338],{"class":337},[270,697,356],{"class":280},[270,699,359],{"class":308},[270,701,363],{"class":362},[270,703,309],{"class":308},[270,705,368],{"class":337},[270,707,656],{"class":341},[270,709,659],{"class":337},[270,711,662],{"class":308},[270,713,597],{"class":362},[270,715,368],{"class":337},[270,717,718],{"class":341}," 0.7",[270,720,547],{"class":308},[270,722,674],{"class":337},[270,724,677],{"class":341},[270,726,547],{"class":308},[270,728,682],{"class":337},[270,730,685],{"class":341},[270,732,379],{"class":308},[270,734,736,738,741,743,745,748,751,754,756,758,760,762],{"class":272,"line":735},18,[270,737,641],{"class":280},[270,739,740],{"class":337},"\u002F=",[270,742,319],{"class":280},[270,744,359],{"class":308},[270,746,747],{"class":362},"sum",[270,749,750],{"class":308},"()",[270,752,753],{"class":280},"; b ",[270,755,740],{"class":337},[270,757,324],{"class":280},[270,759,359],{"class":308},[270,761,747],{"class":362},[270,763,764],{"class":308},"()\n",[270,766,768,770,772,774,777,780,784,787,790,793,796,799,801,804,806,808,811,814,816,818,820,822],{"class":272,"line":767},19,[270,769,371],{"class":280},[270,771,338],{"class":337},[270,773,662],{"class":308},[270,775,776],{"class":280},"grid",[270,778,779],{"class":308},"[:,",[270,781,783],{"class":782},"s39Yj"," None",[270,785,786],{"class":308},"]",[270,788,789],{"class":337}," -",[270,791,792],{"class":280}," grid",[270,794,795],{"class":308},"[",[270,797,798],{"class":782},"None",[270,800,316],{"class":308},[270,802,803],{"class":308}," :])",[270,805,682],{"class":337},[270,807,685],{"class":341},[270,809,810],{"class":308},").",[270,812,813],{"class":362},"astype",[270,815,309],{"class":308},[270,817,417],{"class":362},[270,819,359],{"class":308},[270,821,423],{"class":422},[270,823,379],{"class":308},[270,825,827],{"class":272,"line":826},20,[270,828,294],{"emptyLinePlaceholder":293},[270,830,832,835,837,839,841,843,845,847,849,851,853,855,857,860],{"class":272,"line":831},21,[270,833,834],{"class":280},"P ",[270,836,338],{"class":337},[270,838,305],{"class":362},[270,840,309],{"class":308},[270,842,313],{"class":362},[270,844,316],{"class":308},[270,846,319],{"class":362},[270,848,316],{"class":308},[270,850,324],{"class":362},[270,852,316],{"class":308},[270,854,329],{"class":411},[270,856,338],{"class":337},[270,858,859],{"class":341},"0.05",[270,861,379],{"class":308},[270,863,865,868,870,873,877,880,882,884,887,889,892,894,896,898,901,903,906,908,910,912,914,917,919,922,925,928],{"class":272,"line":864},22,[270,866,867],{"class":399},"print",[270,869,309],{"class":308},[270,871,872],{"class":300},"f",[270,874,876],{"class":875},"s_sjI","\"Row error: ",[270,878,879],{"class":341},"{",[270,881,417],{"class":362},[270,883,359],{"class":308},[270,885,886],{"class":362},"abs",[270,888,309],{"class":308},[270,890,891],{"class":362},"P",[270,893,359],{"class":308},[270,895,747],{"class":362},[270,897,309],{"class":308},[270,899,900],{"class":411},"axis",[270,902,338],{"class":337},[270,904,905],{"class":341},"1",[270,907,547],{"class":308},[270,909,789],{"class":337},[270,911,319],{"class":362},[270,913,810],{"class":308},[270,915,916],{"class":362},"max",[270,918,750],{"class":308},[270,920,921],{"class":300},":.2e",[270,923,924],{"class":341},"}",[270,926,927],{"class":875},"\"",[270,929,379],{"class":308},[270,931,933,935,937,939,942,944,946,948,950,952,954,956,958,960,962,964,966,968,970,972,974,976,978,980,982,984],{"class":272,"line":932},23,[270,934,867],{"class":399},[270,936,309],{"class":308},[270,938,872],{"class":300},[270,940,941],{"class":875},"\"Col error: ",[270,943,879],{"class":341},[270,945,417],{"class":362},[270,947,359],{"class":308},[270,949,886],{"class":362},[270,951,309],{"class":308},[270,953,891],{"class":362},[270,955,359],{"class":308},[270,957,747],{"class":362},[270,959,309],{"class":308},[270,961,900],{"class":411},[270,963,338],{"class":337},[270,965,611],{"class":341},[270,967,547],{"class":308},[270,969,789],{"class":337},[270,971,324],{"class":362},[270,973,810],{"class":308},[270,975,916],{"class":362},[270,977,750],{"class":308},[270,979,921],{"class":300},[270,981,924],{"class":341},[270,983,927],{"class":875},[270,985,379],{"class":308},[187,987,988],{},"Each iteration enforces one of the two marginal constraints exactly while relaxing the other. Convergence is geometric: the marginal errors drop by a constant factor each round.",[182,990,992],{"id":991},"log-domain-stability","Log-domain stability",[187,994,995,996,998,999,1002,1003,257,1005,1007,1008,257,1010,1012,1013,257,1016,1019,1020,1023],{},"When ",[191,997,236],{}," is small, ",[191,1000,1001],{},"K[i,j] = exp(−C[i,j]\u002Fε)"," underflows to zero for large costs. The ",[191,1004,256],{},[191,1006,260],{}," normalisations then divide by zero. The standard fix is to work in log space throughout, replacing ",[191,1009,256],{},[191,1011,260],{}," with dual potentials ",[191,1014,1015],{},"f = ε log u",[191,1017,1018],{},"g = ε log v",". ",[191,1021,1022],{},"torchmatch"," uses this log-domain implementation:",[214,1025,1027],{"className":264,"code":1026,"language":266,"meta":222,"style":222},"import torch\nimport torchmatch\nfrom torchmatch.transport.matrix import Backend\n\nN = 16\ngrid = torch.linspace(0, 1, N)\na = torch.exp(-0.5 * ((grid - 0.3) \u002F 0.15) ** 2)\nb = torch.exp(-0.5 * ((grid - 0.7) \u002F 0.15) ** 2)\na \u002F= a.sum(); b \u002F= b.sum()\nC = (grid[:, None] - grid[None, :]) ** 2   # (N, N)\n\nlog_plan = torchmatch.transport.matrix.solve(\n    C.unsqueeze(0),\n    a=a.unsqueeze(0),\n    b=b.unsqueeze(0),\n    backend=Backend.LOG_SINKHORN,\n    reg=0.05,\n    n_iter=200,\n)\nP = log_plan.exp().squeeze(0)\nprint(f\"Transport cost: {(P * C).sum():.4f}\")\n",[191,1028,1029,1036,1043,1066,1070,1078,1105,1147,1189,1215,1251,1255,1280,1297,1317,1336,1355,1366,1377,1381,1406],{"__ignoreMap":222},[270,1030,1031,1033],{"class":272,"line":273},[270,1032,277],{"class":276},[270,1034,1035],{"class":280}," torch\n",[270,1037,1038,1040],{"class":272,"line":290},[270,1039,277],{"class":276},[270,1041,1042],{"class":280}," torchmatch\n",[270,1044,1045,1048,1051,1053,1056,1058,1061,1063],{"class":272,"line":297},[270,1046,1047],{"class":276},"from",[270,1049,1050],{"class":280}," torchmatch",[270,1052,359],{"class":308},[270,1054,1055],{"class":280},"transport",[270,1057,359],{"class":308},[270,1059,1060],{"class":280},"matrix ",[270,1062,277],{"class":276},[270,1064,1065],{"class":280}," Backend\n",[270,1067,1068],{"class":272,"line":348},[270,1069,294],{"emptyLinePlaceholder":293},[270,1071,1072,1074,1076],{"class":272,"line":382},[270,1073,586],{"class":280},[270,1075,338],{"class":337},[270,1077,591],{"class":341},[270,1079,1080,1082,1084,1087,1089,1091,1093,1095,1097,1099,1101,1103],{"class":272,"line":428},[270,1081,597],{"class":280},[270,1083,338],{"class":337},[270,1085,1086],{"class":280}," torch",[270,1088,359],{"class":308},[270,1090,606],{"class":362},[270,1092,309],{"class":308},[270,1094,611],{"class":341},[270,1096,316],{"class":308},[270,1098,616],{"class":341},[270,1100,316],{"class":308},[270,1102,621],{"class":362},[270,1104,379],{"class":308},[270,1106,1107,1109,1111,1113,1115,1117,1119,1121,1123,1125,1127,1129,1131,1133,1135,1137,1139,1141,1143,1145],{"class":272,"line":433},[270,1108,641],{"class":280},[270,1110,338],{"class":337},[270,1112,1086],{"class":280},[270,1114,359],{"class":308},[270,1116,363],{"class":362},[270,1118,309],{"class":308},[270,1120,368],{"class":337},[270,1122,656],{"class":341},[270,1124,659],{"class":337},[270,1126,662],{"class":308},[270,1128,597],{"class":362},[270,1130,368],{"class":337},[270,1132,669],{"class":341},[270,1134,547],{"class":308},[270,1136,674],{"class":337},[270,1138,677],{"class":341},[270,1140,547],{"class":308},[270,1142,682],{"class":337},[270,1144,685],{"class":341},[270,1146,379],{"class":308},[270,1148,1149,1151,1153,1155,1157,1159,1161,1163,1165,1167,1169,1171,1173,1175,1177,1179,1181,1183,1185,1187],{"class":272,"line":455},[270,1150,693],{"class":280},[270,1152,338],{"class":337},[270,1154,1086],{"class":280},[270,1156,359],{"class":308},[270,1158,363],{"class":362},[270,1160,309],{"class":308},[270,1162,368],{"class":337},[270,1164,656],{"class":341},[270,1166,659],{"class":337},[270,1168,662],{"class":308},[270,1170,597],{"class":362},[270,1172,368],{"class":337},[270,1174,718],{"class":341},[270,1176,547],{"class":308},[270,1178,674],{"class":337},[270,1180,677],{"class":341},[270,1182,547],{"class":308},[270,1184,682],{"class":337},[270,1186,685],{"class":341},[270,1188,379],{"class":308},[270,1190,1191,1193,1195,1197,1199,1201,1203,1205,1207,1209,1211,1213],{"class":272,"line":488},[270,1192,641],{"class":280},[270,1194,740],{"class":337},[270,1196,319],{"class":280},[270,1198,359],{"class":308},[270,1200,747],{"class":362},[270,1202,750],{"class":308},[270,1204,753],{"class":280},[270,1206,740],{"class":337},[270,1208,324],{"class":280},[270,1210,359],{"class":308},[270,1212,747],{"class":362},[270,1214,764],{"class":308},[270,1216,1217,1219,1221,1223,1225,1227,1229,1231,1233,1235,1237,1239,1241,1243,1245,1247],{"class":272,"line":523},[270,1218,371],{"class":280},[270,1220,338],{"class":337},[270,1222,468],{"class":308},[270,1224,776],{"class":280},[270,1226,779],{"class":308},[270,1228,783],{"class":782},[270,1230,786],{"class":308},[270,1232,789],{"class":337},[270,1234,792],{"class":280},[270,1236,795],{"class":308},[270,1238,798],{"class":782},[270,1240,316],{"class":308},[270,1242,803],{"class":308},[270,1244,682],{"class":337},[270,1246,685],{"class":341},[270,1248,1250],{"class":1249},"sutJx","   # (N, N)\n",[270,1252,1253],{"class":272,"line":528},[270,1254,294],{"emptyLinePlaceholder":293},[270,1256,1257,1260,1262,1264,1266,1268,1270,1273,1275,1277],{"class":272,"line":569},[270,1258,1259],{"class":280},"log_plan ",[270,1261,338],{"class":337},[270,1263,1050],{"class":280},[270,1265,359],{"class":308},[270,1267,1055],{"class":422},[270,1269,359],{"class":308},[270,1271,1272],{"class":422},"matrix",[270,1274,359],{"class":308},[270,1276,197],{"class":362},[270,1278,1279],{"class":308},"(\n",[270,1281,1282,1285,1287,1290,1292,1294],{"class":272,"line":578},[270,1283,1284],{"class":362},"    C",[270,1286,359],{"class":308},[270,1288,1289],{"class":362},"unsqueeze",[270,1291,309],{"class":308},[270,1293,611],{"class":341},[270,1295,1296],{"class":308},"),\n",[270,1298,1299,1302,1304,1307,1309,1311,1313,1315],{"class":272,"line":583},[270,1300,1301],{"class":411},"    a",[270,1303,338],{"class":337},[270,1305,1306],{"class":362},"a",[270,1308,359],{"class":308},[270,1310,1289],{"class":362},[270,1312,309],{"class":308},[270,1314,611],{"class":341},[270,1316,1296],{"class":308},[270,1318,1319,1322,1324,1326,1328,1330,1332,1334],{"class":272,"line":594},[270,1320,1321],{"class":411},"    b",[270,1323,338],{"class":337},[270,1325,405],{"class":362},[270,1327,359],{"class":308},[270,1329,1289],{"class":362},[270,1331,309],{"class":308},[270,1333,611],{"class":341},[270,1335,1296],{"class":308},[270,1337,1338,1341,1343,1346,1348,1352],{"class":272,"line":638},[270,1339,1340],{"class":411},"    backend",[270,1342,338],{"class":337},[270,1344,1345],{"class":362},"Backend",[270,1347,359],{"class":308},[270,1349,1351],{"class":1350},"swQdS","LOG_SINKHORN",[270,1353,1354],{"class":308},",\n",[270,1356,1357,1360,1362,1364],{"class":272,"line":690},[270,1358,1359],{"class":411},"    reg",[270,1361,338],{"class":337},[270,1363,859],{"class":341},[270,1365,1354],{"class":308},[270,1367,1368,1371,1373,1375],{"class":272,"line":735},[270,1369,1370],{"class":411},"    n_iter",[270,1372,338],{"class":337},[270,1374,342],{"class":341},[270,1376,1354],{"class":308},[270,1378,1379],{"class":272,"line":767},[270,1380,379],{"class":308},[270,1382,1383,1385,1387,1390,1392,1394,1397,1400,1402,1404],{"class":272,"line":826},[270,1384,834],{"class":280},[270,1386,338],{"class":337},[270,1388,1389],{"class":280}," log_plan",[270,1391,359],{"class":308},[270,1393,363],{"class":362},[270,1395,1396],{"class":308},"().",[270,1398,1399],{"class":362},"squeeze",[270,1401,309],{"class":308},[270,1403,611],{"class":341},[270,1405,379],{"class":308},[270,1407,1408,1410,1412,1414,1417,1419,1421,1423,1426,1429,1431,1433,1435,1438,1440,1442],{"class":272,"line":831},[270,1409,867],{"class":399},[270,1411,309],{"class":308},[270,1413,872],{"class":300},[270,1415,1416],{"class":875},"\"Transport cost: ",[270,1418,879],{"class":341},[270,1420,309],{"class":308},[270,1422,834],{"class":362},[270,1424,1425],{"class":337},"*",[270,1427,1428],{"class":362}," C",[270,1430,810],{"class":308},[270,1432,747],{"class":362},[270,1434,750],{"class":308},[270,1436,1437],{"class":300},":.4f",[270,1439,924],{"class":341},[270,1441,927],{"class":875},[270,1443,379],{"class":308},[187,1445,1446,1448,1449,359],{},[191,1447,1351],{}," is the default backend selected by ",[191,1450,1451],{},"Backend.AUTO",[182,1453,1455],{"id":1454},"what-ε-controls","What ε controls",[187,1457,1458],{},"The key tradeoff:",[1460,1461,1462,1474],"ul",{},[1463,1464,1465,1469,1470,1473],"li",{},[1466,1467,1468],"strong",{},"Large ε"," (e.g. 0.5): the entropy term dominates; P spreads mass everywhere. The plan looks close to the outer product ",[191,1471,1472],{},"a · bᵀ",". The transport cost is above-optimal.",[1463,1475,1476,1479],{},[1466,1477,1478],{},"Small ε"," (e.g. 0.005): the cost term dominates; P concentrates on the cheapest routes and approaches the exact OT plan. More iterations are needed to converge.",[214,1481,1483],{"className":264,"code":1482,"language":266,"meta":222,"style":222},"regs = [0.5, 0.1, 0.02, 0.005]\n\nfor reg in regs:\n    P_r = sinkhorn_numpy(C.numpy(), a.numpy(), b.numpy(), reg=reg, n_iter=500)\n    cost_r = (P_r * C.numpy()).sum()\n    sparsity = (P_r > 1e-4).mean()\n    print(f\"ε={reg:5.3f}  cost={cost_r:.4f}  nonzero={sparsity:.1%}\")\n",[191,1484,1485,1515,1519,1535,1590,1617,1641],{"__ignoreMap":222},[270,1486,1487,1490,1492,1495,1497,1499,1502,1504,1507,1509,1512],{"class":272,"line":273},[270,1488,1489],{"class":280},"regs ",[270,1491,338],{"class":337},[270,1493,1494],{"class":308}," [",[270,1496,656],{"class":341},[270,1498,316],{"class":308},[270,1500,1501],{"class":341}," 0.1",[270,1503,316],{"class":308},[270,1505,1506],{"class":341}," 0.02",[270,1508,316],{"class":308},[270,1510,1511],{"class":341}," 0.005",[270,1513,1514],{"class":308},"]\n",[270,1516,1517],{"class":272,"line":290},[270,1518,294],{"emptyLinePlaceholder":293},[270,1520,1521,1524,1527,1529,1532],{"class":272,"line":297},[270,1522,1523],{"class":276},"for",[270,1525,1526],{"class":280}," reg ",[270,1528,442],{"class":276},[270,1530,1531],{"class":280}," regs",[270,1533,1534],{"class":308},":\n",[270,1536,1537,1540,1542,1544,1546,1548,1550,1553,1556,1558,1560,1562,1564,1566,1568,1570,1572,1574,1576,1579,1581,1583,1585,1588],{"class":272,"line":348},[270,1538,1539],{"class":280},"    P_r ",[270,1541,338],{"class":337},[270,1543,305],{"class":362},[270,1545,309],{"class":308},[270,1547,313],{"class":362},[270,1549,359],{"class":308},[270,1551,1552],{"class":362},"numpy",[270,1554,1555],{"class":308},"(),",[270,1557,319],{"class":362},[270,1559,359],{"class":308},[270,1561,1552],{"class":362},[270,1563,1555],{"class":308},[270,1565,324],{"class":362},[270,1567,359],{"class":308},[270,1569,1552],{"class":362},[270,1571,1555],{"class":308},[270,1573,329],{"class":411},[270,1575,338],{"class":337},[270,1577,1578],{"class":362},"reg",[270,1580,316],{"class":308},[270,1582,334],{"class":411},[270,1584,338],{"class":337},[270,1586,1587],{"class":341},"500",[270,1589,379],{"class":308},[270,1591,1592,1595,1597,1599,1602,1604,1606,1608,1610,1613,1615],{"class":272,"line":382},[270,1593,1594],{"class":280},"    cost_r ",[270,1596,338],{"class":337},[270,1598,468],{"class":308},[270,1600,1601],{"class":280},"P_r ",[270,1603,1425],{"class":337},[270,1605,1428],{"class":280},[270,1607,359],{"class":308},[270,1609,1552],{"class":362},[270,1611,1612],{"class":308},"()).",[270,1614,747],{"class":362},[270,1616,764],{"class":308},[270,1618,1619,1622,1624,1626,1628,1631,1634,1636,1639],{"class":272,"line":428},[270,1620,1621],{"class":280},"    sparsity ",[270,1623,338],{"class":337},[270,1625,468],{"class":308},[270,1627,1601],{"class":280},[270,1629,1630],{"class":337},">",[270,1632,1633],{"class":341}," 1e-4",[270,1635,810],{"class":308},[270,1637,1638],{"class":362},"mean",[270,1640,764],{"class":308},[270,1642,1643,1646,1648,1650,1653,1655,1657,1660,1662,1665,1667,1670,1672,1674,1677,1679,1682,1685,1687,1689],{"class":272,"line":433},[270,1644,1645],{"class":399},"    print",[270,1647,309],{"class":308},[270,1649,872],{"class":300},[270,1651,1652],{"class":875},"\"ε=",[270,1654,879],{"class":341},[270,1656,1578],{"class":362},[270,1658,1659],{"class":300},":5.3f",[270,1661,924],{"class":341},[270,1663,1664],{"class":875},"  cost=",[270,1666,879],{"class":341},[270,1668,1669],{"class":362},"cost_r",[270,1671,1437],{"class":300},[270,1673,924],{"class":341},[270,1675,1676],{"class":875},"  nonzero=",[270,1678,879],{"class":341},[270,1680,1681],{"class":362},"sparsity",[270,1683,1684],{"class":300},":.1%",[270,1686,924],{"class":341},[270,1688,927],{"class":875},[270,1690,379],{"class":308},[187,1692,1693,1694,1696],{},"For most training use cases, ",[191,1695,1578],{}," between 0.01 and 0.1 is a good starting range.",[182,1698,1700],{"id":1699},"exact-ot-as-a-reference","Exact OT as a reference",[187,1702,1703,1704,1706],{},"When you need the true optimal plan — for analysis, for a small problem, or to validate that ",[191,1705,236],{}," is small enough — the network simplex gives the exact answer:",[214,1708,1710],{"className":264,"code":1709,"language":266,"meta":222,"style":222},"import torch\nimport torchmatch\nfrom torchmatch.transport.matrix import Backend\n\nN = 32\ngrid = torch.linspace(0, 1, N, dtype=torch.float32)\na = torch.ones(N) \u002F N\nb = torch.ones(N) \u002F N\nC = (grid[:, None] - grid[None, :]) ** 2\n\nplan_exact = torchmatch.transport.matrix.solve(\n    C.unsqueeze(0),\n    a=a.unsqueeze(0),\n    b=b.unsqueeze(0),\n    backend=Backend.EXACT_EMD,\n)\nP_exact = plan_exact.exp().squeeze(0)\nprint(f\"Exact cost: {(P_exact * C).sum():.4f}\")\nprint(f\"Non-zero entries: {(P_exact > 1e-6).float().mean():.1%}\")\n",[191,1711,1712,1718,1724,1742,1746,1755,1795,1819,1841,1874,1878,1901,1915,1933,1951,1966,1970,1994,2029],{"__ignoreMap":222},[270,1713,1714,1716],{"class":272,"line":273},[270,1715,277],{"class":276},[270,1717,1035],{"class":280},[270,1719,1720,1722],{"class":272,"line":290},[270,1721,277],{"class":276},[270,1723,1042],{"class":280},[270,1725,1726,1728,1730,1732,1734,1736,1738,1740],{"class":272,"line":297},[270,1727,1047],{"class":276},[270,1729,1050],{"class":280},[270,1731,359],{"class":308},[270,1733,1055],{"class":280},[270,1735,359],{"class":308},[270,1737,1060],{"class":280},[270,1739,277],{"class":276},[270,1741,1065],{"class":280},[270,1743,1744],{"class":272,"line":348},[270,1745,294],{"emptyLinePlaceholder":293},[270,1747,1748,1750,1752],{"class":272,"line":382},[270,1749,586],{"class":280},[270,1751,338],{"class":337},[270,1753,1754],{"class":341}," 32\n",[270,1756,1757,1759,1761,1763,1765,1767,1769,1771,1773,1775,1777,1779,1781,1783,1785,1788,1790,1793],{"class":272,"line":428},[270,1758,597],{"class":280},[270,1760,338],{"class":337},[270,1762,1086],{"class":280},[270,1764,359],{"class":308},[270,1766,606],{"class":362},[270,1768,309],{"class":308},[270,1770,611],{"class":341},[270,1772,316],{"class":308},[270,1774,616],{"class":341},[270,1776,316],{"class":308},[270,1778,621],{"class":362},[270,1780,316],{"class":308},[270,1782,412],{"class":411},[270,1784,338],{"class":337},[270,1786,1787],{"class":362},"torch",[270,1789,359],{"class":308},[270,1791,1792],{"class":422},"float32",[270,1794,379],{"class":308},[270,1796,1797,1799,1801,1803,1805,1807,1809,1812,1814,1816],{"class":272,"line":433},[270,1798,641],{"class":280},[270,1800,338],{"class":337},[270,1802,1086],{"class":280},[270,1804,359],{"class":308},[270,1806,394],{"class":362},[270,1808,309],{"class":308},[270,1810,1811],{"class":362},"N",[270,1813,547],{"class":308},[270,1815,674],{"class":337},[270,1817,1818],{"class":280}," N\n",[270,1820,1821,1823,1825,1827,1829,1831,1833,1835,1837,1839],{"class":272,"line":455},[270,1822,693],{"class":280},[270,1824,338],{"class":337},[270,1826,1086],{"class":280},[270,1828,359],{"class":308},[270,1830,394],{"class":362},[270,1832,309],{"class":308},[270,1834,1811],{"class":362},[270,1836,547],{"class":308},[270,1838,674],{"class":337},[270,1840,1818],{"class":280},[270,1842,1843,1845,1847,1849,1851,1853,1855,1857,1859,1861,1863,1865,1867,1869,1871],{"class":272,"line":488},[270,1844,371],{"class":280},[270,1846,338],{"class":337},[270,1848,468],{"class":308},[270,1850,776],{"class":280},[270,1852,779],{"class":308},[270,1854,783],{"class":782},[270,1856,786],{"class":308},[270,1858,789],{"class":337},[270,1860,792],{"class":280},[270,1862,795],{"class":308},[270,1864,798],{"class":782},[270,1866,316],{"class":308},[270,1868,803],{"class":308},[270,1870,682],{"class":337},[270,1872,1873],{"class":341}," 2\n",[270,1875,1876],{"class":272,"line":523},[270,1877,294],{"emptyLinePlaceholder":293},[270,1879,1880,1883,1885,1887,1889,1891,1893,1895,1897,1899],{"class":272,"line":528},[270,1881,1882],{"class":280},"plan_exact ",[270,1884,338],{"class":337},[270,1886,1050],{"class":280},[270,1888,359],{"class":308},[270,1890,1055],{"class":422},[270,1892,359],{"class":308},[270,1894,1272],{"class":422},[270,1896,359],{"class":308},[270,1898,197],{"class":362},[270,1900,1279],{"class":308},[270,1902,1903,1905,1907,1909,1911,1913],{"class":272,"line":569},[270,1904,1284],{"class":362},[270,1906,359],{"class":308},[270,1908,1289],{"class":362},[270,1910,309],{"class":308},[270,1912,611],{"class":341},[270,1914,1296],{"class":308},[270,1916,1917,1919,1921,1923,1925,1927,1929,1931],{"class":272,"line":578},[270,1918,1301],{"class":411},[270,1920,338],{"class":337},[270,1922,1306],{"class":362},[270,1924,359],{"class":308},[270,1926,1289],{"class":362},[270,1928,309],{"class":308},[270,1930,611],{"class":341},[270,1932,1296],{"class":308},[270,1934,1935,1937,1939,1941,1943,1945,1947,1949],{"class":272,"line":583},[270,1936,1321],{"class":411},[270,1938,338],{"class":337},[270,1940,405],{"class":362},[270,1942,359],{"class":308},[270,1944,1289],{"class":362},[270,1946,309],{"class":308},[270,1948,611],{"class":341},[270,1950,1296],{"class":308},[270,1952,1953,1955,1957,1959,1961,1964],{"class":272,"line":594},[270,1954,1340],{"class":411},[270,1956,338],{"class":337},[270,1958,1345],{"class":362},[270,1960,359],{"class":308},[270,1962,1963],{"class":1350},"EXACT_EMD",[270,1965,1354],{"class":308},[270,1967,1968],{"class":272,"line":638},[270,1969,379],{"class":308},[270,1971,1972,1975,1977,1980,1982,1984,1986,1988,1990,1992],{"class":272,"line":690},[270,1973,1974],{"class":280},"P_exact ",[270,1976,338],{"class":337},[270,1978,1979],{"class":280}," plan_exact",[270,1981,359],{"class":308},[270,1983,363],{"class":362},[270,1985,1396],{"class":308},[270,1987,1399],{"class":362},[270,1989,309],{"class":308},[270,1991,611],{"class":341},[270,1993,379],{"class":308},[270,1995,1996,1998,2000,2002,2005,2007,2009,2011,2013,2015,2017,2019,2021,2023,2025,2027],{"class":272,"line":735},[270,1997,867],{"class":399},[270,1999,309],{"class":308},[270,2001,872],{"class":300},[270,2003,2004],{"class":875},"\"Exact cost: ",[270,2006,879],{"class":341},[270,2008,309],{"class":308},[270,2010,1974],{"class":362},[270,2012,1425],{"class":337},[270,2014,1428],{"class":362},[270,2016,810],{"class":308},[270,2018,747],{"class":362},[270,2020,750],{"class":308},[270,2022,1437],{"class":300},[270,2024,924],{"class":341},[270,2026,927],{"class":875},[270,2028,379],{"class":308},[270,2030,2031,2033,2035,2037,2040,2042,2044,2046,2048,2051,2053,2056,2058,2060,2062,2064,2066,2068],{"class":272,"line":767},[270,2032,867],{"class":399},[270,2034,309],{"class":308},[270,2036,872],{"class":300},[270,2038,2039],{"class":875},"\"Non-zero entries: ",[270,2041,879],{"class":341},[270,2043,309],{"class":308},[270,2045,1974],{"class":362},[270,2047,1630],{"class":337},[270,2049,2050],{"class":341}," 1e-6",[270,2052,810],{"class":308},[270,2054,2055],{"class":362},"float",[270,2057,1396],{"class":308},[270,2059,1638],{"class":362},[270,2061,750],{"class":308},[270,2063,1684],{"class":300},[270,2065,924],{"class":341},[270,2067,927],{"class":875},[270,2069,379],{"class":308},[187,2071,2072,2074,2075,2077,2078,2080],{},[191,2073,1963],{}," runs on CPU only, does not accept ",[191,2076,1578],{}," or ",[191,2079,450],{},", and returns a sparse plan. For N > a few hundred it becomes slow; the Sinkhorn backends are more practical there.",[182,2082,2084],{"id":2083},"sinkhorn-divergence","Sinkhorn divergence",[187,2086,2087,2088,2091,2092,2095,2096,2098],{},"Raw Sinkhorn loss has a self-transport bias: even when ",[191,2089,2090],{},"a == b",", ",[191,2093,2094],{},"OT_ε(a, a) > 0"," because the entropy penalty pushes the plan away from the identity. This is a problem when using the loss as a training objective — the model can never reach zero loss, and the gradient at ",[191,2097,2090],{}," is non-zero.",[187,2100,2101,2103],{},[1466,2102,2084],{}," corrects for this by subtracting the self-transport costs:",[214,2105,2108],{"className":2106,"code":2107,"language":219},[217],"SD_ε(a, b) = OT_ε(a, b) − ½ OT_ε(a, a) − ½ OT_ε(b, b)\n",[191,2109,2107],{"__ignoreMap":222},[187,2111,2112,2113,2115],{},"It is zero when ",[191,2114,2090],{},", symmetric, and positive otherwise. Use it whenever the loss should be a proper distance — generative model training, distribution matching, point-cloud registration:",[214,2117,2119],{"className":264,"code":2118,"language":266,"meta":222,"style":222},"import torch\nimport torchmatch\nfrom torchmatch.transport.matrix import Backend\n\nN = 16\ngrid = torch.linspace(0, 1, N)\nC = (grid[:, None] - grid[None, :]) ** 2\n\na_base = torch.exp(-0.5 * ((grid - 0.3) \u002F 0.15) ** 2)\na_base \u002F= a_base.sum()\nC_t = C.unsqueeze(0)\n\nfor offset in [0.0, 0.1, 0.3, 0.5]:\n    b = torch.exp(-0.5 * ((grid - 0.3 - offset) \u002F 0.15) ** 2)\n    b \u002F= b.sum()\n    div = torchmatch.transport.matrix.solve(\n        C_t,\n        a=a_base.unsqueeze(0),\n        b=b.unsqueeze(0),\n        backend=Backend.SINKHORN_DIVERGENCE,\n        reg=0.05, n_iter=300,\n    )\n    print(f\"offset={offset:.1f}  divergence={div.item():.5f}\")\n# offset=0.0 → divergence ≈ 0.0\n# offset=0.5 → divergence > 0\n",[191,2120,2121,2127,2133,2151,2155,2163,2189,2221,2225,2268,2283,2302,2306,2336,2384,2398,2421,2428,2448,2467,2483,2503,2508,2553,2559],{"__ignoreMap":222},[270,2122,2123,2125],{"class":272,"line":273},[270,2124,277],{"class":276},[270,2126,1035],{"class":280},[270,2128,2129,2131],{"class":272,"line":290},[270,2130,277],{"class":276},[270,2132,1042],{"class":280},[270,2134,2135,2137,2139,2141,2143,2145,2147,2149],{"class":272,"line":297},[270,2136,1047],{"class":276},[270,2138,1050],{"class":280},[270,2140,359],{"class":308},[270,2142,1055],{"class":280},[270,2144,359],{"class":308},[270,2146,1060],{"class":280},[270,2148,277],{"class":276},[270,2150,1065],{"class":280},[270,2152,2153],{"class":272,"line":348},[270,2154,294],{"emptyLinePlaceholder":293},[270,2156,2157,2159,2161],{"class":272,"line":382},[270,2158,586],{"class":280},[270,2160,338],{"class":337},[270,2162,591],{"class":341},[270,2164,2165,2167,2169,2171,2173,2175,2177,2179,2181,2183,2185,2187],{"class":272,"line":428},[270,2166,597],{"class":280},[270,2168,338],{"class":337},[270,2170,1086],{"class":280},[270,2172,359],{"class":308},[270,2174,606],{"class":362},[270,2176,309],{"class":308},[270,2178,611],{"class":341},[270,2180,316],{"class":308},[270,2182,616],{"class":341},[270,2184,316],{"class":308},[270,2186,621],{"class":362},[270,2188,379],{"class":308},[270,2190,2191,2193,2195,2197,2199,2201,2203,2205,2207,2209,2211,2213,2215,2217,2219],{"class":272,"line":433},[270,2192,371],{"class":280},[270,2194,338],{"class":337},[270,2196,468],{"class":308},[270,2198,776],{"class":280},[270,2200,779],{"class":308},[270,2202,783],{"class":782},[270,2204,786],{"class":308},[270,2206,789],{"class":337},[270,2208,792],{"class":280},[270,2210,795],{"class":308},[270,2212,798],{"class":782},[270,2214,316],{"class":308},[270,2216,803],{"class":308},[270,2218,682],{"class":337},[270,2220,1873],{"class":341},[270,2222,2223],{"class":272,"line":455},[270,2224,294],{"emptyLinePlaceholder":293},[270,2226,2227,2230,2232,2234,2236,2238,2240,2242,2244,2246,2248,2250,2252,2254,2256,2258,2260,2262,2264,2266],{"class":272,"line":488},[270,2228,2229],{"class":280},"a_base ",[270,2231,338],{"class":337},[270,2233,1086],{"class":280},[270,2235,359],{"class":308},[270,2237,363],{"class":362},[270,2239,309],{"class":308},[270,2241,368],{"class":337},[270,2243,656],{"class":341},[270,2245,659],{"class":337},[270,2247,662],{"class":308},[270,2249,597],{"class":362},[270,2251,368],{"class":337},[270,2253,669],{"class":341},[270,2255,547],{"class":308},[270,2257,674],{"class":337},[270,2259,677],{"class":341},[270,2261,547],{"class":308},[270,2263,682],{"class":337},[270,2265,685],{"class":341},[270,2267,379],{"class":308},[270,2269,2270,2272,2274,2277,2279,2281],{"class":272,"line":523},[270,2271,2229],{"class":280},[270,2273,740],{"class":337},[270,2275,2276],{"class":280}," a_base",[270,2278,359],{"class":308},[270,2280,747],{"class":362},[270,2282,764],{"class":308},[270,2284,2285,2288,2290,2292,2294,2296,2298,2300],{"class":272,"line":528},[270,2286,2287],{"class":280},"C_t ",[270,2289,338],{"class":337},[270,2291,1428],{"class":280},[270,2293,359],{"class":308},[270,2295,1289],{"class":362},[270,2297,309],{"class":308},[270,2299,611],{"class":341},[270,2301,379],{"class":308},[270,2303,2304],{"class":272,"line":569},[270,2305,294],{"emptyLinePlaceholder":293},[270,2307,2308,2310,2313,2315,2317,2320,2322,2324,2326,2328,2330,2333],{"class":272,"line":578},[270,2309,1523],{"class":276},[270,2311,2312],{"class":280}," offset ",[270,2314,442],{"class":276},[270,2316,1494],{"class":308},[270,2318,2319],{"class":341},"0.0",[270,2321,316],{"class":308},[270,2323,1501],{"class":341},[270,2325,316],{"class":308},[270,2327,669],{"class":341},[270,2329,316],{"class":308},[270,2331,2332],{"class":341}," 0.5",[270,2334,2335],{"class":308},"]:\n",[270,2337,2338,2341,2343,2345,2347,2349,2351,2353,2355,2357,2359,2361,2363,2365,2367,2370,2372,2374,2376,2378,2380,2382],{"class":272,"line":583},[270,2339,2340],{"class":280},"    b ",[270,2342,338],{"class":337},[270,2344,1086],{"class":280},[270,2346,359],{"class":308},[270,2348,363],{"class":362},[270,2350,309],{"class":308},[270,2352,368],{"class":337},[270,2354,656],{"class":341},[270,2356,659],{"class":337},[270,2358,662],{"class":308},[270,2360,597],{"class":362},[270,2362,368],{"class":337},[270,2364,669],{"class":341},[270,2366,789],{"class":337},[270,2368,2369],{"class":362}," offset",[270,2371,547],{"class":308},[270,2373,674],{"class":337},[270,2375,677],{"class":341},[270,2377,547],{"class":308},[270,2379,682],{"class":337},[270,2381,685],{"class":341},[270,2383,379],{"class":308},[270,2385,2386,2388,2390,2392,2394,2396],{"class":272,"line":594},[270,2387,2340],{"class":280},[270,2389,740],{"class":337},[270,2391,324],{"class":280},[270,2393,359],{"class":308},[270,2395,747],{"class":362},[270,2397,764],{"class":308},[270,2399,2400,2403,2405,2407,2409,2411,2413,2415,2417,2419],{"class":272,"line":638},[270,2401,2402],{"class":280},"    div ",[270,2404,338],{"class":337},[270,2406,1050],{"class":280},[270,2408,359],{"class":308},[270,2410,1055],{"class":422},[270,2412,359],{"class":308},[270,2414,1272],{"class":422},[270,2416,359],{"class":308},[270,2418,197],{"class":362},[270,2420,1279],{"class":308},[270,2422,2423,2426],{"class":272,"line":690},[270,2424,2425],{"class":362},"        C_t",[270,2427,1354],{"class":308},[270,2429,2430,2433,2435,2438,2440,2442,2444,2446],{"class":272,"line":735},[270,2431,2432],{"class":411},"        a",[270,2434,338],{"class":337},[270,2436,2437],{"class":362},"a_base",[270,2439,359],{"class":308},[270,2441,1289],{"class":362},[270,2443,309],{"class":308},[270,2445,611],{"class":341},[270,2447,1296],{"class":308},[270,2449,2450,2453,2455,2457,2459,2461,2463,2465],{"class":272,"line":767},[270,2451,2452],{"class":411},"        b",[270,2454,338],{"class":337},[270,2456,405],{"class":362},[270,2458,359],{"class":308},[270,2460,1289],{"class":362},[270,2462,309],{"class":308},[270,2464,611],{"class":341},[270,2466,1296],{"class":308},[270,2468,2469,2472,2474,2476,2478,2481],{"class":272,"line":826},[270,2470,2471],{"class":411},"        backend",[270,2473,338],{"class":337},[270,2475,1345],{"class":362},[270,2477,359],{"class":308},[270,2479,2480],{"class":1350},"SINKHORN_DIVERGENCE",[270,2482,1354],{"class":308},[270,2484,2485,2488,2490,2492,2494,2496,2498,2501],{"class":272,"line":831},[270,2486,2487],{"class":411},"        reg",[270,2489,338],{"class":337},[270,2491,859],{"class":341},[270,2493,316],{"class":308},[270,2495,334],{"class":411},[270,2497,338],{"class":337},[270,2499,2500],{"class":341},"300",[270,2502,1354],{"class":308},[270,2504,2505],{"class":272,"line":864},[270,2506,2507],{"class":308},"    )\n",[270,2509,2510,2512,2514,2516,2519,2521,2524,2527,2529,2532,2534,2537,2539,2542,2544,2547,2549,2551],{"class":272,"line":932},[270,2511,1645],{"class":399},[270,2513,309],{"class":308},[270,2515,872],{"class":300},[270,2517,2518],{"class":875},"\"offset=",[270,2520,879],{"class":341},[270,2522,2523],{"class":362},"offset",[270,2525,2526],{"class":300},":.1f",[270,2528,924],{"class":341},[270,2530,2531],{"class":875},"  divergence=",[270,2533,879],{"class":341},[270,2535,2536],{"class":362},"div",[270,2538,359],{"class":308},[270,2540,2541],{"class":362},"item",[270,2543,750],{"class":308},[270,2545,2546],{"class":300},":.5f",[270,2548,924],{"class":341},[270,2550,927],{"class":875},[270,2552,379],{"class":308},[270,2554,2556],{"class":272,"line":2555},24,[270,2557,2558],{"class":1249},"# offset=0.0 → divergence ≈ 0.0\n",[270,2560,2562],{"class":272,"line":2561},25,[270,2563,2564],{"class":1249},"# offset=0.5 → divergence > 0\n",[187,2566,2567,2569,2570,2091,2573,2576,2577,2580],{},[191,2568,2480],{}," runs three Sinkhorn solves internally (for ",[191,2571,2572],{},"(a,b)",[191,2574,2575],{},"(a,a)",", and ",[191,2578,2579],{},"(b,b)",") and returns the scalar divergence, not a plan tensor.",[182,2582,2584],{"id":2583},"which-backend-to-use","Which backend to use",[2586,2587,2588,2600],"table",{},[2589,2590,2591],"thead",{},[2592,2593,2594,2598],"tr",{},[2595,2596,2597],"th",{},"Goal",[2595,2599,1345],{},[2601,2602,2603,2614,2623,2633],"tbody",{},[2592,2604,2605,2609],{},[2606,2607,2608],"td",{},"Training with a plan-shaped loss",[2606,2610,2611,2613],{},[191,2612,1351],{}," (default)",[2592,2615,2616,2619],{},[2606,2617,2618],{},"Training as a distribution distance",[2606,2620,2621],{},[191,2622,2480],{},[2592,2624,2625,2628],{},[2606,2626,2627],{},"Unbalanced mass \u002F partial matching",[2606,2629,2630],{},[191,2631,2632],{},"UNBALANCED_SINKHORN",[2592,2634,2635,2638],{},[2606,2636,2637],{},"Exact plan for small N (analysis, verification)",[2606,2639,2640,2642],{},[191,2641,1963],{}," (CPU only)",[182,2644,2646],{"id":2645},"see-also","See also",[1460,2648,2649,2654,2660,2665],{},[1463,2650,2651,2653],{},[1306,2652,90],{"href":91},": the problem definition, transport plans, and Wasserstein distance.",[1463,2655,2656,2659],{},[1306,2657,2658],{"href":99},"Point clouds and shapes",": scaling to large point sets without materialising the cost matrix.",[1463,2661,2662,2664],{},[1306,2663,9],{"href":72},": the full derivation of Sinkhorn and log-domain stability.",[1463,2666,2667,2669],{},[1306,2668,33],{"href":75},": exact parameter names and constraints for each backend.",[2671,2672,2673],"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 .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 .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 .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 .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .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 .swQdS, html code.shiki .swQdS{--shiki-light:#E53935;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":222,"searchDepth":297,"depth":297,"links":2675},[2676,2677,2678,2679,2680,2681,2682,2683,2684],{"id":184,"depth":290,"text":185},{"id":208,"depth":290,"text":209},{"id":240,"depth":290,"text":241},{"id":991,"depth":290,"text":992},{"id":1454,"depth":290,"text":1455},{"id":1699,"depth":290,"text":1700},{"id":2083,"depth":290,"text":2084},{"id":2583,"depth":290,"text":2584},{"id":2645,"depth":290,"text":2646},"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.","md",{},{"title":94},{"title":176,"description":2685},"9PJ4Bc2EH3OJUPr0FH14bbPsJjM44m4lRxk1Iq0zszM",[2692,2694],{"title":90,"path":91,"stem":92,"description":2693,"children":-1},"Earth-mover intuition, transport plans, marginal constraints, and Wasserstein distance — from scratch using torchmatch.transport.matrix.solve.",{"title":98,"path":99,"stem":100,"description":2695,"children":-1},"Computing OT directly on raw point sets with samples.loss, training a neural network shape generator, handling outliers with unbalanced OT, and computing Wasserstein barycenters.",1785218169331]