The Quantum Exact Simulation Toolkit v4.1.0
Loading...
Searching...
No Matches
qureg.h
1/** @file
2 * API signatures for creating and managing Quregs.
3 *
4 * @author Tyson Jones
5 *
6 * @defgroup qureg Qureg
7 * @ingroup api
8 * @brief Data structures for representing quantum states.
9 * @{
10 */
11
12#ifndef QUREG_H
13#define QUREG_H
14
15#include "quest/include/types.h"
16
17
18
19/*
20 * These signatures are divided into three partitions; those which are
21 * natively C and C++ compatible (first partition), then those which are
22 * only exposed to C++ (second partition) because they return 'qcomp'
23 * which cannot cross the C++-to-C ABI, then C++only convenience functions.
24 * The first partition defines the doc groups, and the latter partition
25 * functions are added into them.
26 */
27
28
29
30/*
31 * C and C++ AGNOSTIC FUNCTIONS
32 */
33
34// enable invocation by both C and C++ binaries
35#ifdef __cplusplus
36extern "C" {
37#endif
38
39
40
41/**
42 * @defgroup qureg_structs Structs
43 * @brief Data structures for representing quantum registers.
44 * @{
45 */
46
47
48/// @notyetdoced
49typedef struct {
50
51 // deployment configuration
52 int isMultithreaded;
53 int isGpuAccelerated;
54 int isDistributed;
55
56 // distributed configuration
57 int rank;
58 int numNodes;
59 int logNumNodes;
60
61 // dimension
62 int isDensityMatrix;
63 int numQubits;
64 qindex numAmps;
65 qindex logNumAmps;
66
67 // distributed load
68 qindex numAmpsPerNode;
69 qindex logNumAmpsPerNode;
70 qindex logNumColsPerNode;
71
72 // amplitudes in CPU and GPU memory
73 qcomp* cpuAmps;
74 qcomp* gpuAmps;
75
76 // communication buffer in CPU and GPU memory
77 qcomp* cpuCommBuffer;
78 qcomp* gpuCommBuffer;
79
80} Qureg;
81
82/** @} */
83
84
85
86/**
87 * @defgroup qureg_create Constructors
88 * @brief Functions for creating statevectors and density matrices.
89 * @{
90 */
91
92
93/** Creates a statevector containing @p numQubits qubits, with automatically chosen deployments,
94 * initialised in the zero state.
95 *
96 * The chosen deployments (multithreading, GPU-acceleration and distribution) are informed by
97 * which facilities are compiled, available at runtime, beneficial for the specified Qureg size,
98 * and whether the necessary additional memory structures can fit in accelerators and buffers.
99 *
100 * @par State
101 * Let @f$ N = @f$ @p numQubits. The returned Qureg contains @f$ 2^N @f$ amplitudes, each represented
102 * by a @c qcomp, initialised to state
103 * @f[
104 \ket{0}^{\otimes N}
105 \;\; = \;\;
106 \{ 1, \, 0, \, 0, \, \dots, \, 0 \}.
107 * @f]
108 *
109 * @par Memory
110 * The total allocated memory will depend upon the automatically chosen deployments, since
111 * use of GPU-acceleration requires persistent device memory and distribution necessitates
112 * allocating communication buffers. See createCustomQureg() for more information.
113 *
114 * @equivalences
115 * - This function is equivalent to calling createCustomQureg(), passing @c isDensMatr=0 and @c -1
116 * for all deployments to automate them.
117 * ```
118 Qureg qureg = createCustomQureg(numQubits, 0, -1, -1, -1);
119 * ```
120 * @myexample
121 * ```
122 Qureg qureg = createQureg(30);
123 reportQuregParams(qureg);
124 * ```
125 * @param[in] numQubits the number of qubits in the output Qureg.
126 * @returns A new Qureg instance.
127 * @throws @validationerror
128 * - if @p numQubits < 1
129 * - if the Qureg dimensions would overflow the @c qindex type.
130 * - if the total Qureg memory would overflow the @c size_t type.
131 * - if the system contains insufficient RAM (or VRAM) to store the Qureg in any deployment.
132 * - if any memory allocation unexpectedly fails.
133 * @notyetvalidated
134 * @see
135 * - createDensityQureg() to create a density matrix which can additionally undergo decoherence.
136 * - createForcedQureg() to create a statevector which is forced to make use of all available deployments.
137 * - createCustomQureg() to explicitly set the used deployments.
138 * @author Tyson Jones
139 */
140Qureg createQureg(int numQubits);
141
142
143/** Creates a density matrix containing @p numQubits qubits, with automatically chosen deployments,
144 * initialised in the zero state.
145 *
146 * The chosen deployments (multithreading, GPU-acceleration and distribution) are informed by
147 * which facilities are compiled, available at runtime, beneficial for the specified Qureg size,
148 * and whether the necessary additional memory structures can fit in accelerators and buffers.
149 *
150 * @par State
151 * Let @f$ N = @f$ @p numQubits. The returned Qureg contains @f$ 2^N \times 2^N @f$ amplitudes, each
152 * represented by a @c qcomp, initialised to state
153 * @f[
154 \ket{0}\bra{0}^{\otimes N}
155 \;\; = \;\;
156 \begin{pmatrix}
157 1 & 0 & \dots \\
158 0 & 0 & \\
159 \vdots & & \ddots
160 \end{pmatrix}.
161 * @f]
162 *
163 * @par Memory
164 * A density matrix contains _square_ as many amplitudes as the equal-dimension statevector.
165 * The total allocated memory will depend upon the automatically chosen deployments, since
166 * use of GPU-acceleration requires persistent device memory and distribution necessitates
167 * allocating communication buffers. See createCustomQureg() for more information.
168 *
169 * @equivalences
170 * - This function is equivalent to calling createCustomQureg(), passing @c isDensMatr=1 and @c -1
171 * for all deployments to automate them.
172 * ```
173 Qureg qureg = createCustomQureg(numQubits, 1, -1, -1, -1);
174 * ```
175 * @myexample
176 * ```
177 Qureg qureg = createDensityQureg(15);
178 reportQuregParams(qureg);
179 * ```
180 * @param[in] numQubits the number of qubits in the output Qureg.
181 * @returns A new Qureg instance.
182 * @throws @validationerror
183 * - if @p numQubits < 1
184 * - if the Qureg dimensions would overflow the @c qindex type.
185 * - if the total Qureg memory would overflow the @c size_t type.
186 * - if the system contains insufficient RAM (or VRAM) to store the Qureg in any deployment.
187 * - if any memory allocation unexpectedly fails.
188 * @notyetvalidated
189 * @see
190 * - createQureg() to create a quadratically-smaller statevector Qureg which cannot undergo decoherence.
191 * - createForcedDensityQureg() to create a density matrix which is forced to make use of all available deployments.
192 * - createCustomQureg() to explicitly set the used deployments.
193 * @author Tyson Jones
194 */
195Qureg createDensityQureg(int numQubits);
196
197
198/** @notyetdoced
199 *
200 * @equivalences
201 * - This function is equivalent to calling createCustomQureg(), passing @c isDensMatr=0 and all
202 * deployments enabled by the QuEST environment.
203 * ```
204 QuESTEnv env = getQuESTEnv();
205 Qureg qureg = createCustomQureg(
206 numQubits, 0,
207 env.isDistributed,
208 env.isGpuAccelerated,
209 env.isMultithreaded);
210 * ```
211 */
212Qureg createForcedQureg(int numQubits);
213
214
215/** @notyetdoced
216 *
217 * @equivalences
218 * - This function is equivalent to calling createCustomQureg(), passing @c isDensMatr=1 and all
219 * deployments enabled by the QuEST environment.
220 * ```
221 QuESTEnv env = getQuESTEnv();
222 Qureg qureg = createCustomQureg(
223 numQubits, 1,
224 env.isDistributed,
225 env.isGpuAccelerated,
226 env.isMultithreaded);
227 * ```
228 */
229Qureg createForcedDensityQureg(int numQubits);
230
231
232/** Creates a statevector or density matrix with the specified deployments, initialised
233 * in the zero state. This function is an alternative to createQureg() and createDensityQureg()
234 * which permits explicitly forcing, disabling, or automating particular deployments.
235 *
236 * @par State
237 * Parameters @p numQubits and @p isDensMatr respectively inform the dimension of the
238 * Qureg, and whether the Qureg is a density matrix or statevector.
239 *
240 * Let @f$ N = @f$ @p numQubits.
241 * - When @p isDensMatr=0, the returned statevector contains @f$ 2^N @f$ amplitudes,
242 * initialised to state
243 * @f[
244 \ket{0}^{\otimes N}
245 \;\; = \;\;
246 \{ 1, \, 0, \, 0, \, \dots, \, 0 \}.
247 * @f]
248 * - When @p isDensMatr=1, the returned density matrix contains @f$ 2^{N}\times 2^{N} @f$ amplitudes,
249 * initialised to state
250 * @f[
251 \ket{0}\bra{0}^{\otimes N}
252 \;\; = \;\;
253 \begin{pmatrix}
254 1 & 0 & \dots \\
255 0 & 0 & \\
256 \vdots & & \ddots
257 \end{pmatrix}.
258 * @f]
259 *
260 * @par Deployments
261 * The remaining parameters decide the deployments used to accelerate the Qureg in subsequent
262 * simulation, and the associated additional memory allocations.
263 * - @p useDistrib indicates whether (@c =1) or not (@c =0) to distribute the Qureg's amplitudes
264 * across all available MPI nodes. This is suitable for Qureg which are too large to fit into a
265 * single node, and requires allocating an additional communication buffer per-node. When
266 * @c useDistrib=0 but the QuEST executable is launched in distributed settings, the Qureg
267 * amplitudes will be duplicated upon every node.
268 * - @p useGpuAccel indicates whether (@c =1) or not (@c =0) to GPU-accelerate the Qureg, and
269 * requires allocating additional persistent memory in the GPU VRAM. When combined with
270 * @c useDistrib=1, every node will allocate both communication buffers _and_ persistent GPU
271 * memory, and an additional persistent GPU-memory communication buffer.
272 * - @p useMultithread indicates whether (@c =1) or not (@c =0) to use multithreading when
273 * subsequently modifying the Qureg with a CPU routine. This requires no additional allocations,
274 * and typically has no effect when GPU acceleration is also enabled.
275 *
276 * The deployment parameters can also be @c -1 to let QuEST choose that parameter, taking into
277 * account the other forced deployments. While it is always safe to _disable_ a deployment,
278 * forcing a deployment which is invalid (e.g. because the device has insufficient free memory)
279 * will throw a validation error.
280 *
281 * @par Memory
282 * The total allocated memory depends on all parameters (_except_
283 * @p useMultithread), and the size of the variable-precision @c qcomp used to represent each
284 * amplitude. This is determined by preprocessor @c FLOAT_PRECISION via
285 *
286 * <center>
287 * | @c FLOAT_PRECISION | @c qcomp size (bytes) |
288 * | --- | --- |
289 * | 1 | 8 |
290 * | 2 | 16 |
291 * | 4 | 16, 20, 32 |
292 * </center>
293 * where the quad-precision size is platform specific, and is often the size of _two_
294 * `long double` primitives.
295 *
296 * Let:
297 * - @f$ N = @f$ @p numQubits
298 * - @f$ D=2^N @f$ or @f$ =2^{2N} @f$ (the total number of amplitudes in the state)
299 * - @f$ B = @f$ @c sizeof(qcomp) (the size in bytes)
300 * - @f$ W @f$ be the total number of distributed nodes (the "world size").
301 *
302 * The allocated CPU memory (RAM) and GPU memory (VRAM) is
303 *
304 * <center>
305 * | @p useDistrib | @p useGpuAccel | RAM per node | RAM total | VRAM per node | VRAM total | memory total |
306 * |---|---|---|---|---|---|---|
307 * | 0 | 0 | @f$ B \, D @f$ | @f$ W B \, D @f$ | 0 | 0 | @f$ W B \, D @f$ |
308 * | 0 | 1 | @f$ B \, D @f$ | @f$ W B \, D @f$ | @f$ B \, D @f$ | @f$ W B \, D @f$ | @f$ 2 \, W B \, D @f$ |
309 * | 1 | 0 | @f$ 2 \, B \, D \, / \, W @f$ | @f$ 2 \, B \, D @f$ | 0 | 0 | @f$ 2 \, B \, D @f$ |
310 * | 1 | 1 | @f$ 2 \, B \, D \, / \, W @f$ | @f$ 2 \, B \, D @f$ | @f$ 2 \, B \, D \, / \, W @f$ | @f$ 2 \, B \, D @f$ | @f$ 4 \, B \, D @f$ |
311 * </center>
312 *
313 * For illustration, using the default @c FLOAT_PRECISION=2 whereby @f$ B = 16 @f$ bytes, the <b>RAM _per node_</b>
314 * over varying distributions is:
315 *
316 * <center>
317 * | @p isDensMatr | @p numQubits | @f$ W=1 @f$ | @f$ W=2 @f$ | @f$ W=4 @f$ | @f$ W=8 @f$ | @f$ W=16 @f$ | @f$ W=1024 @f$ |
318 * | ------------- | ------------ | ----------- | ----------- | ----------- | ----------- | ------------ | ------------ |
319 * | 0 | 20 | 16 MiB | 16 MiB | 8 MiB | 4 MiB | 2 MiB | 32 KiB |
320 * | 0 | 30 | 16 GiB | 16 GiB | 8 GiB | 4 GiB | 2 GiB | 32 MiB |
321 * | 0 | 35 | 512 GiB | 512 GiB | 256 GiB | 128 GiB | 64 GiB | 1 GiB |
322 * | 0 | 40 | 16 TiB | 16 TiB | 8 TiB | 4 TiB | 2 TiB | 32 GiB |
323 * | 0 | 45 | 512 TiB | 512 TiB | 256 TiB | 128 TiB | 64 TiB | 1 TiB |
324 * | 0 | 50 | 16 PiB | 16 PiB | 8 PiB | 4 PiB | 2 PiB | 32 TiB |
325 * | 1 | 10 | 16 MiB | 16 MiB | 8 MiB | 4 MiB | 2 MiB | 32 KiB |
326 * | 1 | 15 | 16 GiB | 16 GiB | 8 GiB | 4 GiB | 2 GiB | 32 MiB |
327 * | 1 | 20 | 16 TiB | 16 TiB | 8 TiB | 4 TiB | 2 TiB | 32 GiB |
328 * | 1 | 25 | 16 PiB | 16 PiB | 8 PiB | 4 PiB | 2 PiB | 32 TiB |
329 * </center>
330 *
331 * @constraints
332 * - Cannot use any deployment which has not been prior enabled during compilation, or disabled by createCustomQuESTEnv().
333 * - Cannot distribute @f$ N @f$ qubits over more than @f$ 2^N @f$ nodes (regardless of @p isDensMatr).
334 * - Cannot distribute when the executable was not launched using MPI (e.g. via @c mpirun).
335 * - Cannot GPU-accelerate when a GPU is not available at runtime, or has insufficient memory.
336 *
337 * @myexample
338 * ```
339 int numQubits = 30;
340 int isDensMatr = 0;
341
342 int useDistrib = 1; // use distribution
343 int useMultithread = 0; // don't use multithreading
344 int useGpuAccel = -1; // automate whether to GPU-accelerate
345
346 Qureg qureg = createCustomQureg(
347 numQubits, isDensMatr,
348 useDistrib, useGpuAccel, useMultithread);
349
350 reportQuregParams(qureg);
351 * ```
352 *
353 * @param[in] numQubits the number of qubits in the output Qureg.
354 * @param[in] isDensMatr whether the Qureg is a density matrix (@c =1) or statevector (@c =0).
355 * @param[in] useDistrib whether to force (@c =1), disable (@c =0) or automate (@c =-1) distribution.
356 * @param[in] useGpuAccel whether to force (@c =1), disable (@c =0) or automate (@c =-1) GPU acceleration.
357 * @param[in] useMultithread whether to force (@c =1), disable (@c =0) or automate (@c =-1) multithreading.
358 * @returns A new Qureg instance of the specified dimension and deployments.
359 * @throws @validationerror
360 * - if @p numQubits < 1
361 * - if @p isDensMatr is not @c 0 or @c 1
362 * - if any of @p useDistrib, @p useGpuAccel, @p useMultithread is not @c 0, @c 1 or @c -1.
363 * - if any of @p useDistrib, @p useGpuAccel, @p useMultithread is forced (@c =1) but is unsupported by the
364 * active QuESTEnv. This can happen because:
365 * - the particular deployment was disabled by initCustomQuESTEnv().
366 * - the deployment was not enabled during compilation.
367 * - @p useDistrib=1 but QuEST was not launched by MPI (e.g. via @c mpirun).
368 * - @p useGpuAccel=1 but a GPU is not accessible at runtime.
369 * - if @p useDistrib=1 but the Qureg is too small to distribute over the running nodes.
370 * - if the Qureg dimensions would overflow the @c qindex type.
371 * - if the total Qureg memory would overflow the @c size_t type.
372 * - if the system contains insufficient RAM (or VRAM) to store the Qureg.
373 * - if any memory allocation unexpectedly fails.
374 * @notyetvalidated
375 * @see
376 * - createQureg() to automate deployments (equivalent to passing @c -1).
377 * - createForcedQureg() to use all available deployments.
378 * @author Tyson Jones
379 */
380Qureg createCustomQureg(int numQubits, int isDensMatr, int useDistrib, int useGpuAccel, int useMultithread);
381
382
383/// @notyetdoced
385
386
387/** @} */
388
389
390
391/**
392 * @defgroup qureg_destroy Destructors
393 * @brief Functions for destroying existing Qureg.
394 * @{
395 */
396
397
398/// @notyetdoced
399void destroyQureg(Qureg qureg);
400
401
402/** @} */
403
404
405
406/**
407 * @defgroup qureg_report Reporters
408 * @brief Functions for printing Qureg states or reporting their configuration.
409 * @{
410 */
411
412
413/** @notyetdoced
414 * @notyettested
415 *
416 * @see
417 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_quregs.c) and
418 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_quregs.cpp) examples
419 */
420void reportQuregParams(Qureg qureg);
421
422
423/** @notyetdoced
424 * @notyettested
425 *
426 * @see
427 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_quregs.c) and
428 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_quregs.cpp) examples
429 */
430void reportQureg(Qureg qureg);
431
432
433/** @} */
434
435
436
437/**
438 * @defgroup qureg_sync Synchronisation
439 * @brief Functions for copying memory between a Qureg's CPU (RAM) and GPU (VRAM) memory.
440 * @details These functions are only necessary when the user wishes to manually probe or
441 * modify the Qureg amplitudes (rather than use functions like getQuregAmps() and
442 * setQuregAmps()), to ensure that the CPU and GPU copies of the Qureg are identical.
443 * These functions have no effect when running without GPU-acceleration, but remain
444 * legal and harmless to call, to achieve platform agnosticism.
445 * @{
446 */
447
448
449/// @notyetdoced
450/// @notyettested
451void syncQuregToGpu(Qureg qureg);
452
453
454/// @notyetdoced
455/// @notyettested
456void syncQuregFromGpu(Qureg qureg);
457
458
459/// @notyetdoced
460/// @notyettested
461void syncSubQuregToGpu(Qureg qureg, qindex localStartInd, qindex numLocalAmps);
462
463
464/// @notyetdoced
465/// @notyettested
466void syncSubQuregFromGpu(Qureg qureg, qindex localStartInd, qindex numLocalAmps);
467
468
469/** @} */
470
471
472
473/**
474 * @defgroup qureg_get Getters
475 * @brief Functions for obtaining amplitudes from statevectors or density matrices.
476 * @{
477 */
478
479
480/// @notyetdoced
481void getQuregAmps(qcomp* outAmps, Qureg qureg, qindex startInd, qindex numAmps);
482
483
484/// @notyetdoced
485void getDensityQuregAmps(qcomp** outAmps, Qureg qureg, qindex startRow, qindex startCol, qindex numRows, qindex numCols);
486
487
488/** @} */
489
490
491// end de-mangler
492#ifdef __cplusplus
493}
494#endif
495
496
497
498/*
499 * C++ ONLY FUNCTIONS
500 *
501 * which are not directly C-compatible because they pass or
502 * return qcomp primitives by-value (rather than by pointer).
503 * This is prohibited because the C and C++ ABI does not agree
504 * on a complex type, though C's _Complex has the same memory
505 * layout as C++'s std::complex<>. To work around this, the
506 * below functions have a C-compatible wrapper defined in
507 * wrappers.h which passes/receives the primitives by pointer;
508 * a qcomp ptr can be safely passed from the C++ source binary
509 * the user's C binary. These functions use the existing doxygen
510 * doc groups defined above
511 */
512
513
514/// @ingroup qureg_get
515/// @notyetdoced
516qcomp getQuregAmp(Qureg qureg, qindex index);
517
518
519/// @ingroup qureg_get
520/// @notyetdoced
521qcomp getDensityQuregAmp(Qureg qureg, qindex row, qindex column);
522
523
524
525/*
526 * C++ OVERLOADS
527 *
528 * which are only accessible to C++ binaries, and accept
529 * arguments more natural to C++ (e.g. std::vector). We
530 * manually add these to their respective Doxygen doc groups.
531 */
532
533#ifdef __cplusplus
534
535#include <vector>
536
537
538/// @ingroup qureg_get
539/// @notyettested
540/// @notyetvalidated
541/// @notyetdoced
542/// @cpponly
543/// @see getQuregAmps()
544std::vector<qcomp> getQuregAmps(Qureg qureg, qindex startInd, qindex numAmps);
545
546
547/// @ingroup qureg_get
548/// @notyettested
549/// @notyetvalidated
550/// @notyetdoced
551/// @cpponly
552/// @see getDensityQuregAmps()
553std::vector<std::vector<qcomp>> getDensityQuregAmps(Qureg qureg, qindex startRow, qindex startCol, qindex numRows, qindex numCols);
554
555
556#endif // __cplusplus
557
558
559
560/*
561 * ORPHAN DOC GROUP
562 */
563
564/**
565 * @defgroup qureg_setters Setters
566 * @brief See @ref init_amps "Amplitude initialisations".
567 */
568
569
570
571#endif // QUREG_H
572
573/** @} */ // (end file-wide doxygen defgroup)
Qureg createDensityQureg(int numQubits)
Definition qureg.cpp:290
Qureg createForcedQureg(int numQubits)
Definition qureg.cpp:298
Qureg createForcedDensityQureg(int numQubits)
Definition qureg.cpp:308
Qureg createCloneQureg(Qureg qureg)
Definition qureg.cpp:318
Qureg createCustomQureg(int numQubits, int isDensMatr, int useDistrib, int useGpuAccel, int useMultithread)
Definition qureg.cpp:276
Qureg createQureg(int numQubits)
Definition qureg.cpp:282
void destroyQureg(Qureg qureg)
Definition qureg.cpp:333
qcomp getQuregAmp(Qureg qureg, qindex index)
Definition qureg.cpp:487
void getDensityQuregAmps(qcomp **outAmps, Qureg qureg, qindex startRow, qindex startCol, qindex numRows, qindex numCols)
Definition qureg.cpp:460
void getQuregAmps(qcomp *outAmps, Qureg qureg, qindex startInd, qindex numAmps)
Definition qureg.cpp:451
qcomp getDensityQuregAmp(Qureg qureg, qindex row, qindex column)
Definition qureg.cpp:500
void reportQureg(Qureg qureg)
Definition qureg.cpp:374
void reportQuregParams(Qureg qureg)
Definition qureg.cpp:356
void syncQuregFromGpu(Qureg qureg)
Definition qureg.cpp:402
void syncSubQuregToGpu(Qureg qureg, qindex localStartInd, qindex numLocalAmps)
Definition qureg.cpp:411
void syncSubQuregFromGpu(Qureg qureg, qindex localStartInd, qindex numLocalAmps)
Definition qureg.cpp:430
void syncQuregToGpu(Qureg qureg)
Definition qureg.cpp:395
Definition qureg.h:49