[{"data":1,"prerenderedAt":1892},["ShallowReactive",2],{"navigation":3,"\u002Falgorithms\u002Ftransport\u002Fpoint-clouds":174,"\u002Falgorithms\u002Ftransport\u002Fpoint-clouds-surround":1887},[4,8,101,165,170],{"title":5,"path":6,"stem":7},"Getting started","\u002Fgetting-started","1.getting-started",{"title":9,"path":10,"stem":11,"children":12},"Algorithms","\u002Falgorithms","2.algorithms",[13,15,58],{"title":9,"path":10,"stem":14},"2.algorithms\u002Findex",{"title":16,"path":17,"stem":18,"children":19},"Assignment","\u002Falgorithms\u002Fassignment","2.algorithms\u002F1.assignment\u002Findex",[20,21,25,29,32,36,40],{"title":16,"path":17,"stem":18},{"title":22,"path":23,"stem":24},"Quickstart","\u002Falgorithms\u002Fassignment\u002Fquickstart","2.algorithms\u002F1.assignment\u002F1.quickstart",{"title":26,"path":27,"stem":28},"Tracking","\u002Falgorithms\u002Fassignment\u002Ftracking","2.algorithms\u002F1.assignment\u002F2.tracking",{"title":9,"path":30,"stem":31},"\u002Falgorithms\u002Fassignment\u002Falgorithms","2.algorithms\u002F1.assignment\u002F3.algorithms",{"title":33,"path":34,"stem":35},"Reference","\u002Falgorithms\u002Fassignment\u002Freference","2.algorithms\u002F1.assignment\u002F4.reference",{"title":37,"path":38,"stem":39},"Choosing","\u002Falgorithms\u002Fassignment\u002Fchoosing","2.algorithms\u002F1.assignment\u002F5.choosing",{"title":41,"path":42,"stem":43,"children":44},"Tutorials","\u002Falgorithms\u002Fassignment\u002Ftutorials","2.algorithms\u002F1.assignment\u002F6.tutorials\u002Findex",[45,46,50,54],{"title":41,"path":42,"stem":43},{"title":47,"path":48,"stem":49},"Fundamentals","\u002Falgorithms\u002Fassignment\u002Ftutorials\u002Ffundamentals","2.algorithms\u002F1.assignment\u002F6.tutorials\u002F1.fundamentals",{"title":51,"path":52,"stem":53},"Backends","\u002Falgorithms\u002Fassignment\u002Ftutorials\u002Fbackends","2.algorithms\u002F1.assignment\u002F6.tutorials\u002F2.backends",{"title":55,"path":56,"stem":57},"Object tracking","\u002Falgorithms\u002Fassignment\u002Ftutorials\u002Ftracking","2.algorithms\u002F1.assignment\u002F6.tutorials\u002F3.tracking",{"title":59,"path":60,"stem":61,"children":62},"Transport","\u002Falgorithms\u002Ftransport","2.algorithms\u002F2.transport\u002Findex",[63,64,67,71,74,77,80,84],{"title":59,"path":60,"stem":61},{"title":22,"path":65,"stem":66},"\u002Falgorithms\u002Ftransport\u002Fquickstart","2.algorithms\u002F2.transport\u002F1.quickstart",{"title":68,"path":69,"stem":70},"Point-cloud tutorial","\u002Falgorithms\u002Ftransport\u002Fpoint-clouds","2.algorithms\u002F2.transport\u002F2.point-clouds",{"title":9,"path":72,"stem":73},"\u002Falgorithms\u002Ftransport\u002Falgorithms","2.algorithms\u002F2.transport\u002F3.algorithms",{"title":33,"path":75,"stem":76},"\u002Falgorithms\u002Ftransport\u002Freference","2.algorithms\u002F2.transport\u002F4.reference",{"title":37,"path":78,"stem":79},"\u002Falgorithms\u002Ftransport\u002Fchoosing","2.algorithms\u002F2.transport\u002F5.choosing",{"title":81,"path":82,"stem":83},"Building","\u002Falgorithms\u002Ftransport\u002Fbuilding","2.algorithms\u002F2.transport\u002F6.building",{"title":41,"path":85,"stem":86,"children":87},"\u002Falgorithms\u002Ftransport\u002Ftutorials","2.algorithms\u002F2.transport\u002F7.tutorials\u002Findex",[88,89,93,97],{"title":41,"path":85,"stem":86},{"title":90,"path":91,"stem":92},"Optimal transport","\u002Falgorithms\u002Ftransport\u002Ftutorials\u002Foptimal-transport","2.algorithms\u002F2.transport\u002F7.tutorials\u002F1.optimal-transport",{"title":94,"path":95,"stem":96},"Sinkhorn","\u002Falgorithms\u002Ftransport\u002Ftutorials\u002Fsinkhorn","2.algorithms\u002F2.transport\u002F7.tutorials\u002F2.sinkhorn",{"title":98,"path":99,"stem":100},"Point clouds","\u002Falgorithms\u002Ftransport\u002Ftutorials\u002Fpoint-clouds","2.algorithms\u002F2.transport\u002F7.tutorials\u002F3.point-clouds",{"title":102,"path":103,"stem":104,"children":105},"Resources","\u002Fresources","3.resources",[106,108,147,151,155],{"title":102,"path":103,"stem":107},"3.resources\u002Findex",{"title":41,"path":109,"stem":110,"children":111},"\u002Fresources\u002Ftutorials","3.resources\u002F1.tutorials\u002Findex",[112,113,131],{"title":41,"path":109,"stem":110},{"title":16,"path":114,"stem":115,"children":116,"page":130},"\u002Fresources\u002Ftutorials\u002Fassignment","3.resources\u002F1.tutorials\u002Fassignment",[117,122,126],{"title":118,"path":119,"stem":120,"icon":121},"Tutorial 1 — The Assignment Problem","\u002Fresources\u002Ftutorials\u002Fassignment\u002F01_the_assignment_problem","3.resources\u002F1.tutorials\u002Fassignment\u002F01_the_assignment_problem","i-lucide-notebook",{"title":123,"path":124,"stem":125,"icon":121},"Tutorial 2 — Backends and Batching","\u002Fresources\u002Ftutorials\u002Fassignment\u002F02_backends_and_batching","3.resources\u002F1.tutorials\u002Fassignment\u002F02_backends_and_batching",{"title":127,"path":128,"stem":129,"icon":121},"Tutorial 3 — Object Tracking with the Assignment Problem","\u002Fresources\u002Ftutorials\u002Fassignment\u002F03_object_tracking","3.resources\u002F1.tutorials\u002Fassignment\u002F03_object_tracking",false,{"title":59,"path":132,"stem":133,"children":134,"page":130},"\u002Fresources\u002Ftutorials\u002Ftransport","3.resources\u002F1.tutorials\u002Ftransport",[135,139,143],{"title":136,"path":137,"stem":138,"icon":121},"Tutorial 1 — What Is Optimal Transport?","\u002Fresources\u002Ftutorials\u002Ftransport\u002F01_optimal_transport","3.resources\u002F1.tutorials\u002Ftransport\u002F01_optimal_transport",{"title":140,"path":141,"stem":142,"icon":121},"Tutorial 2 — The Sinkhorn Algorithm","\u002Fresources\u002Ftutorials\u002Ftransport\u002F02_sinkhorn_algorithm","3.resources\u002F1.tutorials\u002Ftransport\u002F02_sinkhorn_algorithm",{"title":144,"path":145,"stem":146,"icon":121},"Tutorial 3 — Point-Cloud OT and Shape Learning","\u002Fresources\u002Ftutorials\u002Ftransport\u002F03_point_clouds","3.resources\u002F1.tutorials\u002Ftransport\u002F03_point_clouds",{"title":148,"path":149,"stem":150},"Assignment applications","\u002Fresources\u002Fassignment-applications","3.resources\u002F2.assignment-applications",{"title":152,"path":153,"stem":154},"Transport applications","\u002Fresources\u002Ftransport-applications","3.resources\u002F3.transport-applications",{"title":156,"path":157,"stem":158,"children":159},"Benchmarks","\u002Fresources\u002Fbenchmarks","3.resources\u002F4.benchmarks\u002Findex",[160,161],{"title":156,"path":157,"stem":158},{"title":162,"path":163,"stem":164},"Contributing benchmarks","\u002Fresources\u002Fbenchmarks\u002Fcontributing","3.resources\u002F4.benchmarks\u002Fcontributing",{"title":166,"path":167,"stem":168,"icon":169},"API Reference","\u002Fapi","4.api","i-lucide-package",{"title":171,"path":172,"stem":173},"References","\u002Freferences","5.references",{"id":175,"title":176,"api":177,"body":178,"description":1881,"extension":1882,"links":177,"meta":1883,"navigation":1884,"path":69,"seo":1885,"stem":70,"__hash__":1886},"docs\u002F2.algorithms\u002F2.transport\u002F2.point-clouds.md","Point-cloud Wasserstein loss",null,{"type":179,"value":180,"toc":1869},"minimark",[181,190,201,206,213,217,722,726,729,1048,1052,1465,1469,1495,1500,1507,1561,1567,1577,1584,1588,1595,1663,1666,1737,1744,1752,1798,1807,1811,1834,1838,1865],[182,183,184,185,189],"p",{},"This tutorial builds a training loop that uses ",[186,187,188],"code",{},"transport.samples.loss"," as a geometry-aware\nloss between predicted and ground-truth 3D point clouds. The pattern applies to shape\nautoencoders, generative models, and any task where you want the model to produce a point\nset close to a target — measured by the cost of moving one set of points onto the other.",[182,191,192,196,197,200],{},[193,194,195],"strong",{},"Prerequisites",": a CUDA device and ",[186,198,199],{},"pip install torchmatch",".",[202,203,205],"h2",{"id":204},"the-problem","The problem",[182,207,208,209,212],{},"Suppose a decoder network takes a latent vector ",[186,210,211],{},"z"," and produces a set of 3D points. A\nnaïve MSE loss on unordered point sets requires a fixed one-to-one pairing between predicted and ground-truth points first — but no such pairing exists when both sets are unordered. The\nWasserstein loss sidesteps the correspondence problem: it measures the minimum cost of\nmoving predicted points onto ground-truth points — each predicted point contributes proportionally to nearby ground-truth points, without needing\na fixed pairing.",[202,214,216],{"id":215},"setup","Setup",[218,219,224],"pre",{"className":220,"code":221,"language":222,"meta":223,"style":223},"language-python shiki shiki-themes material-theme-lighter github-light github-dark","import torch\nimport torch.nn as nn\nimport torchmatch\n\ndevice = torch.device('cuda')\n\n# --- Tiny decoder for illustration ---\nclass Decoder(nn.Module):\n    def __init__(self, latent_dim: int = 64, n_points: int = 512):\n        super().__init__()\n        self.net = nn.Sequential(\n            nn.Linear(latent_dim, 256), nn.ReLU(),\n            nn.Linear(256, 512), nn.ReLU(),\n            nn.Linear(512, n_points * 3),\n        )\n        self.n_points = n_points\n\n    def forward(self, z: torch.Tensor) -> torch.Tensor:\n        # Returns (batch, n_points, 3)\n        return self.net(z).reshape(z.size(0), self.n_points, 3)\n\ndecoder = Decoder().to(device)\noptimiser = torch.optim.Adam(decoder.parameters(), lr=1e-4)\n","python","",[186,225,226,239,260,268,275,309,314,321,344,397,412,437,471,499,527,533,548,553,595,601,652,657,678],{"__ignoreMap":223},[227,228,231,235],"span",{"class":229,"line":230},"line",1,[227,232,234],{"class":233},"sVHd0","import",[227,236,238],{"class":237},"su5hD"," torch\n",[227,240,242,244,247,250,254,257],{"class":229,"line":241},2,[227,243,234],{"class":233},[227,245,246],{"class":237}," torch",[227,248,200],{"class":249},"sP7_E",[227,251,253],{"class":252},"skxfh","nn",[227,255,256],{"class":233}," as",[227,258,259],{"class":237}," nn\n",[227,261,263,265],{"class":229,"line":262},3,[227,264,234],{"class":233},[227,266,267],{"class":237}," torchmatch\n",[227,269,271],{"class":229,"line":270},4,[227,272,274],{"emptyLinePlaceholder":273},true,"\n",[227,276,278,281,285,287,289,293,296,300,304,306],{"class":229,"line":277},5,[227,279,280],{"class":237},"device ",[227,282,284],{"class":283},"smGrS","=",[227,286,246],{"class":237},[227,288,200],{"class":249},[227,290,292],{"class":291},"slqww","device",[227,294,295],{"class":249},"(",[227,297,299],{"class":298},"sjJ54","'",[227,301,303],{"class":302},"s_sjI","cuda",[227,305,299],{"class":298},[227,307,308],{"class":249},")\n",[227,310,312],{"class":229,"line":311},6,[227,313,274],{"emptyLinePlaceholder":273},[227,315,317],{"class":229,"line":316},7,[227,318,320],{"class":319},"sutJx","# --- Tiny decoder for illustration ---\n",[227,322,324,328,332,334,336,338,341],{"class":229,"line":323},8,[227,325,327],{"class":326},"sbsja","class",[227,329,331],{"class":330},"sbgvK"," Decoder",[227,333,295],{"class":249},[227,335,253],{"class":330},[227,337,200],{"class":249},[227,339,340],{"class":330},"Module",[227,342,343],{"class":249},"):\n",[227,345,347,350,354,356,360,363,367,370,374,377,381,383,386,388,390,392,395],{"class":229,"line":346},9,[227,348,349],{"class":326},"    def",[227,351,353],{"class":352},"sptTA"," __init__",[227,355,295],{"class":249},[227,357,359],{"class":358},"smCYv","self",[227,361,362],{"class":249},",",[227,364,366],{"class":365},"sFwrP"," latent_dim",[227,368,369],{"class":249},":",[227,371,373],{"class":372},"sZMiF"," int",[227,375,376],{"class":283}," =",[227,378,380],{"class":379},"srdBf"," 64",[227,382,362],{"class":249},[227,384,385],{"class":365}," n_points",[227,387,369],{"class":249},[227,389,373],{"class":372},[227,391,376],{"class":283},[227,393,394],{"class":379}," 512",[227,396,343],{"class":249},[227,398,400,403,406,409],{"class":229,"line":399},10,[227,401,402],{"class":372},"        super",[227,404,405],{"class":249},"().",[227,407,408],{"class":352},"__init__",[227,410,411],{"class":249},"()\n",[227,413,415,419,421,424,426,429,431,434],{"class":229,"line":414},11,[227,416,418],{"class":417},"s_hVV","        self",[227,420,200],{"class":249},[227,422,423],{"class":252},"net",[227,425,376],{"class":283},[227,427,428],{"class":237}," nn",[227,430,200],{"class":249},[227,432,433],{"class":291},"Sequential",[227,435,436],{"class":249},"(\n",[227,438,440,443,445,448,450,453,455,458,461,463,465,468],{"class":229,"line":439},12,[227,441,442],{"class":291},"            nn",[227,444,200],{"class":249},[227,446,447],{"class":291},"Linear",[227,449,295],{"class":249},[227,451,452],{"class":291},"latent_dim",[227,454,362],{"class":249},[227,456,457],{"class":379}," 256",[227,459,460],{"class":249},"),",[227,462,428],{"class":291},[227,464,200],{"class":249},[227,466,467],{"class":291},"ReLU",[227,469,470],{"class":249},"(),\n",[227,472,474,476,478,480,482,485,487,489,491,493,495,497],{"class":229,"line":473},13,[227,475,442],{"class":291},[227,477,200],{"class":249},[227,479,447],{"class":291},[227,481,295],{"class":249},[227,483,484],{"class":379},"256",[227,486,362],{"class":249},[227,488,394],{"class":379},[227,490,460],{"class":249},[227,492,428],{"class":291},[227,494,200],{"class":249},[227,496,467],{"class":291},[227,498,470],{"class":249},[227,500,502,504,506,508,510,513,515,518,521,524],{"class":229,"line":501},14,[227,503,442],{"class":291},[227,505,200],{"class":249},[227,507,447],{"class":291},[227,509,295],{"class":249},[227,511,512],{"class":379},"512",[227,514,362],{"class":249},[227,516,517],{"class":291}," n_points ",[227,519,520],{"class":283},"*",[227,522,523],{"class":379}," 3",[227,525,526],{"class":249},"),\n",[227,528,530],{"class":229,"line":529},15,[227,531,532],{"class":249},"        )\n",[227,534,536,538,540,543,545],{"class":229,"line":535},16,[227,537,418],{"class":417},[227,539,200],{"class":249},[227,541,542],{"class":252},"n_points",[227,544,376],{"class":283},[227,546,547],{"class":237}," n_points\n",[227,549,551],{"class":229,"line":550},17,[227,552,274],{"emptyLinePlaceholder":273},[227,554,556,558,562,564,566,568,571,573,575,577,580,583,586,588,590,592],{"class":229,"line":555},18,[227,557,349],{"class":326},[227,559,561],{"class":560},"sGLFI"," forward",[227,563,295],{"class":249},[227,565,359],{"class":358},[227,567,362],{"class":249},[227,569,570],{"class":365}," z",[227,572,369],{"class":249},[227,574,246],{"class":237},[227,576,200],{"class":249},[227,578,579],{"class":252},"Tensor",[227,581,582],{"class":249},")",[227,584,585],{"class":249}," ->",[227,587,246],{"class":237},[227,589,200],{"class":249},[227,591,579],{"class":252},[227,593,594],{"class":249},":\n",[227,596,598],{"class":229,"line":597},19,[227,599,600],{"class":319},"        # Returns (batch, n_points, 3)\n",[227,602,604,607,610,612,614,616,618,621,624,626,628,630,633,635,638,640,642,644,646,648,650],{"class":229,"line":603},20,[227,605,606],{"class":233},"        return",[227,608,609],{"class":417}," self",[227,611,200],{"class":249},[227,613,423],{"class":291},[227,615,295],{"class":249},[227,617,211],{"class":291},[227,619,620],{"class":249},").",[227,622,623],{"class":291},"reshape",[227,625,295],{"class":249},[227,627,211],{"class":291},[227,629,200],{"class":249},[227,631,632],{"class":291},"size",[227,634,295],{"class":249},[227,636,637],{"class":379},"0",[227,639,460],{"class":249},[227,641,609],{"class":417},[227,643,200],{"class":249},[227,645,542],{"class":252},[227,647,362],{"class":249},[227,649,523],{"class":379},[227,651,308],{"class":249},[227,653,655],{"class":229,"line":654},21,[227,656,274],{"emptyLinePlaceholder":273},[227,658,660,663,665,667,669,672,674,676],{"class":229,"line":659},22,[227,661,662],{"class":237},"decoder ",[227,664,284],{"class":283},[227,666,331],{"class":291},[227,668,405],{"class":249},[227,670,671],{"class":291},"to",[227,673,295],{"class":249},[227,675,292],{"class":291},[227,677,308],{"class":249},[227,679,681,684,686,688,690,693,695,698,700,703,705,708,711,715,717,720],{"class":229,"line":680},23,[227,682,683],{"class":237},"optimiser ",[227,685,284],{"class":283},[227,687,246],{"class":237},[227,689,200],{"class":249},[227,691,692],{"class":252},"optim",[227,694,200],{"class":249},[227,696,697],{"class":291},"Adam",[227,699,295],{"class":249},[227,701,702],{"class":291},"decoder",[227,704,200],{"class":249},[227,706,707],{"class":291},"parameters",[227,709,710],{"class":249},"(),",[227,712,714],{"class":713},"s99_P"," lr",[227,716,284],{"class":283},[227,718,719],{"class":379},"1e-4",[227,721,308],{"class":249},[202,723,725],{"id":724},"synthetic-target-distribution","Synthetic target distribution",[182,727,728],{},"For illustration, we use a fixed Gaussian mixture as the ground-truth shape. In a real\npipeline this would come from a dataset loader.",[218,730,732],{"className":220,"code":731,"language":222,"meta":223,"style":223},"def make_target(batch: int, n_pts: int, device: torch.device) -> torch.Tensor:\n    \"\"\"Synthetic 3-D point cloud: 4 Gaussian clusters on the unit sphere surface.\"\"\"\n    centres = torch.tensor([\n        [1.0, 0.0, 0.0], [-1.0, 0.0, 0.0],\n        [0.0, 1.0, 0.0], [0.0, -1.0, 0.0],\n    ], device=device)                               # (4, 3)\n    idx  = torch.randint(4, (batch, n_pts), device=device)\n    pts  = centres[idx] + 0.08 * torch.randn(batch, n_pts, 3, device=device)\n    return pts \u002F pts.norm(dim=-1, keepdim=True)     # project to sphere\n\n",[186,733,734,785,798,815,854,889,905,945,1002],{"__ignoreMap":223},[227,735,736,739,742,744,747,749,751,753,756,758,760,762,765,767,769,771,773,775,777,779,781,783],{"class":229,"line":230},[227,737,738],{"class":326},"def",[227,740,741],{"class":560}," make_target",[227,743,295],{"class":249},[227,745,746],{"class":365},"batch",[227,748,369],{"class":249},[227,750,373],{"class":372},[227,752,362],{"class":249},[227,754,755],{"class":365}," n_pts",[227,757,369],{"class":249},[227,759,373],{"class":372},[227,761,362],{"class":249},[227,763,764],{"class":365}," device",[227,766,369],{"class":249},[227,768,246],{"class":237},[227,770,200],{"class":249},[227,772,292],{"class":252},[227,774,582],{"class":249},[227,776,585],{"class":249},[227,778,246],{"class":237},[227,780,200],{"class":249},[227,782,579],{"class":252},[227,784,594],{"class":249},[227,786,787,791,795],{"class":229,"line":241},[227,788,790],{"class":789},"s2W-s","    \"\"\"",[227,792,794],{"class":793},"sithA","Synthetic 3-D point cloud: 4 Gaussian clusters on the unit sphere surface.",[227,796,797],{"class":789},"\"\"\"\n",[227,799,800,803,805,807,809,812],{"class":229,"line":262},[227,801,802],{"class":237},"    centres ",[227,804,284],{"class":283},[227,806,246],{"class":237},[227,808,200],{"class":249},[227,810,811],{"class":291},"tensor",[227,813,814],{"class":249},"([\n",[227,816,817,820,823,825,828,830,832,835,838,841,843,845,847,849,851],{"class":229,"line":270},[227,818,819],{"class":249},"        [",[227,821,822],{"class":379},"1.0",[227,824,362],{"class":249},[227,826,827],{"class":379}," 0.0",[227,829,362],{"class":249},[227,831,827],{"class":379},[227,833,834],{"class":249},"],",[227,836,837],{"class":249}," [",[227,839,840],{"class":283},"-",[227,842,822],{"class":379},[227,844,362],{"class":249},[227,846,827],{"class":379},[227,848,362],{"class":249},[227,850,827],{"class":379},[227,852,853],{"class":249},"],\n",[227,855,856,858,861,863,866,868,870,872,874,876,878,881,883,885,887],{"class":229,"line":277},[227,857,819],{"class":249},[227,859,860],{"class":379},"0.0",[227,862,362],{"class":249},[227,864,865],{"class":379}," 1.0",[227,867,362],{"class":249},[227,869,827],{"class":379},[227,871,834],{"class":249},[227,873,837],{"class":249},[227,875,860],{"class":379},[227,877,362],{"class":249},[227,879,880],{"class":283}," -",[227,882,822],{"class":379},[227,884,362],{"class":249},[227,886,827],{"class":379},[227,888,853],{"class":249},[227,890,891,894,896,898,900,902],{"class":229,"line":311},[227,892,893],{"class":249},"    ],",[227,895,764],{"class":713},[227,897,284],{"class":283},[227,899,292],{"class":291},[227,901,582],{"class":249},[227,903,904],{"class":319},"                               # (4, 3)\n",[227,906,907,910,912,914,916,919,921,924,926,929,931,933,935,937,939,941,943],{"class":229,"line":316},[227,908,909],{"class":237},"    idx  ",[227,911,284],{"class":283},[227,913,246],{"class":237},[227,915,200],{"class":249},[227,917,918],{"class":291},"randint",[227,920,295],{"class":249},[227,922,923],{"class":379},"4",[227,925,362],{"class":249},[227,927,928],{"class":249}," (",[227,930,746],{"class":291},[227,932,362],{"class":249},[227,934,755],{"class":291},[227,936,460],{"class":249},[227,938,764],{"class":713},[227,940,284],{"class":283},[227,942,292],{"class":291},[227,944,308],{"class":249},[227,946,947,950,952,955,958,961,964,967,970,973,975,977,980,982,984,986,988,990,992,994,996,998,1000],{"class":229,"line":323},[227,948,949],{"class":237},"    pts  ",[227,951,284],{"class":283},[227,953,954],{"class":237}," centres",[227,956,957],{"class":249},"[",[227,959,960],{"class":237},"idx",[227,962,963],{"class":249},"]",[227,965,966],{"class":283}," +",[227,968,969],{"class":379}," 0.08",[227,971,972],{"class":283}," *",[227,974,246],{"class":237},[227,976,200],{"class":249},[227,978,979],{"class":291},"randn",[227,981,295],{"class":249},[227,983,746],{"class":291},[227,985,362],{"class":249},[227,987,755],{"class":291},[227,989,362],{"class":249},[227,991,523],{"class":379},[227,993,362],{"class":249},[227,995,764],{"class":713},[227,997,284],{"class":283},[227,999,292],{"class":291},[227,1001,308],{"class":249},[227,1003,1004,1007,1010,1013,1016,1018,1021,1023,1026,1029,1032,1034,1037,1039,1043,1045],{"class":229,"line":346},[227,1005,1006],{"class":233},"    return",[227,1008,1009],{"class":237}," pts ",[227,1011,1012],{"class":283},"\u002F",[227,1014,1015],{"class":237}," pts",[227,1017,200],{"class":249},[227,1019,1020],{"class":291},"norm",[227,1022,295],{"class":249},[227,1024,1025],{"class":713},"dim",[227,1027,1028],{"class":283},"=-",[227,1030,1031],{"class":379},"1",[227,1033,362],{"class":249},[227,1035,1036],{"class":713}," keepdim",[227,1038,284],{"class":283},[227,1040,1042],{"class":1041},"s39Yj","True",[227,1044,582],{"class":249},[227,1046,1047],{"class":319},"     # project to sphere\n",[202,1049,1051],{"id":1050},"training-loop","Training loop",[218,1053,1055],{"className":220,"code":1054,"language":222,"meta":223,"style":223},"BATCH  = 16\nLATENT = 64\nN_PTS  = 512    # points per cloud\nBLUR   = 0.05   # Sinkhorn temperature\n\nfor step in range(1000):\n    z          = torch.randn(BATCH, LATENT, device=device)\n    gt_clouds  = make_target(BATCH, N_PTS, device)  # (B, N, 3)\n    pred_clouds = decoder(z)                         # (B, N, 3)\n\n    # transport.samples.loss operates on pairs of (N, D) tensors, so\n    # loop over the batch dimension (or use torch.vmap for batching).\n    total_loss = torch.tensor(0.0, device=device)\n    for pred, gt in zip(pred_clouds, gt_clouds):\n        total_loss = total_loss + torchmatch.transport.samples.loss(\n            pred, gt, blur=BLUR,\n        )\n    loss = total_loss \u002F BATCH\n\n    optimiser.zero_grad()\n    loss.backward()\n    optimiser.step()\n\n    if step % 100 == 0:\n        print(f'step {step:4d}  loss {loss.item():.4f}')\n",[186,1056,1057,1068,1078,1090,1104,1108,1129,1161,1188,1207,1211,1216,1221,1248,1278,1311,1333,1337,1351,1355,1367,1379,1390,1394,1416],{"__ignoreMap":223},[227,1058,1059,1062,1065],{"class":229,"line":230},[227,1060,1061],{"class":417},"BATCH",[227,1063,1064],{"class":283},"  =",[227,1066,1067],{"class":379}," 16\n",[227,1069,1070,1073,1075],{"class":229,"line":241},[227,1071,1072],{"class":417},"LATENT",[227,1074,376],{"class":283},[227,1076,1077],{"class":379}," 64\n",[227,1079,1080,1083,1085,1087],{"class":229,"line":262},[227,1081,1082],{"class":417},"N_PTS",[227,1084,1064],{"class":283},[227,1086,394],{"class":379},[227,1088,1089],{"class":319},"    # points per cloud\n",[227,1091,1092,1095,1098,1101],{"class":229,"line":270},[227,1093,1094],{"class":417},"BLUR",[227,1096,1097],{"class":283},"   =",[227,1099,1100],{"class":379}," 0.05",[227,1102,1103],{"class":319},"   # Sinkhorn temperature\n",[227,1105,1106],{"class":229,"line":277},[227,1107,274],{"emptyLinePlaceholder":273},[227,1109,1110,1113,1116,1119,1122,1124,1127],{"class":229,"line":311},[227,1111,1112],{"class":233},"for",[227,1114,1115],{"class":237}," step ",[227,1117,1118],{"class":233},"in",[227,1120,1121],{"class":352}," range",[227,1123,295],{"class":249},[227,1125,1126],{"class":379},"1000",[227,1128,343],{"class":249},[227,1130,1131,1134,1136,1138,1140,1142,1144,1146,1148,1151,1153,1155,1157,1159],{"class":229,"line":316},[227,1132,1133],{"class":237},"    z          ",[227,1135,284],{"class":283},[227,1137,246],{"class":237},[227,1139,200],{"class":249},[227,1141,979],{"class":291},[227,1143,295],{"class":249},[227,1145,1061],{"class":352},[227,1147,362],{"class":249},[227,1149,1150],{"class":352}," LATENT",[227,1152,362],{"class":249},[227,1154,764],{"class":713},[227,1156,284],{"class":283},[227,1158,292],{"class":291},[227,1160,308],{"class":249},[227,1162,1163,1166,1168,1170,1172,1174,1176,1179,1181,1183,1185],{"class":229,"line":323},[227,1164,1165],{"class":237},"    gt_clouds  ",[227,1167,284],{"class":283},[227,1169,741],{"class":291},[227,1171,295],{"class":249},[227,1173,1061],{"class":352},[227,1175,362],{"class":249},[227,1177,1178],{"class":352}," N_PTS",[227,1180,362],{"class":249},[227,1182,764],{"class":291},[227,1184,582],{"class":249},[227,1186,1187],{"class":319},"  # (B, N, 3)\n",[227,1189,1190,1193,1195,1198,1200,1202,1204],{"class":229,"line":346},[227,1191,1192],{"class":237},"    pred_clouds ",[227,1194,284],{"class":283},[227,1196,1197],{"class":291}," decoder",[227,1199,295],{"class":249},[227,1201,211],{"class":291},[227,1203,582],{"class":249},[227,1205,1206],{"class":319},"                         # (B, N, 3)\n",[227,1208,1209],{"class":229,"line":399},[227,1210,274],{"emptyLinePlaceholder":273},[227,1212,1213],{"class":229,"line":414},[227,1214,1215],{"class":319},"    # transport.samples.loss operates on pairs of (N, D) tensors, so\n",[227,1217,1218],{"class":229,"line":439},[227,1219,1220],{"class":319},"    # loop over the batch dimension (or use torch.vmap for batching).\n",[227,1222,1223,1226,1228,1230,1232,1234,1236,1238,1240,1242,1244,1246],{"class":229,"line":473},[227,1224,1225],{"class":237},"    total_loss ",[227,1227,284],{"class":283},[227,1229,246],{"class":237},[227,1231,200],{"class":249},[227,1233,811],{"class":291},[227,1235,295],{"class":249},[227,1237,860],{"class":379},[227,1239,362],{"class":249},[227,1241,764],{"class":713},[227,1243,284],{"class":283},[227,1245,292],{"class":291},[227,1247,308],{"class":249},[227,1249,1250,1253,1256,1258,1261,1263,1266,1268,1271,1273,1276],{"class":229,"line":501},[227,1251,1252],{"class":233},"    for",[227,1254,1255],{"class":237}," pred",[227,1257,362],{"class":249},[227,1259,1260],{"class":237}," gt ",[227,1262,1118],{"class":233},[227,1264,1265],{"class":352}," zip",[227,1267,295],{"class":249},[227,1269,1270],{"class":291},"pred_clouds",[227,1272,362],{"class":249},[227,1274,1275],{"class":291}," gt_clouds",[227,1277,343],{"class":249},[227,1279,1280,1283,1285,1288,1291,1294,1296,1299,1301,1304,1306,1309],{"class":229,"line":529},[227,1281,1282],{"class":237},"        total_loss ",[227,1284,284],{"class":283},[227,1286,1287],{"class":237}," total_loss ",[227,1289,1290],{"class":283},"+",[227,1292,1293],{"class":237}," torchmatch",[227,1295,200],{"class":249},[227,1297,1298],{"class":252},"transport",[227,1300,200],{"class":249},[227,1302,1303],{"class":252},"samples",[227,1305,200],{"class":249},[227,1307,1308],{"class":291},"loss",[227,1310,436],{"class":249},[227,1312,1313,1316,1318,1321,1323,1326,1328,1330],{"class":229,"line":535},[227,1314,1315],{"class":291},"            pred",[227,1317,362],{"class":249},[227,1319,1320],{"class":291}," gt",[227,1322,362],{"class":249},[227,1324,1325],{"class":713}," blur",[227,1327,284],{"class":283},[227,1329,1094],{"class":352},[227,1331,1332],{"class":249},",\n",[227,1334,1335],{"class":229,"line":550},[227,1336,532],{"class":249},[227,1338,1339,1342,1344,1346,1348],{"class":229,"line":555},[227,1340,1341],{"class":237},"    loss ",[227,1343,284],{"class":283},[227,1345,1287],{"class":237},[227,1347,1012],{"class":283},[227,1349,1350],{"class":417}," BATCH\n",[227,1352,1353],{"class":229,"line":597},[227,1354,274],{"emptyLinePlaceholder":273},[227,1356,1357,1360,1362,1365],{"class":229,"line":603},[227,1358,1359],{"class":237},"    optimiser",[227,1361,200],{"class":249},[227,1363,1364],{"class":291},"zero_grad",[227,1366,411],{"class":249},[227,1368,1369,1372,1374,1377],{"class":229,"line":654},[227,1370,1371],{"class":237},"    loss",[227,1373,200],{"class":249},[227,1375,1376],{"class":291},"backward",[227,1378,411],{"class":249},[227,1380,1381,1383,1385,1388],{"class":229,"line":659},[227,1382,1359],{"class":237},[227,1384,200],{"class":249},[227,1386,1387],{"class":291},"step",[227,1389,411],{"class":249},[227,1391,1392],{"class":229,"line":680},[227,1393,274],{"emptyLinePlaceholder":273},[227,1395,1397,1400,1402,1405,1408,1411,1414],{"class":229,"line":1396},24,[227,1398,1399],{"class":233},"    if",[227,1401,1115],{"class":237},[227,1403,1404],{"class":283},"%",[227,1406,1407],{"class":379}," 100",[227,1409,1410],{"class":283}," ==",[227,1412,1413],{"class":379}," 0",[227,1415,594],{"class":249},[227,1417,1419,1422,1424,1427,1430,1433,1435,1438,1441,1444,1446,1448,1450,1453,1456,1459,1461,1463],{"class":229,"line":1418},25,[227,1420,1421],{"class":352},"        print",[227,1423,295],{"class":249},[227,1425,1426],{"class":326},"f",[227,1428,1429],{"class":302},"'step ",[227,1431,1432],{"class":379},"{",[227,1434,1387],{"class":291},[227,1436,1437],{"class":326},":4d",[227,1439,1440],{"class":379},"}",[227,1442,1443],{"class":302},"  loss ",[227,1445,1432],{"class":379},[227,1447,1308],{"class":291},[227,1449,200],{"class":249},[227,1451,1452],{"class":291},"item",[227,1454,1455],{"class":249},"()",[227,1457,1458],{"class":326},":.4f",[227,1460,1440],{"class":379},[227,1462,299],{"class":302},[227,1464,308],{"class":249},[202,1466,1468],{"id":1467},"using-the-sinkhorn-divergence","Using the Sinkhorn divergence",[182,1470,1471,1472,1475,1476,1479,1480,1483,1484,1487,1488,1490,1491,1494],{},"The Sinkhorn solver approximates the true Wasserstein loss by adding an entropy term controlled by ",[186,1473,1474],{},"ε"," (equivalently, ",[186,1477,1478],{},"blur²","). This approximation has two side-effects: the raw Sinkhorn loss ",[186,1481,1482],{},"S_ε(x, y)"," is not symmetric and does not vanish when ",[186,1485,1486],{},"x == y"," for\nfinite ",[186,1489,1474],{},". The ",[193,1492,1493],{},"debiased Sinkhorn divergence"," corrects both properties:",[182,1496,1497],{},[186,1498,1499],{},"D_ε(x, y) = S_ε(x, y) − ½ S_ε(x, x) − ½ S_ε(y, y)",[182,1501,1502,1503,1506],{},"Pass ",[186,1504,1505],{},"debias=True"," to use it. Each loss call makes three forward solver calls, which is\nroughly 3× slower but yields a proper divergence.",[218,1508,1510],{"className":220,"code":1509,"language":222,"meta":223,"style":223},"loss = torchmatch.transport.samples.loss(pred, gt, blur=BLUR, debias=True)\n",[186,1511,1512],{"__ignoreMap":223},[227,1513,1514,1517,1519,1521,1523,1525,1527,1529,1531,1533,1535,1538,1540,1542,1544,1546,1548,1550,1552,1555,1557,1559],{"class":229,"line":230},[227,1515,1516],{"class":237},"loss ",[227,1518,284],{"class":283},[227,1520,1293],{"class":237},[227,1522,200],{"class":249},[227,1524,1298],{"class":252},[227,1526,200],{"class":249},[227,1528,1303],{"class":252},[227,1530,200],{"class":249},[227,1532,1308],{"class":291},[227,1534,295],{"class":249},[227,1536,1537],{"class":291},"pred",[227,1539,362],{"class":249},[227,1541,1320],{"class":291},[227,1543,362],{"class":249},[227,1545,1325],{"class":713},[227,1547,284],{"class":283},[227,1549,1094],{"class":352},[227,1551,362],{"class":249},[227,1553,1554],{"class":713}," debias",[227,1556,284],{"class":283},[227,1558,1042],{"class":1041},[227,1560,308],{"class":249},[182,1562,1563,1564,1566],{},"Use ",[186,1565,1505],{}," when:",[1568,1569,1570,1574],"ul",{},[1571,1572,1573],"li",{},"the loss value needs to compare meaningfully across training (it equals zero when the two clouds match, making values comparable across iterations)",[1571,1575,1576],{},"the loss must equal zero when predicted and ground-truth clouds are identical (e.g., when reporting the loss as a validation metric)",[182,1578,1579,1580,1583],{},"Use the default (",[186,1581,1582],{},"debias=False",") when training speed matters. The bias shifts loss values by a constant that depends only on each cloud individually, which usually does not change the direction of the gradient.",[202,1585,1587],{"id":1586},"handling-outliers-with-unbalanced-ot","Handling outliers with unbalanced OT",[182,1589,1590,1591,1594],{},"Standard OT requires every predicted point to be fully matched to some ground-truth point, so outliers are forced to pair with the nearest GT point and inflate the loss. Unbalanced OT relaxes this requirement via a ",[186,1592,1593],{},"reach"," parameter: points that are far from any counterpart are allowed to go unmatched, at a penalty proportional to how much mass is left unaccounted for.",[218,1596,1598],{"className":220,"code":1597,"language":222,"meta":223,"style":223},"loss = torchmatch.transport.samples.loss(\n    pred, gt,\n    blur=BLUR,\n    reach=0.5,  # smaller reach → more outlier tolerance\n)\n",[186,1599,1600,1622,1633,1644,1659],{"__ignoreMap":223},[227,1601,1602,1604,1606,1608,1610,1612,1614,1616,1618,1620],{"class":229,"line":230},[227,1603,1516],{"class":237},[227,1605,284],{"class":283},[227,1607,1293],{"class":237},[227,1609,200],{"class":249},[227,1611,1298],{"class":252},[227,1613,200],{"class":249},[227,1615,1303],{"class":252},[227,1617,200],{"class":249},[227,1619,1308],{"class":291},[227,1621,436],{"class":249},[227,1623,1624,1627,1629,1631],{"class":229,"line":241},[227,1625,1626],{"class":291},"    pred",[227,1628,362],{"class":249},[227,1630,1320],{"class":291},[227,1632,1332],{"class":249},[227,1634,1635,1638,1640,1642],{"class":229,"line":262},[227,1636,1637],{"class":713},"    blur",[227,1639,284],{"class":283},[227,1641,1094],{"class":352},[227,1643,1332],{"class":249},[227,1645,1646,1649,1651,1654,1656],{"class":229,"line":270},[227,1647,1648],{"class":713},"    reach",[227,1650,284],{"class":283},[227,1652,1653],{"class":379},"0.5",[227,1655,362],{"class":249},[227,1657,1658],{"class":319},"  # smaller reach → more outlier tolerance\n",[227,1660,1661],{"class":229,"line":277},[227,1662,308],{"class":249},[182,1664,1665],{},"Or use asymmetric reach when only one side has outliers:",[218,1667,1669],{"className":220,"code":1668,"language":222,"meta":223,"style":223},"loss = torchmatch.transport.samples.loss(\n    pred, gt,\n    blur=BLUR,\n    reach_x=0.3,  # predicted cloud has outliers; relax source marginal\n    # reach_y left at None → target marginal is exact\n)\n",[186,1670,1671,1693,1703,1713,1728,1733],{"__ignoreMap":223},[227,1672,1673,1675,1677,1679,1681,1683,1685,1687,1689,1691],{"class":229,"line":230},[227,1674,1516],{"class":237},[227,1676,284],{"class":283},[227,1678,1293],{"class":237},[227,1680,200],{"class":249},[227,1682,1298],{"class":252},[227,1684,200],{"class":249},[227,1686,1303],{"class":252},[227,1688,200],{"class":249},[227,1690,1308],{"class":291},[227,1692,436],{"class":249},[227,1694,1695,1697,1699,1701],{"class":229,"line":241},[227,1696,1626],{"class":291},[227,1698,362],{"class":249},[227,1700,1320],{"class":291},[227,1702,1332],{"class":249},[227,1704,1705,1707,1709,1711],{"class":229,"line":262},[227,1706,1637],{"class":713},[227,1708,284],{"class":283},[227,1710,1094],{"class":352},[227,1712,1332],{"class":249},[227,1714,1715,1718,1720,1723,1725],{"class":229,"line":270},[227,1716,1717],{"class":713},"    reach_x",[227,1719,284],{"class":283},[227,1721,1722],{"class":379},"0.3",[227,1724,362],{"class":249},[227,1726,1727],{"class":319},"  # predicted cloud has outliers; relax source marginal\n",[227,1729,1730],{"class":229,"line":277},[227,1731,1732],{"class":319},"    # reach_y left at None → target marginal is exact\n",[227,1734,1735],{"class":229,"line":311},[227,1736,308],{"class":249},[202,1738,1740,1741],{"id":1739},"choosing-blur","Choosing ",[186,1742,1743],{},"blur",[182,1745,1746,1748,1749,1751],{},[186,1747,1743],{}," controls the smoothness of the transport plan. Larger values assign mass more diffusely and make the loss faster to compute but less sensitive to fine-grained geometry. It equals the square root of the regularisation strength ",[186,1750,1474],{}," used in the algorithm. Practical ranges:",[1753,1754,1755,1770],"table",{},[1756,1757,1758],"thead",{},[1759,1760,1761,1765],"tr",{},[1762,1763,1764],"th",{},"Point cloud scale",[1762,1766,1767,1768],{},"Suggested ",[186,1769,1743],{},[1771,1772,1773,1782,1790],"tbody",{},[1759,1774,1775,1779],{},[1776,1777,1778],"td",{},"Unit sphere, O(1) coordinate range",[1776,1780,1781],{},"0.05 – 0.2",[1759,1783,1784,1787],{},[1776,1785,1786],{},"Centred, O(10) range",[1776,1788,1789],{},"0.5 – 2.0",[1759,1791,1792,1795],{},[1776,1793,1794],{},"Centred, O(100) range",[1776,1796,1797],{},"5 – 20",[182,1799,1800,1801,1803,1804,200],{},"To set ",[186,1802,1743],{}," automatically: normalise the point clouds to zero-mean unit variance before\ncomputing the loss, and fix ",[186,1805,1806],{},"blur=0.05",[202,1808,1810],{"id":1809},"performance-notes","Performance notes",[1568,1812,1813,1822,1827],{},[1571,1814,1815,1817,1818,1821],{},[186,1816,188],{}," materialises no ",[186,1819,1820],{},"N × M"," cost matrix. The Triton streaming\nkernel computes pairwise costs tile by tile without ever storing the full N×M matrix, keeping memory use proportional to N+M rather than N×M.",[1571,1823,1824,1825,200],{},"For the balanced case, a single forward + backward pass over 512-point clouds costs\nabout 0.5–2 ms on an A100 depending on ",[186,1826,1743],{},[1571,1828,1829,1830,1833],{},"Loop over the batch dimension (as in the example above) or use ",[186,1831,1832],{},"torch.vmap"," for batching.\nA native batched samples face is planned.",[202,1835,1837],{"id":1836},"see-also","See also",[1568,1839,1840,1846,1854],{},[1571,1841,1842,1845],{},[1843,1844,9],"a",{"href":72}," — the mathematical derivation of Sinkhorn and debiasing.",[1571,1847,1848,1850,1851,200],{},[1843,1849,33],{"href":75}," — full signature for ",[186,1852,1853],{},"samples.loss",[1571,1855,1856,1858,1859,1861,1862,200],{},[1843,1857,37],{"href":78}," — when ",[186,1860,1853],{}," beats ",[186,1863,1864],{},"matrix.solve",[1866,1867,1868],"style",{},"html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .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 .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .slqww, html code.shiki .slqww{--shiki-light:#6182B8;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .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 .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}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 .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 .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .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 .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":223,"searchDepth":262,"depth":262,"links":1870},[1871,1872,1873,1874,1875,1876,1877,1879,1880],{"id":204,"depth":241,"text":205},{"id":215,"depth":241,"text":216},{"id":724,"depth":241,"text":725},{"id":1050,"depth":241,"text":1051},{"id":1467,"depth":241,"text":1468},{"id":1586,"depth":241,"text":1587},{"id":1739,"depth":241,"text":1878},"Choosing blur",{"id":1809,"depth":241,"text":1810},{"id":1836,"depth":241,"text":1837},"End-to-end tutorial — computing and differentiating a Wasserstein loss between two 3D point clouds using transport.samples.loss.","md",{},{"title":68},{"title":176,"description":1881},"NkzwjyPHVWYFvaBU-aCT4uKvZEUYT6FxAgwa7xWNoAY",[1888,1890],{"title":22,"path":65,"stem":66,"description":1889,"children":-1},"First use of transport.matrix.solve and transport.samples.loss — install, import, and compute your first OT plan.",{"title":9,"path":72,"stem":73,"description":1891,"children":-1},"The optimal transport problem, Sinkhorn, debiasing, unbalanced OT, and the network simplex — plus how the matrix-face Python LSE loops and the samples-face Triton streaming kernel implement them.",1785218164314]