|
20 | 20 |
|
21 | 21 | #pragma once
|
22 | 22 |
|
| 23 | +#include <algorithm> |
23 | 24 | #include <complex>
|
24 | 25 | #include <cuComplex.h>
|
25 | 26 | #include <cutensornet.h>
|
@@ -164,6 +165,97 @@ template <class TensorNetT> class MeasurementsTNCuda {
|
164 | 165 | return h_res;
|
165 | 166 | }
|
166 | 167 |
|
| 168 | + /** |
| 169 | + * @brief Utility method for samples. |
| 170 | + * |
| 171 | + * @param wires Wires can be a subset or the full system. |
| 172 | + * @param num_samples Number of samples |
| 173 | + * @param numHyperSamples Number of hyper samples to use in the calculation |
| 174 | + * and is default as 1. |
| 175 | + * |
| 176 | + * @return std::vector<std::size_t> A 1-d array storing the samples. |
| 177 | + * Each sample has a length equal to the number of wires. Each sample can |
| 178 | + * be accessed using the stride `sample_id * num_wires`, where `sample_id` |
| 179 | + * is a number between `0` and `num_samples - 1`. |
| 180 | + */ |
| 181 | + auto generate_samples(const std::vector<std::size_t> &wires, |
| 182 | + const std::size_t num_samples, |
| 183 | + const int32_t numHyperSamples = 1) |
| 184 | + -> std::vector<std::size_t> { |
| 185 | + std::vector<int64_t> samples(num_samples * wires.size()); |
| 186 | + |
| 187 | + const std::vector<int32_t> modesToSample = |
| 188 | + cuUtil::NormalizeCastIndices<std::size_t, int32_t>( |
| 189 | + wires, tensor_network_.getNumQubits()); |
| 190 | + |
| 191 | + cutensornetStateSampler_t sampler; |
| 192 | + |
| 193 | + PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateSampler( |
| 194 | + /* const cutensornetHandle_t */ tensor_network_.getTNCudaHandle(), |
| 195 | + /* cutensornetState_t */ tensor_network_.getQuantumState(), |
| 196 | + /* int32_t numModesToSample */ modesToSample.size(), |
| 197 | + /* const int32_t *modesToSample */ modesToSample.data(), |
| 198 | + /* cutensornetStateSampler_t * */ &sampler)); |
| 199 | + |
| 200 | + // Configure the quantum circuit sampler |
| 201 | + const cutensornetSamplerAttributes_t samplerAttributes = |
| 202 | + CUTENSORNET_SAMPLER_CONFIG_NUM_HYPER_SAMPLES; |
| 203 | + |
| 204 | + PL_CUTENSORNET_IS_SUCCESS(cutensornetSamplerConfigure( |
| 205 | + /* const cutensornetHandle_t */ tensor_network_.getTNCudaHandle(), |
| 206 | + /* cutensornetStateSampler_t */ sampler, |
| 207 | + /* cutensornetSamplerAttributes_t */ samplerAttributes, |
| 208 | + /* const void *attributeValue */ &numHyperSamples, |
| 209 | + /* size_t attributeSize */ sizeof(numHyperSamples))); |
| 210 | + |
| 211 | + cutensornetWorkspaceDescriptor_t workDesc; |
| 212 | + PL_CUTENSORNET_IS_SUCCESS(cutensornetCreateWorkspaceDescriptor( |
| 213 | + /* const cutensornetHandle_t */ tensor_network_.getTNCudaHandle(), |
| 214 | + /* cutensornetWorkspaceDescriptor_t * */ &workDesc)); |
| 215 | + |
| 216 | + const std::size_t scratchSize = cuUtil::getFreeMemorySize() / 2; |
| 217 | + |
| 218 | + // Prepare the quantum circuit sampler for sampling |
| 219 | + PL_CUTENSORNET_IS_SUCCESS(cutensornetSamplerPrepare( |
| 220 | + /* const cutensornetHandle_t */ tensor_network_.getTNCudaHandle(), |
| 221 | + /* cutensornetStateSampler_t */ sampler, |
| 222 | + /* size_t maxWorkspaceSizeDevice */ scratchSize, |
| 223 | + /* cutensornetWorkspaceDescriptor_t */ workDesc, |
| 224 | + /* cudaStream_t unused as of v24.08 */ 0x0)); |
| 225 | + |
| 226 | + std::size_t worksize = |
| 227 | + getWorkSpaceMemorySize(tensor_network_.getTNCudaHandle(), workDesc); |
| 228 | + |
| 229 | + PL_ABORT_IF(worksize > scratchSize, |
| 230 | + "Insufficient workspace size on Device.\n"); |
| 231 | + |
| 232 | + const std::size_t d_scratch_length = worksize / sizeof(size_t) + 1; |
| 233 | + DataBuffer<std::size_t> d_scratch(d_scratch_length, |
| 234 | + tensor_network_.getDevTag(), true); |
| 235 | + |
| 236 | + setWorkSpaceMemory(tensor_network_.getTNCudaHandle(), workDesc, |
| 237 | + reinterpret_cast<void *>(d_scratch.getData()), |
| 238 | + worksize); |
| 239 | + |
| 240 | + PL_CUTENSORNET_IS_SUCCESS(cutensornetSamplerSample( |
| 241 | + /* const cutensornetHandle_t */ tensor_network_.getTNCudaHandle(), |
| 242 | + /* cutensornetStateSampler_t */ sampler, |
| 243 | + /* int64_t numShots */ num_samples, |
| 244 | + /* cutensornetWorkspaceDescriptor_t */ workDesc, |
| 245 | + /* int64_t * */ samples.data(), |
| 246 | + /* cudaStream_t unused as of v24.08 */ 0x0)); |
| 247 | + |
| 248 | + PL_CUTENSORNET_IS_SUCCESS( |
| 249 | + cutensornetDestroyWorkspaceDescriptor(workDesc)); |
| 250 | + PL_CUTENSORNET_IS_SUCCESS(cutensornetDestroySampler(sampler)); |
| 251 | + |
| 252 | + std::vector<std::size_t> samples_size_t(samples.size()); |
| 253 | + |
| 254 | + std::transform(samples.begin(), samples.end(), samples_size_t.begin(), |
| 255 | + [](int64_t x) { return static_cast<std::size_t>(x); }); |
| 256 | + return samples_size_t; |
| 257 | + } |
| 258 | + |
167 | 259 | /**
|
168 | 260 | * @brief Calculate var value for a general ObservableTNCuda Observable.
|
169 | 261 | *
|
|
0 commit comments