使用 cuTensorNet 执行门分裂操作采用了与 QR 示例SVD 示例 非常相似的工作流程。在此,我们重点介绍两个 API 之间的显着差异。完整代码可以在 NVIDIA/cuQuantum 存储库中找到(此处)。

定义张量操作数

与 QR/SVD 分解一样,我们首先通过指定数据类型、模式分区和范围来定义所有张量操作数。在此过程中,我们选择执行固定范围截断,大小为 16。

 84   /************************************************************************************
 85   * Gate Split: A_{i,j,k,l} B_{k,o,p,q} G_{m,n,l,o}-> A'_{i,j,x,m} S_{x} B'_{x,n,p,q}  
 86   *************************************************************************************/
 87   typedef float floatType;
 88   cudaDataType_t typeData = CUDA_R_32F;
 89   cutensornetComputeType_t typeCompute = CUTENSORNET_COMPUTE_32F;
 90
 91   // Create vector of modes
 92   std::vector<int32_t> modesAIn{'i','j','k','l'};
 93   std::vector<int32_t> modesBIn{'k','o','p','q'};
 94   std::vector<int32_t> modesGIn{'m','n','l','o'}; // input, G is the gate operator
 95
 96   std::vector<int32_t> modesAOut{'i','j','x','m'}; 
 97   std::vector<int32_t> modesBOut{'x','n','p','q'}; // SVD output
 98
 99   // Extents
100   std::unordered_map<int32_t, int64_t> extent;
101   extent['i'] = 16;
102   extent['j'] = 16;
103   extent['k'] = 16;
104   extent['l'] = 2;
105   extent['m'] = 2;
106   extent['n'] = 2;
107   extent['o'] = 2;
108   extent['p'] = 16;
109   extent['q'] = 16;
110   
111   const int64_t maxExtent = 16; //truncate to a maximal extent of 16
112   extent['x'] = maxExtent;
113
114   // Create a vector of extents for each tensor
115   std::vector<int64_t> extentAIn;
116   for (auto mode : modesAIn)
117      extentAIn.push_back(extent[mode]);
118   std::vector<int64_t> extentBIn;
119   for (auto mode : modesBIn)
120      extentBIn.push_back(extent[mode]);
121   std::vector<int64_t> extentGIn;
122   for (auto mode : modesGIn)
123      extentGIn.push_back(extent[mode]);
124   std::vector<int64_t> extentAOut;
125   for (auto mode : modesAOut)
126      extentAOut.push_back(extent[mode]);
127   std::vector<int64_t> extentBOut;
128   for (auto mode : modesBOut)
129      extentBOut.push_back(extent[mode]);
130   

执行

SVD 示例 类似,我们可以在 cutensornetTensorSVDConfig_t 中指定 SVD 选项。可以通过调用 cutensornetWorkspaceComputeGateSplitSizes() 和提供的 cutensornetGateSplitAlgo_t 来实现工作区大小查询。最后,我们可以通过调用 cutensornetGateSplit() 来执行门分裂计算。

299   /**********************
300   * Execution
301   **********************/
302
303   GPUTimer timer{stream};
304   double minTimeCUTENSOR = 1e100;
305   const int numRuns = 3; // to get stable perf results
306   for (int i=0; i < numRuns; ++i)
307   {  
308      // restore output
309      cudaMemsetAsync(D_AOut, 0, sizeAOut, stream);
310      cudaMemsetAsync(D_S, 0, sizeS, stream);
311      cudaMemsetAsync(D_BOut, 0, sizeBOut, stream);
312
313      // With value-based truncation, `cutensornetGateSplit` can potentially update the shared extent in descTensorA/BOut.
314      // We here restore descTensorA/BOut to the original problem.
315      HANDLE_ERROR( cutensornetDestroyTensorDescriptor(descTensorAOut) );
316      HANDLE_ERROR( cutensornetDestroyTensorDescriptor(descTensorBOut) );
317      HANDLE_ERROR( cutensornetCreateTensorDescriptor(handle, numModesAOut, extentAOut.data(), strides, modesAOut.data(), typeData, &descTensorAOut) );
318      HANDLE_ERROR( cutensornetCreateTensorDescriptor(handle, numModesBOut, extentBOut.data(), strides, modesBOut.data(), typeData, &descTensorBOut) );
319
320      cudaDeviceSynchronize();
321      timer.start();
322      HANDLE_ERROR( cutensornetGateSplit(handle, 
323                                         descTensorAIn, D_AIn,
324                                         descTensorBIn, D_BIn,
325                                         descTensorGIn, D_GIn,
326                                         descTensorAOut, D_AOut,
327                                         D_S,
328                                         descTensorBOut, D_BOut,
329                                         gateAlgo,
330                                         svdConfig, typeCompute, svdInfo, 
331                                         workDesc, stream) );
332      // Synchronize and measure timing
333      auto time = timer.seconds();
334      minTimeCUTENSOR = (minTimeCUTENSOR < time) ? minTimeCUTENSOR : time;
335   }
336
337   printf("Performing Gate Split\n");

注意

cutensornetTensorSVD() 中一样,由于我们在本示例中启用了加权截断选项,如果我们希望多次执行相同的计算,则需要恢复输出 A 和 B 的张量描述符。

计算完成后,我们始终需要释放所有资源。