[{"data":1,"prerenderedAt":5779},["ShallowReactive",2],{"navigation":3,"\u002Fresources\u002Ftutorials\u002Ftransport\u002F03_point_clouds":174,"\u002Fresources\u002Ftutorials\u002Ftransport\u002F03_point_clouds-surround":5775},[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":144,"api":176,"body":177,"description":190,"extension":5770,"links":176,"meta":5771,"navigation":5772,"path":145,"seo":5773,"stem":146,"__hash__":5774},"docs\u002F3.resources\u002F1.tutorials\u002Ftransport\u002F03_point_clouds.md",null,{"type":178,"value":179,"toc":5760},"minimark",[180,184,191,214,224,521,526,529,534,553,564,570,574,1113,1119,1533,1536,1540,1547,1873,1878,2482,2487,3045,3048,3694,3699,3703,3706,3716,4791,4796,4799,4803,4806,4809,5699,5704,5707,5711,5744,5756],[181,182,144],"h1",{"id":183},"tutorial-3-point-cloud-ot-and-shape-learning",[185,186,187],"p",{},[188,189,190],"strong",{},"What you will learn",[192,193,194,202,205,208,211],"ul",{},[195,196,197,198],"li",{},"How to compute OT between raw point clouds with ",[199,200,201],"code",{},"transport.samples.loss",[195,203,204],{},"Why the samples face avoids the N×M cost matrix allocation",[195,206,207],{},"How to use Wasserstein loss as a training objective for a shape generator",[195,209,210],{},"The difference between balanced and unbalanced OT for point clouds",[195,212,213],{},"Wasserstein barycenters: averaging shapes in OT space",[185,215,216,219,220,223],{},[188,217,218],{},"Prerequisites"," — Tutorials 1 and 2.  A CUDA GPU is needed for the\nsamples face (",[199,221,222],{},"samples.loss"," is CUDA-only); the matrix face runs on CPU.",[225,226,231],"pre",{"className":227,"code":228,"language":229,"meta":230,"style":230},"language-python shiki shiki-themes material-theme-lighter github-light github-dark","%matplotlib inline\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport torch\nimport torch.nn as nn\nimport torchmatch\n\nplt.rcParams.update({\"figure.dpi\": 120, \"font.size\": 11})\nCUDA = torch.cuda.is_available()\ndevice = torch.device(\"cuda\" if CUDA else \"cpu\")\nrng = np.random.default_rng(42)\nprint(f\"torchmatch {torchmatch.__version__}  |  device: {device}\")\n","python","",[199,232,233,246,270,284,292,310,318,325,381,406,451,479],{"__ignoreMap":230},[234,235,238,242],"span",{"class":236,"line":237},"line",1,[234,239,241],{"class":240},"smGrS","%",[234,243,245],{"class":244},"su5hD","matplotlib inline\n",[234,247,249,253,256,260,264,267],{"class":236,"line":248},2,[234,250,252],{"class":251},"sVHd0","import",[234,254,255],{"class":244}," matplotlib",[234,257,259],{"class":258},"sP7_E",".",[234,261,263],{"class":262},"skxfh","pyplot",[234,265,266],{"class":251}," as",[234,268,269],{"class":244}," plt\n",[234,271,273,275,278,281],{"class":236,"line":272},3,[234,274,252],{"class":251},[234,276,277],{"class":244}," numpy ",[234,279,280],{"class":251},"as",[234,282,283],{"class":244}," np\n",[234,285,287,289],{"class":236,"line":286},4,[234,288,252],{"class":251},[234,290,291],{"class":244}," torch\n",[234,293,295,297,300,302,305,307],{"class":236,"line":294},5,[234,296,252],{"class":251},[234,298,299],{"class":244}," torch",[234,301,259],{"class":258},[234,303,304],{"class":262},"nn",[234,306,266],{"class":251},[234,308,309],{"class":244}," nn\n",[234,311,313,315],{"class":236,"line":312},6,[234,314,252],{"class":251},[234,316,317],{"class":244}," torchmatch\n",[234,319,321],{"class":236,"line":320},7,[234,322,324],{"emptyLinePlaceholder":323},true,"\n",[234,326,328,331,333,336,338,342,345,349,353,355,358,362,365,368,371,373,375,378],{"class":236,"line":327},8,[234,329,330],{"class":244},"plt",[234,332,259],{"class":258},[234,334,335],{"class":262},"rcParams",[234,337,259],{"class":258},[234,339,341],{"class":340},"slqww","update",[234,343,344],{"class":258},"({",[234,346,348],{"class":347},"sjJ54","\"",[234,350,352],{"class":351},"s_sjI","figure.dpi",[234,354,348],{"class":347},[234,356,357],{"class":258},":",[234,359,361],{"class":360},"srdBf"," 120",[234,363,364],{"class":258},",",[234,366,367],{"class":347}," \"",[234,369,370],{"class":351},"font.size",[234,372,348],{"class":347},[234,374,357],{"class":258},[234,376,377],{"class":360}," 11",[234,379,380],{"class":258},"})\n",[234,382,384,388,391,393,395,398,400,403],{"class":236,"line":383},9,[234,385,387],{"class":386},"s_hVV","CUDA",[234,389,390],{"class":240}," =",[234,392,299],{"class":244},[234,394,259],{"class":258},[234,396,397],{"class":262},"cuda",[234,399,259],{"class":258},[234,401,402],{"class":340},"is_available",[234,404,405],{"class":258},"()\n",[234,407,409,412,415,417,419,422,425,427,429,431,434,438,441,443,446,448],{"class":236,"line":408},10,[234,410,411],{"class":244},"device ",[234,413,414],{"class":240},"=",[234,416,299],{"class":244},[234,418,259],{"class":258},[234,420,421],{"class":340},"device",[234,423,424],{"class":258},"(",[234,426,348],{"class":347},[234,428,397],{"class":351},[234,430,348],{"class":347},[234,432,433],{"class":251}," if",[234,435,437],{"class":436},"sptTA"," CUDA",[234,439,440],{"class":251}," else",[234,442,367],{"class":347},[234,444,445],{"class":351},"cpu",[234,447,348],{"class":347},[234,449,450],{"class":258},")\n",[234,452,454,457,459,462,464,467,469,472,474,477],{"class":236,"line":453},11,[234,455,456],{"class":244},"rng ",[234,458,414],{"class":240},[234,460,461],{"class":244}," np",[234,463,259],{"class":258},[234,465,466],{"class":262},"random",[234,468,259],{"class":258},[234,470,471],{"class":340},"default_rng",[234,473,424],{"class":258},[234,475,476],{"class":360},"42",[234,478,450],{"class":258},[234,480,482,485,487,491,494,497,500,502,505,508,511,513,515,517,519],{"class":236,"line":481},12,[234,483,484],{"class":436},"print",[234,486,424],{"class":258},[234,488,490],{"class":489},"sbsja","f",[234,492,493],{"class":351},"\"torchmatch ",[234,495,496],{"class":360},"{",[234,498,499],{"class":340},"torchmatch",[234,501,259],{"class":258},[234,503,504],{"class":386},"__version__",[234,506,507],{"class":360},"}",[234,509,510],{"class":351},"  |  device: ",[234,512,496],{"class":360},[234,514,421],{"class":340},[234,516,507],{"class":360},[234,518,348],{"class":351},[234,520,450],{"class":258},[522,523],"docyard-notebook-output",{"data":524,"kind":525},"VzA2MDMgMTc6MTQ6MzEuNTkzMDAwIDExMjQ1MjMgdG9yY2gvdXRpbHMvY3BwX2V4dGVuc2lvbi5weToxNDBdIE5vIENVREEgcnVudGltZSBpcyBmb3VuZCwgdXNpbmcgQ1VEQV9IT01FPScvbml4L3N0b3JlLzJ3YnJyOG55aTNpbml3cWtpaGYzNzc1cmdtcmgzZDM3LWN1ZGEtbWVyZ2VkLTEyLjgnCg==","stream",[522,527],{"data":528,"kind":525},"dG9yY2htYXRjaCAxLjAuMCAgfCAgZGV2aWNlOiBjcHUK",[530,531,533],"h2",{"id":532},"_1-why-point-cloud-ot-is-different","1  Why point-cloud OT is different",[185,535,536,537,540,541,544,545,548,549,552],{},"In the matrix tutorials the cost matrix ",[199,538,539],{},"C[i, j]"," was given explicitly.\nFor point clouds ",[199,542,543],{},"x ∈ ℝ^{N×D}"," and ",[199,546,547],{},"y ∈ ℝ^{M×D}",", the cost is the\nsquared Euclidean distance ",[199,550,551],{},"|x_i − y_j|²"," computed on the fly.",[185,554,555,556,559,560,563],{},"At ",[199,557,558],{},"N = M = 4096",", the cost matrix would be ",[199,561,562],{},"4096 × 4096 × 4 bytes ≈ 64 MB","\nper problem.  For a training batch of 32, that is 2 GB — just for the cost\nmatrices, before the plan itself.",[185,565,566,569],{},[199,567,568],{},"torchmatch.transport.samples.loss"," avoids this entirely: a Triton streaming\nkernel computes costs block-by-block and accumulates the Sinkhorn log-sum-exp\ninto length-N and length-M potential vectors, never writing the full N×M\ncost to memory.",[530,571,573],{"id":572},"_2-first-point-cloud-loss","2  First point-cloud loss",[225,575,577],{"className":227,"code":576,"language":229,"meta":230,"style":230},"N = 512\n# Source: 2-D ring\nangles = torch.linspace(0, 2 * torch.pi, N)\nx = torch.stack([torch.cos(angles), torch.sin(angles)], dim=1)  # (N, 2) ring\n\n# Target: 2-D square\ny_np = rng.uniform(-1, 1, (N, 2)).astype(np.float32)\ny = torch.from_numpy(y_np)\n\nfig, axes = plt.subplots(1, 2, figsize=(9, 4))\naxes[0].scatter(x[:, 0], x[:, 1], s=8, color=\"#1a6daf\", alpha=0.7)\naxes[0].set_title(\"Source x  (ring)\")\naxes[0].set_aspect(\"equal\")\naxes[1].scatter(y[:, 0], y[:, 1], s=8, color=\"#E03520\", alpha=0.7)\naxes[1].set_title(\"Target y  (uniform square)\")\naxes[1].set_aspect(\"equal\")\nplt.suptitle(\"Point clouds before OT\")\nplt.tight_layout()\nplt.show()\n",[199,578,579,589,595,636,698,702,707,764,785,789,837,910,934,959,1021,1045,1068,1089,1101],{"__ignoreMap":230},[234,580,581,584,586],{"class":236,"line":237},[234,582,583],{"class":244},"N ",[234,585,414],{"class":240},[234,587,588],{"class":360}," 512\n",[234,590,591],{"class":236,"line":248},[234,592,594],{"class":593},"sutJx","# Source: 2-D ring\n",[234,596,597,600,602,604,606,609,611,614,616,619,622,624,626,629,631,634],{"class":236,"line":272},[234,598,599],{"class":244},"angles ",[234,601,414],{"class":240},[234,603,299],{"class":244},[234,605,259],{"class":258},[234,607,608],{"class":340},"linspace",[234,610,424],{"class":258},[234,612,613],{"class":360},"0",[234,615,364],{"class":258},[234,617,618],{"class":360}," 2",[234,620,621],{"class":240}," *",[234,623,299],{"class":340},[234,625,259],{"class":258},[234,627,628],{"class":262},"pi",[234,630,364],{"class":258},[234,632,633],{"class":340}," N",[234,635,450],{"class":258},[234,637,638,641,643,645,647,650,653,656,658,661,663,666,669,671,673,676,678,680,683,687,689,692,695],{"class":236,"line":286},[234,639,640],{"class":244},"x ",[234,642,414],{"class":240},[234,644,299],{"class":244},[234,646,259],{"class":258},[234,648,649],{"class":340},"stack",[234,651,652],{"class":258},"([",[234,654,655],{"class":340},"torch",[234,657,259],{"class":258},[234,659,660],{"class":340},"cos",[234,662,424],{"class":258},[234,664,665],{"class":340},"angles",[234,667,668],{"class":258},"),",[234,670,299],{"class":340},[234,672,259],{"class":258},[234,674,675],{"class":340},"sin",[234,677,424],{"class":258},[234,679,665],{"class":340},[234,681,682],{"class":258},")],",[234,684,686],{"class":685},"s99_P"," dim",[234,688,414],{"class":240},[234,690,691],{"class":360},"1",[234,693,694],{"class":258},")",[234,696,697],{"class":593},"  # (N, 2) ring\n",[234,699,700],{"class":236,"line":294},[234,701,324],{"emptyLinePlaceholder":323},[234,703,704],{"class":236,"line":312},[234,705,706],{"class":593},"# Target: 2-D square\n",[234,708,709,712,714,717,719,722,724,727,729,731,734,736,739,742,744,746,749,752,754,757,759,762],{"class":236,"line":320},[234,710,711],{"class":244},"y_np ",[234,713,414],{"class":240},[234,715,716],{"class":244}," rng",[234,718,259],{"class":258},[234,720,721],{"class":340},"uniform",[234,723,424],{"class":258},[234,725,726],{"class":240},"-",[234,728,691],{"class":360},[234,730,364],{"class":258},[234,732,733],{"class":360}," 1",[234,735,364],{"class":258},[234,737,738],{"class":258}," (",[234,740,741],{"class":340},"N",[234,743,364],{"class":258},[234,745,618],{"class":360},[234,747,748],{"class":258},")).",[234,750,751],{"class":340},"astype",[234,753,424],{"class":258},[234,755,756],{"class":340},"np",[234,758,259],{"class":258},[234,760,761],{"class":262},"float32",[234,763,450],{"class":258},[234,765,766,769,771,773,775,778,780,783],{"class":236,"line":327},[234,767,768],{"class":244},"y ",[234,770,414],{"class":240},[234,772,299],{"class":244},[234,774,259],{"class":258},[234,776,777],{"class":340},"from_numpy",[234,779,424],{"class":258},[234,781,782],{"class":340},"y_np",[234,784,450],{"class":258},[234,786,787],{"class":236,"line":383},[234,788,324],{"emptyLinePlaceholder":323},[234,790,791,794,796,799,801,804,806,809,811,813,815,817,819,822,824,826,829,831,834],{"class":236,"line":408},[234,792,793],{"class":244},"fig",[234,795,364],{"class":258},[234,797,798],{"class":244}," axes ",[234,800,414],{"class":240},[234,802,803],{"class":244}," plt",[234,805,259],{"class":258},[234,807,808],{"class":340},"subplots",[234,810,424],{"class":258},[234,812,691],{"class":360},[234,814,364],{"class":258},[234,816,618],{"class":360},[234,818,364],{"class":258},[234,820,821],{"class":685}," figsize",[234,823,414],{"class":240},[234,825,424],{"class":258},[234,827,828],{"class":360},"9",[234,830,364],{"class":258},[234,832,833],{"class":360}," 4",[234,835,836],{"class":258},"))\n",[234,838,839,842,845,847,850,853,855,858,861,864,867,870,872,874,876,879,881,884,886,889,891,893,896,898,900,903,905,908],{"class":236,"line":453},[234,840,841],{"class":244},"axes",[234,843,844],{"class":258},"[",[234,846,613],{"class":360},[234,848,849],{"class":258},"].",[234,851,852],{"class":340},"scatter",[234,854,424],{"class":258},[234,856,857],{"class":340},"x",[234,859,860],{"class":258},"[:,",[234,862,863],{"class":360}," 0",[234,865,866],{"class":258},"],",[234,868,869],{"class":340}," x",[234,871,860],{"class":258},[234,873,733],{"class":360},[234,875,866],{"class":258},[234,877,878],{"class":685}," s",[234,880,414],{"class":240},[234,882,883],{"class":360},"8",[234,885,364],{"class":258},[234,887,888],{"class":685}," color",[234,890,414],{"class":240},[234,892,348],{"class":347},[234,894,895],{"class":351},"#1a6daf",[234,897,348],{"class":347},[234,899,364],{"class":258},[234,901,902],{"class":685}," alpha",[234,904,414],{"class":240},[234,906,907],{"class":360},"0.7",[234,909,450],{"class":258},[234,911,912,914,916,918,920,923,925,927,930,932],{"class":236,"line":481},[234,913,841],{"class":244},[234,915,844],{"class":258},[234,917,613],{"class":360},[234,919,849],{"class":258},[234,921,922],{"class":340},"set_title",[234,924,424],{"class":258},[234,926,348],{"class":347},[234,928,929],{"class":351},"Source x  (ring)",[234,931,348],{"class":347},[234,933,450],{"class":258},[234,935,937,939,941,943,945,948,950,952,955,957],{"class":236,"line":936},13,[234,938,841],{"class":244},[234,940,844],{"class":258},[234,942,613],{"class":360},[234,944,849],{"class":258},[234,946,947],{"class":340},"set_aspect",[234,949,424],{"class":258},[234,951,348],{"class":347},[234,953,954],{"class":351},"equal",[234,956,348],{"class":347},[234,958,450],{"class":258},[234,960,962,964,966,968,970,972,974,977,979,981,983,986,988,990,992,994,996,998,1000,1002,1004,1006,1009,1011,1013,1015,1017,1019],{"class":236,"line":961},14,[234,963,841],{"class":244},[234,965,844],{"class":258},[234,967,691],{"class":360},[234,969,849],{"class":258},[234,971,852],{"class":340},[234,973,424],{"class":258},[234,975,976],{"class":340},"y",[234,978,860],{"class":258},[234,980,863],{"class":360},[234,982,866],{"class":258},[234,984,985],{"class":340}," y",[234,987,860],{"class":258},[234,989,733],{"class":360},[234,991,866],{"class":258},[234,993,878],{"class":685},[234,995,414],{"class":240},[234,997,883],{"class":360},[234,999,364],{"class":258},[234,1001,888],{"class":685},[234,1003,414],{"class":240},[234,1005,348],{"class":347},[234,1007,1008],{"class":351},"#E03520",[234,1010,348],{"class":347},[234,1012,364],{"class":258},[234,1014,902],{"class":685},[234,1016,414],{"class":240},[234,1018,907],{"class":360},[234,1020,450],{"class":258},[234,1022,1024,1026,1028,1030,1032,1034,1036,1038,1041,1043],{"class":236,"line":1023},15,[234,1025,841],{"class":244},[234,1027,844],{"class":258},[234,1029,691],{"class":360},[234,1031,849],{"class":258},[234,1033,922],{"class":340},[234,1035,424],{"class":258},[234,1037,348],{"class":347},[234,1039,1040],{"class":351},"Target y  (uniform square)",[234,1042,348],{"class":347},[234,1044,450],{"class":258},[234,1046,1048,1050,1052,1054,1056,1058,1060,1062,1064,1066],{"class":236,"line":1047},16,[234,1049,841],{"class":244},[234,1051,844],{"class":258},[234,1053,691],{"class":360},[234,1055,849],{"class":258},[234,1057,947],{"class":340},[234,1059,424],{"class":258},[234,1061,348],{"class":347},[234,1063,954],{"class":351},[234,1065,348],{"class":347},[234,1067,450],{"class":258},[234,1069,1071,1073,1075,1078,1080,1082,1085,1087],{"class":236,"line":1070},17,[234,1072,330],{"class":244},[234,1074,259],{"class":258},[234,1076,1077],{"class":340},"suptitle",[234,1079,424],{"class":258},[234,1081,348],{"class":347},[234,1083,1084],{"class":351},"Point clouds before OT",[234,1086,348],{"class":347},[234,1088,450],{"class":258},[234,1090,1092,1094,1096,1099],{"class":236,"line":1091},18,[234,1093,330],{"class":244},[234,1095,259],{"class":258},[234,1097,1098],{"class":340},"tight_layout",[234,1100,405],{"class":258},[234,1102,1104,1106,1108,1111],{"class":236,"line":1103},19,[234,1105,330],{"class":244},[234,1107,259],{"class":258},[234,1109,1110],{"class":340},"show",[234,1112,405],{"class":258},[185,1114,1115],{},[1116,1117],"img",{"alt":230,"src":1118},"\u002F_nb\u002F2e471921bc2230e3.png",[225,1120,1122],{"className":227,"code":1121,"language":229,"meta":230,"style":230},"if CUDA:\n    x_gpu = x.to(device).requires_grad_(True)\n    y_gpu = y.to(device)\n\n    loss = torchmatch.transport.samples.loss(x_gpu, y_gpu, blur=0.1)\n    print(f\"Sinkhorn loss (ring → square): {loss.item():.4f}\")\n\n    # Gradients flow back through x\n    loss.backward()\n    print(f\"Gradient norm on x: {x_gpu.grad.norm().item():.4f}\")\n    print(f\"Gradient shape: {x_gpu.grad.shape}\")\nelse:\n    print(\"CUDA not available — using matrix face on CPU as an approximation\")\n    C_cpu = torch.cdist(x, y).pow(2).unsqueeze(0)\n    log_plan = torchmatch.transport.matrix.solve(C_cpu, reg=0.1, n_iter=200)\n    cost_val = (log_plan.exp() * C_cpu).sum().item()\n    print(f\"Approximate transport cost (matrix face, CPU): {cost_val:.4f}\")\n",[199,1123,1124,1134,1166,1185,1189,1236,1269,1273,1278,1290,1330,1360,1367,1382,1425,1474,1509],{"__ignoreMap":230},[234,1125,1126,1129,1131],{"class":236,"line":237},[234,1127,1128],{"class":251},"if",[234,1130,437],{"class":386},[234,1132,1133],{"class":258},":\n",[234,1135,1136,1139,1141,1143,1145,1148,1150,1152,1155,1158,1160,1164],{"class":236,"line":248},[234,1137,1138],{"class":244},"    x_gpu ",[234,1140,414],{"class":240},[234,1142,869],{"class":244},[234,1144,259],{"class":258},[234,1146,1147],{"class":340},"to",[234,1149,424],{"class":258},[234,1151,421],{"class":340},[234,1153,1154],{"class":258},").",[234,1156,1157],{"class":340},"requires_grad_",[234,1159,424],{"class":258},[234,1161,1163],{"class":1162},"s39Yj","True",[234,1165,450],{"class":258},[234,1167,1168,1171,1173,1175,1177,1179,1181,1183],{"class":236,"line":272},[234,1169,1170],{"class":244},"    y_gpu ",[234,1172,414],{"class":240},[234,1174,985],{"class":244},[234,1176,259],{"class":258},[234,1178,1147],{"class":340},[234,1180,424],{"class":258},[234,1182,421],{"class":340},[234,1184,450],{"class":258},[234,1186,1187],{"class":236,"line":286},[234,1188,324],{"emptyLinePlaceholder":323},[234,1190,1191,1194,1196,1199,1201,1204,1206,1209,1211,1214,1216,1219,1221,1224,1226,1229,1231,1234],{"class":236,"line":294},[234,1192,1193],{"class":244},"    loss ",[234,1195,414],{"class":240},[234,1197,1198],{"class":244}," torchmatch",[234,1200,259],{"class":258},[234,1202,1203],{"class":262},"transport",[234,1205,259],{"class":258},[234,1207,1208],{"class":262},"samples",[234,1210,259],{"class":258},[234,1212,1213],{"class":340},"loss",[234,1215,424],{"class":258},[234,1217,1218],{"class":340},"x_gpu",[234,1220,364],{"class":258},[234,1222,1223],{"class":340}," y_gpu",[234,1225,364],{"class":258},[234,1227,1228],{"class":685}," blur",[234,1230,414],{"class":240},[234,1232,1233],{"class":360},"0.1",[234,1235,450],{"class":258},[234,1237,1238,1241,1243,1245,1248,1250,1252,1254,1257,1260,1263,1265,1267],{"class":236,"line":312},[234,1239,1240],{"class":436},"    print",[234,1242,424],{"class":258},[234,1244,490],{"class":489},[234,1246,1247],{"class":351},"\"Sinkhorn loss (ring → square): ",[234,1249,496],{"class":360},[234,1251,1213],{"class":340},[234,1253,259],{"class":258},[234,1255,1256],{"class":340},"item",[234,1258,1259],{"class":258},"()",[234,1261,1262],{"class":489},":.4f",[234,1264,507],{"class":360},[234,1266,348],{"class":351},[234,1268,450],{"class":258},[234,1270,1271],{"class":236,"line":320},[234,1272,324],{"emptyLinePlaceholder":323},[234,1274,1275],{"class":236,"line":327},[234,1276,1277],{"class":593},"    # Gradients flow back through x\n",[234,1279,1280,1283,1285,1288],{"class":236,"line":383},[234,1281,1282],{"class":244},"    loss",[234,1284,259],{"class":258},[234,1286,1287],{"class":340},"backward",[234,1289,405],{"class":258},[234,1291,1292,1294,1296,1298,1301,1303,1305,1307,1310,1312,1315,1318,1320,1322,1324,1326,1328],{"class":236,"line":408},[234,1293,1240],{"class":436},[234,1295,424],{"class":258},[234,1297,490],{"class":489},[234,1299,1300],{"class":351},"\"Gradient norm on x: ",[234,1302,496],{"class":360},[234,1304,1218],{"class":340},[234,1306,259],{"class":258},[234,1308,1309],{"class":262},"grad",[234,1311,259],{"class":258},[234,1313,1314],{"class":340},"norm",[234,1316,1317],{"class":258},"().",[234,1319,1256],{"class":340},[234,1321,1259],{"class":258},[234,1323,1262],{"class":489},[234,1325,507],{"class":360},[234,1327,348],{"class":351},[234,1329,450],{"class":258},[234,1331,1332,1334,1336,1338,1341,1343,1345,1347,1349,1351,1354,1356,1358],{"class":236,"line":453},[234,1333,1240],{"class":436},[234,1335,424],{"class":258},[234,1337,490],{"class":489},[234,1339,1340],{"class":351},"\"Gradient shape: ",[234,1342,496],{"class":360},[234,1344,1218],{"class":340},[234,1346,259],{"class":258},[234,1348,1309],{"class":262},[234,1350,259],{"class":258},[234,1352,1353],{"class":262},"shape",[234,1355,507],{"class":360},[234,1357,348],{"class":351},[234,1359,450],{"class":258},[234,1361,1362,1365],{"class":236,"line":481},[234,1363,1364],{"class":251},"else",[234,1366,1133],{"class":258},[234,1368,1369,1371,1373,1375,1378,1380],{"class":236,"line":936},[234,1370,1240],{"class":436},[234,1372,424],{"class":258},[234,1374,348],{"class":347},[234,1376,1377],{"class":351},"CUDA not available — using matrix face on CPU as an approximation",[234,1379,348],{"class":347},[234,1381,450],{"class":258},[234,1383,1384,1387,1389,1391,1393,1396,1398,1400,1402,1404,1406,1409,1411,1414,1416,1419,1421,1423],{"class":236,"line":961},[234,1385,1386],{"class":244},"    C_cpu ",[234,1388,414],{"class":240},[234,1390,299],{"class":244},[234,1392,259],{"class":258},[234,1394,1395],{"class":340},"cdist",[234,1397,424],{"class":258},[234,1399,857],{"class":340},[234,1401,364],{"class":258},[234,1403,985],{"class":340},[234,1405,1154],{"class":258},[234,1407,1408],{"class":340},"pow",[234,1410,424],{"class":258},[234,1412,1413],{"class":360},"2",[234,1415,1154],{"class":258},[234,1417,1418],{"class":340},"unsqueeze",[234,1420,424],{"class":258},[234,1422,613],{"class":360},[234,1424,450],{"class":258},[234,1426,1427,1430,1432,1434,1436,1438,1440,1443,1445,1448,1450,1453,1455,1458,1460,1462,1464,1467,1469,1472],{"class":236,"line":1023},[234,1428,1429],{"class":244},"    log_plan ",[234,1431,414],{"class":240},[234,1433,1198],{"class":244},[234,1435,259],{"class":258},[234,1437,1203],{"class":262},[234,1439,259],{"class":258},[234,1441,1442],{"class":262},"matrix",[234,1444,259],{"class":258},[234,1446,1447],{"class":340},"solve",[234,1449,424],{"class":258},[234,1451,1452],{"class":340},"C_cpu",[234,1454,364],{"class":258},[234,1456,1457],{"class":685}," reg",[234,1459,414],{"class":240},[234,1461,1233],{"class":360},[234,1463,364],{"class":258},[234,1465,1466],{"class":685}," n_iter",[234,1468,414],{"class":240},[234,1470,1471],{"class":360},"200",[234,1473,450],{"class":258},[234,1475,1476,1479,1481,1483,1486,1488,1491,1493,1495,1498,1500,1503,1505,1507],{"class":236,"line":1047},[234,1477,1478],{"class":244},"    cost_val ",[234,1480,414],{"class":240},[234,1482,738],{"class":258},[234,1484,1485],{"class":244},"log_plan",[234,1487,259],{"class":258},[234,1489,1490],{"class":340},"exp",[234,1492,1259],{"class":258},[234,1494,621],{"class":240},[234,1496,1497],{"class":244}," C_cpu",[234,1499,1154],{"class":258},[234,1501,1502],{"class":340},"sum",[234,1504,1317],{"class":258},[234,1506,1256],{"class":340},[234,1508,405],{"class":258},[234,1510,1511,1513,1515,1517,1520,1522,1525,1527,1529,1531],{"class":236,"line":1070},[234,1512,1240],{"class":436},[234,1514,424],{"class":258},[234,1516,490],{"class":489},[234,1518,1519],{"class":351},"\"Approximate transport cost (matrix face, CPU): ",[234,1521,496],{"class":360},[234,1523,1524],{"class":340},"cost_val",[234,1526,1262],{"class":489},[234,1528,507],{"class":360},[234,1530,348],{"class":351},[234,1532,450],{"class":258},[522,1534],{"data":1535,"kind":525},"Q1VEQSBub3QgYXZhaWxhYmxlIOKAlCB1c2luZyBtYXRyaXggZmFjZSBvbiBDUFUgYXMgYW4gYXBwcm94aW1hdGlvbgpBcHByb3hpbWF0ZSB0cmFuc3BvcnQgY29zdCAobWF0cml4IGZhY2UsIENQVSk6IDAuMTkwNgo=",[530,1537,1539],{"id":1538},"_3-training-a-shape-generator","3  Training a shape generator",[185,1541,1542,1543,1546],{},"We train a tiny MLP to map a 2-D latent space to a 2-D point cloud.\nThe training loss is ",[199,1544,1545],{},"samples.loss(predicted, target)"," — the Wasserstein\ndistance between the generated cloud and a fixed target shape.",[225,1548,1550],{"className":227,"code":1549,"language":229,"meta":230,"style":230},"class PointDecoder(nn.Module):\n    \"\"\"Maps latent code z ∈ ℝ^{latent_dim} to a point cloud in ℝ^{N×2}.\"\"\"\n\n    def __init__(self, latent_dim: int = 8, n_points: int = 256):\n        super().__init__()\n        self.n_points = n_points\n        self.net = nn.Sequential(\n            nn.Linear(latent_dim, 64),\n            nn.Tanh(),\n            nn.Linear(64, 128),\n            nn.Tanh(),\n            nn.Linear(128, n_points * 2),\n        )\n\n    def forward(self, z: torch.Tensor) -> torch.Tensor:\n        return self.net(z).reshape(z.size(0), self.n_points, 2)\n",[199,1551,1552,1573,1586,1590,1637,1649,1664,1686,1709,1721,1741,1751,1776,1781,1785,1824],{"__ignoreMap":230},[234,1553,1554,1557,1561,1563,1565,1567,1570],{"class":236,"line":237},[234,1555,1556],{"class":489},"class",[234,1558,1560],{"class":1559},"sbgvK"," PointDecoder",[234,1562,424],{"class":258},[234,1564,304],{"class":1559},[234,1566,259],{"class":258},[234,1568,1569],{"class":1559},"Module",[234,1571,1572],{"class":258},"):\n",[234,1574,1575,1579,1583],{"class":236,"line":248},[234,1576,1578],{"class":1577},"s2W-s","    \"\"\"",[234,1580,1582],{"class":1581},"sithA","Maps latent code z ∈ ℝ^{latent_dim} to a point cloud in ℝ^{N×2}.",[234,1584,1585],{"class":1577},"\"\"\"\n",[234,1587,1588],{"class":236,"line":272},[234,1589,324],{"emptyLinePlaceholder":323},[234,1591,1592,1595,1598,1600,1604,1606,1610,1612,1616,1618,1621,1623,1626,1628,1630,1632,1635],{"class":236,"line":286},[234,1593,1594],{"class":489},"    def",[234,1596,1597],{"class":436}," __init__",[234,1599,424],{"class":258},[234,1601,1603],{"class":1602},"smCYv","self",[234,1605,364],{"class":258},[234,1607,1609],{"class":1608},"sFwrP"," latent_dim",[234,1611,357],{"class":258},[234,1613,1615],{"class":1614},"sZMiF"," int",[234,1617,390],{"class":240},[234,1619,1620],{"class":360}," 8",[234,1622,364],{"class":258},[234,1624,1625],{"class":1608}," n_points",[234,1627,357],{"class":258},[234,1629,1615],{"class":1614},[234,1631,390],{"class":240},[234,1633,1634],{"class":360}," 256",[234,1636,1572],{"class":258},[234,1638,1639,1642,1644,1647],{"class":236,"line":294},[234,1640,1641],{"class":1614},"        super",[234,1643,1317],{"class":258},[234,1645,1646],{"class":436},"__init__",[234,1648,405],{"class":258},[234,1650,1651,1654,1656,1659,1661],{"class":236,"line":312},[234,1652,1653],{"class":386},"        self",[234,1655,259],{"class":258},[234,1657,1658],{"class":262},"n_points",[234,1660,390],{"class":240},[234,1662,1663],{"class":244}," n_points\n",[234,1665,1666,1668,1670,1673,1675,1678,1680,1683],{"class":236,"line":320},[234,1667,1653],{"class":386},[234,1669,259],{"class":258},[234,1671,1672],{"class":262},"net",[234,1674,390],{"class":240},[234,1676,1677],{"class":244}," nn",[234,1679,259],{"class":258},[234,1681,1682],{"class":340},"Sequential",[234,1684,1685],{"class":258},"(\n",[234,1687,1688,1691,1693,1696,1698,1701,1703,1706],{"class":236,"line":327},[234,1689,1690],{"class":340},"            nn",[234,1692,259],{"class":258},[234,1694,1695],{"class":340},"Linear",[234,1697,424],{"class":258},[234,1699,1700],{"class":340},"latent_dim",[234,1702,364],{"class":258},[234,1704,1705],{"class":360}," 64",[234,1707,1708],{"class":258},"),\n",[234,1710,1711,1713,1715,1718],{"class":236,"line":383},[234,1712,1690],{"class":340},[234,1714,259],{"class":258},[234,1716,1717],{"class":340},"Tanh",[234,1719,1720],{"class":258},"(),\n",[234,1722,1723,1725,1727,1729,1731,1734,1736,1739],{"class":236,"line":408},[234,1724,1690],{"class":340},[234,1726,259],{"class":258},[234,1728,1695],{"class":340},[234,1730,424],{"class":258},[234,1732,1733],{"class":360},"64",[234,1735,364],{"class":258},[234,1737,1738],{"class":360}," 128",[234,1740,1708],{"class":258},[234,1742,1743,1745,1747,1749],{"class":236,"line":453},[234,1744,1690],{"class":340},[234,1746,259],{"class":258},[234,1748,1717],{"class":340},[234,1750,1720],{"class":258},[234,1752,1753,1755,1757,1759,1761,1764,1766,1769,1772,1774],{"class":236,"line":481},[234,1754,1690],{"class":340},[234,1756,259],{"class":258},[234,1758,1695],{"class":340},[234,1760,424],{"class":258},[234,1762,1763],{"class":360},"128",[234,1765,364],{"class":258},[234,1767,1768],{"class":340}," n_points ",[234,1770,1771],{"class":240},"*",[234,1773,618],{"class":360},[234,1775,1708],{"class":258},[234,1777,1778],{"class":236,"line":936},[234,1779,1780],{"class":258},"        )\n",[234,1782,1783],{"class":236,"line":961},[234,1784,324],{"emptyLinePlaceholder":323},[234,1786,1787,1789,1793,1795,1797,1799,1802,1804,1806,1808,1811,1813,1816,1818,1820,1822],{"class":236,"line":1023},[234,1788,1594],{"class":489},[234,1790,1792],{"class":1791},"sGLFI"," forward",[234,1794,424],{"class":258},[234,1796,1603],{"class":1602},[234,1798,364],{"class":258},[234,1800,1801],{"class":1608}," z",[234,1803,357],{"class":258},[234,1805,299],{"class":244},[234,1807,259],{"class":258},[234,1809,1810],{"class":262},"Tensor",[234,1812,694],{"class":258},[234,1814,1815],{"class":258}," ->",[234,1817,299],{"class":244},[234,1819,259],{"class":258},[234,1821,1810],{"class":262},[234,1823,1133],{"class":258},[234,1825,1826,1829,1832,1834,1836,1838,1841,1843,1846,1848,1850,1852,1855,1857,1859,1861,1863,1865,1867,1869,1871],{"class":236,"line":1047},[234,1827,1828],{"class":251},"        return",[234,1830,1831],{"class":386}," self",[234,1833,259],{"class":258},[234,1835,1672],{"class":340},[234,1837,424],{"class":258},[234,1839,1840],{"class":340},"z",[234,1842,1154],{"class":258},[234,1844,1845],{"class":340},"reshape",[234,1847,424],{"class":258},[234,1849,1840],{"class":340},[234,1851,259],{"class":258},[234,1853,1854],{"class":340},"size",[234,1856,424],{"class":258},[234,1858,613],{"class":360},[234,1860,668],{"class":258},[234,1862,1831],{"class":386},[234,1864,259],{"class":258},[234,1866,1658],{"class":262},[234,1868,364],{"class":258},[234,1870,618],{"class":360},[234,1872,450],{"class":258},[1874,1875,1877],"h3",{"id":1876},"target-the-letter-s-piecewise","Target: the letter \"S\" (piecewise)",[225,1879,1881],{"className":227,"code":1880,"language":229,"meta":230,"style":230},"def make_s_shape(n_points: int = 256) -> np.ndarray:\n    \"\"\"Sample points roughly in an 'S' shape.\"\"\"\n    t = np.linspace(0, 2 * np.pi, n_points \u002F\u002F 2)\n    top = np.stack(\n        [0.5 * np.cos(t[: n_points \u002F\u002F 2]), 0.35 + 0.35 * np.sin(t[: n_points \u002F\u002F 2])],\n        axis=1,\n    )\n    bot = np.stack(\n        [\n            0.5 * np.cos(t[: n_points \u002F\u002F 2] + np.pi),\n            -0.35 + 0.35 * np.sin(t[: n_points \u002F\u002F 2] + np.pi),\n        ],\n        axis=1,\n    )\n    pts = np.concatenate([top, bot], axis=0)\n    noise = rng.normal(0, 0.03, pts.shape)\n    return (pts + noise).astype(np.float32)\n\n\nN_TRAIN = 256\ntarget_np = make_s_shape(N_TRAIN)\ntarget = torch.from_numpy(target_np)\n\nplt.figure(figsize=(3, 4))\nplt.scatter(target_np[:, 0], target_np[:, 1], s=10, color=\"#E03520\")\nplt.title(\"Target shape (S)\")\nplt.axis(\"equal\")\nplt.tight_layout()\nplt.show()\n",[199,1882,1883,1916,1925,1965,1980,2044,2056,2061,2076,2081,2119,2163,2168,2178,2182,2217,2251,2281,2285,2289,2300,2316,2337,2342,2370,2419,2440,2460,2471],{"__ignoreMap":230},[234,1884,1885,1888,1891,1893,1895,1897,1899,1901,1903,1905,1907,1909,1911,1914],{"class":236,"line":237},[234,1886,1887],{"class":489},"def",[234,1889,1890],{"class":1791}," make_s_shape",[234,1892,424],{"class":258},[234,1894,1658],{"class":1608},[234,1896,357],{"class":258},[234,1898,1615],{"class":1614},[234,1900,390],{"class":240},[234,1902,1634],{"class":360},[234,1904,694],{"class":258},[234,1906,1815],{"class":258},[234,1908,461],{"class":244},[234,1910,259],{"class":258},[234,1912,1913],{"class":262},"ndarray",[234,1915,1133],{"class":258},[234,1917,1918,1920,1923],{"class":236,"line":248},[234,1919,1578],{"class":1577},[234,1921,1922],{"class":1581},"Sample points roughly in an 'S' shape.",[234,1924,1585],{"class":1577},[234,1926,1927,1930,1932,1934,1936,1938,1940,1942,1944,1946,1948,1950,1952,1954,1956,1958,1961,1963],{"class":236,"line":272},[234,1928,1929],{"class":244},"    t ",[234,1931,414],{"class":240},[234,1933,461],{"class":244},[234,1935,259],{"class":258},[234,1937,608],{"class":340},[234,1939,424],{"class":258},[234,1941,613],{"class":360},[234,1943,364],{"class":258},[234,1945,618],{"class":360},[234,1947,621],{"class":240},[234,1949,461],{"class":340},[234,1951,259],{"class":258},[234,1953,628],{"class":262},[234,1955,364],{"class":258},[234,1957,1768],{"class":340},[234,1959,1960],{"class":240},"\u002F\u002F",[234,1962,618],{"class":360},[234,1964,450],{"class":258},[234,1966,1967,1970,1972,1974,1976,1978],{"class":236,"line":286},[234,1968,1969],{"class":244},"    top ",[234,1971,414],{"class":240},[234,1973,461],{"class":244},[234,1975,259],{"class":258},[234,1977,649],{"class":340},[234,1979,1685],{"class":258},[234,1981,1982,1985,1988,1990,1992,1994,1996,1998,2001,2004,2006,2008,2010,2013,2016,2019,2021,2023,2025,2027,2029,2031,2033,2035,2037,2039,2041],{"class":236,"line":294},[234,1983,1984],{"class":258},"        [",[234,1986,1987],{"class":360},"0.5",[234,1989,621],{"class":240},[234,1991,461],{"class":340},[234,1993,259],{"class":258},[234,1995,660],{"class":340},[234,1997,424],{"class":258},[234,1999,2000],{"class":340},"t",[234,2002,2003],{"class":258},"[:",[234,2005,1768],{"class":340},[234,2007,1960],{"class":240},[234,2009,618],{"class":360},[234,2011,2012],{"class":258},"]),",[234,2014,2015],{"class":360}," 0.35",[234,2017,2018],{"class":240}," +",[234,2020,2015],{"class":360},[234,2022,621],{"class":240},[234,2024,461],{"class":340},[234,2026,259],{"class":258},[234,2028,675],{"class":340},[234,2030,424],{"class":258},[234,2032,2000],{"class":340},[234,2034,2003],{"class":258},[234,2036,1768],{"class":340},[234,2038,1960],{"class":240},[234,2040,618],{"class":360},[234,2042,2043],{"class":258},"])],\n",[234,2045,2046,2049,2051,2053],{"class":236,"line":312},[234,2047,2048],{"class":685},"        axis",[234,2050,414],{"class":240},[234,2052,691],{"class":360},[234,2054,2055],{"class":258},",\n",[234,2057,2058],{"class":236,"line":320},[234,2059,2060],{"class":258},"    )\n",[234,2062,2063,2066,2068,2070,2072,2074],{"class":236,"line":327},[234,2064,2065],{"class":244},"    bot ",[234,2067,414],{"class":240},[234,2069,461],{"class":244},[234,2071,259],{"class":258},[234,2073,649],{"class":340},[234,2075,1685],{"class":258},[234,2077,2078],{"class":236,"line":383},[234,2079,2080],{"class":258},"        [\n",[234,2082,2083,2086,2088,2090,2092,2094,2096,2098,2100,2102,2104,2106,2109,2111,2113,2115,2117],{"class":236,"line":408},[234,2084,2085],{"class":360},"            0.5",[234,2087,621],{"class":240},[234,2089,461],{"class":340},[234,2091,259],{"class":258},[234,2093,660],{"class":340},[234,2095,424],{"class":258},[234,2097,2000],{"class":340},[234,2099,2003],{"class":258},[234,2101,1768],{"class":340},[234,2103,1960],{"class":240},[234,2105,618],{"class":360},[234,2107,2108],{"class":258},"]",[234,2110,2018],{"class":240},[234,2112,461],{"class":340},[234,2114,259],{"class":258},[234,2116,628],{"class":262},[234,2118,1708],{"class":258},[234,2120,2121,2124,2127,2129,2131,2133,2135,2137,2139,2141,2143,2145,2147,2149,2151,2153,2155,2157,2159,2161],{"class":236,"line":453},[234,2122,2123],{"class":240},"            -",[234,2125,2126],{"class":360},"0.35",[234,2128,2018],{"class":240},[234,2130,2015],{"class":360},[234,2132,621],{"class":240},[234,2134,461],{"class":340},[234,2136,259],{"class":258},[234,2138,675],{"class":340},[234,2140,424],{"class":258},[234,2142,2000],{"class":340},[234,2144,2003],{"class":258},[234,2146,1768],{"class":340},[234,2148,1960],{"class":240},[234,2150,618],{"class":360},[234,2152,2108],{"class":258},[234,2154,2018],{"class":240},[234,2156,461],{"class":340},[234,2158,259],{"class":258},[234,2160,628],{"class":262},[234,2162,1708],{"class":258},[234,2164,2165],{"class":236,"line":481},[234,2166,2167],{"class":258},"        ],\n",[234,2169,2170,2172,2174,2176],{"class":236,"line":936},[234,2171,2048],{"class":685},[234,2173,414],{"class":240},[234,2175,691],{"class":360},[234,2177,2055],{"class":258},[234,2179,2180],{"class":236,"line":961},[234,2181,2060],{"class":258},[234,2183,2184,2187,2189,2191,2193,2196,2198,2201,2203,2206,2208,2211,2213,2215],{"class":236,"line":1023},[234,2185,2186],{"class":244},"    pts ",[234,2188,414],{"class":240},[234,2190,461],{"class":244},[234,2192,259],{"class":258},[234,2194,2195],{"class":340},"concatenate",[234,2197,652],{"class":258},[234,2199,2200],{"class":340},"top",[234,2202,364],{"class":258},[234,2204,2205],{"class":340}," bot",[234,2207,866],{"class":258},[234,2209,2210],{"class":685}," axis",[234,2212,414],{"class":240},[234,2214,613],{"class":360},[234,2216,450],{"class":258},[234,2218,2219,2222,2224,2226,2228,2231,2233,2235,2237,2240,2242,2245,2247,2249],{"class":236,"line":1047},[234,2220,2221],{"class":244},"    noise ",[234,2223,414],{"class":240},[234,2225,716],{"class":244},[234,2227,259],{"class":258},[234,2229,2230],{"class":340},"normal",[234,2232,424],{"class":258},[234,2234,613],{"class":360},[234,2236,364],{"class":258},[234,2238,2239],{"class":360}," 0.03",[234,2241,364],{"class":258},[234,2243,2244],{"class":340}," pts",[234,2246,259],{"class":258},[234,2248,1353],{"class":262},[234,2250,450],{"class":258},[234,2252,2253,2256,2258,2261,2264,2267,2269,2271,2273,2275,2277,2279],{"class":236,"line":1070},[234,2254,2255],{"class":251},"    return",[234,2257,738],{"class":258},[234,2259,2260],{"class":244},"pts ",[234,2262,2263],{"class":240},"+",[234,2265,2266],{"class":244}," noise",[234,2268,1154],{"class":258},[234,2270,751],{"class":340},[234,2272,424],{"class":258},[234,2274,756],{"class":340},[234,2276,259],{"class":258},[234,2278,761],{"class":262},[234,2280,450],{"class":258},[234,2282,2283],{"class":236,"line":1091},[234,2284,324],{"emptyLinePlaceholder":323},[234,2286,2287],{"class":236,"line":1103},[234,2288,324],{"emptyLinePlaceholder":323},[234,2290,2292,2295,2297],{"class":236,"line":2291},20,[234,2293,2294],{"class":386},"N_TRAIN",[234,2296,390],{"class":240},[234,2298,2299],{"class":360}," 256\n",[234,2301,2303,2306,2308,2310,2312,2314],{"class":236,"line":2302},21,[234,2304,2305],{"class":244},"target_np ",[234,2307,414],{"class":240},[234,2309,1890],{"class":340},[234,2311,424],{"class":258},[234,2313,2294],{"class":436},[234,2315,450],{"class":258},[234,2317,2319,2322,2324,2326,2328,2330,2332,2335],{"class":236,"line":2318},22,[234,2320,2321],{"class":244},"target ",[234,2323,414],{"class":240},[234,2325,299],{"class":244},[234,2327,259],{"class":258},[234,2329,777],{"class":340},[234,2331,424],{"class":258},[234,2333,2334],{"class":340},"target_np",[234,2336,450],{"class":258},[234,2338,2340],{"class":236,"line":2339},23,[234,2341,324],{"emptyLinePlaceholder":323},[234,2343,2345,2347,2349,2352,2354,2357,2359,2361,2364,2366,2368],{"class":236,"line":2344},24,[234,2346,330],{"class":244},[234,2348,259],{"class":258},[234,2350,2351],{"class":340},"figure",[234,2353,424],{"class":258},[234,2355,2356],{"class":685},"figsize",[234,2358,414],{"class":240},[234,2360,424],{"class":258},[234,2362,2363],{"class":360},"3",[234,2365,364],{"class":258},[234,2367,833],{"class":360},[234,2369,836],{"class":258},[234,2371,2373,2375,2377,2379,2381,2383,2385,2387,2389,2392,2394,2396,2398,2400,2402,2405,2407,2409,2411,2413,2415,2417],{"class":236,"line":2372},25,[234,2374,330],{"class":244},[234,2376,259],{"class":258},[234,2378,852],{"class":340},[234,2380,424],{"class":258},[234,2382,2334],{"class":340},[234,2384,860],{"class":258},[234,2386,863],{"class":360},[234,2388,866],{"class":258},[234,2390,2391],{"class":340}," target_np",[234,2393,860],{"class":258},[234,2395,733],{"class":360},[234,2397,866],{"class":258},[234,2399,878],{"class":685},[234,2401,414],{"class":240},[234,2403,2404],{"class":360},"10",[234,2406,364],{"class":258},[234,2408,888],{"class":685},[234,2410,414],{"class":240},[234,2412,348],{"class":347},[234,2414,1008],{"class":351},[234,2416,348],{"class":347},[234,2418,450],{"class":258},[234,2420,2422,2424,2426,2429,2431,2433,2436,2438],{"class":236,"line":2421},26,[234,2423,330],{"class":244},[234,2425,259],{"class":258},[234,2427,2428],{"class":340},"title",[234,2430,424],{"class":258},[234,2432,348],{"class":347},[234,2434,2435],{"class":351},"Target shape (S)",[234,2437,348],{"class":347},[234,2439,450],{"class":258},[234,2441,2443,2445,2447,2450,2452,2454,2456,2458],{"class":236,"line":2442},27,[234,2444,330],{"class":244},[234,2446,259],{"class":258},[234,2448,2449],{"class":340},"axis",[234,2451,424],{"class":258},[234,2453,348],{"class":347},[234,2455,954],{"class":351},[234,2457,348],{"class":347},[234,2459,450],{"class":258},[234,2461,2463,2465,2467,2469],{"class":236,"line":2462},28,[234,2464,330],{"class":244},[234,2466,259],{"class":258},[234,2468,1098],{"class":340},[234,2470,405],{"class":258},[234,2472,2474,2476,2478,2480],{"class":236,"line":2473},29,[234,2475,330],{"class":244},[234,2477,259],{"class":258},[234,2479,1110],{"class":340},[234,2481,405],{"class":258},[185,2483,2484],{},[1116,2485],{"alt":230,"src":2486},"\u002F_nb\u002F627f3604a024f596.png",[225,2488,2490],{"className":227,"code":2489,"language":229,"meta":230,"style":230},"LATENT_DIM = 8\nmodel = PointDecoder(latent_dim=LATENT_DIM, n_points=N_TRAIN).to(device)\noptimizer = torch.optim.Adam(model.parameters(), lr=3e-3)\ntarget_d = target.to(device)\n\nlosses = []\nSTEPS = 300 if CUDA else 80  # fewer steps on CPU fallback\nBLUR = 0.05 if CUDA else 0.15  # larger blur for faster CPU convergence\n\nfor step in range(STEPS):\n    z = torch.randn(1, LATENT_DIM, device=device)\n    pred = model(z).squeeze(0)  # (N_TRAIN, 2)\n\n    if CUDA:\n        loss = torchmatch.transport.samples.loss(pred, target_d, blur=BLUR)\n    else:\n        # CPU fallback via matrix face\n        C = torch.cdist(pred.unsqueeze(0), target_d.unsqueeze(0)).pow(2)\n        log_plan = torchmatch.transport.matrix.solve(C, reg=BLUR**2, n_iter=100)\n        loss = (log_plan.exp() * C).sum()\n\n    optimizer.zero_grad()\n    loss.backward()\n    optimizer.step()\n    losses.append(loss.item())\n\nprint(f\"Final loss: {losses[-1]:.4f}  (started at {losses[0]:.4f})\")\n",[199,2491,2492,2502,2537,2579,2599,2603,2613,2635,2657,2661,2681,2715,2743,2747,2756,2797,2804,2809,2856,2906,2933,2937,2949,2959,2970,2991,2995],{"__ignoreMap":230},[234,2493,2494,2497,2499],{"class":236,"line":237},[234,2495,2496],{"class":386},"LATENT_DIM",[234,2498,390],{"class":240},[234,2500,2501],{"class":360}," 8\n",[234,2503,2504,2507,2509,2511,2513,2515,2517,2519,2521,2523,2525,2527,2529,2531,2533,2535],{"class":236,"line":248},[234,2505,2506],{"class":244},"model ",[234,2508,414],{"class":240},[234,2510,1560],{"class":340},[234,2512,424],{"class":258},[234,2514,1700],{"class":685},[234,2516,414],{"class":240},[234,2518,2496],{"class":436},[234,2520,364],{"class":258},[234,2522,1625],{"class":685},[234,2524,414],{"class":240},[234,2526,2294],{"class":436},[234,2528,1154],{"class":258},[234,2530,1147],{"class":340},[234,2532,424],{"class":258},[234,2534,421],{"class":340},[234,2536,450],{"class":258},[234,2538,2539,2542,2544,2546,2548,2551,2553,2556,2558,2561,2563,2566,2569,2572,2574,2577],{"class":236,"line":272},[234,2540,2541],{"class":244},"optimizer ",[234,2543,414],{"class":240},[234,2545,299],{"class":244},[234,2547,259],{"class":258},[234,2549,2550],{"class":262},"optim",[234,2552,259],{"class":258},[234,2554,2555],{"class":340},"Adam",[234,2557,424],{"class":258},[234,2559,2560],{"class":340},"model",[234,2562,259],{"class":258},[234,2564,2565],{"class":340},"parameters",[234,2567,2568],{"class":258},"(),",[234,2570,2571],{"class":685}," lr",[234,2573,414],{"class":240},[234,2575,2576],{"class":360},"3e-3",[234,2578,450],{"class":258},[234,2580,2581,2584,2586,2589,2591,2593,2595,2597],{"class":236,"line":286},[234,2582,2583],{"class":244},"target_d ",[234,2585,414],{"class":240},[234,2587,2588],{"class":244}," target",[234,2590,259],{"class":258},[234,2592,1147],{"class":340},[234,2594,424],{"class":258},[234,2596,421],{"class":340},[234,2598,450],{"class":258},[234,2600,2601],{"class":236,"line":294},[234,2602,324],{"emptyLinePlaceholder":323},[234,2604,2605,2608,2610],{"class":236,"line":312},[234,2606,2607],{"class":244},"losses ",[234,2609,414],{"class":240},[234,2611,2612],{"class":258}," []\n",[234,2614,2615,2618,2620,2623,2625,2627,2629,2632],{"class":236,"line":320},[234,2616,2617],{"class":386},"STEPS",[234,2619,390],{"class":240},[234,2621,2622],{"class":360}," 300",[234,2624,433],{"class":251},[234,2626,437],{"class":386},[234,2628,440],{"class":251},[234,2630,2631],{"class":360}," 80",[234,2633,2634],{"class":593},"  # fewer steps on CPU fallback\n",[234,2636,2637,2640,2642,2645,2647,2649,2651,2654],{"class":236,"line":327},[234,2638,2639],{"class":386},"BLUR",[234,2641,390],{"class":240},[234,2643,2644],{"class":360}," 0.05",[234,2646,433],{"class":251},[234,2648,437],{"class":386},[234,2650,440],{"class":251},[234,2652,2653],{"class":360}," 0.15",[234,2655,2656],{"class":593},"  # larger blur for faster CPU convergence\n",[234,2658,2659],{"class":236,"line":383},[234,2660,324],{"emptyLinePlaceholder":323},[234,2662,2663,2666,2669,2672,2675,2677,2679],{"class":236,"line":408},[234,2664,2665],{"class":251},"for",[234,2667,2668],{"class":244}," step ",[234,2670,2671],{"class":251},"in",[234,2673,2674],{"class":436}," range",[234,2676,424],{"class":258},[234,2678,2617],{"class":436},[234,2680,1572],{"class":258},[234,2682,2683,2686,2688,2690,2692,2695,2697,2699,2701,2704,2706,2709,2711,2713],{"class":236,"line":453},[234,2684,2685],{"class":244},"    z ",[234,2687,414],{"class":240},[234,2689,299],{"class":244},[234,2691,259],{"class":258},[234,2693,2694],{"class":340},"randn",[234,2696,424],{"class":258},[234,2698,691],{"class":360},[234,2700,364],{"class":258},[234,2702,2703],{"class":436}," LATENT_DIM",[234,2705,364],{"class":258},[234,2707,2708],{"class":685}," device",[234,2710,414],{"class":240},[234,2712,421],{"class":340},[234,2714,450],{"class":258},[234,2716,2717,2720,2722,2725,2727,2729,2731,2734,2736,2738,2740],{"class":236,"line":481},[234,2718,2719],{"class":244},"    pred ",[234,2721,414],{"class":240},[234,2723,2724],{"class":340}," model",[234,2726,424],{"class":258},[234,2728,1840],{"class":340},[234,2730,1154],{"class":258},[234,2732,2733],{"class":340},"squeeze",[234,2735,424],{"class":258},[234,2737,613],{"class":360},[234,2739,694],{"class":258},[234,2741,2742],{"class":593},"  # (N_TRAIN, 2)\n",[234,2744,2745],{"class":236,"line":936},[234,2746,324],{"emptyLinePlaceholder":323},[234,2748,2749,2752,2754],{"class":236,"line":961},[234,2750,2751],{"class":251},"    if",[234,2753,437],{"class":386},[234,2755,1133],{"class":258},[234,2757,2758,2761,2763,2765,2767,2769,2771,2773,2775,2777,2779,2782,2784,2787,2789,2791,2793,2795],{"class":236,"line":1023},[234,2759,2760],{"class":244},"        loss ",[234,2762,414],{"class":240},[234,2764,1198],{"class":244},[234,2766,259],{"class":258},[234,2768,1203],{"class":262},[234,2770,259],{"class":258},[234,2772,1208],{"class":262},[234,2774,259],{"class":258},[234,2776,1213],{"class":340},[234,2778,424],{"class":258},[234,2780,2781],{"class":340},"pred",[234,2783,364],{"class":258},[234,2785,2786],{"class":340}," target_d",[234,2788,364],{"class":258},[234,2790,1228],{"class":685},[234,2792,414],{"class":240},[234,2794,2639],{"class":436},[234,2796,450],{"class":258},[234,2798,2799,2802],{"class":236,"line":1047},[234,2800,2801],{"class":251},"    else",[234,2803,1133],{"class":258},[234,2805,2806],{"class":236,"line":1070},[234,2807,2808],{"class":593},"        # CPU fallback via matrix face\n",[234,2810,2811,2814,2816,2818,2820,2822,2824,2826,2828,2830,2832,2834,2836,2838,2840,2842,2844,2846,2848,2850,2852,2854],{"class":236,"line":1091},[234,2812,2813],{"class":244},"        C ",[234,2815,414],{"class":240},[234,2817,299],{"class":244},[234,2819,259],{"class":258},[234,2821,1395],{"class":340},[234,2823,424],{"class":258},[234,2825,2781],{"class":340},[234,2827,259],{"class":258},[234,2829,1418],{"class":340},[234,2831,424],{"class":258},[234,2833,613],{"class":360},[234,2835,668],{"class":258},[234,2837,2786],{"class":340},[234,2839,259],{"class":258},[234,2841,1418],{"class":340},[234,2843,424],{"class":258},[234,2845,613],{"class":360},[234,2847,748],{"class":258},[234,2849,1408],{"class":340},[234,2851,424],{"class":258},[234,2853,1413],{"class":360},[234,2855,450],{"class":258},[234,2857,2858,2861,2863,2865,2867,2869,2871,2873,2875,2877,2879,2882,2884,2886,2888,2890,2893,2895,2897,2899,2901,2904],{"class":236,"line":1103},[234,2859,2860],{"class":244},"        log_plan ",[234,2862,414],{"class":240},[234,2864,1198],{"class":244},[234,2866,259],{"class":258},[234,2868,1203],{"class":262},[234,2870,259],{"class":258},[234,2872,1442],{"class":262},[234,2874,259],{"class":258},[234,2876,1447],{"class":340},[234,2878,424],{"class":258},[234,2880,2881],{"class":340},"C",[234,2883,364],{"class":258},[234,2885,1457],{"class":685},[234,2887,414],{"class":240},[234,2889,2639],{"class":436},[234,2891,2892],{"class":240},"**",[234,2894,1413],{"class":360},[234,2896,364],{"class":258},[234,2898,1466],{"class":685},[234,2900,414],{"class":240},[234,2902,2903],{"class":360},"100",[234,2905,450],{"class":258},[234,2907,2908,2910,2912,2914,2916,2918,2920,2922,2924,2927,2929,2931],{"class":236,"line":2291},[234,2909,2760],{"class":244},[234,2911,414],{"class":240},[234,2913,738],{"class":258},[234,2915,1485],{"class":244},[234,2917,259],{"class":258},[234,2919,1490],{"class":340},[234,2921,1259],{"class":258},[234,2923,621],{"class":240},[234,2925,2926],{"class":244}," C",[234,2928,1154],{"class":258},[234,2930,1502],{"class":340},[234,2932,405],{"class":258},[234,2934,2935],{"class":236,"line":2302},[234,2936,324],{"emptyLinePlaceholder":323},[234,2938,2939,2942,2944,2947],{"class":236,"line":2318},[234,2940,2941],{"class":244},"    optimizer",[234,2943,259],{"class":258},[234,2945,2946],{"class":340},"zero_grad",[234,2948,405],{"class":258},[234,2950,2951,2953,2955,2957],{"class":236,"line":2339},[234,2952,1282],{"class":244},[234,2954,259],{"class":258},[234,2956,1287],{"class":340},[234,2958,405],{"class":258},[234,2960,2961,2963,2965,2968],{"class":236,"line":2344},[234,2962,2941],{"class":244},[234,2964,259],{"class":258},[234,2966,2967],{"class":340},"step",[234,2969,405],{"class":258},[234,2971,2972,2975,2977,2980,2982,2984,2986,2988],{"class":236,"line":2372},[234,2973,2974],{"class":244},"    losses",[234,2976,259],{"class":258},[234,2978,2979],{"class":340},"append",[234,2981,424],{"class":258},[234,2983,1213],{"class":340},[234,2985,259],{"class":258},[234,2987,1256],{"class":340},[234,2989,2990],{"class":258},"())\n",[234,2992,2993],{"class":236,"line":2421},[234,2994,324],{"emptyLinePlaceholder":323},[234,2996,2997,2999,3001,3003,3006,3008,3011,3013,3015,3017,3019,3021,3023,3026,3028,3030,3032,3034,3036,3038,3040,3043],{"class":236,"line":2442},[234,2998,484],{"class":436},[234,3000,424],{"class":258},[234,3002,490],{"class":489},[234,3004,3005],{"class":351},"\"Final loss: ",[234,3007,496],{"class":360},[234,3009,3010],{"class":340},"losses",[234,3012,844],{"class":258},[234,3014,726],{"class":240},[234,3016,691],{"class":360},[234,3018,2108],{"class":258},[234,3020,1262],{"class":489},[234,3022,507],{"class":360},[234,3024,3025],{"class":351},"  (started at ",[234,3027,496],{"class":360},[234,3029,3010],{"class":340},[234,3031,844],{"class":258},[234,3033,613],{"class":360},[234,3035,2108],{"class":258},[234,3037,1262],{"class":489},[234,3039,507],{"class":360},[234,3041,3042],{"class":351},")\"",[234,3044,450],{"class":258},[522,3046],{"data":3047,"kind":525},"RmluYWwgbG9zczogMC4wMzE3ICAoc3RhcnRlZCBhdCAwLjE2OTcpCg==",[225,3049,3051],{"className":227,"code":3050,"language":229,"meta":230,"style":230},"# Visualise training progress\nfig, axes = plt.subplots(1, 3, figsize=(13, 4))\n\naxes[0].semilogy(losses)\naxes[0].set_xlabel(\"Training step\")\naxes[0].set_ylabel(\"Wasserstein loss (log scale)\")\naxes[0].set_title(\"Training curve\")\naxes[0].grid(True, alpha=0.3)\n\nmodel.eval()\nwith torch.no_grad():\n    z_eval = torch.randn(1, LATENT_DIM, device=device)\n    pred_eval = model(z_eval).squeeze(0).cpu().numpy()\n\naxes[1].scatter(\n    target_np[:, 0], target_np[:, 1], s=15, color=\"#E03520\", alpha=0.7, label=\"Target\"\n)\naxes[1].scatter(\n    pred_eval[:, 0],\n    pred_eval[:, 1],\n    s=15,\n    color=\"#1a6daf\",\n    alpha=0.7,\n    label=\"Generated\",\n)\naxes[1].set_title(f\"Generated vs target  (step {STEPS})\")\naxes[1].set_aspect(\"equal\")\naxes[1].legend()\n\naxes[2].scatter(target_np[:, 0], target_np[:, 1], s=15, color=\"#E03520\", alpha=0.5)\naxes[2].set_title(\"Target\")\naxes[2].set_aspect(\"equal\")\n\nplt.tight_layout()\nplt.show()\n",[199,3052,3053,3058,3100,3104,3123,3147,3171,3194,3222,3226,3237,3252,3283,3316,3320,3334,3395,3399,3413,3425,3435,3446,3461,3472,3488,3492,3521,3543,3558,3562,3621,3644,3667,3672,3683],{"__ignoreMap":230},[234,3054,3055],{"class":236,"line":237},[234,3056,3057],{"class":593},"# Visualise training progress\n",[234,3059,3060,3062,3064,3066,3068,3070,3072,3074,3076,3078,3080,3083,3085,3087,3089,3091,3094,3096,3098],{"class":236,"line":248},[234,3061,793],{"class":244},[234,3063,364],{"class":258},[234,3065,798],{"class":244},[234,3067,414],{"class":240},[234,3069,803],{"class":244},[234,3071,259],{"class":258},[234,3073,808],{"class":340},[234,3075,424],{"class":258},[234,3077,691],{"class":360},[234,3079,364],{"class":258},[234,3081,3082],{"class":360}," 3",[234,3084,364],{"class":258},[234,3086,821],{"class":685},[234,3088,414],{"class":240},[234,3090,424],{"class":258},[234,3092,3093],{"class":360},"13",[234,3095,364],{"class":258},[234,3097,833],{"class":360},[234,3099,836],{"class":258},[234,3101,3102],{"class":236,"line":272},[234,3103,324],{"emptyLinePlaceholder":323},[234,3105,3106,3108,3110,3112,3114,3117,3119,3121],{"class":236,"line":286},[234,3107,841],{"class":244},[234,3109,844],{"class":258},[234,3111,613],{"class":360},[234,3113,849],{"class":258},[234,3115,3116],{"class":340},"semilogy",[234,3118,424],{"class":258},[234,3120,3010],{"class":340},[234,3122,450],{"class":258},[234,3124,3125,3127,3129,3131,3133,3136,3138,3140,3143,3145],{"class":236,"line":294},[234,3126,841],{"class":244},[234,3128,844],{"class":258},[234,3130,613],{"class":360},[234,3132,849],{"class":258},[234,3134,3135],{"class":340},"set_xlabel",[234,3137,424],{"class":258},[234,3139,348],{"class":347},[234,3141,3142],{"class":351},"Training step",[234,3144,348],{"class":347},[234,3146,450],{"class":258},[234,3148,3149,3151,3153,3155,3157,3160,3162,3164,3167,3169],{"class":236,"line":312},[234,3150,841],{"class":244},[234,3152,844],{"class":258},[234,3154,613],{"class":360},[234,3156,849],{"class":258},[234,3158,3159],{"class":340},"set_ylabel",[234,3161,424],{"class":258},[234,3163,348],{"class":347},[234,3165,3166],{"class":351},"Wasserstein loss (log scale)",[234,3168,348],{"class":347},[234,3170,450],{"class":258},[234,3172,3173,3175,3177,3179,3181,3183,3185,3187,3190,3192],{"class":236,"line":320},[234,3174,841],{"class":244},[234,3176,844],{"class":258},[234,3178,613],{"class":360},[234,3180,849],{"class":258},[234,3182,922],{"class":340},[234,3184,424],{"class":258},[234,3186,348],{"class":347},[234,3188,3189],{"class":351},"Training curve",[234,3191,348],{"class":347},[234,3193,450],{"class":258},[234,3195,3196,3198,3200,3202,3204,3207,3209,3211,3213,3215,3217,3220],{"class":236,"line":327},[234,3197,841],{"class":244},[234,3199,844],{"class":258},[234,3201,613],{"class":360},[234,3203,849],{"class":258},[234,3205,3206],{"class":340},"grid",[234,3208,424],{"class":258},[234,3210,1163],{"class":1162},[234,3212,364],{"class":258},[234,3214,902],{"class":685},[234,3216,414],{"class":240},[234,3218,3219],{"class":360},"0.3",[234,3221,450],{"class":258},[234,3223,3224],{"class":236,"line":383},[234,3225,324],{"emptyLinePlaceholder":323},[234,3227,3228,3230,3232,3235],{"class":236,"line":408},[234,3229,2560],{"class":244},[234,3231,259],{"class":258},[234,3233,3234],{"class":340},"eval",[234,3236,405],{"class":258},[234,3238,3239,3242,3244,3246,3249],{"class":236,"line":453},[234,3240,3241],{"class":251},"with",[234,3243,299],{"class":244},[234,3245,259],{"class":258},[234,3247,3248],{"class":340},"no_grad",[234,3250,3251],{"class":258},"():\n",[234,3253,3254,3257,3259,3261,3263,3265,3267,3269,3271,3273,3275,3277,3279,3281],{"class":236,"line":481},[234,3255,3256],{"class":244},"    z_eval ",[234,3258,414],{"class":240},[234,3260,299],{"class":244},[234,3262,259],{"class":258},[234,3264,2694],{"class":340},[234,3266,424],{"class":258},[234,3268,691],{"class":360},[234,3270,364],{"class":258},[234,3272,2703],{"class":436},[234,3274,364],{"class":258},[234,3276,2708],{"class":685},[234,3278,414],{"class":240},[234,3280,421],{"class":340},[234,3282,450],{"class":258},[234,3284,3285,3288,3290,3292,3294,3297,3299,3301,3303,3305,3307,3309,3311,3314],{"class":236,"line":936},[234,3286,3287],{"class":244},"    pred_eval ",[234,3289,414],{"class":240},[234,3291,2724],{"class":340},[234,3293,424],{"class":258},[234,3295,3296],{"class":340},"z_eval",[234,3298,1154],{"class":258},[234,3300,2733],{"class":340},[234,3302,424],{"class":258},[234,3304,613],{"class":360},[234,3306,1154],{"class":258},[234,3308,445],{"class":340},[234,3310,1317],{"class":258},[234,3312,3313],{"class":340},"numpy",[234,3315,405],{"class":258},[234,3317,3318],{"class":236,"line":961},[234,3319,324],{"emptyLinePlaceholder":323},[234,3321,3322,3324,3326,3328,3330,3332],{"class":236,"line":1023},[234,3323,841],{"class":244},[234,3325,844],{"class":258},[234,3327,691],{"class":360},[234,3329,849],{"class":258},[234,3331,852],{"class":340},[234,3333,1685],{"class":258},[234,3335,3336,3339,3341,3343,3345,3347,3349,3351,3353,3355,3357,3360,3362,3364,3366,3368,3370,3372,3374,3376,3378,3380,3382,3385,3387,3389,3392],{"class":236,"line":1047},[234,3337,3338],{"class":340},"    target_np",[234,3340,860],{"class":258},[234,3342,863],{"class":360},[234,3344,866],{"class":258},[234,3346,2391],{"class":340},[234,3348,860],{"class":258},[234,3350,733],{"class":360},[234,3352,866],{"class":258},[234,3354,878],{"class":685},[234,3356,414],{"class":240},[234,3358,3359],{"class":360},"15",[234,3361,364],{"class":258},[234,3363,888],{"class":685},[234,3365,414],{"class":240},[234,3367,348],{"class":347},[234,3369,1008],{"class":351},[234,3371,348],{"class":347},[234,3373,364],{"class":258},[234,3375,902],{"class":685},[234,3377,414],{"class":240},[234,3379,907],{"class":360},[234,3381,364],{"class":258},[234,3383,3384],{"class":685}," label",[234,3386,414],{"class":240},[234,3388,348],{"class":347},[234,3390,3391],{"class":351},"Target",[234,3393,3394],{"class":347},"\"\n",[234,3396,3397],{"class":236,"line":1070},[234,3398,450],{"class":258},[234,3400,3401,3403,3405,3407,3409,3411],{"class":236,"line":1091},[234,3402,841],{"class":244},[234,3404,844],{"class":258},[234,3406,691],{"class":360},[234,3408,849],{"class":258},[234,3410,852],{"class":340},[234,3412,1685],{"class":258},[234,3414,3415,3418,3420,3422],{"class":236,"line":1103},[234,3416,3417],{"class":340},"    pred_eval",[234,3419,860],{"class":258},[234,3421,863],{"class":360},[234,3423,3424],{"class":258},"],\n",[234,3426,3427,3429,3431,3433],{"class":236,"line":2291},[234,3428,3417],{"class":340},[234,3430,860],{"class":258},[234,3432,733],{"class":360},[234,3434,3424],{"class":258},[234,3436,3437,3440,3442,3444],{"class":236,"line":2302},[234,3438,3439],{"class":685},"    s",[234,3441,414],{"class":240},[234,3443,3359],{"class":360},[234,3445,2055],{"class":258},[234,3447,3448,3451,3453,3455,3457,3459],{"class":236,"line":2318},[234,3449,3450],{"class":685},"    color",[234,3452,414],{"class":240},[234,3454,348],{"class":347},[234,3456,895],{"class":351},[234,3458,348],{"class":347},[234,3460,2055],{"class":258},[234,3462,3463,3466,3468,3470],{"class":236,"line":2339},[234,3464,3465],{"class":685},"    alpha",[234,3467,414],{"class":240},[234,3469,907],{"class":360},[234,3471,2055],{"class":258},[234,3473,3474,3477,3479,3481,3484,3486],{"class":236,"line":2344},[234,3475,3476],{"class":685},"    label",[234,3478,414],{"class":240},[234,3480,348],{"class":347},[234,3482,3483],{"class":351},"Generated",[234,3485,348],{"class":347},[234,3487,2055],{"class":258},[234,3489,3490],{"class":236,"line":2372},[234,3491,450],{"class":258},[234,3493,3494,3496,3498,3500,3502,3504,3506,3508,3511,3513,3515,3517,3519],{"class":236,"line":2421},[234,3495,841],{"class":244},[234,3497,844],{"class":258},[234,3499,691],{"class":360},[234,3501,849],{"class":258},[234,3503,922],{"class":340},[234,3505,424],{"class":258},[234,3507,490],{"class":489},[234,3509,3510],{"class":351},"\"Generated vs target  (step ",[234,3512,496],{"class":360},[234,3514,2617],{"class":436},[234,3516,507],{"class":360},[234,3518,3042],{"class":351},[234,3520,450],{"class":258},[234,3522,3523,3525,3527,3529,3531,3533,3535,3537,3539,3541],{"class":236,"line":2442},[234,3524,841],{"class":244},[234,3526,844],{"class":258},[234,3528,691],{"class":360},[234,3530,849],{"class":258},[234,3532,947],{"class":340},[234,3534,424],{"class":258},[234,3536,348],{"class":347},[234,3538,954],{"class":351},[234,3540,348],{"class":347},[234,3542,450],{"class":258},[234,3544,3545,3547,3549,3551,3553,3556],{"class":236,"line":2462},[234,3546,841],{"class":244},[234,3548,844],{"class":258},[234,3550,691],{"class":360},[234,3552,849],{"class":258},[234,3554,3555],{"class":340},"legend",[234,3557,405],{"class":258},[234,3559,3560],{"class":236,"line":2473},[234,3561,324],{"emptyLinePlaceholder":323},[234,3563,3565,3567,3569,3571,3573,3575,3577,3579,3581,3583,3585,3587,3589,3591,3593,3595,3597,3599,3601,3603,3605,3607,3609,3611,3613,3615,3617,3619],{"class":236,"line":3564},30,[234,3566,841],{"class":244},[234,3568,844],{"class":258},[234,3570,1413],{"class":360},[234,3572,849],{"class":258},[234,3574,852],{"class":340},[234,3576,424],{"class":258},[234,3578,2334],{"class":340},[234,3580,860],{"class":258},[234,3582,863],{"class":360},[234,3584,866],{"class":258},[234,3586,2391],{"class":340},[234,3588,860],{"class":258},[234,3590,733],{"class":360},[234,3592,866],{"class":258},[234,3594,878],{"class":685},[234,3596,414],{"class":240},[234,3598,3359],{"class":360},[234,3600,364],{"class":258},[234,3602,888],{"class":685},[234,3604,414],{"class":240},[234,3606,348],{"class":347},[234,3608,1008],{"class":351},[234,3610,348],{"class":347},[234,3612,364],{"class":258},[234,3614,902],{"class":685},[234,3616,414],{"class":240},[234,3618,1987],{"class":360},[234,3620,450],{"class":258},[234,3622,3624,3626,3628,3630,3632,3634,3636,3638,3640,3642],{"class":236,"line":3623},31,[234,3625,841],{"class":244},[234,3627,844],{"class":258},[234,3629,1413],{"class":360},[234,3631,849],{"class":258},[234,3633,922],{"class":340},[234,3635,424],{"class":258},[234,3637,348],{"class":347},[234,3639,3391],{"class":351},[234,3641,348],{"class":347},[234,3643,450],{"class":258},[234,3645,3647,3649,3651,3653,3655,3657,3659,3661,3663,3665],{"class":236,"line":3646},32,[234,3648,841],{"class":244},[234,3650,844],{"class":258},[234,3652,1413],{"class":360},[234,3654,849],{"class":258},[234,3656,947],{"class":340},[234,3658,424],{"class":258},[234,3660,348],{"class":347},[234,3662,954],{"class":351},[234,3664,348],{"class":347},[234,3666,450],{"class":258},[234,3668,3670],{"class":236,"line":3669},33,[234,3671,324],{"emptyLinePlaceholder":323},[234,3673,3675,3677,3679,3681],{"class":236,"line":3674},34,[234,3676,330],{"class":244},[234,3678,259],{"class":258},[234,3680,1098],{"class":340},[234,3682,405],{"class":258},[234,3684,3686,3688,3690,3692],{"class":236,"line":3685},35,[234,3687,330],{"class":244},[234,3689,259],{"class":258},[234,3691,1110],{"class":340},[234,3693,405],{"class":258},[185,3695,3696],{},[1116,3697],{"alt":230,"src":3698},"\u002F_nb\u002Fcfde5ed683cc73b5.png",[530,3700,3702],{"id":3701},"_4-unbalanced-ot-for-outlier-robust-matching","4  Unbalanced OT for outlier-robust matching",[185,3704,3705],{},"Standard OT forces every source point to send all its mass into the target.  Outlier source points with no target counterpart distort the plan by pulling other matches toward them.",[185,3707,3708,3711,3712,3715],{},[188,3709,3710],{},"Unbalanced OT"," (via the ",[199,3713,3714],{},"reach"," parameter) relaxes the marginal\nconstraints using a KL penalty.  Points that cannot be cheaply matched\nsimply contribute less mass to the coupling.",[225,3717,3719],{"className":227,"code":3718,"language":229,"meta":230,"style":230},"N_clean = 200\nN_outliers = 30\n\n# Clean source: ring\nangles_c = torch.linspace(0, 2 * torch.pi, N_clean)\nx_clean = torch.stack([torch.cos(angles_c), torch.sin(angles_c)], dim=1)\n\n# Add outliers far from the ring\noutlier_xy = torch.tensor(rng.uniform(2.5, 4.0, (N_outliers, 2)), dtype=torch.float32)\nx_with_outliers = torch.cat([x_clean, outlier_xy], dim=0)\n\n# Target: same ring, no outliers\ny_clean = torch.stack([torch.cos(angles_c), torch.sin(angles_c)], dim=1)\n\nfig, axes = plt.subplots(1, 2, figsize=(10, 4))\nfor ax, x_src, title in zip(\n    axes,\n    [x_clean, x_with_outliers],\n    [\"Clean source → ring target\", \"Source with outliers → ring target\"],\n):\n    ax.scatter(\n        y_clean[:, 0], y_clean[:, 1], s=10, color=\"#E03520\", alpha=0.5, label=\"Target\"\n    )\n    ax.scatter(\n        x_src[:N_clean, 0],\n        x_src[:N_clean, 1],\n        s=10,\n        color=\"#1a6daf\",\n        alpha=0.7,\n        label=\"Source\",\n    )\n    if x_src.shape[0] > N_clean:\n        ax.scatter(\n            x_src[N_clean:, 0],\n            x_src[N_clean:, 1],\n            s=25,\n            color=\"#ffd700\",\n            marker=\"*\",\n            label=\"Outliers\",\n            zorder=5,\n        )\n    ax.set_title(title)\n    ax.set_aspect(\"equal\")\n    ax.legend(fontsize=8)\nplt.tight_layout()\nplt.show()\n\nif CUDA:\n    # Balanced OT (outliers distort the plan)\n    loss_balanced = torchmatch.transport.samples.loss(\n        x_with_outliers.to(device), y_clean.to(device), blur=0.1\n    )\n    # Unbalanced OT (outliers are soft-dropped)\n    loss_unbalanced = torchmatch.transport.samples.loss(\n        x_with_outliers.to(device), y_clean.to(device), blur=0.1, reach=0.3\n    )\n    print(f\"Balanced OT loss  (outliers distort): {loss_balanced.item():.4f}\")\n    print(f\"Unbalanced OT loss (reach=0.3):        {loss_unbalanced.item():.4f}\")\n    print(\n        \"Unbalanced OT is more robust: it concentrates mass on the in-distribution points.\"\n    )\nelse:\n    print(\"CUDA not available — unbalanced samples.loss requires CUDA.\")\n    print(\n        \"On a GPU, unbalanced OT (reach=0.3) gives a smaller, more robust loss value.\"\n    )\n",[199,3720,3721,3731,3741,3745,3750,3786,3834,3838,3843,3903,3937,3941,3946,3993,3997,4037,4061,4068,4082,4104,4108,4119,4177,4181,4191,4207,4221,4232,4247,4258,4274,4278,4301,4312,4328,4342,4355,4372,4388,4405,4418,4423,4438,4457,4477,4488,4499,4504,4513,4519,4543,4578,4583,4589,4613,4656,4661,4692,4723,4730,4741,4746,4753,4769,4776,4786],{"__ignoreMap":230},[234,3722,3723,3726,3728],{"class":236,"line":237},[234,3724,3725],{"class":244},"N_clean ",[234,3727,414],{"class":240},[234,3729,3730],{"class":360}," 200\n",[234,3732,3733,3736,3738],{"class":236,"line":248},[234,3734,3735],{"class":244},"N_outliers ",[234,3737,414],{"class":240},[234,3739,3740],{"class":360}," 30\n",[234,3742,3743],{"class":236,"line":272},[234,3744,324],{"emptyLinePlaceholder":323},[234,3746,3747],{"class":236,"line":286},[234,3748,3749],{"class":593},"# Clean source: ring\n",[234,3751,3752,3755,3757,3759,3761,3763,3765,3767,3769,3771,3773,3775,3777,3779,3781,3784],{"class":236,"line":294},[234,3753,3754],{"class":244},"angles_c ",[234,3756,414],{"class":240},[234,3758,299],{"class":244},[234,3760,259],{"class":258},[234,3762,608],{"class":340},[234,3764,424],{"class":258},[234,3766,613],{"class":360},[234,3768,364],{"class":258},[234,3770,618],{"class":360},[234,3772,621],{"class":240},[234,3774,299],{"class":340},[234,3776,259],{"class":258},[234,3778,628],{"class":262},[234,3780,364],{"class":258},[234,3782,3783],{"class":340}," N_clean",[234,3785,450],{"class":258},[234,3787,3788,3791,3793,3795,3797,3799,3801,3803,3805,3807,3809,3812,3814,3816,3818,3820,3822,3824,3826,3828,3830,3832],{"class":236,"line":312},[234,3789,3790],{"class":244},"x_clean ",[234,3792,414],{"class":240},[234,3794,299],{"class":244},[234,3796,259],{"class":258},[234,3798,649],{"class":340},[234,3800,652],{"class":258},[234,3802,655],{"class":340},[234,3804,259],{"class":258},[234,3806,660],{"class":340},[234,3808,424],{"class":258},[234,3810,3811],{"class":340},"angles_c",[234,3813,668],{"class":258},[234,3815,299],{"class":340},[234,3817,259],{"class":258},[234,3819,675],{"class":340},[234,3821,424],{"class":258},[234,3823,3811],{"class":340},[234,3825,682],{"class":258},[234,3827,686],{"class":685},[234,3829,414],{"class":240},[234,3831,691],{"class":360},[234,3833,450],{"class":258},[234,3835,3836],{"class":236,"line":320},[234,3837,324],{"emptyLinePlaceholder":323},[234,3839,3840],{"class":236,"line":327},[234,3841,3842],{"class":593},"# Add outliers far from the ring\n",[234,3844,3845,3848,3850,3852,3854,3857,3859,3862,3864,3866,3868,3871,3873,3876,3878,3880,3883,3885,3887,3890,3893,3895,3897,3899,3901],{"class":236,"line":383},[234,3846,3847],{"class":244},"outlier_xy ",[234,3849,414],{"class":240},[234,3851,299],{"class":244},[234,3853,259],{"class":258},[234,3855,3856],{"class":340},"tensor",[234,3858,424],{"class":258},[234,3860,3861],{"class":340},"rng",[234,3863,259],{"class":258},[234,3865,721],{"class":340},[234,3867,424],{"class":258},[234,3869,3870],{"class":360},"2.5",[234,3872,364],{"class":258},[234,3874,3875],{"class":360}," 4.0",[234,3877,364],{"class":258},[234,3879,738],{"class":258},[234,3881,3882],{"class":340},"N_outliers",[234,3884,364],{"class":258},[234,3886,618],{"class":360},[234,3888,3889],{"class":258},")),",[234,3891,3892],{"class":685}," dtype",[234,3894,414],{"class":240},[234,3896,655],{"class":340},[234,3898,259],{"class":258},[234,3900,761],{"class":262},[234,3902,450],{"class":258},[234,3904,3905,3908,3910,3912,3914,3917,3919,3922,3924,3927,3929,3931,3933,3935],{"class":236,"line":408},[234,3906,3907],{"class":244},"x_with_outliers ",[234,3909,414],{"class":240},[234,3911,299],{"class":244},[234,3913,259],{"class":258},[234,3915,3916],{"class":340},"cat",[234,3918,652],{"class":258},[234,3920,3921],{"class":340},"x_clean",[234,3923,364],{"class":258},[234,3925,3926],{"class":340}," outlier_xy",[234,3928,866],{"class":258},[234,3930,686],{"class":685},[234,3932,414],{"class":240},[234,3934,613],{"class":360},[234,3936,450],{"class":258},[234,3938,3939],{"class":236,"line":453},[234,3940,324],{"emptyLinePlaceholder":323},[234,3942,3943],{"class":236,"line":481},[234,3944,3945],{"class":593},"# Target: same ring, no outliers\n",[234,3947,3948,3951,3953,3955,3957,3959,3961,3963,3965,3967,3969,3971,3973,3975,3977,3979,3981,3983,3985,3987,3989,3991],{"class":236,"line":936},[234,3949,3950],{"class":244},"y_clean ",[234,3952,414],{"class":240},[234,3954,299],{"class":244},[234,3956,259],{"class":258},[234,3958,649],{"class":340},[234,3960,652],{"class":258},[234,3962,655],{"class":340},[234,3964,259],{"class":258},[234,3966,660],{"class":340},[234,3968,424],{"class":258},[234,3970,3811],{"class":340},[234,3972,668],{"class":258},[234,3974,299],{"class":340},[234,3976,259],{"class":258},[234,3978,675],{"class":340},[234,3980,424],{"class":258},[234,3982,3811],{"class":340},[234,3984,682],{"class":258},[234,3986,686],{"class":685},[234,3988,414],{"class":240},[234,3990,691],{"class":360},[234,3992,450],{"class":258},[234,3994,3995],{"class":236,"line":961},[234,3996,324],{"emptyLinePlaceholder":323},[234,3998,3999,4001,4003,4005,4007,4009,4011,4013,4015,4017,4019,4021,4023,4025,4027,4029,4031,4033,4035],{"class":236,"line":1023},[234,4000,793],{"class":244},[234,4002,364],{"class":258},[234,4004,798],{"class":244},[234,4006,414],{"class":240},[234,4008,803],{"class":244},[234,4010,259],{"class":258},[234,4012,808],{"class":340},[234,4014,424],{"class":258},[234,4016,691],{"class":360},[234,4018,364],{"class":258},[234,4020,618],{"class":360},[234,4022,364],{"class":258},[234,4024,821],{"class":685},[234,4026,414],{"class":240},[234,4028,424],{"class":258},[234,4030,2404],{"class":360},[234,4032,364],{"class":258},[234,4034,833],{"class":360},[234,4036,836],{"class":258},[234,4038,4039,4041,4044,4046,4049,4051,4054,4056,4059],{"class":236,"line":1047},[234,4040,2665],{"class":251},[234,4042,4043],{"class":244}," ax",[234,4045,364],{"class":258},[234,4047,4048],{"class":244}," x_src",[234,4050,364],{"class":258},[234,4052,4053],{"class":244}," title ",[234,4055,2671],{"class":251},[234,4057,4058],{"class":436}," zip",[234,4060,1685],{"class":258},[234,4062,4063,4066],{"class":236,"line":1070},[234,4064,4065],{"class":340},"    axes",[234,4067,2055],{"class":258},[234,4069,4070,4073,4075,4077,4080],{"class":236,"line":1091},[234,4071,4072],{"class":258},"    [",[234,4074,3921],{"class":340},[234,4076,364],{"class":258},[234,4078,4079],{"class":340}," x_with_outliers",[234,4081,3424],{"class":258},[234,4083,4084,4086,4088,4091,4093,4095,4097,4100,4102],{"class":236,"line":1103},[234,4085,4072],{"class":258},[234,4087,348],{"class":347},[234,4089,4090],{"class":351},"Clean source → ring target",[234,4092,348],{"class":347},[234,4094,364],{"class":258},[234,4096,367],{"class":347},[234,4098,4099],{"class":351},"Source with outliers → ring target",[234,4101,348],{"class":347},[234,4103,3424],{"class":258},[234,4105,4106],{"class":236,"line":2291},[234,4107,1572],{"class":258},[234,4109,4110,4113,4115,4117],{"class":236,"line":2302},[234,4111,4112],{"class":244},"    ax",[234,4114,259],{"class":258},[234,4116,852],{"class":340},[234,4118,1685],{"class":258},[234,4120,4121,4124,4126,4128,4130,4133,4135,4137,4139,4141,4143,4145,4147,4149,4151,4153,4155,4157,4159,4161,4163,4165,4167,4169,4171,4173,4175],{"class":236,"line":2318},[234,4122,4123],{"class":340},"        y_clean",[234,4125,860],{"class":258},[234,4127,863],{"class":360},[234,4129,866],{"class":258},[234,4131,4132],{"class":340}," y_clean",[234,4134,860],{"class":258},[234,4136,733],{"class":360},[234,4138,866],{"class":258},[234,4140,878],{"class":685},[234,4142,414],{"class":240},[234,4144,2404],{"class":360},[234,4146,364],{"class":258},[234,4148,888],{"class":685},[234,4150,414],{"class":240},[234,4152,348],{"class":347},[234,4154,1008],{"class":351},[234,4156,348],{"class":347},[234,4158,364],{"class":258},[234,4160,902],{"class":685},[234,4162,414],{"class":240},[234,4164,1987],{"class":360},[234,4166,364],{"class":258},[234,4168,3384],{"class":685},[234,4170,414],{"class":240},[234,4172,348],{"class":347},[234,4174,3391],{"class":351},[234,4176,3394],{"class":347},[234,4178,4179],{"class":236,"line":2339},[234,4180,2060],{"class":258},[234,4182,4183,4185,4187,4189],{"class":236,"line":2344},[234,4184,4112],{"class":244},[234,4186,259],{"class":258},[234,4188,852],{"class":340},[234,4190,1685],{"class":258},[234,4192,4193,4196,4198,4201,4203,4205],{"class":236,"line":2372},[234,4194,4195],{"class":340},"        x_src",[234,4197,2003],{"class":258},[234,4199,4200],{"class":340},"N_clean",[234,4202,364],{"class":258},[234,4204,863],{"class":360},[234,4206,3424],{"class":258},[234,4208,4209,4211,4213,4215,4217,4219],{"class":236,"line":2421},[234,4210,4195],{"class":340},[234,4212,2003],{"class":258},[234,4214,4200],{"class":340},[234,4216,364],{"class":258},[234,4218,733],{"class":360},[234,4220,3424],{"class":258},[234,4222,4223,4226,4228,4230],{"class":236,"line":2442},[234,4224,4225],{"class":685},"        s",[234,4227,414],{"class":240},[234,4229,2404],{"class":360},[234,4231,2055],{"class":258},[234,4233,4234,4237,4239,4241,4243,4245],{"class":236,"line":2462},[234,4235,4236],{"class":685},"        color",[234,4238,414],{"class":240},[234,4240,348],{"class":347},[234,4242,895],{"class":351},[234,4244,348],{"class":347},[234,4246,2055],{"class":258},[234,4248,4249,4252,4254,4256],{"class":236,"line":2473},[234,4250,4251],{"class":685},"        alpha",[234,4253,414],{"class":240},[234,4255,907],{"class":360},[234,4257,2055],{"class":258},[234,4259,4260,4263,4265,4267,4270,4272],{"class":236,"line":3564},[234,4261,4262],{"class":685},"        label",[234,4264,414],{"class":240},[234,4266,348],{"class":347},[234,4268,4269],{"class":351},"Source",[234,4271,348],{"class":347},[234,4273,2055],{"class":258},[234,4275,4276],{"class":236,"line":3623},[234,4277,2060],{"class":258},[234,4279,4280,4282,4284,4286,4288,4290,4292,4294,4297,4299],{"class":236,"line":3646},[234,4281,2751],{"class":251},[234,4283,4048],{"class":244},[234,4285,259],{"class":258},[234,4287,1353],{"class":262},[234,4289,844],{"class":258},[234,4291,613],{"class":360},[234,4293,2108],{"class":258},[234,4295,4296],{"class":240}," >",[234,4298,3783],{"class":244},[234,4300,1133],{"class":258},[234,4302,4303,4306,4308,4310],{"class":236,"line":3669},[234,4304,4305],{"class":244},"        ax",[234,4307,259],{"class":258},[234,4309,852],{"class":340},[234,4311,1685],{"class":258},[234,4313,4314,4317,4319,4321,4324,4326],{"class":236,"line":3674},[234,4315,4316],{"class":340},"            x_src",[234,4318,844],{"class":258},[234,4320,4200],{"class":340},[234,4322,4323],{"class":258},":,",[234,4325,863],{"class":360},[234,4327,3424],{"class":258},[234,4329,4330,4332,4334,4336,4338,4340],{"class":236,"line":3685},[234,4331,4316],{"class":340},[234,4333,844],{"class":258},[234,4335,4200],{"class":340},[234,4337,4323],{"class":258},[234,4339,733],{"class":360},[234,4341,3424],{"class":258},[234,4343,4345,4348,4350,4353],{"class":236,"line":4344},36,[234,4346,4347],{"class":685},"            s",[234,4349,414],{"class":240},[234,4351,4352],{"class":360},"25",[234,4354,2055],{"class":258},[234,4356,4358,4361,4363,4365,4368,4370],{"class":236,"line":4357},37,[234,4359,4360],{"class":685},"            color",[234,4362,414],{"class":240},[234,4364,348],{"class":347},[234,4366,4367],{"class":351},"#ffd700",[234,4369,348],{"class":347},[234,4371,2055],{"class":258},[234,4373,4375,4378,4380,4382,4384,4386],{"class":236,"line":4374},38,[234,4376,4377],{"class":685},"            marker",[234,4379,414],{"class":240},[234,4381,348],{"class":347},[234,4383,1771],{"class":351},[234,4385,348],{"class":347},[234,4387,2055],{"class":258},[234,4389,4391,4394,4396,4398,4401,4403],{"class":236,"line":4390},39,[234,4392,4393],{"class":685},"            label",[234,4395,414],{"class":240},[234,4397,348],{"class":347},[234,4399,4400],{"class":351},"Outliers",[234,4402,348],{"class":347},[234,4404,2055],{"class":258},[234,4406,4408,4411,4413,4416],{"class":236,"line":4407},40,[234,4409,4410],{"class":685},"            zorder",[234,4412,414],{"class":240},[234,4414,4415],{"class":360},"5",[234,4417,2055],{"class":258},[234,4419,4421],{"class":236,"line":4420},41,[234,4422,1780],{"class":258},[234,4424,4426,4428,4430,4432,4434,4436],{"class":236,"line":4425},42,[234,4427,4112],{"class":244},[234,4429,259],{"class":258},[234,4431,922],{"class":340},[234,4433,424],{"class":258},[234,4435,2428],{"class":340},[234,4437,450],{"class":258},[234,4439,4441,4443,4445,4447,4449,4451,4453,4455],{"class":236,"line":4440},43,[234,4442,4112],{"class":244},[234,4444,259],{"class":258},[234,4446,947],{"class":340},[234,4448,424],{"class":258},[234,4450,348],{"class":347},[234,4452,954],{"class":351},[234,4454,348],{"class":347},[234,4456,450],{"class":258},[234,4458,4460,4462,4464,4466,4468,4471,4473,4475],{"class":236,"line":4459},44,[234,4461,4112],{"class":244},[234,4463,259],{"class":258},[234,4465,3555],{"class":340},[234,4467,424],{"class":258},[234,4469,4470],{"class":685},"fontsize",[234,4472,414],{"class":240},[234,4474,883],{"class":360},[234,4476,450],{"class":258},[234,4478,4480,4482,4484,4486],{"class":236,"line":4479},45,[234,4481,330],{"class":244},[234,4483,259],{"class":258},[234,4485,1098],{"class":340},[234,4487,405],{"class":258},[234,4489,4491,4493,4495,4497],{"class":236,"line":4490},46,[234,4492,330],{"class":244},[234,4494,259],{"class":258},[234,4496,1110],{"class":340},[234,4498,405],{"class":258},[234,4500,4502],{"class":236,"line":4501},47,[234,4503,324],{"emptyLinePlaceholder":323},[234,4505,4507,4509,4511],{"class":236,"line":4506},48,[234,4508,1128],{"class":251},[234,4510,437],{"class":386},[234,4512,1133],{"class":258},[234,4514,4516],{"class":236,"line":4515},49,[234,4517,4518],{"class":593},"    # Balanced OT (outliers distort the plan)\n",[234,4520,4522,4525,4527,4529,4531,4533,4535,4537,4539,4541],{"class":236,"line":4521},50,[234,4523,4524],{"class":244},"    loss_balanced ",[234,4526,414],{"class":240},[234,4528,1198],{"class":244},[234,4530,259],{"class":258},[234,4532,1203],{"class":262},[234,4534,259],{"class":258},[234,4536,1208],{"class":262},[234,4538,259],{"class":258},[234,4540,1213],{"class":340},[234,4542,1685],{"class":258},[234,4544,4546,4549,4551,4553,4555,4557,4559,4561,4563,4565,4567,4569,4571,4573,4575],{"class":236,"line":4545},51,[234,4547,4548],{"class":340},"        x_with_outliers",[234,4550,259],{"class":258},[234,4552,1147],{"class":340},[234,4554,424],{"class":258},[234,4556,421],{"class":340},[234,4558,668],{"class":258},[234,4560,4132],{"class":340},[234,4562,259],{"class":258},[234,4564,1147],{"class":340},[234,4566,424],{"class":258},[234,4568,421],{"class":340},[234,4570,668],{"class":258},[234,4572,1228],{"class":685},[234,4574,414],{"class":240},[234,4576,4577],{"class":360},"0.1\n",[234,4579,4581],{"class":236,"line":4580},52,[234,4582,2060],{"class":258},[234,4584,4586],{"class":236,"line":4585},53,[234,4587,4588],{"class":593},"    # Unbalanced OT (outliers are soft-dropped)\n",[234,4590,4592,4595,4597,4599,4601,4603,4605,4607,4609,4611],{"class":236,"line":4591},54,[234,4593,4594],{"class":244},"    loss_unbalanced ",[234,4596,414],{"class":240},[234,4598,1198],{"class":244},[234,4600,259],{"class":258},[234,4602,1203],{"class":262},[234,4604,259],{"class":258},[234,4606,1208],{"class":262},[234,4608,259],{"class":258},[234,4610,1213],{"class":340},[234,4612,1685],{"class":258},[234,4614,4616,4618,4620,4622,4624,4626,4628,4630,4632,4634,4636,4638,4640,4642,4644,4646,4648,4651,4653],{"class":236,"line":4615},55,[234,4617,4548],{"class":340},[234,4619,259],{"class":258},[234,4621,1147],{"class":340},[234,4623,424],{"class":258},[234,4625,421],{"class":340},[234,4627,668],{"class":258},[234,4629,4132],{"class":340},[234,4631,259],{"class":258},[234,4633,1147],{"class":340},[234,4635,424],{"class":258},[234,4637,421],{"class":340},[234,4639,668],{"class":258},[234,4641,1228],{"class":685},[234,4643,414],{"class":240},[234,4645,1233],{"class":360},[234,4647,364],{"class":258},[234,4649,4650],{"class":685}," reach",[234,4652,414],{"class":240},[234,4654,4655],{"class":360},"0.3\n",[234,4657,4659],{"class":236,"line":4658},56,[234,4660,2060],{"class":258},[234,4662,4664,4666,4668,4670,4673,4675,4678,4680,4682,4684,4686,4688,4690],{"class":236,"line":4663},57,[234,4665,1240],{"class":436},[234,4667,424],{"class":258},[234,4669,490],{"class":489},[234,4671,4672],{"class":351},"\"Balanced OT loss  (outliers distort): ",[234,4674,496],{"class":360},[234,4676,4677],{"class":340},"loss_balanced",[234,4679,259],{"class":258},[234,4681,1256],{"class":340},[234,4683,1259],{"class":258},[234,4685,1262],{"class":489},[234,4687,507],{"class":360},[234,4689,348],{"class":351},[234,4691,450],{"class":258},[234,4693,4695,4697,4699,4701,4704,4706,4709,4711,4713,4715,4717,4719,4721],{"class":236,"line":4694},58,[234,4696,1240],{"class":436},[234,4698,424],{"class":258},[234,4700,490],{"class":489},[234,4702,4703],{"class":351},"\"Unbalanced OT loss (reach=0.3):        ",[234,4705,496],{"class":360},[234,4707,4708],{"class":340},"loss_unbalanced",[234,4710,259],{"class":258},[234,4712,1256],{"class":340},[234,4714,1259],{"class":258},[234,4716,1262],{"class":489},[234,4718,507],{"class":360},[234,4720,348],{"class":351},[234,4722,450],{"class":258},[234,4724,4726,4728],{"class":236,"line":4725},59,[234,4727,1240],{"class":436},[234,4729,1685],{"class":258},[234,4731,4733,4736,4739],{"class":236,"line":4732},60,[234,4734,4735],{"class":347},"        \"",[234,4737,4738],{"class":351},"Unbalanced OT is more robust: it concentrates mass on the in-distribution points.",[234,4740,3394],{"class":347},[234,4742,4744],{"class":236,"line":4743},61,[234,4745,2060],{"class":258},[234,4747,4749,4751],{"class":236,"line":4748},62,[234,4750,1364],{"class":251},[234,4752,1133],{"class":258},[234,4754,4756,4758,4760,4762,4765,4767],{"class":236,"line":4755},63,[234,4757,1240],{"class":436},[234,4759,424],{"class":258},[234,4761,348],{"class":347},[234,4763,4764],{"class":351},"CUDA not available — unbalanced samples.loss requires CUDA.",[234,4766,348],{"class":347},[234,4768,450],{"class":258},[234,4770,4772,4774],{"class":236,"line":4771},64,[234,4773,1240],{"class":436},[234,4775,1685],{"class":258},[234,4777,4779,4781,4784],{"class":236,"line":4778},65,[234,4780,4735],{"class":347},[234,4782,4783],{"class":351},"On a GPU, unbalanced OT (reach=0.3) gives a smaller, more robust loss value.",[234,4785,3394],{"class":347},[234,4787,4789],{"class":236,"line":4788},66,[234,4790,2060],{"class":258},[185,4792,4793],{},[1116,4794],{"alt":230,"src":4795},"\u002F_nb\u002Fb82d365133d492ec.png",[522,4797],{"data":4798,"kind":525},"Q1VEQSBub3QgYXZhaWxhYmxlIOKAlCB1bmJhbGFuY2VkIHNhbXBsZXMubG9zcyByZXF1aXJlcyBDVURBLgpPbiBhIEdQVSwgdW5iYWxhbmNlZCBPVCAocmVhY2g9MC4zKSBnaXZlcyBhIHNtYWxsZXIsIG1vcmUgcm9idXN0IGxvc3MgdmFsdWUuCg==",[530,4800,4802],{"id":4801},"_5-wasserstein-barycenters-via-matrix-face","5  Wasserstein barycenters (via matrix face)",[185,4804,4805],{},"The Wasserstein barycenter of a set of distributions is the \"average\"\ndistribution in OT space.  Unlike the Euclidean average, the barycenter respects the geometry: the barycenter of two rings is still a ring, not a blob.",[185,4807,4808],{},"We approximate the barycenter using the matrix face by running Sinkhorn\nbetween an initialised barycenter and each source distribution, then\nupdating the barycenter to match the weighted mean of the transported mass.",[225,4810,4812],{"className":227,"code":4811,"language":229,"meta":230,"style":230},"def make_ring(n, radius=1.0, noise=0.05):\n    angles = np.linspace(0, 2 * np.pi, n, endpoint=False).astype(np.float32)\n    pts = np.stack([radius * np.cos(angles), radius * np.sin(angles)], axis=1)\n    pts += rng.normal(0, noise, pts.shape).astype(np.float32)\n    return pts\n\n\nN_bar = 64\n# Three shapes to average: ring at different rotations \u002F scales\nshapes = [\n    make_ring(N_bar, radius=0.5),\n    make_ring(N_bar, radius=1.0),\n    make_ring(N_bar, radius=1.5),\n]\n\nfig, axes = plt.subplots(1, 4, figsize=(14, 3.5))\ncolors_shapes = [\"#1a6daf\", \"#E03520\", \"#2d9e2d\"]\nfor i, (shape, color) in enumerate(zip(shapes, colors_shapes)):\n    axes[i].scatter(shape[:, 0], shape[:, 1], s=20, color=color)\n    axes[i].set_title(f\"Shape {i + 1}\")\n    axes[i].set_aspect(\"equal\")\n    axes[i].set_xlim(-2, 2)\n    axes[i].set_ylim(-2, 2)\n\n# Simple free-support barycenter: average positions (Euclidean, for comparison)\nbarycenter_euclidean = np.mean(shapes, axis=0)\naxes[3].scatter(\n    barycenter_euclidean[:, 0], barycenter_euclidean[:, 1], s=20, color=\"#888888\"\n)\naxes[3].set_title(\"Euclidean mean\\n(collapses to blob)\")\naxes[3].set_aspect(\"equal\")\naxes[3].set_xlim(-2, 2)\naxes[3].set_ylim(-2, 2)\n\nplt.suptitle(\"Three rings at different radii → their average\", y=1.02)\nplt.tight_layout()\nplt.show()\n\nprint(\"Note: the Euclidean mean of three concentric rings blurs together.\")\nprint(\"The Wasserstein barycenter (a ring at the average radius) is a cleaner average.\")\nprint(\n    \"Computing a proper free-support Wasserstein barycenter requires iterative OT solves\"\n)\nprint(\"and is covered in the torchmatch transport reference.\")\n",[199,4813,4814,4847,4905,4961,5004,5011,5015,5019,5029,5034,5044,5064,5082,5101,5106,5110,5152,5187,5230,5280,5313,5335,5360,5385,5389,5394,5422,5436,5475,5479,5508,5530,5554,5578,5582,5610,5620,5630,5634,5649,5664,5670,5680,5684],{"__ignoreMap":230},[234,4815,4816,4818,4821,4823,4826,4828,4831,4833,4836,4838,4840,4842,4845],{"class":236,"line":237},[234,4817,1887],{"class":489},[234,4819,4820],{"class":1791}," make_ring",[234,4822,424],{"class":258},[234,4824,4825],{"class":1608},"n",[234,4827,364],{"class":258},[234,4829,4830],{"class":1608}," radius",[234,4832,414],{"class":240},[234,4834,4835],{"class":360},"1.0",[234,4837,364],{"class":258},[234,4839,2266],{"class":1608},[234,4841,414],{"class":240},[234,4843,4844],{"class":360},"0.05",[234,4846,1572],{"class":258},[234,4848,4849,4852,4854,4856,4858,4860,4862,4864,4866,4868,4870,4872,4874,4876,4878,4881,4883,4886,4888,4891,4893,4895,4897,4899,4901,4903],{"class":236,"line":248},[234,4850,4851],{"class":244},"    angles ",[234,4853,414],{"class":240},[234,4855,461],{"class":244},[234,4857,259],{"class":258},[234,4859,608],{"class":340},[234,4861,424],{"class":258},[234,4863,613],{"class":360},[234,4865,364],{"class":258},[234,4867,618],{"class":360},[234,4869,621],{"class":240},[234,4871,461],{"class":340},[234,4873,259],{"class":258},[234,4875,628],{"class":262},[234,4877,364],{"class":258},[234,4879,4880],{"class":340}," n",[234,4882,364],{"class":258},[234,4884,4885],{"class":685}," endpoint",[234,4887,414],{"class":240},[234,4889,4890],{"class":1162},"False",[234,4892,1154],{"class":258},[234,4894,751],{"class":340},[234,4896,424],{"class":258},[234,4898,756],{"class":340},[234,4900,259],{"class":258},[234,4902,761],{"class":262},[234,4904,450],{"class":258},[234,4906,4907,4909,4911,4913,4915,4917,4919,4922,4924,4926,4928,4930,4932,4934,4936,4939,4941,4943,4945,4947,4949,4951,4953,4955,4957,4959],{"class":236,"line":272},[234,4908,2186],{"class":244},[234,4910,414],{"class":240},[234,4912,461],{"class":244},[234,4914,259],{"class":258},[234,4916,649],{"class":340},[234,4918,652],{"class":258},[234,4920,4921],{"class":340},"radius ",[234,4923,1771],{"class":240},[234,4925,461],{"class":340},[234,4927,259],{"class":258},[234,4929,660],{"class":340},[234,4931,424],{"class":258},[234,4933,665],{"class":340},[234,4935,668],{"class":258},[234,4937,4938],{"class":340}," radius ",[234,4940,1771],{"class":240},[234,4942,461],{"class":340},[234,4944,259],{"class":258},[234,4946,675],{"class":340},[234,4948,424],{"class":258},[234,4950,665],{"class":340},[234,4952,682],{"class":258},[234,4954,2210],{"class":685},[234,4956,414],{"class":240},[234,4958,691],{"class":360},[234,4960,450],{"class":258},[234,4962,4963,4965,4968,4970,4972,4974,4976,4978,4980,4982,4984,4986,4988,4990,4992,4994,4996,4998,5000,5002],{"class":236,"line":286},[234,4964,2186],{"class":244},[234,4966,4967],{"class":240},"+=",[234,4969,716],{"class":244},[234,4971,259],{"class":258},[234,4973,2230],{"class":340},[234,4975,424],{"class":258},[234,4977,613],{"class":360},[234,4979,364],{"class":258},[234,4981,2266],{"class":340},[234,4983,364],{"class":258},[234,4985,2244],{"class":340},[234,4987,259],{"class":258},[234,4989,1353],{"class":262},[234,4991,1154],{"class":258},[234,4993,751],{"class":340},[234,4995,424],{"class":258},[234,4997,756],{"class":340},[234,4999,259],{"class":258},[234,5001,761],{"class":262},[234,5003,450],{"class":258},[234,5005,5006,5008],{"class":236,"line":294},[234,5007,2255],{"class":251},[234,5009,5010],{"class":244}," pts\n",[234,5012,5013],{"class":236,"line":312},[234,5014,324],{"emptyLinePlaceholder":323},[234,5016,5017],{"class":236,"line":320},[234,5018,324],{"emptyLinePlaceholder":323},[234,5020,5021,5024,5026],{"class":236,"line":327},[234,5022,5023],{"class":244},"N_bar ",[234,5025,414],{"class":240},[234,5027,5028],{"class":360}," 64\n",[234,5030,5031],{"class":236,"line":383},[234,5032,5033],{"class":593},"# Three shapes to average: ring at different rotations \u002F scales\n",[234,5035,5036,5039,5041],{"class":236,"line":408},[234,5037,5038],{"class":244},"shapes ",[234,5040,414],{"class":240},[234,5042,5043],{"class":258}," [\n",[234,5045,5046,5049,5051,5054,5056,5058,5060,5062],{"class":236,"line":453},[234,5047,5048],{"class":340},"    make_ring",[234,5050,424],{"class":258},[234,5052,5053],{"class":340},"N_bar",[234,5055,364],{"class":258},[234,5057,4830],{"class":685},[234,5059,414],{"class":240},[234,5061,1987],{"class":360},[234,5063,1708],{"class":258},[234,5065,5066,5068,5070,5072,5074,5076,5078,5080],{"class":236,"line":481},[234,5067,5048],{"class":340},[234,5069,424],{"class":258},[234,5071,5053],{"class":340},[234,5073,364],{"class":258},[234,5075,4830],{"class":685},[234,5077,414],{"class":240},[234,5079,4835],{"class":360},[234,5081,1708],{"class":258},[234,5083,5084,5086,5088,5090,5092,5094,5096,5099],{"class":236,"line":936},[234,5085,5048],{"class":340},[234,5087,424],{"class":258},[234,5089,5053],{"class":340},[234,5091,364],{"class":258},[234,5093,4830],{"class":685},[234,5095,414],{"class":240},[234,5097,5098],{"class":360},"1.5",[234,5100,1708],{"class":258},[234,5102,5103],{"class":236,"line":961},[234,5104,5105],{"class":258},"]\n",[234,5107,5108],{"class":236,"line":1023},[234,5109,324],{"emptyLinePlaceholder":323},[234,5111,5112,5114,5116,5118,5120,5122,5124,5126,5128,5130,5132,5134,5136,5138,5140,5142,5145,5147,5150],{"class":236,"line":1047},[234,5113,793],{"class":244},[234,5115,364],{"class":258},[234,5117,798],{"class":244},[234,5119,414],{"class":240},[234,5121,803],{"class":244},[234,5123,259],{"class":258},[234,5125,808],{"class":340},[234,5127,424],{"class":258},[234,5129,691],{"class":360},[234,5131,364],{"class":258},[234,5133,833],{"class":360},[234,5135,364],{"class":258},[234,5137,821],{"class":685},[234,5139,414],{"class":240},[234,5141,424],{"class":258},[234,5143,5144],{"class":360},"14",[234,5146,364],{"class":258},[234,5148,5149],{"class":360}," 3.5",[234,5151,836],{"class":258},[234,5153,5154,5157,5159,5162,5164,5166,5168,5170,5172,5174,5176,5178,5180,5183,5185],{"class":236,"line":1070},[234,5155,5156],{"class":244},"colors_shapes ",[234,5158,414],{"class":240},[234,5160,5161],{"class":258}," [",[234,5163,348],{"class":347},[234,5165,895],{"class":351},[234,5167,348],{"class":347},[234,5169,364],{"class":258},[234,5171,367],{"class":347},[234,5173,1008],{"class":351},[234,5175,348],{"class":347},[234,5177,364],{"class":258},[234,5179,367],{"class":347},[234,5181,5182],{"class":351},"#2d9e2d",[234,5184,348],{"class":347},[234,5186,5105],{"class":258},[234,5188,5189,5191,5194,5196,5198,5200,5202,5204,5206,5209,5212,5214,5217,5219,5222,5224,5227],{"class":236,"line":1091},[234,5190,2665],{"class":251},[234,5192,5193],{"class":244}," i",[234,5195,364],{"class":258},[234,5197,738],{"class":258},[234,5199,1353],{"class":244},[234,5201,364],{"class":258},[234,5203,888],{"class":244},[234,5205,694],{"class":258},[234,5207,5208],{"class":251}," in",[234,5210,5211],{"class":436}," enumerate",[234,5213,424],{"class":258},[234,5215,5216],{"class":436},"zip",[234,5218,424],{"class":258},[234,5220,5221],{"class":340},"shapes",[234,5223,364],{"class":258},[234,5225,5226],{"class":340}," colors_shapes",[234,5228,5229],{"class":258},")):\n",[234,5231,5232,5234,5236,5239,5241,5243,5245,5247,5249,5251,5253,5256,5258,5260,5262,5264,5266,5269,5271,5273,5275,5278],{"class":236,"line":1103},[234,5233,4065],{"class":244},[234,5235,844],{"class":258},[234,5237,5238],{"class":244},"i",[234,5240,849],{"class":258},[234,5242,852],{"class":340},[234,5244,424],{"class":258},[234,5246,1353],{"class":340},[234,5248,860],{"class":258},[234,5250,863],{"class":360},[234,5252,866],{"class":258},[234,5254,5255],{"class":340}," shape",[234,5257,860],{"class":258},[234,5259,733],{"class":360},[234,5261,866],{"class":258},[234,5263,878],{"class":685},[234,5265,414],{"class":240},[234,5267,5268],{"class":360},"20",[234,5270,364],{"class":258},[234,5272,888],{"class":685},[234,5274,414],{"class":240},[234,5276,5277],{"class":340},"color",[234,5279,450],{"class":258},[234,5281,5282,5284,5286,5288,5290,5292,5294,5296,5299,5301,5304,5306,5309,5311],{"class":236,"line":2291},[234,5283,4065],{"class":244},[234,5285,844],{"class":258},[234,5287,5238],{"class":244},[234,5289,849],{"class":258},[234,5291,922],{"class":340},[234,5293,424],{"class":258},[234,5295,490],{"class":489},[234,5297,5298],{"class":351},"\"Shape ",[234,5300,496],{"class":360},[234,5302,5303],{"class":340},"i ",[234,5305,2263],{"class":240},[234,5307,5308],{"class":360}," 1}",[234,5310,348],{"class":351},[234,5312,450],{"class":258},[234,5314,5315,5317,5319,5321,5323,5325,5327,5329,5331,5333],{"class":236,"line":2302},[234,5316,4065],{"class":244},[234,5318,844],{"class":258},[234,5320,5238],{"class":244},[234,5322,849],{"class":258},[234,5324,947],{"class":340},[234,5326,424],{"class":258},[234,5328,348],{"class":347},[234,5330,954],{"class":351},[234,5332,348],{"class":347},[234,5334,450],{"class":258},[234,5336,5337,5339,5341,5343,5345,5348,5350,5352,5354,5356,5358],{"class":236,"line":2318},[234,5338,4065],{"class":244},[234,5340,844],{"class":258},[234,5342,5238],{"class":244},[234,5344,849],{"class":258},[234,5346,5347],{"class":340},"set_xlim",[234,5349,424],{"class":258},[234,5351,726],{"class":240},[234,5353,1413],{"class":360},[234,5355,364],{"class":258},[234,5357,618],{"class":360},[234,5359,450],{"class":258},[234,5361,5362,5364,5366,5368,5370,5373,5375,5377,5379,5381,5383],{"class":236,"line":2339},[234,5363,4065],{"class":244},[234,5365,844],{"class":258},[234,5367,5238],{"class":244},[234,5369,849],{"class":258},[234,5371,5372],{"class":340},"set_ylim",[234,5374,424],{"class":258},[234,5376,726],{"class":240},[234,5378,1413],{"class":360},[234,5380,364],{"class":258},[234,5382,618],{"class":360},[234,5384,450],{"class":258},[234,5386,5387],{"class":236,"line":2344},[234,5388,324],{"emptyLinePlaceholder":323},[234,5390,5391],{"class":236,"line":2372},[234,5392,5393],{"class":593},"# Simple free-support barycenter: average positions (Euclidean, for comparison)\n",[234,5395,5396,5399,5401,5403,5405,5408,5410,5412,5414,5416,5418,5420],{"class":236,"line":2421},[234,5397,5398],{"class":244},"barycenter_euclidean ",[234,5400,414],{"class":240},[234,5402,461],{"class":244},[234,5404,259],{"class":258},[234,5406,5407],{"class":340},"mean",[234,5409,424],{"class":258},[234,5411,5221],{"class":340},[234,5413,364],{"class":258},[234,5415,2210],{"class":685},[234,5417,414],{"class":240},[234,5419,613],{"class":360},[234,5421,450],{"class":258},[234,5423,5424,5426,5428,5430,5432,5434],{"class":236,"line":2442},[234,5425,841],{"class":244},[234,5427,844],{"class":258},[234,5429,2363],{"class":360},[234,5431,849],{"class":258},[234,5433,852],{"class":340},[234,5435,1685],{"class":258},[234,5437,5438,5441,5443,5445,5447,5450,5452,5454,5456,5458,5460,5462,5464,5466,5468,5470,5473],{"class":236,"line":2462},[234,5439,5440],{"class":340},"    barycenter_euclidean",[234,5442,860],{"class":258},[234,5444,863],{"class":360},[234,5446,866],{"class":258},[234,5448,5449],{"class":340}," barycenter_euclidean",[234,5451,860],{"class":258},[234,5453,733],{"class":360},[234,5455,866],{"class":258},[234,5457,878],{"class":685},[234,5459,414],{"class":240},[234,5461,5268],{"class":360},[234,5463,364],{"class":258},[234,5465,888],{"class":685},[234,5467,414],{"class":240},[234,5469,348],{"class":347},[234,5471,5472],{"class":351},"#888888",[234,5474,3394],{"class":347},[234,5476,5477],{"class":236,"line":2473},[234,5478,450],{"class":258},[234,5480,5481,5483,5485,5487,5489,5491,5493,5495,5498,5501,5504,5506],{"class":236,"line":3564},[234,5482,841],{"class":244},[234,5484,844],{"class":258},[234,5486,2363],{"class":360},[234,5488,849],{"class":258},[234,5490,922],{"class":340},[234,5492,424],{"class":258},[234,5494,348],{"class":347},[234,5496,5497],{"class":351},"Euclidean mean",[234,5499,5500],{"class":386},"\\n",[234,5502,5503],{"class":351},"(collapses to blob)",[234,5505,348],{"class":347},[234,5507,450],{"class":258},[234,5509,5510,5512,5514,5516,5518,5520,5522,5524,5526,5528],{"class":236,"line":3623},[234,5511,841],{"class":244},[234,5513,844],{"class":258},[234,5515,2363],{"class":360},[234,5517,849],{"class":258},[234,5519,947],{"class":340},[234,5521,424],{"class":258},[234,5523,348],{"class":347},[234,5525,954],{"class":351},[234,5527,348],{"class":347},[234,5529,450],{"class":258},[234,5531,5532,5534,5536,5538,5540,5542,5544,5546,5548,5550,5552],{"class":236,"line":3646},[234,5533,841],{"class":244},[234,5535,844],{"class":258},[234,5537,2363],{"class":360},[234,5539,849],{"class":258},[234,5541,5347],{"class":340},[234,5543,424],{"class":258},[234,5545,726],{"class":240},[234,5547,1413],{"class":360},[234,5549,364],{"class":258},[234,5551,618],{"class":360},[234,5553,450],{"class":258},[234,5555,5556,5558,5560,5562,5564,5566,5568,5570,5572,5574,5576],{"class":236,"line":3669},[234,5557,841],{"class":244},[234,5559,844],{"class":258},[234,5561,2363],{"class":360},[234,5563,849],{"class":258},[234,5565,5372],{"class":340},[234,5567,424],{"class":258},[234,5569,726],{"class":240},[234,5571,1413],{"class":360},[234,5573,364],{"class":258},[234,5575,618],{"class":360},[234,5577,450],{"class":258},[234,5579,5580],{"class":236,"line":3674},[234,5581,324],{"emptyLinePlaceholder":323},[234,5583,5584,5586,5588,5590,5592,5594,5597,5599,5601,5603,5605,5608],{"class":236,"line":3685},[234,5585,330],{"class":244},[234,5587,259],{"class":258},[234,5589,1077],{"class":340},[234,5591,424],{"class":258},[234,5593,348],{"class":347},[234,5595,5596],{"class":351},"Three rings at different radii → their average",[234,5598,348],{"class":347},[234,5600,364],{"class":258},[234,5602,985],{"class":685},[234,5604,414],{"class":240},[234,5606,5607],{"class":360},"1.02",[234,5609,450],{"class":258},[234,5611,5612,5614,5616,5618],{"class":236,"line":4344},[234,5613,330],{"class":244},[234,5615,259],{"class":258},[234,5617,1098],{"class":340},[234,5619,405],{"class":258},[234,5621,5622,5624,5626,5628],{"class":236,"line":4357},[234,5623,330],{"class":244},[234,5625,259],{"class":258},[234,5627,1110],{"class":340},[234,5629,405],{"class":258},[234,5631,5632],{"class":236,"line":4374},[234,5633,324],{"emptyLinePlaceholder":323},[234,5635,5636,5638,5640,5642,5645,5647],{"class":236,"line":4390},[234,5637,484],{"class":436},[234,5639,424],{"class":258},[234,5641,348],{"class":347},[234,5643,5644],{"class":351},"Note: the Euclidean mean of three concentric rings blurs together.",[234,5646,348],{"class":347},[234,5648,450],{"class":258},[234,5650,5651,5653,5655,5657,5660,5662],{"class":236,"line":4407},[234,5652,484],{"class":436},[234,5654,424],{"class":258},[234,5656,348],{"class":347},[234,5658,5659],{"class":351},"The Wasserstein barycenter (a ring at the average radius) is a cleaner average.",[234,5661,348],{"class":347},[234,5663,450],{"class":258},[234,5665,5666,5668],{"class":236,"line":4420},[234,5667,484],{"class":436},[234,5669,1685],{"class":258},[234,5671,5672,5675,5678],{"class":236,"line":4425},[234,5673,5674],{"class":347},"    \"",[234,5676,5677],{"class":351},"Computing a proper free-support Wasserstein barycenter requires iterative OT solves",[234,5679,3394],{"class":347},[234,5681,5682],{"class":236,"line":4440},[234,5683,450],{"class":258},[234,5685,5686,5688,5690,5692,5695,5697],{"class":236,"line":4459},[234,5687,484],{"class":436},[234,5689,424],{"class":258},[234,5691,348],{"class":347},[234,5693,5694],{"class":351},"and is covered in the torchmatch transport reference.",[234,5696,348],{"class":347},[234,5698,450],{"class":258},[185,5700,5701],{},[1116,5702],{"alt":230,"src":5703},"\u002F_nb\u002Fbed8c67b378d2405.png",[522,5705],{"data":5706,"kind":525},"Tm90ZTogdGhlIEV1Y2xpZGVhbiBtZWFuIG9mIHRocmVlIGNvbmNlbnRyaWMgcmluZ3MgYmx1cnMgdG9nZXRoZXIuClRoZSBXYXNzZXJzdGVpbiBiYXJ5Y2VudGVyIChhIHJpbmcgYXQgdGhlIGF2ZXJhZ2UgcmFkaXVzKSBpcyBhIGNsZWFuZXIgYXZlcmFnZS4KQ29tcHV0aW5nIGEgcHJvcGVyIGZyZWUtc3VwcG9ydCBXYXNzZXJzdGVpbiBiYXJ5Y2VudGVyIHJlcXVpcmVzIGl0ZXJhdGl2ZSBPVCBzb2x2ZXMKYW5kIGlzIGNvdmVyZWQgaW4gdGhlIHRvcmNobWF0Y2ggdHJhbnNwb3J0IHJlZmVyZW5jZS4K",[530,5708,5710],{"id":5709},"summary","Summary",[192,5712,5713,5723,5732,5741],{},[195,5714,5715,5718,5719,5722],{},[199,5716,5717],{},"torchmatch.transport.samples.loss(x, y)"," computes the Sinkhorn loss\nbetween two point clouds ",[188,5720,5721],{},"without"," materialising the N×M cost matrix —\nthe Triton kernel fuses cost computation with the LSE accumulation.",[195,5724,5725,5726,5728,5729,5731],{},"Gradients flow through ",[199,5727,857],{}," and (optionally) ",[199,5730,976],{},", enabling\ndifferentiable training of point-cloud generative models.",[195,5733,5734,5736,5737,5740],{},[199,5735,3714],{}," enables ",[188,5738,5739],{},"unbalanced OT",": outlier points contribute less mass\nto the coupling rather than distorting the plan.",[195,5742,5743],{},"The Wasserstein barycenter is the OT-space \"average\" of distributions;\nit preserves structural properties (shape, topology) that Euclidean\naveraging destroys.",[185,5745,5746,5747,5751,5752,5755],{},"These three tutorials cover the core torchmatch transport API.  See the\n",[5748,5749,5750],"a",{"href":75},"Transport reference"," for full signatures and the\n",[5748,5753,5754],{"href":153},"Applications page"," for more use cases.",[5757,5758,5759],"style",{},"html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}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 .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .slqww, html code.shiki .slqww{--shiki-light:#6182B8;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}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 .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s2W-s, html code.shiki .s2W-s{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#032F62;--shiki-default-font-style:inherit;--shiki-dark:#9ECBFF;--shiki-dark-font-style:inherit}html pre.shiki code .sithA, html code.shiki .sithA{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#032F62;--shiki-default-font-style:inherit;--shiki-dark:#9ECBFF;--shiki-dark-font-style:inherit}html pre.shiki code .smCYv, html code.shiki .smCYv{--shiki-light:#E53935;--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 .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 .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":230,"searchDepth":272,"depth":272,"links":5761},[5762,5763,5764,5767,5768,5769],{"id":532,"depth":248,"text":533},{"id":572,"depth":248,"text":573},{"id":1538,"depth":248,"text":1539,"children":5765},[5766],{"id":1876,"depth":272,"text":1877},{"id":3701,"depth":248,"text":3702},{"id":4801,"depth":248,"text":4802},{"id":5709,"depth":248,"text":5710},"md",{"notebook":323},{"icon":121},{"title":144,"description":190},"6IuAGWmGry5TPgl8ghwfev-qFcoCJzmtfTGX-UrMYR4",[5776,5777],{"title":140,"path":141,"stem":142,"description":190,"icon":121,"children":-1},{"title":148,"path":149,"stem":150,"description":5778,"children":-1},"Historical and modern applications of the linear assignment problem — from 1950s operations research to DETR, multi-object tracking, and cluster evaluation in contemporary deep learning.",1785218166349]