The Quantum Exact Simulation Toolkit v4.3.0
Loading...
Searching...
No Matches
matrices.h
1/** @file
2 * Definitions of all dense and diagonal matrices, their getters and setters,
3 * as well as their reporting utilities. Note that Kraus maps are treated in
4 * a bespoke file (channels.h).
5 *
6 * This file uses extensive preprocessor trickery to achieve overloaded,
7 * platform agnostic, C and C++ compatible, precision agnostic, getters
8 * and setters of complex matrices. All macros herein expand to single-line
9 * definitions, for safety. Some intendedly private functions are necessarily
10 * exposed here to the user, and are prefixed with an underscore.
11 *
12 * Note too that designated initialisers are generally avoided, since while
13 * C99/C11 compatible, they are not explicitly supported by C++14 (only from
14 * C++20) except through compiler extensions
15 *
16 * @author Tyson Jones
17 * @author Richard Meister (aided in design)
18 * @author Erich Essmann (aided in design, patched on MSVC)
19 *
20 * @defgroup matrices Matrices
21 * @ingroup api
22 * @brief Data structures for representing operator matrices.
23 * @{
24 */
25
26#ifndef MATRICES_H
27#define MATRICES_H
28
29#include "quest/include/types.h"
30#include "quest/include/paulis.h"
31
32// C++ gets vector initialiser overloads, whereas C gets a macro
33#ifdef __cplusplus
34 #include <vector>
35#endif
36
37
38
39/*
40 * unlike some other headers, we here intermix the C and C++-only
41 * signatures, grouping them semantically & by their doc groups
42 */
43
44
45
46/**
47 * @defgroup matrices_structs Structs
48 * @brief Data structures for representing operator matrices.
49 * @{
50 */
51
52
53/*
54 * DENSE MATRIX STRUCTS
55 *
56 * which are visible to both C and C++, where qcomp resolves
57 * to the native complex type. These are not de-mangled because
58 * C++ structs are already C compatible.
59 *
60 * The compile-time sized structs have field 'elems', while
61 * dynamic-sized structs have separate 'cpuElems' and
62 * 'gpuElemsFlat', for persistent GPU allocation, and ergo need
63 * syncing. Note 'gpuElemsFlat' is always 1D (hence the name).
64 */
65
66
67/** A one-qubit, @f$2\times 2@f$, dense complex matrix.
68 *
69 * > [!TIP]
70 * > This matrix is stored in stack memory, and so never needs explicit destruction,
71 * > and like all QuEST types, is safe to pass and return to/from functions by-value.
72 *
73 * @myexample
74 *
75 * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.c) and
76 * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.cpp)
77 * examples of initialising CompMatr1.
78 *
79 * @see
80 * - getCompMatr1()
81 * - getInlineCompMatr1()
82 * - reportCompMatr1()
83 * - applyCompMatr1()
84 */
85typedef struct {
86
87 /** The number of qubits upon which the matrix can act, which is always @c =1.
88 */
90
91 /** The matrix dimension, which is always @c =2.
92 */
93 qindex numRows;
94
95 /** The 2D matrix elements. These are safe to update at any time.
96 */
97 qcomp elems[2][2];
98
99} CompMatr1;
100
101
102/** A two-qubit, @f$4\times 4@f$, dense complex matrix.
103 *
104 * > [!TIP]
105 * > This matrix is stored in stack memory, and so never needs explicit destruction,
106 * > and like all QuEST types, is safe to pass and return to/from functions by-value.
107 *
108 * @myexample
109 *
110 * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.c) and
111 * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.cpp)
112 * examples of initialising CompMatr2.
113 *
114 * @see
115 * - getCompMatr2()
116 * - getInlineCompMatr2()
117 * - reportCompMatr2()
118 * - applyCompMatr2()
119 */
120typedef struct {
121
122 /** The number of qubits upon which the matrix can act, which is always @c =2.
123 */
125
126 /** The matrix dimension, which is always @c =4.
127 */
128 qindex numRows;
129
130 /** The 2D matrix elements. These are safe to update at any time.
131 */
132 qcomp elems[4][4];
133
134} CompMatr2;
135
136
137/** A variable-size, @f$n@f$-qubit, @f$2^n \times 2^n@f$, dense complex matrix.
138 *
139 * Unlike CompMatr1 and CompMatr2, the elements of this matrix are stored in
140 * heap memory. But like all QuEST structs, it is safe to copy, and ergo to pass
141 * to functions by-value, or be returned from them. However, its destructor
142 * must only ever be called upon one such copy.
143 *
144 * @myexample
145 *
146 * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.c) and
147 * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.cpp)
148 * examples of initialising CompMatr.
149 *
150 * @see
151 * - createCompMatr()
152 * - [createInlineCompMatr()](https://quest-kit.github.io/QuEST/group__matrices__create.html#gad0ac51cb08a5d0b4e0878a5fde7ca893)
153 * - [setInlineCompMatr()](https://quest-kit.github.io/QuEST/group__matrices__setters.html#ga00993b6b571985fd04697e487a561517)
154 * - setCompMatr()
155 * - syncCompMatr()
156 * - reportCompMatr()
157 * - applyCompMatr()
158 * - destroyCompMatr()
159 */
160typedef struct {
161
162 // beware that CompMatr instances are sometimes 'spoofed' inside localiser.cpp,
163 // which will set the fields from other object instances (like a SuperOp). As
164 // such, adding new fields to this struct may require updating these spoofers.
165
166 /** The number of qubits upon which the matrix can act.
167 *
168 * The total memory costs of the matrix scale exponentially with the
169 * number of qubits; an @f$n@f$-qubit matrix contains @f$4^n@f$
170 * complex elements.
171 */
173
174 /** The dimension of the matrix, which is a square matrix, and so
175 * equals both the number of rows and columns.
176 *
177 * Letting @f$n=@f$ #numQubits, then #numRows @f$=2^n@f$.
178 */
179 qindex numRows;
180
181 /** Whether the matrix is (within validation epsilon tolerance) unitary (@c =1), or known to be
182 * non-unitary (@c =0), or whether it is unknown (@c =-1).
183 *
184 * This is a heap pointer to a persistent flag which is initially @c =-1 at matrix creation, and
185 * is only ever consulted and/or updated by input validation within functions like applyCompMatr(),
186 * when such validation is enabled. Calling setCompMatr() or syncCompMatr() restores #isApproxUnitary
187 * to @c -1.
188 *
189 * Unitarity is measured approximately, with reference to the validation
190 * epsilon as modified with setQuESTValidationEpsilon(). This flag will never be updated from
191 * @c =-1 when validation is disabled. Like all epsilon-dependent fields, it is restored
192 * to @c =-1 automatically whenever setQuESTValidationEpsilon() or setQuESTValidationEpsilonToDefault()
193 * are called.
194 *
195 * @see
196 * - setQuESTValidationEpsilon()
197 */
199
200 /** Whether the matrix is (within validation epsilon tolerance) Hermitian (@c =1), or known to
201 * be non-Hermitian (@c =0), or whether it is unknown (@c =-1).
202 *
203 * This is a heap pointer to a persistent flag which is initially @c =-1 at matrix creation, and
204 * is only ever consulted and/or updated by input validation within functions which expect
205 * Hermiticity. Calling setCompMatr() or syncCompMatr() restores
206 * #isApproxHermitian to @c -1.
207 *
208 * > [!NOTE]
209 * > There are presently _no_ QuEST functions which expect Hermiticity of a CompMatr,
210 * > and so this field is presently never modified from its initial value of @c =-1.
211 *
212 * Hermiticity is measured approximately, with reference to the validation
213 * epsilon as modified with setQuESTValidationEpsilon(). This flag will never be updated from
214 * @c =-1 when validation is disabled. Like all epsilon-dependent fields, it is restored
215 * to @c =-1 automatically whenever setQuESTValidationEpsilon() or setQuESTValidationEpsilonToDefault()
216 * are called.
217 *
218 * @see
219 * - setQuESTValidationEpsilon()
220 */
221 int* isApproxHermitian; // @todo currently unused (relevant to not-yet-implemented calc-expec-val)
222
223 /** Whether the matrix elements were ever synchronised.
224 *
225 * This is a heap pointer to a persistent flag which is initially @c 0 at matrix creation,
226 * but which is permanently overwritten to @c 1 when synchronisation is performed, such as
227 * via syncCompMatr() or setCompMatr(). The flag indicates whether the matrix
228 * elements have been initialised (and when QuEST is GPU-accelerated, whether they have been
229 * copied to GPU device memory), and ergo whether it is valid to pass the matrix to a
230 * simulation function like applyCompMatr().
231 *
232 * Note this flag can only indicate whether the matrix has _ever_ been synced; it cannot be
233 * used to detect whether manual modification of #cpuElems made after an initial sync have been
234 * re-synced, as required for correct behaviour in GPU mode.
235 *
236 * @see
237 * - syncCompMatr()
238 */
240
241 /** The 2D matrix elements, stored in CPU host memory.
242 *
243 * It is safest to modify this matrix through setCompMatr(), but direct modification
244 * is possible; the matrix element of the `r`-th row and `c`-th column is stored
245 * at `cpuElems[r][c]`.
246 *
247 * > [!IMPORTANT]
248 * > It is _critical_ to call syncCompMatr() after direct modification of
249 * > #cpuElems in order to update persistent matrix properties,
250 * > such as its data in GPU device memory (even when not running in
251 * > GPU-accelerated mode).
252 *
253 * The field #cpuElems merely aliases the 1D #cpuElemsFlat field, such that
254 * modifications of #cpuElems also updates #cpuElemsFlat.
255 *
256 * @see
257 * - setCompMatr()
258 * - [setInlineCompMatr()](https://quest-kit.github.io/QuEST/group__matrices__setters.html#ga00993b6b571985fd04697e487a561517)
259 * - syncCompMatr()
260 */
261 qcomp** cpuElems;
262
263 /** A 1D row-major form of #cpuElems.
264 *
265 * Modification of the matrix elements should be done through #cpuElems
266 * for mathematical clarity, though this 1D contiguous form may be convenient
267 * when performing copying.
268 *
269 * > [!IMPORTANT]
270 * > It is _critical_ to call syncCompMatr() after direct modification of
271 * > #cpuElemsFlat in order to update persistent matrix properties,
272 * > such as its data in GPU device memory (even when not running in
273 * > GPU-accelerated mode).
274 *
275 * @see
276 * - setCompMatr()
277 * - [setInlineCompMatr()](https://quest-kit.github.io/QuEST/group__matrices__setters.html#ga00993b6b571985fd04697e487a561517)
278 * - syncCompMatr()
279 */
281
282 /** The matrix elements, stored in GPU device memory, in a 1D row-major form.
283 *
284 * This is a copy of #cpuElemsFlat consulted by QuEST's GPU backend and should
285 * _never_ be modified directly. Instead, it is updated by calling syncCompMatr()
286 * after modifying #cpuElems or #cpuElemsFlat, which is performed automatically by
287 * API functions like setCompMatr(). In this way, #gpuElemsFlat and #cpuElemsFlat
288 * should never be out of sync with one another.
289 *
290 * Within a GPU-enabled QuEST environment, every CompMatr allocates #gpuElemsFlat
291 * in GPU memory, even if never ultimately consulted from the GPU backend.
292 */
294
295} CompMatr;
296
297
298/*
299 * DIAGONAL MATRIX STRUCTS
300 *
301 * with all the same nuances as the CompMatr structs described above.
302 */
303
304
305/** A one-qubit, @f$2\times 2@f$, diagonal complex matrix, stored as a length-2 array.
306 *
307 * > [!TIP]
308 * > This matrix is stored in stack memory, and so never needs explicit destruction,
309 * > and like all QuEST types, is safe to pass and return to/from functions by-value.
310 *
311 * @myexample
312 *
313 * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.c) and
314 * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.cpp)
315 * examples of initialising DiagMatr1.
316 *
317 * @see
318 * - getDiagMatr1()
319 * - getInlineDiagMatr1()
320 * - reportDiagMatr1()
321 * - applyDiagMatr1()
322 */
323typedef struct {
324
325 /** The number of qubits upon which the matrix can act, which is always @c =1.
326 */
328
329 /** The matrix dimension, equal to the number of contained diagonal elements, which is always @c =2.
330 */
331 qindex numElems;
332
333 /** The diagonal elements of the matrix, stored as a flat array, in CPU stack memory.
334 * These are safe to directly modify at any time, to update the matrix.
335 */
336 qcomp elems[2];
337
338} DiagMatr1;
339
340
341/** A two-qubit, @f$4\times 4@f$, diagonal complex matrix, stored as a length-4 array.
342 *
343 * > [!TIP]
344 * > This matrix is stored in stack memory, and so never needs explicit destruction,
345 * > and like all QuEST types, is safe to pass and return to/from functions by-value.
346 *
347 * @myexample
348 *
349 * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.c) and
350 * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.cpp)
351 * examples of initialising DiagMatr2.
352 *
353 * @see
354 * - getDiagMatr2()
355 * - getInlineDiagMatr2()
356 * - reportDiagMatr2()
357 * - applyDiagMatr2()
358 */
359typedef struct {
360
361 /** The number of qubits upon which the matrix can act, which is always @c =2.
362 */
364
365 /** The matrix dimension, equal to the number of contained diagonal elements, which is always @c =4.
366 */
367 qindex numElems;
368
369 /** The diagonal elements of the matrix, stored as a flat array, in CPU stack memory.
370 * These are safe to directly modify at any time, to update the matrix.
371 */
372 qcomp elems[4];
373
374} DiagMatr2;
375
376
377/** A variable-size, @f$n@f$-qubit, @f$2^n \times 2^n@f$, diagonal complex matrix,
378 * stored as a length-@f$2^n@f$ array.
379 *
380 * This is intended for _local_ diagonal matrices, smaller than the Qureg upon
381 * which they operate. For a full-state diagonal matrix, see FullStateDiagMatr.
382 *
383 * Unlike DiagMatr1 and DiagMatr2, the diagonal elements of this matrix are stored in
384 * heap memory. But like all QuEST structs, it is safe to copy, and ergo to pass
385 * to functions by-value, or be returned from them. However, its destructor
386 * must only ever be called upon one such copy.
387 *
388 * @myexample
389 *
390 * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.c) and
391 * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.cpp)
392 * examples of initialising DiagMatr.
393 *
394 * @see
395 * - createDiagMatr()
396 * - [createInlineDiagMatr()](https://quest-kit.github.io/QuEST/group__matrices__create.html#gad0ac51cb08a5d0b4e0878a5fde7ca893)
397 * - [setInlineDiagMatr()](https://quest-kit.github.io/QuEST/group__matrices__setters.html#ga7b2c2e134546df6101c6001727bc6d69)
398 * - setDiagMatr()
399 * - syncDiagMatr()
400 * - reportDiagMatr()
401 * - applyDiagMatr()
402 * - destroyDiagMatr()
403 */
404typedef struct {
405
406 /** The number of qubits upon which the matrix can act.
407 *
408 * The total memory costs of the matrix scale exponentially with the
409 * number of qubits; an @f$n@f$-qubit diagonal matrix contains @f$2^n@f$
410 * complex elements.
411 */
413
414 /** The dimension of the matrix, which is a square matrix, and so
415 * equals both the number of rows and columns, and the number of diagonal terms.
416 *
417 * Letting @f$n=@f$ #numQubits, then #numElems @f$=2^n@f$.
418 */
419 qindex numElems;
420
421 /** Whether the matrix is (within validation epsilon tolerance) unitary (@c =1), or known to be
422 * non-unitary (@c =0), or whether it is unknown (@c =-1).
423 *
424 * This is a heap pointer to a persistent flag which is initially @c =-1 at matrix creation, and
425 * is only ever consulted and/or updated by input validation within functions like applyDiagMatr(),
426 * when such validation is enabled. Calling setDiagMatr() or syncDiagMatr() restores #isApproxUnitary
427 * to @c -1.
428 *
429 * Unitarity is measured approximately, with reference to the validation
430 * epsilon as modified with setQuESTValidationEpsilon(). This flag will never be updated from
431 * @c =-1 when validation is disabled. Like all epsilon-dependent fields, it is restored
432 * to @c =-1 automatically whenever setQuESTValidationEpsilon() or setQuESTValidationEpsilonToDefault()
433 * are called.
434 *
435 * @see
436 * - setQuESTValidationEpsilon()
437 */
439
440 /** Whether the matrix is (within validation epsilon tolerance) Hermitian (@c =1), or known to be
441 * non-Hermitian (@c =0), or whether it is unknown (@c =-1).
442 *
443 * > [!NOTE]
444 * > There are presently _no_ QuEST functions which expect Hermiticity of a DiagMatr,
445 * > and so this field is presently never modified from its initial value of @c =-1.
446 *
447 * This field has all the same nuances and mechanisms as #isApproxUnitary.
448 */
449 int* isApproxHermitian; // @todo currently unused (relevant to not-yet-implemented calc-expec-val)
450
451 /** Whether all diagonal elements of the matrix are "approximately" non-zero (have a magnitude
452 * exceeding the validation epsilon) in which case this field @c =1, or whether the matrix is
453 * known to contain an approximate zero (@c =0), or whether the property is unknown (@c =-1).
454 *
455 * This property is relevant when attempting to raise the DiagMatr to a negative power,
456 * such as through applyDiagMatrPower().
457 *
458 * This field has all the same nuances and mechanisms as #isApproxUnitary.
459 */
461
462 /** Whether all diagonal elements of the matrix are strictly zero or positive (@c =1), or
463 * whether one or more elements are known to be negative (@c =0), or whether the property is
464 * unknown (@c =-1).
465 *
466 * This property is relevant when attempting to raise the DiagMatr to non-integer power,
467 * such as through applyDiagMatrPower().
468 *
469 * This field has similar nuances and mechanics as #isApproxUnitary, but is _not_ dependent
470 * upon the validation epsilon (as controlled with setQuESTValidationEpsilon()).
471 */
473
474 /** Whether the matrix elements were ever synchronised.
475 *
476 * This is a heap pointer to a persistent flag which is initially @c 0 at matrix creation,
477 * but which is permanently overwritten to @c 1 when synchronisation is performed, such as
478 * via syncDiagMatr() or setDiagMatr(). The flag indicates whether the matrix
479 * elements have been initialised (and when QuEST is GPU-accelerated, whether they have been
480 * copied to GPU device memory), and ergo whether it is valid to pass the matrix to a
481 * simulation function like applyDiagMatr().
482 *
483 * Note this flag can only indicate whether the matrix has _ever_ been synced; it cannot be
484 * used to detect whether manual modification of #cpuElems made after an initial sync have been
485 * re-synced, as required for correct behaviour in GPU mode.
486 *
487 * @see
488 * - syncDiagMatr()
489 */
491
492 /** The matrix diagonal elements, stored in CPU host memory.
493 *
494 * It is safest to modify this matrix through setDiagMatr(), but direct modification
495 * is possible.
496 *
497 * > [!IMPORTANT]
498 * > It is _critical_ to call syncDiagMatr() after direct modification of
499 * > #cpuElems in order to update persistent matrix properties,
500 * > such as its data in GPU device memory (even when not running in
501 * > GPU-accelerated mode).
502 *
503 * @see
504 * - syncDiagMatr()
505 */
506 qcomp* cpuElems;
507
508 /** The matrix diagonal elements, stored in GPU device memory.
509 *
510 * This is a copy of #cpuElems consulted by QuEST's GPU backend and should
511 * _never_ be modified directly. Instead, it is updated by calling syncDiagMatr()
512 * after modifying #cpuElems, which is performed automatically by
513 * API functions like setDiagMatr(). In this way, #gpuElems and #cpuElems
514 * should never be out of sync with one another.
515 *
516 * Within a GPU-enabled QuEST environment, every DiagMatr allocates #gpuElems
517 * in GPU memory, even if never ultimately consulted from the GPU backend.
518 */
519 qcomp* gpuElems;
520
521} DiagMatr;
522
523
524/*
525 * DISTRIBUTED MATRIX STRUCTS
526 */
527
528
529/** A variable-size but full-state diagonal complex matrix, which can only act upon a
530 * Qureg of the same dimension.
531 *
532 * Unlike DiagMatr, a FullStateDiagMatr is intendedly non-local and can be distributed,
533 * just like a Qureg of the same dimension.
534 *
535 * @myexample
536 *
537 * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.c) and
538 * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.cpp)
539 * examples of initialising FullStateDiagMatr.
540 *
541 * @see
542 * - createFullStateDiagMatr()
543 * - [setInlineFullStateDiagMatr()](fhttps://quest-kit.github.io/QuEST/group__matrices__setters.html#gaa27aaa1a001a41f36a60847a19d824d4)
544 * - setFullStateDiagMatr()
545 * - setFullStateDiagMatrFromMultiVarFunc()
546 * - setFullStateDiagMatrFromMultiDimLists()
547 * - setFullStateDiagMatrFromPauliStrSum()
548 * - syncFullStateDiagMatr()
549 * - reportFullStateDiagMatr()
550 * - applyFullStateDiagMatr()
551 * - calcExpecFullStateDiagMatr()
552 * - destroyFullStateDiagMatr()
553 */
554typedef struct {
555
556 /** The number of qubits in the Qureg upon which the matrix can act.
557 *
558 * The total memory costs of the matrix scale exponentially with the
559 * number of qubits; an @f$n@f$-qubit full-state diagonal matrix contains @f$2^n@f$
560 * complex elements, which may be distributed across MPI nodes.
561 */
563
564 /** The total dimension of the matrix, which is a square matrix, and so
565 * equals both the number of rows and columns, and the number of diagonal terms.
566 *
567 * Letting @f$n=@f$ #numQubits, then #numElems @f$=2^n@f$. This is the total number
568 * of elements across all nodes, and so is independent of whether the matrix is
569 * distributed.
570 */
571 qindex numElems;
572
573 /** Whether the matrix has allocated GPU memory, and so can be used by QuEST's
574 * GPU-accelerated backend.
575 *
576 * Unlike CompMatr and DiagMatr, a FullStateDiagMatr can opt _not_ to allocate GPU memory when
577 * QuEST is running in GPU-accelerated mode.
578 */
580
581 /** Whether multithreading will be employed when initialising or simulating the matrix.
582 *
583 * When a QuEST function receives both a Qureg and a FullStateDiagMatr, multithreading
584 * is performed when _either_ or _both_ structs have multithreading enabled.
585 */
587
588 /** Whether the matrix elements are distributed, informing the size of #cpuElems on
589 * every node.
590 *
591 * When distributed, each node contains only a subset of the full matrix's diagonal
592 * elements, in an identical fashion to how statevector Qureg are distributed.
593 * Unlike a Qureg however, a FullStateDiagMatr has no attached communication buffer,
594 * so have _half_ the total memory costs of a same-size distributed statevector Qureg.
595 *
596 * When not distributed, every node contains a duplicate copy of all elements in the matrix.
597 */
599
600 /** The number of diagonal matrix elements stored on each distributed node, and the
601 * length of #cpuElems and #gpuElems.
602 *
603 * This differs from #numElems only when the matrix is distributed, in which case it
604 * equals #numElems divided by the number of nodes.
605 */
607
608 /** Whether the matrix is (within validation epsilon tolerance) unitary (@c =1), or known to be
609 * non-unitary (@c =0), or whether it is unknown (@c =-1).
610 *
611 * This is a heap pointer to a persistent flag which is initially @c =-1 at matrix creation, and
612 * is only ever consulted and/or updated by input validation within functions like
613 * applyFullStateDiagMatr(), when such validation is enabled. Calling functions like
614 * setFullStateDiagMatr() or syncFullStateDiagMatr() restores #isApproxUnitary to @c -1.
615 *
616 * Unitarity is measured approximately, with reference to the validation
617 * epsilon as modified with setQuESTValidationEpsilon(). This flag will never be updated from
618 * @c =-1 when validation is disabled. Like all epsilon-dependent fields, it is restored
619 * to @c =-1 automatically whenever setQuESTValidationEpsilon() or setQuESTValidationEpsilonToDefault()
620 * are called.
621 *
622 * When distributed, this property reflects the _global_ state of the entire matrix across
623 * all nodes, and so should always be identical across nodes.
624 *
625 * @see
626 * - setQuESTValidationEpsilon()
627 */
629
630 /** Whether the matrix is (within validation epsilon tolerance) Hermitian (@c =1), or known to be
631 * non-Hermitian (@c =0), or whether it is unknown (@c =-1).
632 *
633 * This field is relevant to functions like calcExpecFullStateDiagMatr(), and
634 * otherwise has all the same nuances and mechanisms as #isApproxUnitary.
635 */
637
638 /** Whether all diagonal elements of the matrix are "approximately" non-zero (have a magnitude
639 * exceeding the validation epsilon) in which case this field @c =1, or whether the matrix is
640 * known to contain an approximate zero (@c =0), or whether the property is unknown (@c =-1).
641 *
642 * This property is relevant when attempting to raise the matrix to a negative power,
643 * such as through applyFullStateDiagMatrPower().
644 *
645 * This field has all the same nuances and mechanisms as #isApproxUnitary.
646 */
648
649 /** Whether all diagonal elements of the matrix are strictly zero or positive (@c =1), or
650 * whether one or more elements are known to be negative (@c =0), or whether the property is
651 * unknown (@c =-1).
652 *
653 * This property is relevant when attempting to raise the matrix to non-integer power,
654 * such as through applyFullStateDiagMatrPower().
655 *
656 * This field has similar nuances and mechanics as #isApproxUnitary, but is _not_ dependent
657 * upon the validation epsilon (as controlled with setQuESTValidationEpsilon()).
658 */
660
661 /** Whether the matrix elements were ever synchronised.
662 *
663 * This is a heap pointer to a persistent flag which is initially @c 0 at matrix creation,
664 * but which is permanently overwritten to @c 1 when synchronisation is performed, such as
665 * via syncFullStateDiagMatr() or setFullStateDiagMatr(). The flag indicates whether the matrix
666 * elements have been initialised (and when QuEST is GPU-accelerated, whether they have been
667 * copied to GPU device memory), and ergo whether it is valid to pass the matrix to a
668 * simulation function like applyFullStateDiagMatr().
669 *
670 * Note this flag can only indicate whether the matrix has _ever_ been synced; it cannot be
671 * used to detect whether manual modification of #cpuElems made after an initial sync have been
672 * re-synced, as required for correct behaviour in GPU mode.
673 *
674 * @see
675 * - syncFullStateDiagMatr()
676 */
678
679 /** This node's matrix diagonal elements, stored in CPU host memory.
680 *
681 * This is an array of length #numElemsPerNode, containing the diagonal elements of
682 * the matrix. It is safest to modify these elements through functions like
683 * setFullStateDiagMatr(). Direct modification is possible, but in distributed
684 * simulation, must be done with care. The @f$i@f$-th local element on the node
685 * with rank @f$r@f$ corresponds to the full matrix element @f$(m r + i, m r + i)@f$,
686 * where @f$m=@f$ #numElemsPerNode.
687 *
688 * > [!IMPORTANT]
689 * > It is _critical_ to call syncFullStateDiagMatr() after direct modification of
690 * > #cpuElems on any node, in order to update persistent matrix properties,
691 * > such as its data in GPU device memory (even when not running in
692 * > GPU-accelerated mode).
693 *
694 * @see
695 * - setFullStateDiagMatr()
696 * - setFullStateDiagMatrFromMultiVarFunc()
697 * - setFullStateDiagMatrFromMultiDimLists()
698 * - setFullStateDiagMatrFromPauliStrSum()
699 * - syncFullStateDiagMatr()
700 */
701 qcomp* cpuElems;
702
703 /** The matrix diagonal elements, stored in GPU device memory.
704 *
705 * This is a copy of #cpuElems consulted by QuEST's GPU backend and should
706 * _never_ be modified directly. Instead, it is updated by calling
707 * syncFullStateDiagMatr()
708 * after modifying #cpuElems, which is performed automatically by
709 * API functions like setFullStateDiagMatr(). In this way, #gpuElems and #cpuElems
710 * should never be out of sync with one another.
711 *
712 * The #gpuElems memory is only allocated when #isGpuAccelerated @c =1.
713 */
714 qcomp* gpuElems;
715
717
718
719/** @} */
720
721
722
723// we define the remaining doc groups in advance, since their signatures are
724// more naturally grouped in an implementation-specific way below. Note the
725// above structs were not doc'd this way (which would be more consistent)
726// because it inexplicably causes Doxygen to duplicate their section at the
727// top-level under Matrices (rather than under Structs). Bizarre! The order
728// of declaration below will match the order shown in the html doc.
729/**
730 * @defgroup matrices_getters Getters
731 * @brief Functions for obtaining fixed-size matrices.
732 *
733 * @defgroup matrices_create Constructors
734 * @brief Functions for creating variable-size matrices.
735 *
736 * @defgroup matrices_destroy Destructors
737 * @brief Functions for destroying existing matrices.
738 *
739 * @defgroup matrices_reporters Reporters
740 * @brief Functions for printing matrices.
741 *
742 * @defgroup matrices_setters Setters
743 * @brief Functions for overwriting the elements of matrices.
744 *
745 * @defgroup matrices_sync Synchronisation
746 * @brief Functions for overwriting a matrix's GPU (VRAM) memory with its CPU (RAM) contents.
747 * @details These functions are only necessary when the user wishes to manually modify the
748 * elements of a matrix (in lieu of using the @ref matrices_setters "Setters"), to
749 * thereafter synchronise the changes to the GPU copy of the channel. These functions
750 * have no effect when running without GPU-acceleration, but remain legal and harmless
751 * to call (to achieve platform agnosticism).
752 */
753
754
755
756/*
757 * FIZED-SIZE MATRIX GETTERS VIA POINTERS
758 *
759 * which are defined here in the header because the 'qcomp' type is interpreted
760 * distinctly by C++ (the backend) and C (user code). The C and C++ ABIs do not
761 * agree on a complex type, so a qcomp (to C; a _Complex, and to C++; a std::complex)
762 * cannot be directly passed between C and C++ compiled binaries; nor can a CompMatr1
763 * struct which unwraps the qcomp[][] array. However, the C and C++ complex types have
764 * identical memory layouts, so pointers to qcomp types can safely be passed between
765 * C and C++ binaries. Ordinarily we leverage this by defining all qcomp-handling API
766 * functions in C++, and defining additional C-only wrappers in wrappers.h, which pass
767 * only pointers to qcomp. Alas, we cannot use this trick here, because the CompMatr1/2
768 * fields are declared 'const'; we cannot modify them through pointers, nor should we
769 * try to address them. Ergo we directly define these functions below (static inline to
770 * avoid symbol duplication), initializing the struct in one line. These functions will be
771 * separately interpreted by the C and C++ compilers, resolving qcomp to their individual
772 * native complex types.
773 *
774 * These functions permit users to pass heap and stack pointers:
775 * - qcomp** ptr = malloc(...); getCompMatr1(ptr);
776 * - qcomp* ptrs[2]; getCompMatr1(ptrs);
777 * in both C and C++. Because of 1D pointer decay, they also permit:
778 * - qcomp* ptr = malloc(...); getDiagMatr1(ptr);
779 * - qcomp arr[2]; getDiagMatr1(arr);
780 */
781
782
783// private validators
784#ifdef __cplusplus
785extern "C" {
786#endif
787
788/// @private
789extern void _validateNewNestedElemsPtrNotNull(qcomp** ptrs, int numQubits, const char* caller);
790
791/// @private
792extern void _validateNewElemsPtrNotNull(qcomp* ptr, const char* caller);
793
794#ifdef __cplusplus
795}
796#endif
797
798
799/** @ingroup matrices_getters
800 * @notyetdoced
801 *
802 * @see
803 * - reportCompMatr1()
804 * - getInlineCompMatr2()
805 * - getDiagMatr1()
806 * - getCompMatr2()
807 * - createCompMatr()
808 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and
809 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
810 */
811static inline CompMatr1 getCompMatr1(qcomp** in) {
812 _validateNewNestedElemsPtrNotNull(in, 1, __func__);
813
814 CompMatr1 out;
815
816 out.numQubits = 1;
817 out.numRows = 2;
818 for (int r=0; r<2; r++)
819 for (int c=0; c<2; c++)
820 out.elems[r][c] = in[r][c];
821
822 return out;
823}
824
825
826/** @ingroup matrices_getters
827 * @notyetdoced
828 *
829 * @see
830 * - reportCompMatr2()
831 * - getInlineCompMatr2()
832 * - getDiagMatr2()
833 * - createCompMatr()
834 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and
835 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
836 */
837static inline CompMatr2 getCompMatr2(qcomp** in) {
838 _validateNewNestedElemsPtrNotNull(in, 2, __func__);
839
840 CompMatr2 out;
841
842 out.numQubits = 2;
843 out.numRows = 4;
844 for (int r=0; r<4; r++)
845 for (int c=0; c<4; c++)
846 out.elems[r][c] = in[r][c];
847
848 return out;
849}
850
851
852/** @ingroup matrices_getters
853 * @notyetdoced
854 *
855 * @see
856 * - reportDiagMatr1()
857 * - getInlineDiagMatr1()
858 * - getCompMatr1()
859 * - getDiagMatr2()
860 * - createDiagMatr()
861 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and
862 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
863 */
864static inline DiagMatr1 getDiagMatr1(qcomp* in) {
865 _validateNewElemsPtrNotNull(in, __func__);
866
867 DiagMatr1 out;
868
869 out.numQubits = 1;
870 out.numElems = 2;
871 for (int i=0; i<2; i++)
872 out.elems[i] = in[i];
873
874 return out;
875}
876
877
878/** @ingroup matrices_getters
879 * @notyetdoced
880 *
881 * @see
882 * - reportDiagMatr2()
883 * - getInlineDiagMatr2()
884 * - getCompMatr2()
885 * - createDiagMatr()
886 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and
887 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
888 */
889static inline DiagMatr2 getDiagMatr2(qcomp* in) {
890 _validateNewElemsPtrNotNull(in, __func__);
891
892 DiagMatr2 out;
893
894 out.numQubits = 2;
895 out.numElems = 4;
896 for (int i=0; i<4; i++)
897 out.elems[i] = in[i];
898
899 return out;
900}
901
902
903
904/*
905 * FIZED-SIZE MATRIX GETTERS VIA ARRAYS & VECTORS
906 *
907 * which define additional overloads for arrays, VLAs, C99 temporary arrays,
908 * vectors and vector initialisation lists. This empowers C users to call:
909 * - qcomp arr[2][2]; getCompMatr1(arr);
910 * - int n=2; qcomp arr[n][n]; getCompMatr1(arr);
911 * - getCompMatr1( (qcomp[2][2]) {...} );
912 * and C++ users call:
913 * - qcomp arr[2][2]; getCompMatr1(arr);
914 * - std::vector vec(2); getCompMatr1(vec);
915 * - getCompMatr1( {...} );
916 */
917
918
919// define the array overloads with a distinct name from the base
920// C function - we will alias it with getCompMatr() using Generics
921
922/// @private
923static inline CompMatr1 _getCompMatr1FromArr(qcomp in[2][2]) {
924
925 qcomp* rowPtrs[] = {in[0], in[1]};
926 return getCompMatr1(rowPtrs);
927}
928
929/// @private
930static inline CompMatr2 _getCompMatr2FromArr(qcomp in[4][4]) {
931
932 qcomp* rowPtrs[] = {in[0], in[1], in[2], in[3]};
933 return getCompMatr2(rowPtrs);
934}
935
936
937// no array overloads are necessary for getDiagMatr(), because
938// a 1D array automatically decays to a pointer
939
940
941#ifdef __cplusplus
942
943 // C++ defines overloads which merely wrap _getCompMatr1FromArr(), for fixed-size arrays.
944 // C++ also defines additional std::vector overloads (for convenience, and for inline initialisation).
945 // these are defined in matrices.cpp because they invoke validation (checking vector sizes)
946
947
948 /// @ingroup matrices_getters
949 /// @notyetdoced
950 static inline CompMatr1 getCompMatr1(qcomp in[2][2]) { return _getCompMatr1FromArr(in); }
951
952
953 /// @ingroup matrices_getters
954 /// @notyetdoced
955 static inline CompMatr2 getCompMatr2(qcomp in[4][4]) { return _getCompMatr2FromArr(in); }
956
957
958 /** @ingroup matrices_getters
959 * @notyetdoced
960 * @cpponly
961 *
962 * @see
963 * - reportCompMatr1()
964 * - getInlineCompMatr1()
965 * - getDiagMatr1()
966 * - getCompMatr2()
967 * - createCompMatr()
968 * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
969 */
970 CompMatr1 getCompMatr1(std::vector<std::vector<qcomp>> in);
971
972
973 /** @ingroup matrices_getters
974 * @notyetdoced
975 * @cpponly
976 *
977 * @see
978 * - reportCompMatr2()
979 * - getInlineCompMatr2()
980 * - getDiagMatr2()
981 * - createCompMatr()
982 * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
983 */
984 CompMatr2 getCompMatr2(std::vector<std::vector<qcomp>> in);
985
986
987 /** @ingroup matrices_getters
988 * @notyetdoced
989 * @cpponly
990 *
991 * @see
992 * - reportDiagMatr1()
993 * - getInlineDiagMatr1()
994 * - getCompMatr1()
995 * - getDiagMatr2()
996 * - createDiagMatr()
997 * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
998 */
999 DiagMatr1 getDiagMatr1(std::vector<qcomp> in);
1000
1001
1002 /** @ingroup matrices_getters
1003 * @notyetdoced
1004 * @cpponly
1005 *
1006 * @see
1007 * - reportDiagMatr2()
1008 * - getInlineDiagMatr2()
1009 * - getCompMatr2()
1010 * - createDiagMatr()
1011 * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1012 */
1013 DiagMatr2 getDiagMatr2(std::vector<qcomp> in);
1014
1015
1016#else
1017
1018 // C uses C11 Generics to effectively overload getCompMatr1/2 to accept both
1019 // pointers (as prior defined) and arrays (wrapping _getCompMatr1FromArr()). Note:
1020 // - our macros below accept C99 variadic arguments so that users pass C99
1021 // compound literals (e.g. (qcomp[]) {1,2}) in addition to existing ptrs.
1022 // they cannot however exclude the (qcomp[]) syntax like C++ users enjoy,
1023 // which is why we will subsequently define a getInlineCompMatr1()
1024 // - Generics evaluate at compile-time (AFTER preprocessing) so their RHS
1025 // expressions are limited; because of this, it is impossible to avoid
1026 // defining the _getCompMatr1FromArr() inner functions to avoid exposing them.
1027 // - our Generics explicitly check for pointer types (qcomp**), but we use default
1028 // to catch all array types (qcomp[][n], or qcomp(*)[] due to automatic Generic
1029 // pointer decay in GCC). This makes the code more consistent with our variable-size
1030 // CompMatr macros later in this file, which cannot use VLA in Generics at all. It
1031 // also avoids the user having to see a Generic compilation error message when they
1032 // pass an invalid type.
1033 // - Generic expansion does not recurse, hence our macro safely has the same name
1034 // (e.g. getCompMatr1) as the inner function, defining a true overload
1035 // - we could not have _Generic's 'default' to catch unrecognised types at compile
1036 // time to issue a custom message, because we must expand _Generic to a function
1037 // rather than a macro; preprocessing is finished by the time _Generic evaluates,
1038 // so a macro would always be substituted before compilation and if it contained
1039 // a compile-time error, it will always be triggered. A function error however
1040 // would compile fine, but the error message would only be triggered at runtime
1041 // when the user actually calls getCompMatr1() which is much worse than a slightly
1042 // less clear compile-time error! A non-portable solution to this is to use
1043 // _Pragma() in the RHS which is evaluated at compile-time (NOT pre-procesing),
1044 // e.g. default: _Pragma("GCC error \"arg not allowed\"").
1045
1046
1047 /// @neverdoced
1048 #define getCompMatr1(...) \
1049 _Generic((__VA_ARGS__), \
1050 qcomp** : getCompMatr1, \
1051 default : _getCompMatr1FromArr \
1052 )((__VA_ARGS__))
1053
1054
1055 /// @neverdoced
1056 #define getCompMatr2(...) \
1057 _Generic((__VA_ARGS__), \
1058 qcomp** : getCompMatr2, \
1059 default : _getCompMatr2FromArr \
1060 )((__VA_ARGS__))
1061
1062
1063 // note the above macros do not need explicit, separate doxygen
1064 // doc because the C++ overloads above it have identical signatures
1065
1066#endif
1067
1068
1069
1070/*
1071 * FIXED-SIZE MATRIX GETTERS VIA LITERALS
1072 *
1073 * which enable C users to give inline 2D array literals without having to use the
1074 * compound literal syntax. We expose these macros to C++ too for API consistency.
1075 * although C++'s getCompMatr1 vector overload achieves the same thing, and cannot
1076 * use C-style temporary arrays.
1077 *
1078 * These empower C and C++ users to call
1079 * - getInlineCompMatr1( {{1,2},{3,4}} )
1080 */
1081
1082
1083#ifdef __cplusplus
1084
1085 // C++ merely invokes the std::vector initialiser overload
1086
1087 /// @neverdoced
1088 #define getInlineCompMatr1(...) \
1089 getCompMatr1(__VA_ARGS__)
1090
1091 /// @neverdoced
1092 #define getInlineCompMatr2(...) \
1093 getCompMatr2(__VA_ARGS__)
1094
1095 /// @neverdoced
1096 #define getInlineDiagMatr1(...) \
1097 getDiagMatr1(__VA_ARGS__)
1098
1099 /// @neverdoced
1100 #define getInlineDiagMatr2(...) \
1101 getDiagMatr2(__VA_ARGS__)
1102
1103#else
1104
1105 // C adds compound literal syntax to make a temporary array. Helpfully,
1106 // explicitly specifying the DiagMatr dimension enables defaulting-to-zero
1107
1108 /// @neverdoced
1109 #define getInlineCompMatr1(...) \
1110 _getCompMatr1FromArr((qcomp[2][2]) __VA_ARGS__)
1111
1112 /// @neverdoced
1113 #define getInlineCompMatr2(...) \
1114 _getCompMatr2FromArr((qcomp[4][4]) __VA_ARGS__)
1115
1116 /// @neverdoced
1117 #define getInlineDiagMatr1(...) \
1118 getDiagMatr1((qcomp[2]) __VA_ARGS__)
1119
1120 /// @neverdoced
1121 #define getInlineDiagMatr2(...) \
1122 getDiagMatr2((qcomp[4]) __VA_ARGS__)
1123
1124#endif
1125
1126// spoofing above macros as functions to doc
1127#if 0
1128
1129 /** @ingroup matrices_getters
1130 * @notyetdoced
1131 * @macrodoc
1132 *
1133 * @see
1134 * - reportCompMatr1()
1135 * - getInlineDiagMatr1()
1136 * - getInlineCompMatr2()
1137 * - createCompMatr()
1138 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and
1139 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1140 */
1142
1143 /** @ingroup matrices_getters
1144 * @notyetdoced
1145 * @macrodoc
1146 *
1147 * @see
1148 * - reportCompMatr2()
1149 * - getInlineDiagMatr2()
1150 * - createCompMatr()
1151 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and
1152 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1153 */
1155
1156 /** @ingroup matrices_getters
1157 * @notyetdoced
1158 * @macrodoc
1159 *
1160 * @see
1161 * - reportDiagMatr1()
1162 * - getInlineCompMatr1()
1163 * - getInlineDiagMatr2()
1164 * - createDiagMatr()
1165 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and
1166 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1167 */
1169
1170 /** @ingroup matrices_getters
1171 * @notyetdoced
1172 * @macrodoc
1173 *
1174 * @see
1175 * - reportDiagMatr2()
1176 * - getInlineCompMatr2()
1177 * - createDiagMatr()
1178 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and
1179 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1180 */
1182
1183#endif
1184
1185
1186
1187/*
1188 * VARIABLE-SIZE MATRIX CONSTRUCTORS, DESTRUCTORS, SYNC
1189 */
1190
1191
1192// de-mangle so below are directly callable by C and C++ binary
1193#ifdef __cplusplus
1194extern "C" {
1195#endif
1196
1197
1198 /** @ingroup matrices_create
1199 * @notyetdoced
1200 *
1201 * @see
1202 * - setCompMatr()
1203 * - syncCompMatr()
1204 * - createInlineCompMatr()
1205 * - createDiagMatr()
1206 * - getCompMatr1()
1207 * - getCompMatr2()
1208 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and
1209 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1210 */
1211 CompMatr createCompMatr(int numQubits);
1212
1213
1214 /** @ingroup matrices_create
1215 * @notyetdoced
1216 *
1217 * @see
1218 * - setDiagMatr()
1219 * - syncDiagMatr()
1220 * - createInlineDiagMatr()
1221 * - createCompMatr()
1222 * - getDiagMatr1()
1223 * - getDiagMatr2()
1224 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and
1225 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1226 */
1227 DiagMatr createDiagMatr(int numQubits);
1228
1229
1230 /** @ingroup matrices_create
1231 * @notyetdoced
1232 *
1233 * @see
1234 * - createCustomFullStateDiagMatr()
1235 * - setFullStateDiagMatr()
1236 * - syncFullStateDiagMatr()
1237 * - createDiagMatr()
1238 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and
1239 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1240 */
1242
1243
1244 /** @ingroup matrices_create
1245 * @notyetdoced
1246 *
1247 * @see
1248 * - createFullStateDiagMatr()
1249 * - setFullStateDiagMatr()
1250 * - syncFullStateDiagMatr()
1251 * - createDiagMatr()
1252 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and
1253 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1254 */
1255 FullStateDiagMatr createCustomFullStateDiagMatr(int numQubits, int useDistrib, int useGpuAccel, int useMultithread);
1256
1257
1258 /// @ingroup matrices_destroy
1259 /// @notyetdoced
1260 void destroyCompMatr(CompMatr matrix);
1261
1262
1263 /// @ingroup matrices_destroy
1264 /// @notyetdoced
1265 void destroyDiagMatr(DiagMatr matrix);
1266
1267
1268 /// @ingroup matrices_destroy
1269 /// @notyetdoced
1271
1272
1273 /// @ingroup matrices_sync
1274 /// @notyetdoced
1275 void syncCompMatr(CompMatr matr);
1276
1277
1278 /// @ingroup matrices_sync
1279 /// @notyetdoced
1280 void syncDiagMatr(DiagMatr matr);
1281
1282
1283 /// @ingroup matrices_sync
1284 /// @notyetdoced
1286
1287
1288#ifdef __cplusplus
1289}
1290#endif
1291
1292
1293
1294/*
1295 * VARIABLE-SIZE MATRIX SETTERS VIA POINTERS
1296 *
1297 * These functions permit users to pass heap and stack pointers:
1298 * - qcomp** ptr = malloc(...); setCompMatr(m, ptr);
1299 * - qcomp* ptrs[8]; setCompMatr(m, ptrs);
1300 * in both C and C++. By decay, they also permit arrays to diagonals:
1301 * - qcomp* ptr = malloc(...); setDiagMatr(m, ptr);
1302 * - qcomp arr[8]; setDiagMatr(m, arr);
1303 */
1304
1305
1306// de-mangle so below are directly callable by C and C++ binary
1307#ifdef __cplusplus
1308extern "C" {
1309#endif
1310
1311
1312 /** @ingroup matrices_setters
1313 * @notyetdoced
1314 *
1315 * @see
1316 * - setInlineCompMatr()
1317 * - reportCompMatr()
1318 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and
1319 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1320 */
1321 void setCompMatr(CompMatr matr, qcomp** vals);
1322
1323
1324 /** @ingroup matrices_setters
1325 * @notyetdoced
1326 *
1327 * @see
1328 * - setInlineDiagMatr()
1329 * - reportDiagMatr()
1330 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and
1331 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1332 */
1333 void setDiagMatr(DiagMatr out, qcomp* in);
1334
1335
1336 /** @ingroup matrices_setters
1337 * @notyetdoced
1338 * @notyettested
1339 *
1340 * @see
1341 * - [setInlineFullStateDiagMatr()](fhttps://quest-kit.github.io/QuEST/group__matrices__setters.html#gaa27aaa1a001a41f36a60847a19d824d4)
1342 * - reportFullStateDiagMatr()
1343 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and
1344 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1345 */
1346 void setFullStateDiagMatr(FullStateDiagMatr out, qindex startInd, qcomp* in, qindex numElems);
1347
1348
1349#ifdef __cplusplus
1350}
1351#endif
1352
1353
1354
1355/*
1356 * VARIABLE-SIZE MATRIX SETTERS VIA ARRAYS & VECTORS
1357 *
1358 * which define additional overloads for arrays, VLAs, vectors and vector initialisation lists.
1359 * C users can call:
1360 * - qcomp arr[8][8]; setCompMatr(m, arr);
1361 * - int n=8; qcomp arr[n][n]; setCompMatr(m, arr);
1362 * - setCompMatr(m, (qcomp[8][8]) {{...}});
1363 * - inline temporary VLA remains impossible even in C99, however
1364 * and C++ users can call:
1365 * - int n=8; std::vector vec(n); setCompMatr(m, vec);
1366 * - setCompMatr(m, {{...}});
1367 */
1368
1369
1370#if defined(__cplusplus)
1371
1372 // C++ defines vector overloads, permitting inline initialisation
1373
1374
1375 /** @ingroup matrices_setters
1376 * @notyetdoced
1377 * @cpponly
1378 *
1379 * @see
1380 * - setInlineCompMatr()
1381 * - reportCompMatr()
1382 * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1383 */
1384 void setCompMatr(CompMatr out, std::vector<std::vector<qcomp>> in);
1385
1386
1387 /** @ingroup matrices_setters
1388 * @notyetdoced
1389 * @cpponly
1390 *
1391 * @see
1392 * - setInlineDiagMatr()
1393 * - reportDiagMatr()
1394 * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1395 */
1396 void setDiagMatr(DiagMatr out, std::vector<qcomp> in);
1397
1398
1399 /** @ingroup matrices_setters
1400 * @notyetdoced
1401 * @notyettested
1402 * @cpponly
1403 *
1404 * @see
1405 * - [setInlineFullStateDiagMatr()](fhttps://quest-kit.github.io/QuEST/group__matrices__setters.html#gaa27aaa1a001a41f36a60847a19d824d4)
1406 * - reportFullStateDiagMatr()
1407 * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1408 */
1409 void setFullStateDiagMatr(FullStateDiagMatr out, qindex startInd, std::vector<qcomp> in);
1410
1411
1412 // C++ cannot accept 2D arrays at all, because it does not support C99 VLA.
1413 // It can however accept 1D arrays (which decay to pointers) already to setDiagMatr()
1414
1415#elif !defined(_MSC_VER)
1416
1417 // C first defines a bespoke functions receiving C99 VLAs, which we have to define here in
1418 // the header becauses the C++ source cannot use VLA, nor should we pass a 2D qcomp array
1419 // directly between C and C++ binaries (due to limited interoperability)
1420
1421
1422 // C must validate struct fields before accessing passed 2D arrays to avoid seg-faults
1423 /// @private
1424 extern void _validateParamsToSetCompMatrFromArr(CompMatr matr);
1425
1426
1427 // static inline to avoid header-symbol duplication
1428 /// @private
1429 static inline void _setCompMatrFromArr(CompMatr matr, qcomp arr[matr.numRows][matr.numRows]) {
1430 _validateParamsToSetCompMatrFromArr(matr);
1431
1432 // new ptrs array safely fits in stack, since it's sqrt-smaller than user's passed stack array
1433 qcomp* ptrs[matr.numRows];
1434
1435 // collect pointers to each row of arr
1436 for (qindex r=0; r<matr.numRows; r++)
1437 ptrs[r] = arr[r];
1438
1439 // array decays to qcomp**, and *FromPtr function re-performs validation (eh)
1440 setCompMatr(matr, ptrs); // validation gauranteed to pass
1441 }
1442
1443
1444 // C then overloads setCompMatr() to call the above VLA when given arrays, using C11 Generics.
1445 // See the doc of getCompMatr1() above for an explanation of Generic, and its nuances
1446
1447
1448 /// @neverdoced
1449 #define setCompMatr(matr, ...) \
1450 _Generic((__VA_ARGS__), \
1451 qcomp** : setCompMatr, \
1452 default : _setCompMatrFromArr \
1453 )((matr), (__VA_ARGS__))
1454
1455 // spoofing above macro as functions to doc
1456 #if 0
1457
1458 /** @ingroup matrices_setters
1459 * @notyetdoced
1460 * @macrodoc
1461 * @conly
1462 *
1463 * @see
1464 * - setInlineCompMatr()
1465 * - reportCompMatr()
1466 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) examples
1467 */
1468 void setCompMatr(CompMatr matr, qcomp arr[matr.numRows][matr.numRows]);
1469
1470 #endif
1471
1472
1473 // no need to define bespoke overload for diagonal matrices, because 1D arrays decay to pointers
1474
1475#else
1476
1477 // MSVC's C11 does not support C99 VLAs (which the standard left optional, grr!), so
1478 // we cannot support 2D-array initialisation of CompMatr at all. This means only the
1479 // existing setCompMatr(qcomp**) declared previously is usable by MSVC C users
1480
1481#endif
1482
1483
1484
1485/*
1486 * VARIABLE-SIZE MATRIX SETTERS VIA LITERALS
1487 *
1488 * which enable C users to give inline 2D array literals without having to use the
1489 * VLA compound literal syntax. We expose these macros to C++ too for API consistency,
1490 * although C++'s vector overloads achieve the same thing.
1491 *
1492 * These empower C and C++ users to call e.g.
1493 * - setInlineCompMatr(m, 1, {{1,2},{3,4}})
1494 */
1495
1496
1497#if defined(__cplusplus)
1498
1499 // C++ redirects to vector overloads, passing initialiser lists. The args like 'numQb'
1500 // are superfluous, but needed for consistency with the C API, so we additionally
1501 // validate that they match the struct dimensions (which requires validating the structs).
1502
1503
1504 /** @ingroup matrices_setters
1505 * @notyetdoced
1506 * @cpponly
1507 *
1508 * @see
1509 * - reportCompMatr()
1510 * - createInlineCompMatr()
1511 * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1512 */
1513 void setInlineCompMatr(CompMatr matr, int numQb, std::vector<std::vector<qcomp>> in);
1514
1515
1516 /** @ingroup matrices_setters
1517 * @notyetdoced
1518 * @cpponly
1519 *
1520 * @see
1521 * - reportDiagMatr()
1522 * - createInlineDiagMatr()
1523 * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1524 */
1525 void setInlineDiagMatr(DiagMatr matr, int numQb, std::vector<qcomp> in);
1526
1527
1528 /** @ingroup matrices_setters
1529 * @notyetdoced
1530 * @notyettested
1531 * @cpponly
1532 *
1533 * @see
1534 * - reportFullStateDiagMatr()
1535 * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1536 */
1537 void setInlineFullStateDiagMatr(FullStateDiagMatr matr, qindex startInd, qindex numElems, std::vector<qcomp> in);
1538
1539
1540#elif !defined(_MSC_VER)
1541
1542 // C defines macros which add compound literal syntax so that the user's passed lists
1543 // become compile-time-sized temporary arrays. C99 does not permit inline-initialised
1544 // VLAs, so we cannot have the macro expand to add (qcomp[matr.numRows][matr.numRows])
1545 // in order to preclude passing 'numQb'. We ergo accept and validate 'numQb' macro param.
1546 // We define private inner-functions of a macro, in lieu of writing multiline macros
1547 // using do-while, just to better emulate a function call for users - e.g. they
1548 // can wrap the macro invocations with another function call, etc.
1549
1550
1551 // the C validators check 'numQb' is consistent with the struct, but cannot check the user's passed literal sizes
1552 /// @private
1553 extern void _validateParamsToSetInlineCompMatr(CompMatr matr, int numQb);
1554 /// @private
1555 extern void _validateParamsToSetInlineDiagMatr(DiagMatr matr, int numQb);
1556 /// @private
1557 extern void _validateParamsToSetInlineFullStateDiagMatr(FullStateDiagMatr matr, qindex startInd, qindex numElems);
1558
1559
1560 /// @private
1561 static inline void _setInlineCompMatr(CompMatr matr, int numQb, qcomp elems[1<<numQb][1<<numQb]) {
1562 _validateParamsToSetInlineCompMatr(matr, numQb);
1563 _setCompMatrFromArr(matr, elems); // validation gauranteed to pass
1564 }
1565
1566 /// @private
1567 static inline void _setInlineDiagMatr(DiagMatr matr, int numQb, qcomp elems[1<<numQb]) {
1568 _validateParamsToSetInlineDiagMatr(matr, numQb);
1569 setDiagMatr(matr, elems); // 1D array decays into pointer, validation gauranteed to pass
1570 }
1571
1572 /// @private
1573 static inline void _setInlineFullStateDiagMatr(FullStateDiagMatr matr, qindex startInd, qindex numElems, qcomp elems[numElems]) {
1574 _validateParamsToSetInlineFullStateDiagMatr(matr, startInd, numElems);
1575 setFullStateDiagMatr(matr, startInd, elems, numElems); // 1D array decays into pointer, validation gauranteed to pass
1576 }
1577
1578
1579 // happily, macro arg 'numQb' must be a compile-time constant, so there is no risk of
1580 // unexpectedly re-evaluating user expressions due to its repetition in the macro
1581
1582
1583 /// @neverdoced
1584 #define setInlineCompMatr(matr, numQb, ...) \
1585 _setInlineCompMatr((matr), (numQb), (qcomp[1<<(numQb)][1<<(numQb)]) __VA_ARGS__)
1586
1587 /// @neverdoced
1588 #define setInlineDiagMatr(matr, numQb, ...) \
1589 _setInlineDiagMatr((matr), (numQb), (qcomp[1<<(numQb)]) __VA_ARGS__)
1590
1591 /// @neverdoced
1592 #define setInlineFullStateDiagMatr(matr, startInd, numElems, ...) \
1593 _setInlineFullStateDiagMatr((matr), (startInd), (numElems), (qcomp[(numElems)]) __VA_ARGS__)
1594
1595 // spoofing above macros as functions to doc
1596 #if 0
1597
1598
1599 /** @ingroup matrices_setters
1600 * @notyetdoced
1601 * @macrodoc
1602 *
1603 * @see
1604 * - reportCompMatr()
1605 * - createInlineCompMatr()
1606 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) examples
1607 */
1608 void setInlineCompMatr(CompMatr matr, int numQb, {{ matrix }});
1609
1610
1611 /** @ingroup matrices_setters
1612 * @notyetdoced
1613 * @macrodoc
1614 *
1615 * @see
1616 * - reportDiagMatr()
1617 * - createInlineDiagMatr()
1618 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) examples
1619 */
1620 void setInlineDiagMatr(DiagMatr matr, int numQb, { list });
1621
1622
1623 /** @ingroup matrices_setters
1624 * @notyettested
1625 * @notyetdoced
1626 * @macrodoc
1627 *
1628 * @see
1629 * - reportFullStateDiagMatr()
1630 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) examples
1631 */
1632 void setInlineFullStateDiagMatr(FullStateDiagMatr matr, qindex startInd, qindex numElems, { list });
1633
1634
1635 #endif
1636
1637
1638#else
1639
1640 // MSVC C11 does not support C99 VLAs, so the inner functions above are illegal.
1641 // As such, we must choose to either forego the internal validation (which
1642 // checks that the passed matrix object has been prior created with e.g.
1643 // createDiagMatr), or expand the macro into a do-while which users cannot ergo
1644 // place inside another function call. We opt to preclude the latter, since it
1645 // seems an unlikely use-case (because the function returns void) and will give
1646 // a compile-time error, whereas removing validation could cause silent seg-faults
1647 // when users incorrectly initialise an un-created matrix.
1648
1649 // Note however that because MSVC does not support C99 VLA in C11, such that
1650 // _setCompMatrFromArr() was not defined, so we cannot define setInlineCompMatr();
1651 // MSVC C users simply miss out on this convenience function. Take it up with Bill!
1652
1653 /// @private
1654 extern void _validateParamsToSetInlineDiagMatr(DiagMatr matr, int numQb);
1655 /// @private
1656 extern void _validateParamsToSetInlineFullStateDiagMatr(FullStateDiagMatr matr, qindex startInd, qindex numElems);
1657
1658
1659 /// @neverdoced
1660 #define setInlineDiagMatr(matr, numQb, ...) \
1661 do { \
1662 _validateParamsToSetInlineDiagMatr((matr), (numQb)); \
1663 setDiagMatr((matr), (numQb), (qcomp[1<<(numQb)]) __VA_ARGS__); \
1664 } while (0)
1665
1666
1667 /// @neverdoced
1668 #define setInlineFullStateDiagMatr(matr, startInd, numElems, ...) \
1669 do { \
1670 _validateParamsToSetInlineFullStateDiagMatr((matr), (startInd), (numElems)); \
1671 setFullStateDiagMatr((matr), (startInd), (elems), (numElems)); \
1672 } while (0)
1673
1674
1675 // the above macros are documented in the previous #if branch
1676
1677#endif
1678
1679
1680
1681/*
1682 * VARIABLE-SIZE MATRIX CREATORS VIA LITERALS
1683 *
1684 * which simply combine the create*() and setInline*() functions, for
1685 * user convenience, and to reduce their risk of passing inconsistent params.
1686 * We do not define inline creators for FullStateDiagMatr, since the
1687 * creator automatically decides whether or not to distribute the matrix;
1688 * ergo the user cannot know how many elements to pass in their literal
1689 * (nor should they ever distribute data which fits into a single literal!)
1690 *
1691 * These empower C and C++ users to call e.g.
1692 * - CompMatr m = createInlineCompMatr(1, {{1,2},{3,4}})
1693 */
1694
1695
1696#if defined(__cplusplus)
1697
1698 // C++ accepts vector initialiser lists
1699
1700
1701 /** @ingroup matrices_create
1702 * @notyetdoced
1703 * @cpponly
1704 *
1705 * @see
1706 * - reportCompMatr()
1707 * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1708 */
1709 CompMatr createInlineCompMatr(int numQb, std::vector<std::vector<qcomp>> elems);
1710
1711
1712 /** @ingroup matrices_create
1713 * @notyetdoced
1714 * @cpponly
1715 *
1716 * @see
1717 * - reportDiagMatr()
1718 * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples
1719 */
1720 DiagMatr createInlineDiagMatr(int numQb, std::vector<qcomp> elems);
1721
1722
1723#elif !defined(_MSC_VER)
1724
1725 // C defines macros which add compound literal syntax so that the user's passed lists
1726 // become compile-time-sized temporary arrays. We use bespoke validation so that the
1727 // error messages reflect the name of the macro, rather than the inner called functions.
1728 // We define a private inner function per macro, in lieu of writing multiline macros
1729 // using do-while, just to better emulate a function call for users - e.g. they
1730 // can wrap the macro invocation with another function call.
1731
1732
1733 /// @private
1734 extern void _validateParamsToCreateInlineCompMatr(int numQb);
1735 /// @private
1736 extern void _validateParamsToCreateInlineDiagMatr(int numQb);
1737
1738
1739 /// @private
1740 static inline CompMatr _createInlineCompMatr(int numQb, qcomp elems[1<<numQb][1<<numQb]) {
1741 _validateParamsToCreateInlineCompMatr(numQb);
1742 CompMatr out = createCompMatr(numQb); // malloc failures will report 'createCompMatr', rather than 'inline' version. Alas!
1743 _setCompMatrFromArr(out, elems);
1744 return out;
1745 }
1746
1747 /// @private
1748 static inline DiagMatr _createInlineDiagMatr(int numQb, qcomp elems[1<<numQb]) {
1749 _validateParamsToCreateInlineDiagMatr(numQb);
1750 DiagMatr out = createDiagMatr(numQb); // malloc failures will report 'createCompMatr', rather than 'inline' version. Alas!
1751 setDiagMatr(out, elems); // 1D array decays to ptr
1752 return out;
1753 }
1754
1755
1756 /// @neverdoced
1757 #define createInlineCompMatr(numQb, ...) \
1758 _createInlineCompMatr((numQb), (qcomp[1<<(numQb)][1<<(numQb)]) __VA_ARGS__)
1759
1760 /// @neverdoced
1761 #define createInlineDiagMatr(numQb, ...) \
1762 _createInlineDiagMatr((numQb), (qcomp[1<<(numQb)]) __VA_ARGS__)
1763
1764 // spoofing above macros as functions to doc
1765 #if 0
1766
1767
1768 /** @ingroup matrices_create
1769 * @notyetdoced
1770 * @macrodoc
1771 *
1772 * @see
1773 * - reportCompMatr()
1774 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) examples
1775 */
1776 CompMatr createInlineCompMatr(int numQb, {{ matrix }});
1777
1778
1779 /** @ingroup matrices_create
1780 * @notyetdoced
1781 * @macrodoc
1782 *
1783 * @see
1784 * - reportDiagMatr()
1785 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) examples
1786 */
1787 DiagMatr createInlineDiagMatr(int numQb, { list });
1788
1789
1790 #endif
1791
1792#else
1793
1794 // MSVC's C11 does not support C99 VLA, so we cannot use the above inner functions.
1795 // The nuisance of trying to create, modify then return a matrix instance using
1796 // MSVC-specific preprocessors is too annoying, so Windows C users miss out! :(
1797
1798#endif
1799
1800
1801
1802/*
1803 * SPECIAL CREATORS AND SETTERS
1804 */
1805
1806
1807#ifdef __cplusplus
1808extern "C" {
1809#endif
1810
1811
1812 /// @todo
1813 /// add std::vector<int> overloads for C++ users for the
1814 /// below functions (missed during original overload work)
1815
1816
1817 /// @ingroup matrices_setters
1818 /// @notyetdoced
1819 /// @notyettested
1820 void setDiagMatrFromMultiVarFunc(DiagMatr out, qcomp (*func)(qindex*), int* numQubitsPerVar, int numVars, int areSigned);
1821
1822
1823 /// @ingroup matrices_setters
1824 /// @notyetdoced
1825 /// @notyettested
1826 void setDiagMatrFromMultiDimLists(DiagMatr out, void* lists, int* numQubitsPerDim, int numDims);
1827
1828
1829 /// @ingroup matrices_create
1830 /// @notyetdoced
1831 /// @notyettested
1833
1834
1835 /// @ingroup matrices_setters
1836 /// @notyetdoced
1837 /// @notyettested
1839
1840
1841 /// @ingroup matrices_setters
1842 /// @notyetdoced
1843 /// @notyettested
1844 void setFullStateDiagMatrFromMultiVarFunc(FullStateDiagMatr out, qcomp (*func)(qindex*), int* numQubitsPerVar, int numVars, int areSigned);
1845
1846
1847 /// @ingroup matrices_setters
1848 /// @notyetdoced
1849 /// @notyettested
1850 void setFullStateDiagMatrFromMultiDimLists(FullStateDiagMatr out, void* lists, int* numQubitsPerDim, int numDims);
1851
1852
1853#ifdef __cplusplus
1854}
1855#endif
1856
1857
1858
1859/*
1860 * MATRIX REPORTERS
1861 */
1862
1863
1864// de-mangle so below are directly callable by C binary
1865#ifdef __cplusplus
1866extern "C" {
1867#endif
1868
1869
1870 /** @ingroup matrices_reporters
1871 * @notyetdoced
1872 * @notyettested
1873 *
1874 * @see
1875 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.c) and
1876 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.cpp) examples
1877 */
1878 void reportCompMatr1(CompMatr1 matrix);
1879
1880
1881 /** @ingroup matrices_reporters
1882 * @notyetdoced
1883 * @notyettested
1884 *
1885 * @see
1886 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.c) and
1887 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.cpp) examples
1888 */
1889 void reportCompMatr2(CompMatr2 matrix);
1890
1891
1892 /** @ingroup matrices_reporters
1893 * @notyetdoced
1894 * @notyettested
1895 *
1896 * @see
1897 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.c) and
1898 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.cpp) examples
1899 */
1900 void reportCompMatr(CompMatr matrix);
1901
1902
1903 /** @ingroup matrices_reporters
1904 * @notyetdoced
1905 * @notyettested
1906 *
1907 * @see
1908 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.c) and
1909 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.cpp) examples
1910 */
1911 void reportDiagMatr1(DiagMatr1 matrix);
1912
1913
1914 /** @ingroup matrices_reporters
1915 * @notyetdoced
1916 * @notyettested
1917 *
1918 * @see
1919 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.c) and
1920 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.cpp) examples
1921 */
1922 void reportDiagMatr2(DiagMatr2 matrix);
1923
1924
1925 /// @ingroup matrices_reporters
1926 /// @notyetdoced
1927 /// @notyettested
1928 void reportDiagMatr(DiagMatr matrix);
1929
1930
1931 /** @ingroup matrices_reporters
1932 * @notyetdoced
1933 * @notyettested
1934 *
1935 * @see
1936 * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.c) and
1937 * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.cpp) examples
1938 */
1940
1941
1942#ifdef __cplusplus
1943}
1944#endif
1945
1946
1947
1948#endif // MATRICES_H
1949
1950/** @} */ // (end file-wide doxygen defgroup)
FullStateDiagMatr createCustomFullStateDiagMatr(int numQubits, int useDistrib, int useGpuAccel, int useMultithread)
Definition matrices.cpp:318
FullStateDiagMatr createFullStateDiagMatr(int numQubits)
Definition matrices.cpp:323
CompMatr createCompMatr(int numQubits)
Definition matrices.cpp:213
DiagMatr createDiagMatr(int numQubits)
Definition matrices.cpp:248
FullStateDiagMatr createFullStateDiagMatrFromPauliStrSum(PauliStrSum in)
Definition matrices.cpp:651
void destroyDiagMatr(DiagMatr matrix)
Definition matrices.cpp:399
void destroyFullStateDiagMatr(FullStateDiagMatr matrix)
Definition matrices.cpp:400
void destroyCompMatr(CompMatr matrix)
Definition matrices.cpp:398
static CompMatr2 getCompMatr2(qcomp **in)
Definition matrices.h:837
static CompMatr1 getCompMatr1(qcomp **in)
Definition matrices.h:811
static DiagMatr2 getDiagMatr2(qcomp *in)
Definition matrices.h:889
CompMatr1 getInlineCompMatr1({{ matrix }})
CompMatr2 getInlineCompMatr2({{ matrix }})
DiagMatr2 getInlineDiagMatr2({ list })
static DiagMatr1 getDiagMatr1(qcomp *in)
Definition matrices.h:864
DiagMatr1 getInlineDiagMatr1({ list })
void reportCompMatr2(CompMatr2 matrix)
Definition matrices.cpp:783
void reportDiagMatr1(DiagMatr1 matrix)
Definition matrices.cpp:785
void reportCompMatr(CompMatr matrix)
Definition matrices.cpp:784
void reportDiagMatr2(DiagMatr2 matrix)
Definition matrices.cpp:786
void reportCompMatr1(CompMatr1 matrix)
Definition matrices.cpp:782
void reportDiagMatr(DiagMatr matrix)
Definition matrices.cpp:787
void reportFullStateDiagMatr(FullStateDiagMatr matr)
Definition matrices.cpp:788
void setFullStateDiagMatrFromMultiDimLists(FullStateDiagMatr out, void *lists, int *numQubitsPerDim, int numDims)
Definition matrices.cpp:723
void setDiagMatrFromMultiDimLists(DiagMatr out, void *lists, int *numQubitsPerDim, int numDims)
Definition matrices.cpp:701
void setFullStateDiagMatrFromMultiVarFunc(FullStateDiagMatr out, qcomp(*func)(qindex *), int *numQubitsPerVar, int numVars, int areSigned)
Definition matrices.cpp:687
void setDiagMatr(DiagMatr out, qcomp *in)
Definition matrices.cpp:431
void setCompMatr(CompMatr matr, qcomp **vals)
Definition matrices.cpp:423
void setFullStateDiagMatr(FullStateDiagMatr out, qindex startInd, qcomp *in, qindex numElems)
Definition matrices.cpp:443
void setDiagMatrFromMultiVarFunc(DiagMatr out, qcomp(*func)(qindex *), int *numQubitsPerVar, int numVars, int areSigned)
Definition matrices.cpp:667
void setFullStateDiagMatrFromPauliStrSum(FullStateDiagMatr out, PauliStrSum in)
Definition matrices.cpp:634
void syncFullStateDiagMatr(FullStateDiagMatr matr)
Definition matrices.cpp:375
void syncDiagMatr(DiagMatr matr)
Definition matrices.cpp:374
void syncCompMatr(CompMatr matr)
Definition matrices.cpp:373
qindex numRows
Definition matrices.h:93
qcomp elems[2][2]
Definition matrices.h:97
int numQubits
Definition matrices.h:89
int numQubits
Definition matrices.h:124
qcomp elems[4][4]
Definition matrices.h:132
qindex numRows
Definition matrices.h:128
qindex numRows
Definition matrices.h:179
qcomp * gpuElemsFlat
Definition matrices.h:293
int * wasGpuSynced
Definition matrices.h:239
int * isApproxHermitian
Definition matrices.h:221
int * isApproxUnitary
Definition matrices.h:198
qcomp * cpuElemsFlat
Definition matrices.h:280
qcomp ** cpuElems
Definition matrices.h:261
int numQubits
Definition matrices.h:172
int numQubits
Definition matrices.h:327
qcomp elems[2]
Definition matrices.h:336
qindex numElems
Definition matrices.h:331
qcomp elems[4]
Definition matrices.h:372
int numQubits
Definition matrices.h:363
qindex numElems
Definition matrices.h:367
int * isApproxNonZero
Definition matrices.h:460
qindex numElems
Definition matrices.h:419
int * isStrictlyNonNegative
Definition matrices.h:472
int * wasGpuSynced
Definition matrices.h:490
qcomp * cpuElems
Definition matrices.h:506
qcomp * gpuElems
Definition matrices.h:519
int * isApproxUnitary
Definition matrices.h:438
int numQubits
Definition matrices.h:412
int * isApproxHermitian
Definition matrices.h:449
int * isApproxUnitary
Definition matrices.h:628
int * isStrictlyNonNegative
Definition matrices.h:659
int * isApproxHermitian
Definition matrices.h:636
qindex numElemsPerNode
Definition matrices.h:606
int * isApproxNonZero
Definition matrices.h:647