From e9036c3f8a47330cb33bc87405ddd3886f5dfd5b Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Thu, 2 Jul 2026 22:46:11 -0400 Subject: [PATCH 01/29] Move API and Tests doc links to top-level --- quest/include/quest.h | 20 +++++++------------ utils/docs/layout/doxygen-awesome-quest.js | 23 ++++++++++++++++++++++ utils/docs/layout/layout.xml | 2 +- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/quest/include/quest.h b/quest/include/quest.h index da1c778e2..4378e00dc 100644 --- a/quest/include/quest.h +++ b/quest/include/quest.h @@ -9,21 +9,18 @@ * @defgroup api 📋 API */ -/** - * @page apilink 📋 API - * The API documentation can be viewed at @ref api. - * - * We're working hard to move that page up one level. 😎 - */ + +// Create empty 'apilink' and 'testlink' top-level pages which +// will appear as links in the left-hand navigation column of +// the rendered doc pages. We will redirect the links to the +// API and Test doc groups within doxygen-awesome-quest.js /** + * @page apilink 📋 API * @page testlink 🧪 Tests - * - * The unit and integration tests can be viewed at @ref tests. - * - * We're working hard to move that page up one level. 😎 */ + #ifndef QUEST_H #define QUEST_H @@ -49,11 +46,8 @@ #include "quest/include/matrices.h" #include "quest/include/wrappers.h" - #if QUEST_INCLUDE_DEPRECATED_FUNCTIONS #include "quest/include/deprecated.h" #endif - - #endif // QUEST_H diff --git a/utils/docs/layout/doxygen-awesome-quest.js b/utils/docs/layout/doxygen-awesome-quest.js index 8b447a418..f6ffa1e5c 100644 --- a/utils/docs/layout/doxygen-awesome-quest.js +++ b/utils/docs/layout/doxygen-awesome-quest.js @@ -1,3 +1,26 @@ +/* + * custom javascript to override Doxygen Awesome's + * default links / behaviour. + * @author Tyson Jones + */ + + +/* redirects the top-level API and Tests links in the left column of the doc + * page (originally apilink.html and testlink.html) to the Doxygen groups of + * the same name (which are themselves seemingly impossible to get into the + * top-level directly! They're always beneath a "Topics" collapsible section, + * which we make invisible in layout.xml) + */ +(function() { + let fn = window.location.pathname.split("/").pop(); + if (fn === "apilink.html") { + window.location.replace(window.location.pathname.replace('apilink.html', 'group__api.html')); + } + if (fn === "testlink.html") { + window.location.replace(window.location.pathname.replace('testlink.html', 'group__tests.html')); + } +})(); + window.addEventListener('DOMContentLoaded', (event) => { diff --git a/utils/docs/layout/layout.xml b/utils/docs/layout/layout.xml index 08a8c5ee6..4b4cb56cf 100644 --- a/utils/docs/layout/layout.xml +++ b/utils/docs/layout/layout.xml @@ -5,7 +5,7 @@ - + From b1cf2d4900b81664e5d3ee3b605509cb47a6c58f Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sat, 4 Jul 2026 12:44:45 -0400 Subject: [PATCH 02/29] Complete decoherence doc except the C++ overloads --- quest/include/decoherence.h | 368 ++++++++++++++++++++++++++++++++++-- 1 file changed, 348 insertions(+), 20 deletions(-) diff --git a/quest/include/decoherence.h b/quest/include/decoherence.h index cbe6b04c5..85bd14e4a 100644 --- a/quest/include/decoherence.h +++ b/quest/include/decoherence.h @@ -29,7 +29,11 @@ extern "C" { #endif -/** @notyetdoced +/** Applies a one-qubit dephasing channel upon the density matrix @p qureg, + * where @p prob is the probability of a @f$ \hat{Z} @f$ error upon the + * @p target qubit. + * + * This is also known as a phase-flip channel. * * @formulae * @@ -43,6 +47,19 @@ extern "C" { \,+\, p \, \hat{Z}_t \,\dmrho\, \hat{Z}_t. * @f] + * + * This is a physically valid operation (is completely positive and trace preserving) + * when @f$ 0 \le p \le 1 @f$, and is a meaningful noise channel (i.e. induces mixing) + * for @f$ 0 < p \le 1/2 @f$. + * + * @constraints + * + * - Parameter @p prob must be a valid probability and ergo satisfy @f$ 0 \le p \le 1 @f$ + * unless validation is disabled via setQuESTValidationOff(), which permits quasi-probability + * channels with even negative probabilities. + * - The maximum permitted error probability is @f$ p = 1/2 @f$ (unless validation is disabled) + * at which the qubit becomes completely "dephased", and the off-diagonal "coherences" become zero. + * - With validation disabled, the channel remains CPTP for @f$ 1/2 \le p \le 1 @f$. * * @equivalences * @@ -71,11 +88,27 @@ extern "C" { * ``` * * @notyetvalidated + * + * @param[in,out] qureg the density matrix to modify. + * @param[in] target the index of the target qubit. + * @param[in] prob the probability of any error. + * @throws @validationerror + * - if @p qureg is not initialised. + * - if @p qureg is not a density matrix (unless @p prob is 0). + * - if @p target is an invalid qubit index. + * - if @p prob < 0, or @p prob > 1/2. + * @see + * - mixTwoQubitDephasing() + * - mixDepolarising() + * - mixPaulis() + * @author Tyson Jones */ void mixDephasing(Qureg qureg, int target, qreal prob); -/** @notyetdoced +/** Applies a two-qubit dephasing channel upon the density matrix @p qureg, + * where @p prob is the probability of a @f$ \hat{Z} @f$ error upon either + * or both of qubits @p target1 and @p target2, which are interchangeable. * * @formulae * @@ -90,11 +123,25 @@ void mixDephasing(Qureg qureg, int target, qreal prob); \frac{p}{3} \left( \hat{Z}_{t_1} \dmrho \hat{Z}_{t_1} \,+\, - \hat{Z}_{t_1} \dmrho \hat{Z}_{t_1} + \hat{Z}_{t_2} \dmrho \hat{Z}_{t_2} \,+\, \hat{Z}_{t_1} \hat{Z}_{t_2} \dmrho \hat{Z}_{t_1} \hat{Z}_{t_2} \right). * @f] + * + * This is a physically valid operation (is completely positive and trace preserving) + * when @f$ 0 \le p \le 1 @f$, and is a meaningful noise channel (i.e. induces mixing) + * for @f$ 0 < p \le 3/4 @f$. + * + * @constraints + * + * - Parameter @p prob must be a valid probability and ergo satisfy @f$ 0 \le p \le 1 @f$ + * unless validation is disabled via setQuESTValidationOff(), which permits quasi-probability + * channels with even negative probabilities. + * - The maximum permitted error probability is @f$ p = 3/4 @f$ (unless validation is disabled), + * at which the channel is "maximum strength" and the off-diagonal "coherences" of the two qubits + * become zero. + * - With validation disabled, the channel remains CPTP for @f$ 3/4 \le p \le 1 @f$. * * @equivalences * @@ -117,11 +164,28 @@ void mixDephasing(Qureg qureg, int target, qreal prob); * ``` * * @notyetvalidated + * + * @param[in,out] qureg the density matrix to modify. + * @param[in] target1 the index of the first target qubit. + * @param[in] target2 the index of the second target qubit. + * @param[in] prob the probability of any error. + * @throws @validationerror + * - if @p qureg is not initialised. + * - if @p qureg is not a density matrix (unless @p prob is 0). + * - if @p target1 or @p target2 is an invalid qubit index, or are the same. + * - if @p prob < 0, or @p prob > 3/4. + * @see + * - createDensityQureg() + * - mixDephasing() + * - mixDepolarising() + * - mixPaulis() + * @author Tyson Jones */ void mixTwoQubitDephasing(Qureg qureg, int target1, int target2, qreal prob); -/** @notyetdoced +/** Applies a one-qubit homogeneous depolarising channel upon the density matrix @p qureg, + * where @p prob is the probability of any error upon the @p target qubit. * * @formulae * @@ -136,6 +200,19 @@ void mixTwoQubitDephasing(Qureg qureg, int target1, int target2, qreal prob); \hat{Z}_t \dmrho \hat{Z}_t \right). * @f] + * + * This is a physically valid operation (is completely positive and trace preserving) + * when @f$ 0 \le p \le 1 @f$, and is a meaningful noise channel (i.e. induces mixing) + * for @f$ 0 < p \le 3/4 @f$. + * + * @constraints + * + * - Parameter @p prob must be a valid probability and ergo satisfy @f$ 0 \le p \le 1 @f$ + * unless validation is disabled via setQuESTValidationOff(), which permits quasi-probability + * channels with even negative probabilities. + * - The maximum permitted error probability is @f$ p = 3/4 @f$ (unless validation is disabled), + * at which the channel is maximum strength, and the qubit enters the maximally mixed state. + * - With validation disabled, the channel remains CPTP for @f$ 3/4 \le p \le 1 @f$. * * @equivalences * @@ -152,7 +229,7 @@ void mixTwoQubitDephasing(Qureg qureg, int target1, int target2, qreal prob); KrausMap map = createInlineKrausMap(1, 4, { {{a,0},{0, a}}, // a * I {{0,b},{b, 0}}, // b * X - {{b,0},{0,-b}} // b * Z + {{b,0},{0,-b}}, // b * Z {{0,-1i*b},{1i*b,0}}, // b * Y }); @@ -160,11 +237,27 @@ void mixTwoQubitDephasing(Qureg qureg, int target1, int target2, qreal prob); * ``` * * @notyetvalidated + * + * @param[in,out] qureg the density matrix to modify. + * @param[in] target the index of the target qubit. + * @param[in] prob the probability of any error. + * @throws @validationerror + * - if @p qureg is not initialised. + * - if @p qureg is not a density matrix (unless @p prob is 0). + * - if @p target is an invalid qubit index. + * - if @p prob < 0, or @p prob > 3/4. + * @see + * - mixTwoQubitDepolarising() + * - mixDephasing() + * - mixPaulis() + * @author Tyson Jones */ void mixDepolarising(Qureg qureg, int target, qreal prob); -/** @notyetdoced +/** Applies a two-qubit homogeneous depolarising channel upon the density matrix @p qureg, + * where @p prob is the probability of any error upon either + * or both of qubits @p target1 and @p target2, which are interchangeable. * * @formulae * @@ -209,12 +302,25 @@ void mixDepolarising(Qureg qureg, int target, qreal prob); \hat{Z}_{t_1} \hat{X}_{t_2} \, \rho \, \hat{Z}_{t_1} \hat{X}_{t_2} + \\ \hat{X}_{t_1} \hat{Z}_{t_2} \, \rho \, \hat{X}_{t_1} \hat{Z}_{t_2} + - \hat{Y}_{t_1} \hat{X}_{t_2} \, \rho \, \hat{Y}_{t_1} \hat{Z}_{t_2} + + \hat{Y}_{t_1} \hat{X}_{t_2} \, \rho \, \hat{Y}_{t_1} \hat{X}_{t_2} + \hat{Z}_{t_1} \hat{Y}_{t_2} \, \rho \, \hat{Z}_{t_1} \hat{Y}_{t_2} \end{gathered} \right). * @f] * + * This is a physically valid operation (is completely positive and trace preserving) + * when @f$ 0 \le p \le 1 @f$, and is a meaningful noise channel (i.e. induces mixing) + * for @f$ 0 < p \le 15/16 @f$. + * + * @constraints + * + * - Parameter @p prob must be a valid probability and ergo satisfy @f$ 0 \le p \le 1 @f$ + * unless validation is disabled via setQuESTValidationOff(), which permits quasi-probability + * channels with even negative probabilities. + * - The maximum permitted error probability is @f$ p = 15/16 @f$ (unless validation is disabled), + * at which the channel is maximum strength, and the target qubits become maximally mixed. + * - With validation disabled, the channel remains CPTP for @f$ 15/16 \le p \le 1 @f$. + * * @equivalences * * This function is equivalent to (but much faster than): @@ -223,11 +329,26 @@ void mixDepolarising(Qureg qureg, int target, qreal prob); * @f$ \hat{\id} \otimes \hat{\id} @f$ which is scaled by @f$ (1-16p/15)^{1/2} @f$. * * @notyetvalidated + * + * @param[in,out] qureg the density matrix to modify. + * @param[in] target1 the index of the first target qubit. + * @param[in] target2 the index of the second target qubit. + * @param[in] prob the probability of any error. + * @throws @validationerror + * - if @p qureg is not initialised. + * - if @p qureg is not a density matrix (unless @p prob is 0). + * - if @p target1 or @p target2 is an invalid qubit index, or are the same. + * - if @p prob < 0, or @p prob > 15/16. + * @see + * - createDensityQureg() + * - mixTwoQubitDephasing() + * @author Tyson Jones */ void mixTwoQubitDepolarising(Qureg qureg, int target1, int target2, qreal prob); -/** @notyetdoced +/** Applies a one-qubit amplitude damping channel upon the density matrix @p qureg, + * where @p prob is the probability of the @p target qubit relaxing to the zero state. * * @formulae * @@ -244,9 +365,20 @@ void mixTwoQubitDepolarising(Qureg qureg, int target1, int target2, qreal prob); * @f[ \hat{K}^{(1)} = \begin{pmatrix} 1 & 0 \\ 0 & \sqrt{1-p} \end{pmatrix}, \;\; - \hat{K}^{(1)} = \begin{pmatrix} 0 & \sqrt{p} \\ 0 & 0 \end{pmatrix}. + \hat{K}^{(2)} = \begin{pmatrix} 0 & \sqrt{p} \\ 0 & 0 \end{pmatrix}. * @f] + * + * This is a physically valid operation (the channel is completely positive and trace + * preserving) for @f$ 0 \le p \le 1 @f$. Note however that it may actually reduce + * mixing and increase purity, depending on @f$ p @f$ and the qubit's initial state. * + * @constraints + * + * - Parameter @p prob must be a valid probability and ergo satisfy @f$ 0 \le p \le 1 @f$. + * Beware that disabling validation with setQuESTValidationOff() and passing @p prob + * outside this domain will result in mathematically erroneous results; amplitudes which + * are erroneously zero, or @c NaN, as output by @c sqrt(). + * * @equivalences * * This function is equivalent to (but much faster than): @@ -261,11 +393,25 @@ void mixTwoQubitDepolarising(Qureg qureg, int target1, int target2, qreal prob); * ``` * * @notyetvalidated + * + * @param[in,out] qureg the density matrix to modify. + * @param[in] target the index of the target qubit. + * @param[in] prob the probability of relaxing to zero. + * @throws @validationerror + * - if @p qureg is not initialised. + * - if @p qureg is not a density matrix (unless @p prob is 0). + * - if @p target is an invalid qubit index. + * - if @p prob < 0 or @p prob > 1. + * @see + * - mixKrausMap() + * @author Tyson Jones */ void mixDamping(Qureg qureg, int target, qreal prob); -/** @notyetdoced +/** Applies a one-qubit inhomogeneous Pauli channel upon the density matrix @p qureg. + * + * This is a generalisation of mixDepolarising(), permitting inhomogeneous error probabilities. * * @formulae * @@ -283,6 +429,27 @@ void mixDamping(Qureg qureg, int target, qreal prob); \,+\, p_z \, \hat{Z}_t \dmrho \hat{Z}_t. * @f] + * + * This operation is physically valid (completely positive and trace preserving) when each + * probability is valid (@f$ 0 \le p_i \le 1 @f$), and together satisfy + * @f[ + * p_x + p_y + p_z \le 1. + * @f] + * The operation is a meaningful noise channel (decreases purity) when the probabilities are + * below that which induces maximal mixing; when the probability of no error is greater than + * the probability of any error. + * @f[ + * 1 - (p_x + p_y + p_z) \ge \max(p_x, p_y, p_z). + * @f] + * + * @constraints + * + * - Each of @p probX, @p probY, and @p probZ must be a valid probability, i.e. @f$ 0 \le p_i \le 1 @f$, + * and the probability of no error (one minus their sum) must also be valid. This can be relaxed + * using setQuESTValidationOff() to effect channels which are not completely-positive and trace-preserving, + * such as quasi-probability channels. + * - The channel strength must not exceed that which induces maximal mixing (unless validation is disabled), + * whereby the probability of any particular error equals that of no error. * * @equivalences * @@ -297,7 +464,7 @@ void mixDamping(Qureg qureg, int target, qreal prob); KrausMap map = createInlineKrausMap(1, 4, { {{a,0},{0, a}}, // a * I {{0,b},{b, 0}}, // b * X - {{d,0},{0,-d}} // d * Z + {{d,0},{0,-d}}, // d * Z {{0,-1i*c},{1i*c,0}}, // c * Y }); @@ -305,30 +472,77 @@ void mixDamping(Qureg qureg, int target, qreal prob); * ``` * * @notyetvalidated + * + * @param[in,out] qureg the density matrix to modify. + * @param[in] target the index of the target qubit. + * @param[in] probX the probability of an X operator upon @p target. + * @param[in] probY the probability of an Y operator upon @p target. + * @param[in] probZ the probability of an Z operator upon @p target. + * @throws @validationerror + * - if @p qureg is not initialised. + * - if @p qureg is not a density matrix (unless @p probX = @p probY = @p probZ = 0). + * - if @p target is an invalid qubit index. + * - if any probability is invalid (below zero or above one). + * - if the probability of any error exceeds that of no error. + * @see + * - mixDephasing() + * - mixDepolarising() + * - mixKrausMap + * @author Tyson Jones */ void mixPaulis(Qureg qureg, int target, qreal probX, qreal probY, qreal probZ); -/** @notyetdoced +/** Modifies the density matrix @p qureg to the mixture of itself and density matrix or + * statevector @p other. * * @formulae * - * Let @f$ \dmrho_1 = @f$ @p qureg, @f$ \dmrho_2 = @f$ @p other and @f$ p = @f$ @p prob. + * Let @f$ \dmrho_1 = @f$ @p qureg and @f$ p = @f$ @p prob. * - * This function effects - * @f[ + * - When @p other is a density matrix @f$ \dmrho_2 @f$, this function effects + * @f[ \dmrho_1 \;\rightarrow \; (1 - p) \, \dmrho_1 \,+\, p \, \dmrho_2. - * @f] + * @f] + * - When @p other is a statevector @f$ \ket{\psi_2} @f$, this function effects + * @f[ + \dmrho_1 \;\rightarrow \; + (1 - p) \, \dmrho_1 + \,+\, + p \, \ketbra{\psi_2}{\psi_2}. + * @f] + * + * @constraints + * + * - @p qureg and @p other must contain the same number of qubits. + * - If @p other is a density matrix, it must be identically distributed to @p qureg + * (although the parallelisation backends, like multithreading and GPU acceleration, are + * permitted to differ). + * - If @p other is a statevector and @p qureg is not distributed, neither too must @p other. * * @notyetvalidated + * + * @param[in,out] qureg the density matrix to modify. + * @param[in] other the density matrix or statevector to mix into @p qureg. + * @param[in] prob the coefficient of @p other in the mixture. + * @throws @validationerror + * - if @p qureg is not initialised. + * - if @p qureg is not a density matrix. + * - if @p qureg and @p other contain a different number of qubits. + * - if @p prob is not a valid probability. + * - if @p other is a density matrix which is differently distributed to @p qureg. + * - if @p other is a distributed statevector, but @p qureg is not distributed. + * @see + * - mixKrausMap() + * @author Tyson Jones */ void mixQureg(Qureg qureg, Qureg other, qreal prob); -/** @notyetdoced +/** Applies a general, any-size channel described as a Kraus map to the density matrix @p qureg. * * @formulae * @@ -339,16 +553,130 @@ void mixQureg(Qureg qureg, Qureg other, qreal prob); * @f[ \dmrho \; \rightarrow \; \sum\limits_i - \hat{K}_{\vec{t}}^{(i)} \dmrho \, {\hat{K}_{\vec{t}}^{(i)}}^\dagger + \hat{K}_{\vec{t}}^{(i)} \dmrho \, {\hat{K}_{\vec{t}}^{(i)}}^\dagger. + * @f] + * + * The channel is completely positive and trace preserving (CPTP) when the Kraus operators satisfy + * @f[ + \sum\limits_i {\hat{K}_{\vec{t}}^{(i)}}^\dagger \hat{K}_{\vec{t}}^{(i)} = \mathbb{1}. + * @f] + * + * @constraints + * + * - The number of channel targets must agree with the size of the Kraus map. + * - The channel must be CPTP unless disabled with setQuESTValidationEpsilon(), specifying + * @c eps=0, or all validation is (dangerously) disabled with setQuESTValidationOff(). + * - When @p qureg is distributed, each node must contain at least @c pow(2,2*numTargets) + * many amplitudes, to ensure sufficient communication buffers are allocated. + * + * @equivalences + * + * This function calls mixSuperOp(), passing the corresponding superoperator of @p map, which has the form + * @f[ + \hat{S} = \sum\limits_i {\hat{K}_{\vec{t}}^{(i)}}^* \otimes \hat{K}_{\vec{t}}^{(i)}. * @f] * * @notyetvalidated + * + * @param[in,out] qureg the density matrix to modify. + * @param[in] targets the list of target qubit indices. + * @param[in] numTargets the length of @p targets + * @param[in] map a compatible-sized KrausMap. + * @throws @validationerror + * - if @p qureg is not initialised. + * - if @p qureg is not a density matrix. + * - if @p targets contains a duplicate or invalid qubit index. + * - if @p numTargets is less than one, or exceeds the size of @p qureg. + * - if @p map is not initialised. + * - if @p map contains a different number of qubits than @p numTargets. + * - if @p map is not CPTP. + * - if @p qureg is distributed and @p numTargets exceeds the number of + * qubits in @p qureg minus half log-2 of the number of processes. + * @see + * - createKrausMap() + * - createInlineKrausMap() + * - setKrausMap() + * @author Tyson Jones */ void mixKrausMap(Qureg qureg, int* targets, int numTargets, KrausMap map); -/// @notyetdoced -/// @notyetvalidated +/** Applies a superoperator upon the linearised density matrix @p qureg, where @p targets + * span the ket space. + * + * @formulae + * + * Let @f$ \dmrho = @f$ @p qureg contain @f$N@f$ qubits, with amplitudes @f$ \alpha_{ij} @f$. + * @f[ + \dmrho = \sum\limits_i^{2^N} \sum\limits_j^{2^N} \alpha_{ij} \ket{i}\bra{j}. + * @f] + * Internally, this matrix of dimension @f$ 2^N \times 2^N @f$ is stored as the vectorised + * form @f$ \ket{\rho} @f$ of dimension @f$ 2^{2N} \times 1 @f$, which concatenates the columns + * of @f$ \dmrho @f$. + * @f[ + \begin{aligned} + \ket{\rho} &= \sum\limits_i^{2^N} \sum\limits_j^{2^N} \alpha_{ij} \ket{j} \ket{i} \\ + &= \sum\limits_k^{2^{2N}} \beta_k \ket{k} + \end{aligned} + * @f] + * This resembles an unnormalised statevector of twice as many qubits as @f$ \dmrho @f$, whereby + * operators are left- and right-multiplied as + * @f[ + \ket{ \hat{A} \, \rho \, \hat{B} } = \hat{B}^T\otimes \hat{A} \ket{\rho}. + * @f] + * + * Let @f$ \vec{t} = @f$ @p targets, @f$ n = @f$ @p numTargets, and let @f$ \hat{S} = @f$ superop. + * The @f$n@f$-qubit superoperator @f$\hat{S}@f$ is a @f$ 2^{2n} \times 2^{2n} @f$ complex matrix + * which operates upon both the ket and bra partitions of the linearised density matrix @f$\ket{\rho}@f$. + * + * The targets @f$\vec{t}@f$ are treated as the ket qubits, specified in order of increasing + * significance, where the first qubit corresponds to the rightmost partition of the matrix + * @f$\hat{S}@f$. Concretely, let @f$\vec{t}+N@f$ notate the list of indices obtained by adding @f$N@f$ + * to every element of @f$\vec{t}@f$, and let @f$(\vec{t} \cup \vec{t}+N)@f$ the result of concatenating + * this new list with @f$\vec{t}@f$. Then, this function effects + * @f[ + \ket{\rho} \rightarrow \hat{S}_{(\vec{t} \cup \vec{t}+N)} \ket{\rho}, + * @f] + * which is mathematically identical to left-applying the @f$2n@f$-qubit matrix @f$\hat{S}@f$ upon a + * @f$2N@f$-qubit statevector @f$\ket{\rho}@f$. + * + * See mixKrausMap() for an example of the construction of @f$\hat{S}@f$. + * + * @constraints + * + * - There is no requirement nor validation that @p superop is CPTP, and so is permitted to + * break state normalisation and interpretability. + * - The number of targets must agree with the number of qubits upon which @p superop acts. + * - When @p qureg is distributed, each node must contain at least @c pow(2,2*numTargets) + * many amplitudes, to ensure sufficient communication buffers are allocated. + * + * @equivalences + * + * This function is equivalent to calling leftapplyCompMatr() upon @p qureg, having prepared + * @p superop as a CompMatr, and passing a target list prepared as @f$(\vec{t} \cup \vec{t}+N)@f$ above. + * + * @notyetvalidated + * + * @param[in,out] qureg the density matrix to modify. + * @param[in] targets the list of target qubit indices. + * @param[in] numTargets the length of @p targets + * @param[in] superop a compatible-sized SuperOp. + * @throws @validationerror + * - if @p qureg is not initialised. + * - if @p qureg is not a density matrix. + * - if @p targets contains a duplicate or invalid qubit index. + * - if @p numTargets is less than one, or exceeds the size of @p qureg. + * - if @p superop is not initialised, or not sync'ed (e.g. via syncSuperOp()). + * - if @p superop contains a different number of qubits than @p numTargets. + * - if @p qureg is distributed and @p numTargets exceeds the number of + * qubits in @p qureg minus half log-2 of the number of processes. + * @see + * - createSuperOp() + * - createInlineSuperOp() + * - setSuperOp() + * - mixKrausMap() + * @author Tyson Jones + */ void mixSuperOp(Qureg qureg, int* targets, int numTargets, SuperOp superop); From d57999e702a0b45561c1c7a75ae2967d896be12d Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 5 Jul 2026 14:44:25 -0400 Subject: [PATCH 03/29] decoherence doc touchups --- quest/include/decoherence.h | 41 ++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/quest/include/decoherence.h b/quest/include/decoherence.h index 85bd14e4a..4e6bfa74f 100644 --- a/quest/include/decoherence.h +++ b/quest/include/decoherence.h @@ -56,7 +56,7 @@ extern "C" { * * - Parameter @p prob must be a valid probability and ergo satisfy @f$ 0 \le p \le 1 @f$ * unless validation is disabled via setQuESTValidationOff(), which permits quasi-probability - * channels with even negative probabilities. + * channels with, for example, negative probabilities. * - The maximum permitted error probability is @f$ p = 1/2 @f$ (unless validation is disabled) * at which the qubit becomes completely "dephased", and the off-diagonal "coherences" become zero. * - With validation disabled, the channel remains CPTP for @f$ 1/2 \le p \le 1 @f$. @@ -137,7 +137,7 @@ void mixDephasing(Qureg qureg, int target, qreal prob); * * - Parameter @p prob must be a valid probability and ergo satisfy @f$ 0 \le p \le 1 @f$ * unless validation is disabled via setQuESTValidationOff(), which permits quasi-probability - * channels with even negative probabilities. + * channels with, for example, negative probabilities. * - The maximum permitted error probability is @f$ p = 3/4 @f$ (unless validation is disabled), * at which the channel is "maximum strength" and the off-diagonal "coherences" of the two qubits * become zero. @@ -209,7 +209,7 @@ void mixTwoQubitDephasing(Qureg qureg, int target1, int target2, qreal prob); * * - Parameter @p prob must be a valid probability and ergo satisfy @f$ 0 \le p \le 1 @f$ * unless validation is disabled via setQuESTValidationOff(), which permits quasi-probability - * channels with even negative probabilities. + * channels with, for example, negative probabilities. * - The maximum permitted error probability is @f$ p = 3/4 @f$ (unless validation is disabled), * at which the channel is maximum strength, and the qubit enters the maximally mixed state. * - With validation disabled, the channel remains CPTP for @f$ 3/4 \le p \le 1 @f$. @@ -316,7 +316,7 @@ void mixDepolarising(Qureg qureg, int target, qreal prob); * * - Parameter @p prob must be a valid probability and ergo satisfy @f$ 0 \le p \le 1 @f$ * unless validation is disabled via setQuESTValidationOff(), which permits quasi-probability - * channels with even negative probabilities. + * channels with, for example, negative probabilities. * - The maximum permitted error probability is @f$ p = 15/16 @f$ (unless validation is disabled), * at which the channel is maximum strength, and the target qubits become maximally mixed. * - With validation disabled, the channel remains CPTP for @f$ 15/16 \le p \le 1 @f$. @@ -357,7 +357,7 @@ void mixTwoQubitDepolarising(Qureg qureg, int target1, int target2, qreal prob); * This function effects * @f[ \dmrho \; \rightarrow \; - \hat{K}_t^{(1)} \dmrho \, {\hat{K}_t^{(2)}}^\dagger + \hat{K}_t^{(1)} \dmrho \, {\hat{K}_t^{(1)}}^\dagger \,+\, \hat{K}_t^{(2)} \dmrho \, {\hat{K}_t^{(2)}}^\dagger * @f] @@ -437,7 +437,7 @@ void mixDamping(Qureg qureg, int target, qreal prob); * @f] * The operation is a meaningful noise channel (decreases purity) when the probabilities are * below that which induces maximal mixing; when the probability of no error is greater than - * the probability of any error. + * (or equal to) the probability of any error. * @f[ * 1 - (p_x + p_y + p_z) \ge \max(p_x, p_y, p_z). * @f] @@ -445,11 +445,12 @@ void mixDamping(Qureg qureg, int target, qreal prob); * @constraints * * - Each of @p probX, @p probY, and @p probZ must be a valid probability, i.e. @f$ 0 \le p_i \le 1 @f$, - * and the probability of no error (one minus their sum) must also be valid. This can be relaxed - * using setQuESTValidationOff() to effect channels which are not completely-positive and trace-preserving, - * such as quasi-probability channels. + * and the probability of no error (one minus their sum) must also be valid. This particular validation + * is insensitive to the validation epsilon as controlled with setQuESTValidationEpsilon(), but can instead + * be relaxed with setQuESTValidationOff(), to effect channels which are not completely-positive and + * trace-preserving, such as quasi-probability channels. * - The channel strength must not exceed that which induces maximal mixing (unless validation is disabled), - * whereby the probability of any particular error equals that of no error. + * whereby the probability of any particular error equals that of no error, as discussed above. * * @equivalences * @@ -493,7 +494,7 @@ void mixDamping(Qureg qureg, int target, qreal prob); void mixPaulis(Qureg qureg, int target, qreal probX, qreal probY, qreal probZ); -/** Modifies the density matrix @p qureg to the mixture of itself and density matrix or +/** Modifies the density matrix @p qureg to the mixture of itself and the density matrix or * statevector @p other. * * @formulae @@ -517,6 +518,9 @@ void mixPaulis(Qureg qureg, int target, qreal probX, qreal probY, qreal probZ); * * @constraints * + * - Parameter @p prob must be a valid probability, satisfying @f$ 0 \le p \le 1 @f$, + * though can be relaxed to any real scalar by disabling validation with + * setQuESTValidationOff(). * - @p qureg and @p other must contain the same number of qubits. * - If @p other is a density matrix, it must be identically distributed to @p qureg * (although the parallelisation backends, like multithreading and GPU acceleration, are @@ -542,7 +546,7 @@ void mixPaulis(Qureg qureg, int target, qreal probX, qreal probY, qreal probZ); void mixQureg(Qureg qureg, Qureg other, qreal prob); -/** Applies a general, any-size channel described as a Kraus map to the density matrix @p qureg. +/** Applies a general, any-size channel described as a Kraus map upon the density matrix @p qureg. * * @formulae * @@ -563,9 +567,12 @@ void mixQureg(Qureg qureg, Qureg other, qreal prob); * * @constraints * - * - The number of channel targets must agree with the size of the Kraus map. - * - The channel must be CPTP unless disabled with setQuESTValidationEpsilon(), specifying - * @c eps=0, or all validation is (dangerously) disabled with setQuESTValidationOff(). + * - The number of channel targets @p numTargets must agree with the size of the Kraus map. + * - The channel must be approximately CPTP, such that difference between + * @f$ \sum\limits_i {\hat{K}_{\vec{t}}^{(i)}}^\dagger \hat{K}_{\vec{t}}^{(i)} @f$ and + * @f$ \mathbb{1} @f$ has no element of absolute value greater than the validation + * epsilon @f$ \valeps @f$. This can be adjusted with setQuESTValidationEpsilon(), and + * relaxed entirely by setting @f$ \valeps = 0 @f$. * - When @p qureg is distributed, each node must contain at least @c pow(2,2*numTargets) * many amplitudes, to ensure sufficient communication buffers are allocated. * @@ -590,7 +597,7 @@ void mixQureg(Qureg qureg, Qureg other, qreal prob); * - if @p map is not initialised. * - if @p map contains a different number of qubits than @p numTargets. * - if @p map is not CPTP. - * - if @p qureg is distributed and @p numTargets exceeds the number of + * - if @p qureg is distributed and @p numTargets exceeds the number of * qubits in @p qureg minus half log-2 of the number of processes. * @see * - createKrausMap() @@ -610,7 +617,7 @@ void mixKrausMap(Qureg qureg, int* targets, int numTargets, KrausMap map); * @f[ \dmrho = \sum\limits_i^{2^N} \sum\limits_j^{2^N} \alpha_{ij} \ket{i}\bra{j}. * @f] - * Internally, this matrix of dimension @f$ 2^N \times 2^N @f$ is stored as the vectorised + * Internally, this matrix of dimension @f$ 2^N \times 2^N @f$ is stored in a vectorised * form @f$ \ket{\rho} @f$ of dimension @f$ 2^{2N} \times 1 @f$, which concatenates the columns * of @f$ \dmrho @f$. * @f[ From 0f6d5be5c0a84fc555aeca874ac916e86628b28d Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 5 Jul 2026 19:18:43 -0400 Subject: [PATCH 04/29] added seeding doc --- quest/include/debug.h | 209 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 205 insertions(+), 4 deletions(-) diff --git a/quest/include/debug.h b/quest/include/debug.h index a51236141..83b09dcdf 100644 --- a/quest/include/debug.h +++ b/quest/include/debug.h @@ -42,19 +42,220 @@ extern "C" { */ -/// @notyetdoced +/** Sets the seeds used by QuEST's random number generation. + * + * This affects and determines all pseudorandom decisions made the QuEST library, + * such as qubit measurement outcomes and random state preparation. The seeds are + * passed without modification to QuEST's 19,937-bit + * [Mersenne Twister](https://cplusplus.com/reference/random/mt19937_64/) generator. + * As such, fully specifying the generator's initial state requires 19,937 seed bits, + * or 623 unsigned integers, although this is rarely necessary. + * + * Seeding can be performed at any time before a random decision (such as measurement); + * no random outcomes/state is stored on any object beforehand. + * + * > [!NOTE] + * > In distributed simulation, only the root node's seeds are consulted (and broadcast + * > to all nodes) while those passed on all other nodes are ignored. + * + * @myexample + * ``` + // make report() print only one trailing newline + setQuESTNumReportedNewlines(1); + + // seed + unsigned seeds[] = {123456789u, 987654321u, 546372819u}; + setQuESTSeeds(seeds, 2); + + // randomly collapse the plus state + initPlusState(qureg); + reportScalar("outcome 0", applyQubitMeasurement(qureg, 0)); + reportScalar("outcome 1", applyQubitMeasurement(qureg, 1)); + reportScalar("outcome 2", applyQubitMeasurement(qureg, 2)); + + // restore RNG to state prior to collapse + setQuESTSeeds(seeds, 2); + + // randomly collapse the plus state again, obtaining same outcomes + reportStr(""); + initPlusState(qureg); + reportScalar("outcome 0", applyQubitMeasurement(qureg, 0)); + reportScalar("outcome 1", applyQubitMeasurement(qureg, 1)); + reportScalar("outcome 2", applyQubitMeasurement(qureg, 2)); + * ``` + * Example output: + * ``` + outcome 0: 0 + outcome 1: 1 + outcome 2: 1 + + outcome 0: 0 + outcome 1: 1 + outcome 2: 1 + * ``` + * + * @param[in] seeds a list of seeds. + * @param[in] numSeeds the length of @p seeds. + * @throws @validationerror + * - if @p seeds is a null pointer. + * - if @p numSeeds is less than one. + * @see + * - getQuESTSeeds() + * - getQuESTNumSeeds() + * - setQuESTSeedsToDefault() + * @author Tyson Jones + */ void setQuESTSeeds(unsigned* seeds, int numSeeds); -/// @notyetdoced +/** Re-randomizes QuEST, seeding its random number generator with new seeds as pseudorandomly + * produced by the @c C++ [@c std::random_device](https://en.cppreference.com/cpp/numeric/random/random_device) + * function, potentially using a hardware RNG. + * + * Similar to setQuESTSeeds(), this affects all pseudorandom decisions made the QuEST library, + * such as qubit measurement outcomes and random state preparation. Unlike setQuESTSeeds() + * however, repeated calls will not guarantee identical random generation; the internally + * processed seeds may differ at each invocation. This is, in fact, the function first + * internally called during QuEST environment initialisation. + * + * Seeding can be performed at any time after QuEST library initialisation, before a + * random decision (such as measurement); no random outcomes/state is stored on any object beforehand. + * + * This function consults @c std::random_device to produce @c DEFAULT_NUM_RNG_SEEDS=4 + * seeds, which is infact insufficient to fully specify an initial state of QuEST's + * [19,937-bit Mersenne Twister](https://cplusplus.com/reference/random/mt19937_64/) + * generator. Presently, @c DEFAULT_NUM_RNG_SEEDS cannot be changed except through + * manual modification and recompilation. + * + * > [!NOTE] + * > In distributed simulation, only the root node's seeds are consulted (and broadcast + * > to all nodes) while those passed on all other nodes are ignored. + * + * @myexample + * ``` + // make report() print only one trailing newline + setQuESTNumReportedNewlines(1); + + // randomise the RNG state + setQuESTSeedsToDefault(); + + // randomly collapse the plus state + initPlusState(qureg); + reportScalar("outcome 0", applyQubitMeasurement(qureg, 0)); + reportScalar("outcome 1", applyQubitMeasurement(qureg, 1)); + reportScalar("outcome 2", applyQubitMeasurement(qureg, 2)); + + // re-randomise the RNG state + setQuESTSeedsToDefault(); + + // randomly collapse the plus state again, obtaining new outcomes + reportStr(""); + initPlusState(qureg); + reportScalar("outcome 0", applyQubitMeasurement(qureg, 0)); + reportScalar("outcome 1", applyQubitMeasurement(qureg, 1)); + reportScalar("outcome 2", applyQubitMeasurement(qureg, 2)); + * ``` + * Example output: + * ``` + outcome 0: 0 + outcome 1: 1 + outcome 2: 0 + + outcome 0: 1 + outcome 1: 1 + outcome 2: 1 + * ``` + * We can view the random seeds chosen by QuEST using getQuESTSeeds(): + * ``` + int numSeeds = getQuESTNumSeeds(); // fixed=4 + unsigned seeds[1000]; // lazily/dangerously assume num<=1000 + + setQuESTSeedsToDefault(); + getQuESTSeeds(seeds); + + for (int i=0; i Date: Sun, 5 Jul 2026 21:11:59 -0400 Subject: [PATCH 05/29] added validation-handling doc --- quest/include/debug.h | 189 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 181 insertions(+), 8 deletions(-) diff --git a/quest/include/debug.h b/quest/include/debug.h index 83b09dcdf..74af2b158 100644 --- a/quest/include/debug.h +++ b/quest/include/debug.h @@ -232,6 +232,7 @@ void setQuESTSeedsToDefault(); * See setQuESTSeedsToDefault() for an example of how getQuESTSeeds() interacts with * other seeding calls. * + * @param[out] seeds the list of seeds * @throws @validationerror * - if the QuEST environment has not been initialised via initQuESTEnv(). * - if @p seeds is a nullptr. @@ -249,6 +250,7 @@ void getQuESTSeeds(unsigned* seeds); * * This is the length of the list output by getQuESTSeeds(). * + * @returns the number of seeds. * @throws @validationerror * - if the QuEST environment has not been initialised via initQuESTEnv(). * @see @@ -274,32 +276,203 @@ int getQuESTNumSeeds(); */ -/** @notyetdoced +/** Sets the function which QuEST will call when encountering an invalid input. + * + * By default, when a user passes an invalid input to QuEST (such as a negative qubit index), + * an internal function @c default_inputErrorHandler() is called which prints a message to + * @c stdout, attempts to gracefully clean up communication in distributed settings, then + * exits execution with @c exit(EXIT_FAILURE). If this is undesired, setQuESTInputErrorHandler() + * allows the user to substitute @p callback for the default handler, which will receive the + * throwing API function name @p func, and the error message string @p msg. + * + * QuEST endeavours to perform input validation upfront before proceeding to any mutation + * of passed objects (like a Qureg). This permits gracefully catching validation errors through + * custom handling without corrupting QuEST's state. For example, @c C++ users may wish + * to throw an exception within @p callback, or MPI superusers may wish to perform custom + * communicator cleanup before exiting. + * + * > [!IMPORTANT] + * > It is crucial that @p callback does not return execution back to the throwing + * > QuEST function, which is likely to cause a segmentation fault or other internal + * > error. Instead, @p callback should exit or throw an exception, caught by the + * > user's control flow. + * + * Note validation can be changed or disabled with setQuESTValidationEpsilon() and + * setQuESTValidationOff(), which affects when @p callback will be called. This function + * can be called at any time to update the error handler. + * + * @myexample + * + * ``` + void myErrorHandler(const char* errFunc, const char* errMsg) { + printf("Ruh-roh, Raggy! Function '%s' has reported '%s'.\n", errFunc, errMsg); + printf("We will now be very good children and exit immediately!\n"); + exit(0); + } + + int main() { + initQuESTEnv(); + setInputErrorHandler(myErrorHandler); + createQureg(9999); // invokes myErrorHandler + ... + } + * ``` * + * @param[in] callback a pointer to a function which accepts two `const char*` arguments. + * @throws @validationerror + * - if the QuEST environment has not been initialised via initQuESTEnv(). + * @throws seg-fault + * - if @p callback is a null-ptr and an invalid input is later encountered. * @see - * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/setting_errorhandler.c) and - * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/setting_errorhandler.cpp) examples + * - [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/setting_errorhandler.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/setting_errorhandler.cpp) examples + * - setQuESTValidationOff() + * @author Tyson Jones */ void setQuESTInputErrorHandler(void (*callback)(const char* func, const char* msg)); -/// @notyetdoced +/** Restores QuEST's input validation. + * + * This means that invalid inputs to other QuEST API functions will call the error handler + * (the default, or one passed to setQuESTInputErrorHandler()), rather than be silently ignored. + * + * This function only has an affect if setQuESTValidationOff() was prior called. This function + * does not affect the validation epsilon controlled with setQuESTValidationEpsilon(), which when + * zero, will still see the skipping of numerically-approximated validations (such as unitarity checks). + * + * @see + * - setQuESTValidationOff() + * @author Tyson Jones + */ void setQuESTValidationOn(); -/// @notyetdoced +/** Disables all of QuEST's input validation. + * + * When a QuEST API function encounters an invalid input, the error will be ignored and execution of the + * function will proceed. This is useful in order to call a QuEST function in a manner which is ordinarily + * forbidden to avoid user mistakes. + * + * > [!IMPORTANT] + * > This function disables all of QuEST's runtime input validation, meaning invalid inputs such as + * > negative qubit indices will be accepted and trusted, likely causing internal errors and segmentation faults. + * + * Users wishing only to adjust numerical validation tolerances, or disable numerical validations such as + * matrix unitarity checks, should instead use the safer setQuESTValidationEpsilon(). If it is essential to + * disable all validation, it should be later restored with setQuESTValidationOn(). + * + * @myexample + * + * ``` + Qureg qureg = createDensityQureg(3); // ~ 6-qubit statevector + CompMatr1 matr = getInlineCompMatr1({{1,2},{3,4}}); + + int target = 4; // 0-2 valid, 3-5 hacky, 6+ seg-fault + + setQuESTValidationOff(); + leftapplyCompMatr1(qureg, target, matr); + setQuESTValidationOn(); + * ``` + * + * @see + * - setQuESTValidationOn() + * - setQuESTValidationEpsilon() + * - setQuESTInputErrorHandler() + * @author Tyson Jones + */ void setQuESTValidationOff(); -/// @notyetdoced +/** Restores QuEST's validation threshold for testing numerical or approximate quantities, to its default value. + * + * The default value is informed by the environment variable `QUEST_DEFAULT_VALIDATION_EPSILON`. If the + * environment variable was not specified during the launch of the QuEST executable, then the default + * validation epsilon is specific to the precision of `qreal`, as controlled by `QUEST_FLOAT_PRECISION`. + * These are: + * | @c QUEST_FLOAT_PRECISION | @c qreal | default epsilon | + * |--------------------------|-----------|-----------------| + * | 1 | @c float | @c 1E-5 | + * | 2 | @c double | @c 1E-12 | + * | 4 | @c long @c double | @c 1E-15 | + * + * @see + * - setQuESTValidationEpsilon() + * @author Tyson Jones + */ void setQuESTValidationEpsilonToDefault(); -/// @notyetdoced +/** Modifies QuEST's validation threshold for testing numerical or approximate quantities, to @p eps. + * + * Many of QuEST's API functions validate that expected numerical properties of the input are satisfied. + * For example, that the matrix passed to applyCompMatr1() is unitary, and ergo that the + * product of the matrix with its own adjoint produces the identity matrix. Due to floating-point error, + * such properties cannot be evaluated exactly, and small disagreement between the expected and given + * property is tolerated. This difference is the validation epsilon, as overridden by this function. + * Precisely how the validation epsilon is used by numerical validation is function specific, and + * individually documented. + * + * > [!TIP] + * > Passing @p eps=0 effectively encodes @p eps=infinity, and *disables* all numerical validation. + * + * The validation epsilon has no effect on non-numerical validation, such as whether qubit incices + * are valid. In general, it is therefore safe to modify and disable numerical validation via this + * function. + * + * The default validation epsilon, which can itself be controlled by the `QUEST_DEFAULT_VALIDATION_EPSILON` + * environment variable, is restored via setQuESTValidationEpsilonToDefault(). + * + * @myexample + * + * ``` + // | max [matr . adj(matr) - identity] |^2 = 576 + CompMatr1 matr = getInlineCompMatr1({{1,2},{3,4}}); // non-unitary + setQuESTValidationEpsilon(576.0); + applyCompMatr1(qureg, 0, matr); // no error + + matr.elems[0][0] = 999; + setQuESTValidationEpsilon(0); // disable all numerical validation + applyCompMatr1(qureg, 0, matr); // no error + + // target=-1 would still trigger an error + // applyCompMatr1(qureg, -1, matr); + * ``` + * + * @param[in] eps the new validation epsilon. + * @throws @validationerror + * - if the QuEST environment has not been initialised via initQuESTEnv(). + * - if @p eps is negative. + * @see + * - setQuESTValidationEpsilonToDefault() + * - getQuESTValidationEpsilon() + * - setQuESTValidationOff() + * @author Tyson Jones + */ void setQuESTValidationEpsilon(qreal eps); -/// @notyetdoced +/** Returns the threshold used by QuEST's numerical validation. + * + * This is the value last passed to setQuESTValidationEpsilon(), unless overridden by + * setQuESTValidationEpsilonToDefault(), or similarly if never called. It indicates the + * precision and correctness demanded of input numerical quantities to the QuEST API. A larger + * epsilon corresponds to more permissive validation, while a smaller epsilon means validation + * is harder to pass and input quantities must be more carefully prepared. + * + * > [!NOTE] + * > A validation epsilon of @c 0 indicates numerical validation is disabled. + * + * The exact usage of the validation epsilon is function specific. For an example, see applyCompMatr1(). + * The validation has no effect when validation has been disabled entirely via setQuESTValidationOff(). + * + * @returns The validation epsilon. + * @see + * - setQuESTValidationEpsilon() + * - setQuESTValidationEpsilonToDefault() + * - setQuESTValidationOff() + * @author Tyson Jones + */ qreal getQuESTValidationEpsilon(); From 916ca915ea5fed046c6f065f388f4a4b1e65981f Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 5 Jul 2026 23:42:18 -0400 Subject: [PATCH 06/29] added set-reporter doc --- quest/include/debug.h | 288 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 267 insertions(+), 21 deletions(-) diff --git a/quest/include/debug.h b/quest/include/debug.h index 74af2b158..e5283709b 100644 --- a/quest/include/debug.h +++ b/quest/include/debug.h @@ -487,51 +487,297 @@ qreal getQuESTValidationEpsilon(); */ -/// @notyetdoced -/// @notyettested +/** Sets the maximum number of rows and columns of data structures subsequently printed by + * QuEST's report functions, with remaining elements ellipted. + * + * This function is useful for keeping @c stdout concise and readable when reporting + * large data structures, such as matrices and Qureg. The ellipted elements are in + * the _center_ of the reported data structure. The specified maximums persist until + * changed again with this function. + * + * > [!TIP] + * > Specifying @p numRows=0 or @p numCols=0 respectively disables ellipsis across + * > rows and columns respectively. Beware this means that functions like reportQureg() + * > will display the entirety of their data, which can be very large. + * + * This function presently affects the output of functions: + * - reportQureg() + * - reportPauliStrSum() + * - reportCompMatr1() + * - reportCompMatr2() + * - reportCompMatr() + * - reportDiagMatr1() + * - reportDiagMatr2() + * - reportDiagMatr() + * - reportFullStateDiagMatr() + * - reportKrausMap() + * - reportSuperOp() + * + * In contrast, it has no effect on the output of functions: + * - reportPauliStr() + * - reportScalar() + * - reportStr() + * + * > When this function is not called, the QuEST defaults are adopted, which are presently: + * > - @c numRows=32 + * > - @c numCols=4 + * + * @myexample + * + * ```cpp + Qureg qureg = createDensityQureg(6); + initRandomPureState(qureg); + setQuESTMaxNumReportedItems(7,4); + reportQureg(qureg); + * ``` + * will report 7 rows and 4 columns of @c qureg. + * ```text + Qureg (6 qubit density matrix, 64x64 qcomps, 64.1 KiB): + 0.012273+(3.2329e-19)i -0.0056906+0.0072884i … -0.0052104-0.0070839i 0.00092891-0.0086299i + -0.0056906-0.0072884i 0.0069669-(1.363e-20)i … -0.0017909+0.0063788i -0.0055556+0.0034498i + 0.014757-0.0083751i -0.0018689+0.012647i … -0.011099-0.0049622i -0.0047721-0.011011i + 0.00078401+0.0014319i -0.0012139-0.00019834i … 0.00049365-0.0010604i 0.0010662-0.00044291i + ⋮ + -0.010456+0.012047i -0.0023056-0.011795i … 0.011393+0.00092115i 0.0076794+0.0082644i + -0.0052104+0.0070839i -0.0017909-0.0063788i … 0.0063009-(3.3799e-20)i 0.0045868+0.0041999i + 0.00092891+0.0086299i -0.0055556-0.0034498i … 0.0045868-0.0041999i 0.0061386-(1.4941e-19)i + * ``` + * + * @param[in] numRows the max number of rows to report (all if @c =0). + * @param[in] numCols the max number of columns to report (all if @c =0). + * @throws @validationerror + * - if the QuEST environment has not been initialised via initQuESTEnv(). + * - if either @p numRows or @p numCols is negative. + * @see + * - [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/reporting_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/reporting_matrices.cpp) examples + * - setQuESTMaxNumReportedSigFigs() + * - setQuESTNumReportedNewlines() + */ void setQuESTMaxNumReportedItems(qindex numRows, qindex numCols); -/** @notyetdoced +/** Sets the maximum number of significant figures in floating-point numbers printed by + * QuEST's reporter functions. + * + * This function is useful for keeping @c stdout concise and readable when reporting + * numerical quantites, such as matrices and Qureg amplitudes. The specified number of + * significant figures persists until changed again with this function. + * + * > [!TIP] + * > Numbers with _fewer_ non-zero significant figures will _not_ be padded with zeros, + * > and so will print fewer digits than @p numSigFigs, keeping the output concise. + * + * > [!NOTE] + * > Complex quantities will have their real and imaginary components separately printed, + * > each with the specified number of significant figures. + * + * > [!IMPORTANT] * > This function does not affect the significant figures in printed memory sizes * > (e.g. `5.32 KiB`) which is always shown with three significant figures * > (or four when in bytes, e.g. `1023 bytes`). + * + * @myexample + * + * ```cpp + Qureg qureg = createQureg(3); + initRandomPureState(qureg); + + setQuESTMaxNumReportedSigFigs(2); + reportQureg(qureg); + + setQuESTMaxNumReportedSigFigs(10); + reportQureg(qureg); + * ``` + * may output + * ```text + Qureg (3 qubit statevector, 8 qcomps, 232 bytes): + 0.49+0.35i |0⟩ + -0.085+0.17i |1⟩ + 0.37+0.099i |2⟩ + -0.14+0.088i |3⟩ + -0.29+0.078i |4⟩ + 0.19+0.019i |5⟩ + 0.02-0.5i |6⟩ + -0.032+0.22i |7⟩ + + Qureg (3 qubit statevector, 8 qcomps, 232 bytes): + 0.4915502074+0.3471270204i |0⟩ + -0.08473589829+0.1685819182i |1⟩ + 0.3702183582+0.0991921232i |2⟩ + -0.142193399+0.08829704821i |3⟩ + -0.2881909331+0.07795511511i |4⟩ + 0.1868915394+0.01946703883i |5⟩ + 0.01956017542-0.5029788111i |6⟩ + -0.03171267079+0.220342331i |7⟩ + * ``` + * Meanwhile, + * ```cpp + CompMatr1 matr = getInlineCompMatr1({{1,2},{3,4.123456789}}); + setQuESTMaxNumReportedSigFigs(3); + reportCompMatr1(matr); + * ``` + * will output + * ```text + CompMatr1 (1 qubit, 2x2 qcomps, 80 bytes): + 1 2 + 3 4.12 + * ``` + * + * @param[in] numSigFigs the max number of significant figures to print in subsequent report functions. + * @throws @validationerror + * - if the QuEST environment has not been initialised via initQuESTEnv(). + * - if @p numSigFigs is negative. + * @see + * - setQuESTMaxNumReportedItems() + * - setQuESTNumReportedNewlines() + * @author Tyson Jones */ void setQuESTMaxNumReportedSigFigs(int numSigFigs); -/// @notyetdoced +/** Sets the number of trailing newlines printed at the end of QuEST's report functions. + * + * These newlines are merely a convenience so that users do not have to manually intersperse + * newlines in @c stdout between functions like reportScalar() and reportPauliStr(), + * which becomes a greater pain in distributed settings when avoiding duplicated output + * across processes. The specified number of newlines persists until changed again with + * this function. + * + * @myexample + * + * By default, the sequence + * ```cpp + reportCompMatr1(getInlineCompMatr1({{1,2},{3,4}})); + reportPauliStr(getInlinePauliStr("XYZ", {0,2,4})); + reportScalar("x", 5); + reportStr("hello world!"); + * ``` + * will print with the internal default of @p numNewLines=2 + * ```text + CompMatr1 (1 qubit, 2x2 qcomps, 80 bytes): + 1 2 + 3 4 + + ZIYIX + + x: 5 + + hello world! + * ``` + * but if called after @c setQuESTNumReportedNewlines(1), will output + * ```text + CompMatr1 (1 qubit, 2x2 qcomps, 80 bytes): + 1 2 + 3 4 + ZIYIX + x: 5 + hello world! + * ``` + * It is possible to forego all trailing newlines, and also to write to @c stdout between + * report functions. + * ```cpp + setQuESTNumReportedNewlines(0); + reportPauliStr(getInlinePauliStr("XYZ", {0,2,4})); + printf(" * "); + reportPauliStr(getInlinePauliStr("ZZZ", {0,1,2})); + printf(" = "); + reportPauliStr(getInlinePauliStr("YZXZ", {0,1,2,4})); + printf("\n"); + * ``` + * ```text + ZIYIX * ZZZ = ZIXZY + * ``` + * + * @param[in] numNewlines the new number of trailing newlines. + * @throws @validationerror + * - if the QuEST environment has not been initialised via initQuESTEnv(). + * - if @p numNewlines is negative. + * @author Tyson Jones + */ void setQuESTNumReportedNewlines(int numNewlines); -/** - * @notyetdoced - * @notyettested +/** Sets the characters used by reportPauliStr() and reportPauliStrSum() to indicate the + * @c I, @c X, @c Y and @c Z Pauli operators. + * * @myexample - * ``` - PauliStr str = getInlinePauliStr("XYZ", {0,10,20}); + * ```cpp + PauliStr str = getInlinePauliStr("XYZZ", {0,10,13,20}); reportPauliStr(str); setQuESTReportedPauliChars(".xyz"); reportPauliStr(str); - * ``` - */ -void setQuESTReportedPauliChars(const char* paulis); - -/** - * @notyetdoced - * @notyettested - * @myexample + setQuESTReportedPauliChars(" !!!"); + reportPauliStr(str); * ``` - PauliStr str = getInlinePauliStr("XYZ", {0,10,20}); + * ```text + ZIIIIIIZIIYIIIIIIIIIX - setQuESTReportedPauliStrStyle(0); - reportPauliStr(str); + z......z..y.........x - setQuESTReportedPauliStrStyle(1); + ! ! ! ! + * ``` + * These symbols are used across all styles accepted by setQuESTReportedPauliStrStyle(). + * ```cpp + setQuESTReportedPauliStrStyle(1); // style=1 + setQuESTReportedPauliChars(".XyS"); reportPauliStr(str); * ``` + * ```text + X0 y10 S13 S20 + * ``` + * + * @param[in] paulis four characters to indicate @c I, @c X, @c Y and @c Z respectively. + * @throws @validationerror + * - if the QuEST environment has not been initialised via initQuESTEnv(). + * - if @p paulis is not length @c 4. + * @throws seg-fault + * - if @p paulis is a null pointer. + * - if @p paulis does not contain a terminal character and is smaller than 4 bytes in size. + * @see + * - setQuESTReportedPauliStrStyle() + * @author Tyson Jones + */ +void setQuESTReportedPauliChars(const char* paulis); + + +/** Sets the visual style of Pauli strings printed by reportPauliStr() and reportPauliStrSum(). + * + * - When @p style=0 (default), every Pauli operator in the string is printed, _until_ the + * largest-index non-identity operator. The rightmost printed operator is the least + * significant (i.e. of qubit index @c 0). + * + * For example: + * ```cpp + setQuESTReportedPauliStrStyle(0); // default + reportPauliStr(getInlinePauliStr("XYZZ", {0,10,13,20})); + * ``` + * ```text + ZIIIIIIZIIYIIIIIIIIIX + * ``` + * + * - When @p style=1, only non-identity Pauli operators are printed, followed by their indices. + * + * For example: + * ```cpp + setQuESTReportedPauliStrStyle(1); + reportPauliStr(getInlinePauliStr("XYZZ", {0,10,13,20})); + * ``` + * ```text + X0 Y10 Z13 Z20 + * ``` + * + * The symbols for @c I, @c X, @c Y and @c Z can be overridden with setQuESTReportedPauliChars(). + * + * @param[in] style either @c 0 or @c 1 to respectively indicate the above styles. + * @throws @validationerror + * - if the QuEST environment has not been initialised via initQuESTEnv(). + * - if @p style is not @c 0 or @c 1. + * @see + * - setQuESTReportedPauliChars() + * @author Tyson Jones */ void setQuESTReportedPauliStrStyle(int style); From c552caf2a3aa0841cd22fc7d02e2d85962bb63a0 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 5 Jul 2026 23:54:07 -0400 Subject: [PATCH 07/29] added GPU cache doc --- quest/include/debug.h | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/quest/include/debug.h b/quest/include/debug.h index e5283709b..837366221 100644 --- a/quest/include/debug.h +++ b/quest/include/debug.h @@ -793,11 +793,42 @@ void setQuESTReportedPauliStrStyle(int style); */ -/// @notyetdoced +/** Returns the current size (in bytes) of the persistent GPU cache used to accelerate + * QuEST. + * + * Some QuEST functions involve allocating non-trivial device data, which persists between + * invocations for effiency. For example, applyCompMatr() when given a matrix of more than + * five qubits, will allocate data proportional in size to the matrix dimension and the + * simulated Qureg size. This allocation happens on-the-fly. + * + * This function returns the size of that cache. It does not include device memory consumed + * by persistent QuEST objects, such as Qureg and CompMatr. + * When QuEST is not running in GPU-accelerated mode, this function always returns @c 0. + * + * @returns The current GPU cache size in bytes. + * @see + * - clearQuESTGpuCache() + * @author Tyson Jones + */ qindex getQuESTGpuCacheSize(); -/// @notyetdoced +/** Clears QuEST's GPU cache. + * + * Some QuEST functions involve allocating non-trivial device data, which persists between + * invocations for effiency. For example, applyCompMatr() when given a matrix of more than + * five qubits, will allocate data proportional in size to the matrix dimension and the + * simulated Qureg size. This allocation happens on-the-fly. + * + * This function clears this cache, freeing memory at the cost of increased runtime when + * calling functions like applyCompMatr(), due to the overhead of reallocation therein. + * This function has no effect on the persistent device memory owned by QuEST objects like + * Qureg and CompMatr, nor does it have any effect when QuEST is not using GPU acceleration. + * + * @see + * - getQuESTGpuCacheSize() + * @author Tyson Jones + */ void clearQuESTGpuCache(); From 52a0bd071b35bb632b3f9ecd29ce09c2dd17c17f Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 5 Jul 2026 23:55:10 -0400 Subject: [PATCH 08/29] hide C++ overloads doc since they clutter the API doc pages, and C++ users will probably see them in autocomplete, else can easily intuit them (or just use the C API) --- utils/docs/Doxyfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/docs/Doxyfile b/utils/docs/Doxyfile index 9432ff058..553a1dc01 100644 --- a/utils/docs/Doxyfile +++ b/utils/docs/Doxyfile @@ -298,7 +298,8 @@ ALIASES = ALIASES += "notyettested=@warning This function has not yet been unit tested and may contain bugs. Please use with caution!" ALIASES += "notyetvalidated=@attention This function's input validation has not yet been unit tested, so erroneous usage may produce unexpected output. Please use with caution!" ALIASES += "notyetdoced=@note Documentation for this function or struct is under construction!" -ALIASES += "cpponly=@remark This function is only available in C++." +# ALIASES += "cpponly=@remark This function is only available in C++." +ALIASES += "cpponly=@private" ALIASES += "conly=@remark This function is only available in C." ALIASES += "macrodoc=@note This entity is actually a macro." ALIASES += "envvardoc=@note This entity is actually an environment variable." From 3f3f008235bbab44a56c0b1192663ae9825a6fe5 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Mon, 6 Jul 2026 22:16:38 -0400 Subject: [PATCH 09/29] rename matr to matrix in operators.h signatures and fixed some other typos --- quest/include/operations.h | 59 ++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/quest/include/operations.h b/quest/include/operations.h index 3c97d2c61..077da8fd6 100644 --- a/quest/include/operations.h +++ b/quest/include/operations.h @@ -98,6 +98,7 @@ digraph { * where the validation epsilon @f$ \valeps @f$ can be adjusted with setQuESTValidationEpsilon(). * * @myexample + * * ``` Qureg qureg = createQureg(5); @@ -199,18 +200,20 @@ digraph { * @equivalences * * - This function is faster than, but mathematically equivalent to, initialising a two-qubit - * matrix (CompMatr2) to the @f$C_1[\hat{U}_0]@f$ matrix above, and calling applyCompMatr2(): - * ``` + * matrix (CompMatr2) to the @f$C_1[\hat{U}_0]@f$ matrix above, and calling applyCompMatr2(), + * passing @p control as the most significant target. + * ``` CompMatr2 m = getInlineCompMatr2({ {1,0,0,0}, {0,1,0,0}, {0,0,u00,u01}, {0,0,u10,u11}}); - applyCompMatr2(qureg, target, control); - * ``` + applyCompMatr2(qureg, target, control, m); + * ``` * * @myexample + * * ``` Qureg qureg = createQureg(5); @@ -459,7 +462,7 @@ digraph { * @see * - applyCompMatr2() */ -void applyControlledCompMatr2(Qureg qureg, int control, int target1, int target2, CompMatr2 matr); +void applyControlledCompMatr2(Qureg qureg, int control, int target1, int target2, CompMatr2 matrix); /** @notyetdoced @@ -503,7 +506,7 @@ digraph { * @see * - applyCompMatr2() */ -void applyMultiControlledCompMatr2(Qureg qureg, int* controls, int numControls, int target1, int target2, CompMatr2 matr); +void applyMultiControlledCompMatr2(Qureg qureg, int* controls, int numControls, int target1, int target2, CompMatr2 matrix); /** @notyetdoced @@ -549,7 +552,7 @@ digraph { * - applyCompMatr2() * - applyMultiStateControlledCompMatr1() */ -void applyMultiStateControlledCompMatr2(Qureg qureg, int* controls, int* states, int numControls, int target1, int target2, CompMatr2 matr); +void applyMultiStateControlledCompMatr2(Qureg qureg, int* controls, int* states, int numControls, int target1, int target2, CompMatr2 matrix); // end de-mangler @@ -565,7 +568,7 @@ void applyMultiStateControlledCompMatr2(Qureg qureg, int* controls, int* states, /// @notyetdoced /// @cppvectoroverload /// @see applyMultiControlledCompMatr2() -void applyMultiControlledCompMatr2(Qureg qureg, std::vector controls, int target1, int target2, CompMatr2 matr); +void applyMultiControlledCompMatr2(Qureg qureg, std::vector controls, int target1, int target2, CompMatr2 matrix); /// @notyettested @@ -573,7 +576,7 @@ void applyMultiControlledCompMatr2(Qureg qureg, std::vector controls, int t /// @notyetdoced /// @cppvectoroverload /// @see applyMultiStateControlledCompMatr2() -void applyMultiStateControlledCompMatr2(Qureg qureg, std::vector controls, std::vector states, int target1, int target2, CompMatr2 matr); +void applyMultiStateControlledCompMatr2(Qureg qureg, std::vector controls, std::vector states, int target1, int target2, CompMatr2 matrix); #endif // __cplusplus @@ -614,7 +617,7 @@ extern "C" { * - leftapplyCompMatr() * - rightapplyCompMatr() */ -void applyCompMatr(Qureg qureg, int* targets, int numTargets, CompMatr matr); +void applyCompMatr(Qureg qureg, int* targets, int numTargets, CompMatr matrix); /// @notyetdoced @@ -626,13 +629,13 @@ void applyControlledCompMatr(Qureg qureg, int control, int* targets, int numTarg /// @notyetdoced /// @see /// - applyMultiControlledCompMatr1() -void applyMultiControlledCompMatr(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, CompMatr matr); +void applyMultiControlledCompMatr(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, CompMatr matrix); /// @notyetdoced /// @see /// - applyMultiStateControlledCompMatr1() -void applyMultiStateControlledCompMatr(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, CompMatr matr); +void applyMultiStateControlledCompMatr(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, CompMatr matrix); // end de-mangler @@ -648,7 +651,7 @@ void applyMultiStateControlledCompMatr(Qureg qureg, int* controls, int* states, /// @notyetdoced /// @cppvectoroverload /// @see applyCompMatr() -void applyCompMatr(Qureg qureg, std::vector targets, CompMatr matr); +void applyCompMatr(Qureg qureg, std::vector targets, CompMatr matrix); /// @notyettested @@ -656,7 +659,7 @@ void applyCompMatr(Qureg qureg, std::vector targets, CompMatr matr); /// @notyetdoced /// @cppvectoroverload /// @see applyControlledCompMatr() -void applyControlledCompMatr(Qureg qureg, int control, std::vector targets, CompMatr matr); +void applyControlledCompMatr(Qureg qureg, int control, std::vector targets, CompMatr matrix); /// @notyettested @@ -664,7 +667,7 @@ void applyControlledCompMatr(Qureg qureg, int control, std::vector targets, /// @notyetdoced /// @cppvectoroverload /// @see applyMultiControlledCompMatr() -void applyMultiControlledCompMatr(Qureg qureg, std::vector controls, std::vector targets, CompMatr matr); +void applyMultiControlledCompMatr(Qureg qureg, std::vector controls, std::vector targets, CompMatr matrix); /// @notyettested @@ -672,7 +675,7 @@ void applyMultiControlledCompMatr(Qureg qureg, std::vector controls, std::v /// @notyetdoced /// @cppvectoroverload /// @see applyMultiStateControlledCompMatr() -void applyMultiStateControlledCompMatr(Qureg qureg, std::vector controls, std::vector states, std::vector targets, CompMatr matr); +void applyMultiStateControlledCompMatr(Qureg qureg, std::vector controls, std::vector states, std::vector targets, CompMatr matrix); #endif // __cplusplus @@ -699,22 +702,22 @@ extern "C" { * - leftapplyCompMatr2() * - rightapplyCompMatr2() */ -void applyDiagMatr1(Qureg qureg, int target, DiagMatr1 matr); +void applyDiagMatr1(Qureg qureg, int target, DiagMatr1 matrix); /// @notyetdoced /// @see applyControlledCompMatr1() -void applyControlledDiagMatr1(Qureg qureg, int control, int target, DiagMatr1 matr); +void applyControlledDiagMatr1(Qureg qureg, int control, int target, DiagMatr1 matrix); /// @notyetdoced /// @see applyMultiControlledCompMatr1() -void applyMultiControlledDiagMatr1(Qureg qureg, int* controls, int numControls, int target, DiagMatr1 matr); +void applyMultiControlledDiagMatr1(Qureg qureg, int* controls, int numControls, int target, DiagMatr1 matrix); /// @notyetdoced /// @see applyMultiStateControlledCompMatr1() -void applyMultiStateControlledDiagMatr1(Qureg qureg, int* controls, int* states, int numControls, int target, DiagMatr1 matr); +void applyMultiStateControlledDiagMatr1(Qureg qureg, int* controls, int* states, int numControls, int target, DiagMatr1 matrix); // end de-mangler @@ -730,7 +733,7 @@ void applyMultiStateControlledDiagMatr1(Qureg qureg, int* controls, int* states, /// @notyetdoced /// @cppvectoroverload /// @see applyMultiControlledDiagMatr1() -void applyMultiControlledDiagMatr1(Qureg qureg, std::vector controls, int target, DiagMatr1 matr); +void applyMultiControlledDiagMatr1(Qureg qureg, std::vector controls, int target, DiagMatr1 matrix); /// @notyettested @@ -738,7 +741,7 @@ void applyMultiControlledDiagMatr1(Qureg qureg, std::vector controls, int t /// @notyetdoced /// @cppvectoroverload /// @see applyMultiStateControlledDiagMatr1() -void applyMultiStateControlledDiagMatr1(Qureg qureg, std::vector controls, std::vector states, int target, DiagMatr1 matr); +void applyMultiStateControlledDiagMatr1(Qureg qureg, std::vector controls, std::vector states, int target, DiagMatr1 matrix); #endif // __cplusplus @@ -761,22 +764,22 @@ extern "C" { /// @notyetdoced /// @see applyCompMatr1() -void applyDiagMatr2(Qureg qureg, int target1, int target2, DiagMatr2 matr); +void applyDiagMatr2(Qureg qureg, int target1, int target2, DiagMatr2 matrix); /// @notyetdoced /// @see applyControlledCompMatr1() -void applyControlledDiagMatr2(Qureg qureg, int control, int target1, int target2, DiagMatr2 matr); +void applyControlledDiagMatr2(Qureg qureg, int control, int target1, int target2, DiagMatr2 matrix); /// @notyetdoced /// @see applyMultiControlledCompMatr1() -void applyMultiControlledDiagMatr2(Qureg qureg, int* controls, int numControls, int target1, int target2, DiagMatr2 matr); +void applyMultiControlledDiagMatr2(Qureg qureg, int* controls, int numControls, int target1, int target2, DiagMatr2 matrix); /// @notyetdoced /// @see applyMultiStateControlledCompMatr1() -void applyMultiStateControlledDiagMatr2(Qureg qureg, int* controls, int* states, int numControls, int target1, int target2, DiagMatr2 matr); +void applyMultiStateControlledDiagMatr2(Qureg qureg, int* controls, int* states, int numControls, int target1, int target2, DiagMatr2 matrix); // end de-mangler @@ -792,7 +795,7 @@ void applyMultiStateControlledDiagMatr2(Qureg qureg, int* controls, int* states, /// @notyetdoced /// @cppvectoroverload /// @see applyMultiControlledDiagMatr2() -void applyMultiControlledDiagMatr2(Qureg qureg, std::vector controls, int target1, int target2, DiagMatr2 matr); +void applyMultiControlledDiagMatr2(Qureg qureg, std::vector controls, int target1, int target2, DiagMatr2 matrix); /// @notyettested @@ -800,7 +803,7 @@ void applyMultiControlledDiagMatr2(Qureg qureg, std::vector controls, int t /// @notyetdoced /// @cppvectoroverload /// @see applyMultiStateControlledDiagMatr2() -void applyMultiStateControlledDiagMatr2(Qureg qureg, std::vector controls, std::vector states, int target1, int target2, DiagMatr2 matr); +void applyMultiStateControlledDiagMatr2(Qureg qureg, std::vector controls, std::vector states, int target1, int target2, DiagMatr2 matrix); #endif // __cplusplus From 699ef28a3e8523820128bb90be464c4532cf6480 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Mon, 6 Jul 2026 23:25:49 -0400 Subject: [PATCH 10/29] added operations.h multi-state-controlled doc stubs by redirection to the non-controlled function, and the multi-state-controlled CompMatr1. Also added stubs for some base functions --- quest/include/operations.h | 376 +++++++++++++++++++++++++++++-------- 1 file changed, 301 insertions(+), 75 deletions(-) diff --git a/quest/include/operations.h b/quest/include/operations.h index 077da8fd6..3b377525f 100644 --- a/quest/include/operations.h +++ b/quest/include/operations.h @@ -302,6 +302,7 @@ digraph { * * @see * - applyCompMatr1() + * @author Tyson Jones */ void applyMultiControlledCompMatr1(Qureg qureg, int* controls, int numControls, int target, CompMatr1 matrix); @@ -309,7 +310,7 @@ void applyMultiControlledCompMatr1(Qureg qureg, int* controls, int numControls, /** @notyetdoced * * Applies an arbitrarily-controlled one-qubit dense unitary @p matrix to the specified - * @p target qubit of @p qureg, conditioned upon the @p controls being in the given @p states. + * @p target qubit of @p qureg, conditioned upon the @p controls being in the corresponding @p states. * * @diagram * @dot @@ -347,6 +348,7 @@ digraph { * * @see * - applyCompMatr1() + * @author Tyson Jones */ void applyMultiStateControlledCompMatr1(Qureg qureg, int* controls, int* states, int numControls, int target, CompMatr1 matrix); @@ -423,6 +425,7 @@ digraph { * - applyCompMatr1() * - leftapplyCompMatr2() * - rightapplyCompMatr2() + * @author Tyson Jones */ void applyCompMatr2(Qureg qureg, int target1, int target2, CompMatr2 matrix); @@ -432,6 +435,8 @@ void applyCompMatr2(Qureg qureg, int target1, int target2, CompMatr2 matrix); * Applies a singly-controlled two-qubit dense unitary @p matrix to qubits * @p target1 and @p target2 (treated as increasing significance) of @p qureg. * + * > See applyControlledCompMatr1() for more information about the @p control qubit. + * * @diagram * @dot digraph { @@ -461,6 +466,7 @@ digraph { * * @see * - applyCompMatr2() + * @author Tyson Jones */ void applyControlledCompMatr2(Qureg qureg, int control, int target1, int target2, CompMatr2 matrix); @@ -512,8 +518,11 @@ void applyMultiControlledCompMatr2(Qureg qureg, int* controls, int numControls, /** @notyetdoced * * Applies an arbitrarily-controlled two-qubit dense unitary @p matrix to qubits - * @p target1 and @p target2 (treated as increasing significance) of @p qureg, - * conditioned upon the @p controls being in the given @p states. + * @p target1 and @p target2 of @p qureg, + * conditioned upon the @p controls being in the corresponding @p states. + * + * > - See applyCompMatr2() for more information about @p target1 and @p target2. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. * * @diagram * @dot @@ -551,6 +560,7 @@ digraph { * @see * - applyCompMatr2() * - applyMultiStateControlledCompMatr1() + * @author Tyson Jones */ void applyMultiStateControlledCompMatr2(Qureg qureg, int* controls, int* states, int numControls, int target1, int target2, CompMatr2 matrix); @@ -598,6 +608,9 @@ extern "C" { /** @notyetdoced + * + * Applies an arbitrarily-sized dense unitary @p matrix to the + * @p targets (treated as increasing significance) of @p qureg. * * @formulae * @@ -616,25 +629,47 @@ extern "C" { * - applyCompMatr1() * - leftapplyCompMatr() * - rightapplyCompMatr() + * @author Tyson Jones */ void applyCompMatr(Qureg qureg, int* targets, int numTargets, CompMatr matrix); -/// @notyetdoced -/// @see -/// - applyControlledCompMatr1() -void applyControlledCompMatr(Qureg qureg, int control, int* targets, int numTargets, CompMatr matr); +/** @notyetdoced + * + * Applies a singly-controlled arbitrarily-sized dense unitary @p matrix to the + * @p targets (treated as increasing significance) of @p qureg. + * + * > - See applyCompMatr() for more information about @p targets and @p matrix. + * > - See applyControlledCompMatr1() for more information about the @p control qubit. + * + * @author Tyson Jones + */ +void applyControlledCompMatr(Qureg qureg, int control, int* targets, int numTargets, CompMatr matrix); -/// @notyetdoced -/// @see -/// - applyMultiControlledCompMatr1() +/** @notyetdoced + * + * Applies a multiply-controlled arbitrarily-sized dense unitary @p matrix upon the + * @p targets (treated as increasing significance) of @p qureg, + * conditioned upon all @p controls being in state @c 1. + * + * > - See applyCompMatr() for more information about @p targets and @p matrix. + * > - See applyMultiControlledCompMatr1() for more information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledCompMatr(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, CompMatr matrix); -/// @notyetdoced -/// @see -/// - applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled arbitrarily-sized dense unitary @p matrix upon the + * @p targets of @p qureg, + * conditioned upon the @p controls being in the corresponding @p states. + * + * > - See applyCompMatr() for more information about @p targets and @p matrix. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + */ void applyMultiStateControlledCompMatr(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, CompMatr matrix); @@ -715,8 +750,17 @@ void applyControlledDiagMatr1(Qureg qureg, int control, int target, DiagMatr1 ma void applyMultiControlledDiagMatr1(Qureg qureg, int* controls, int numControls, int target, DiagMatr1 matrix); -/// @notyetdoced -/// @see applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled one-qubit diagonal unitary @p matrix upon the + * @p target qubit of @p qureg, + * conditioned upon the @p controls being in the corresponding @p states. + * + * > - See applyDiagMatr1() for more information about @p target and @p matrix. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledDiagMatr1(Qureg qureg, int* controls, int* states, int numControls, int target, DiagMatr1 matrix); @@ -777,8 +821,17 @@ void applyControlledDiagMatr2(Qureg qureg, int control, int target1, int target2 void applyMultiControlledDiagMatr2(Qureg qureg, int* controls, int numControls, int target1, int target2, DiagMatr2 matrix); -/// @notyetdoced -/// @see applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled two-qubit diagonal unitary @p matrix upon + * qubits @p target1 and @p target2 of @p qureg, + * conditioned upon the @p controls being in the corresponding @p states. + * + * > - See applyDiagMatr2() for more information about @p target1, @p target2 and @p matrix. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledDiagMatr2(Qureg qureg, int* controls, int* states, int numControls, int target1, int target2, DiagMatr2 matrix); @@ -824,8 +877,20 @@ extern "C" { #endif -/// @notyetdoced -/// @see applyCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-sized diagonal unitary @p matrix upon the @p targets of @p qureg. + * + * > [!TIP] + * > To efficiently apply a diagonal matrix upon _all_ targets of @p qureg, + * > use applyFullStateDiagMatr(). + * + * @see + * - applyDiagMatrPower() + * - applyControlledDiagMatr() + * - applyFullStateDiagMatr() + * @author Tyson Jones + */ void applyDiagMatr(Qureg qureg, int* targets, int numTargets, DiagMatr matrix); @@ -839,16 +904,36 @@ void applyControlledDiagMatr(Qureg qureg, int control, int* targets, int numTarg void applyMultiControlledDiagMatr(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, DiagMatr matrix); -/// @notyetdoced -/// @see applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled arbitrarily-sized diagonal unitary @p matrix upon + * the @p targets of @p qureg, + * conditioned upon the @p controls being in the corresponding @p states. + * + * > - See applyDiagMatr() for more information about @p targets and @p matrix. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledDiagMatr(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, DiagMatr matrix); /** @notyetdoced + * + * Applies an arbitrarily-sized diagonal unitary @p matrix, raised to the power @p exponent, + * upon the @p targets of @p qureg. + * + * > [!TIP] + * > To efficiently apply an exponentiated diagonal matrix upon _all_ targets of @p qureg, + * > use applyFullStateDiagMatrPower(). * * @formulae * * This function is equivalent to applyDiagMatr() except that @p matrix is raised to the given @p exponent. + * + * @see + * - applyControlledDiagMatrPower() + * - applyFullStateDiagMatrPower() */ void applyDiagMatrPower(Qureg qureg, int* targets, int numTargets, DiagMatr matrix, qcomp exponent); @@ -867,10 +952,19 @@ void applyControlledDiagMatrPower(Qureg qureg, int control, int* targets, int nu void applyMultiControlledDiagMatrPower(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, DiagMatr matrix, qcomp exponent); -/// @notyetdoced -/// @see -/// - applyDiagMatrPower() -/// - applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled arbitrarily-sized diagonal unitary @p matrix, + * raised to the power @p exponent, + * upon the @p targets of @p qureg, + * conditioned upon the @p controls being in the corresponding @p states. + * + * > - See applyDiagMatr() for more information about @p targets and @p matrix. + * > - See applyDiagMatrPower() for more information about @p exponent. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledDiagMatrPower(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, DiagMatr matrix, qcomp exponent); @@ -1010,8 +1104,16 @@ void applyControlledS(Qureg qureg, int control, int target); void applyMultiControlledS(Qureg qureg, int* controls, int numControls, int target); -/// @notyetdoced -/// @see applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled S-gate on the @p target qubit of @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyS() for more information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledS(Qureg qureg, int* controls, int* states, int numControls, int target); @@ -1027,8 +1129,16 @@ void applyControlledT(Qureg qureg, int control, int target); void applyMultiControlledT(Qureg qureg, int* controls, int numControls, int target); -/// @notyetdoced -/// @see applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled T-gate on the @p target qubit of @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyT() for more information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledT(Qureg qureg, int* controls, int* states, int numControls, int target); @@ -1044,8 +1154,16 @@ void applyControlledHadamard(Qureg qureg, int control, int target); void applyMultiControlledHadamard(Qureg qureg, int* controls, int numControls, int target); -/// @notyetdoced -/// @see applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled Hadamard gate on the @p target qubit of @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyHadamard() for more information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledHadamard(Qureg qureg, int* controls, int* states, int numControls, int target); @@ -1163,8 +1281,16 @@ void applyControlledSwap(Qureg qureg, int control, int qubit1, int qubit2); void applyMultiControlledSwap(Qureg qureg, int* controls, int numControls, int qubit1, int qubit2); -/// @notyetdoced -/// @see applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled SWAP gate on @p qubit1 and @p qubit2 of @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applySwap() for more information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledSwap(Qureg qureg, int* controls, int* states, int numControls, int qubit1, int qubit2); @@ -1180,8 +1306,16 @@ void applyControlledSqrtSwap(Qureg qureg, int control, int qubit1, int qubit2); void applyMultiControlledSqrtSwap(Qureg qureg, int* controls, int numControls, int qubit1, int qubit2); -/// @notyetdoced -/// @see applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled square-root-of-SWAP gate on @p qubit1 and @p qubit2 of @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applySqrtSwap() for more information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledSqrtSwap(Qureg qureg, int* controls, int* states, int numControls, int qubit1, int qubit2); @@ -1279,18 +1413,42 @@ void applyMultiControlledPauliY(Qureg qureg, int* controls, int numControls, int void applyMultiControlledPauliZ(Qureg qureg, int* controls, int numControls, int target); -/// @notyetdoced -/// @see applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled Pauli @c X operator (or NOT gate) upon the @p target qubit of @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyPauliX() for more information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledPauliX(Qureg qureg, int* controls, int* states, int numControls, int target); -/// @notyetdoced -/// @see applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled Pauli @c Y operator upon the @p target qubit of @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyPauliY() for more information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledPauliY(Qureg qureg, int* controls, int* states, int numControls, int target); -/// @notyetdoced -/// @see applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled Pauli @c Z operator upon the @p target qubit of @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyPauliZ() for more information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledPauliZ(Qureg qureg, int* controls, int* states, int numControls, int target); @@ -1380,8 +1538,16 @@ void applyControlledPauliStr(Qureg qureg, int control, PauliStr str); void applyMultiControlledPauliStr(Qureg qureg, int* controls, int numControls, PauliStr str); -/// @notyetdoced -/// @see applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled tensor product of Pauli operators @p str upon @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyPauliStr() for more information about @p str. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledPauliStr(Qureg qureg, int* controls, int* states, int numControls, PauliStr str); @@ -1441,7 +1607,7 @@ extern "C" { \hat{\sigma}_x \right) * @f] - * upon the @p target qubit, where @f$ \hat{\sigma}_x @f$ is the Pauli X matrix. + * upon the @p target qubit, where @f$ \hat{\sigma}_x @f$ is the Pauli @c X matrix. * * @equivalences * @@ -1480,7 +1646,7 @@ void applyRotateX(Qureg qureg, int target, qreal angle); \hat{\sigma}_y \right) * @f] - * upon the @p target qubit, where @f$ \hat{\sigma}_y @f$ is the Pauli Y matrix. + * upon the @p target qubit, where @f$ \hat{\sigma}_y @f$ is the Pauli @c Y matrix. * * @equivalences * @@ -1519,7 +1685,7 @@ void applyRotateY(Qureg qureg, int target, qreal angle); \hat{\sigma}_z \right) * @f] - * upon the @p target qubit, where @f$ \hat{\sigma}_z @f$ is the Pauli Z matrix. + * upon the @p target qubit, where @f$ \hat{\sigma}_z @f$ is the Pauli @c Z matrix. * * @equivalences * @@ -1568,28 +1734,52 @@ void applyMultiControlledRotateY(Qureg qureg, int* controls, int numControls, in void applyMultiControlledRotateZ(Qureg qureg, int* controls, int numControls, int target, qreal angle); -/// @notyetdoced -/// @see -/// - applyRotateX() -/// - applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled one-qubit rotation of @p angle around the @c X axis, + * upon the @p target qubit of @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyRotateX() for more information about the base operation, and @p angle. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledRotateX(Qureg qureg, int* controls, int* states, int numControls, int target, qreal angle); -/// @notyetdoced -/// @see -/// - applyRotateY() -/// - applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled one-qubit rotation of @p angle around the @c Y axis, + * upon the @p target qubit of @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyRotateY() for more information about the base operation, and @p angle. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledRotateY(Qureg qureg, int* controls, int* states, int numControls, int target, qreal angle); -/// @notyetdoced -/// @see -/// - applyRotateZ() -/// - applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled one-qubit rotation of @p angle around the @c Z axis, + * upon the @p target qubit of @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyRotateZ() for more information about the base operation, and @p angle. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledRotateZ(Qureg qureg, int* controls, int* states, int numControls, int target, qreal angle); /** @notyetdoced + * + * Rotates the @p target qubit of @p qureg by @p angle around an arbitrary axis specified by + * vector @p axisX, @p axisY, @p axisZ. * * @formulae * @@ -1656,10 +1846,17 @@ void applyControlledRotateAroundAxis(Qureg qureg, int ctrl, int targ, qreal angl void applyMultiControlledRotateAroundAxis(Qureg qureg, int* ctrls, int numCtrls, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ); -/// @notyetdoced -/// @see -/// - applyRotateAroundAxis() -/// - applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled one-qubit rotation of @p angle around an arbitrary axis, + * upon the @p target qubit of @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyRotateAroundAxis() for more information about the base operation, @p angle, @p axisX, @p axisY and @p axisZ. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledRotateAroundAxis(Qureg qureg, int* ctrls, int* states, int numCtrls, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ); @@ -1754,6 +1951,8 @@ extern "C" { /** @notyetdoced + * + * Applies a many-qubit rotation upon @p qureg, generated by tensor product of Pauli operators @p str. * * @formulae * @@ -1834,10 +2033,16 @@ void applyControlledPauliGadget(Qureg qureg, int control, PauliStr str, qreal an void applyMultiControlledPauliGadget(Qureg qureg, int* controls, int numControls, PauliStr str, qreal angle); -/// @notyetdoced -/// @see -/// - applyPauliGadget() -/// - applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled many-qubit rotation upon @p qureg, generated by tensor product of Pauli operators @p str, + * and conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyPauliGadget() for more information about the base operation, @p angle, and @p str. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledPauliGadget(Qureg qureg, int* controls, int* states, int numControls, PauliStr str, qreal angle); @@ -1873,7 +2078,7 @@ void applyMultiStateControlledPauliGadget(Qureg qureg, std::vector controls /** * @defgroup op_phasegadget Phase gates - * @brief Functions for applying many-qubit rotations around Pauli Z axis, and phase flips and shifts. + * @brief Functions for applying many-qubit rotations around the Pauli @c Z axis, and phase flips and shifts. * @{ */ @@ -1884,6 +2089,9 @@ extern "C" { /** @notyetdoced + * + * Applies a many-qubit @c Z rotation upon @p qureg, generated by a tensor product of Pauli @c Z operators + * upon @p targets. * * @formulae * @@ -1913,10 +2121,16 @@ void applyControlledPhaseGadget(Qureg qureg, int control, int* targets, int numT void applyMultiControlledPhaseGadget(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, qreal angle); -/// @notyetdoced -/// @see -/// - applyPhaseGadget() -/// - applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled many-qubit @c Z rotation upon @p qureg, generated by a tensor product of Pauli @c Z operators + * upon @p targets, and conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyPhaseGadget() for more information about the base operation, @p angle, and @p targets. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledPhaseGadget(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, qreal angle); @@ -2219,7 +2433,12 @@ extern "C" { #endif -/// @notyetdoced +/** @notyetdoced + * + * Applies a many-qubit NOT gate (or tensor product of Pauli @c X operators) upon the @p targets of @p qureg. + * + * @author Tyson Jones + */ void applyMultiQubitNot(Qureg qureg, int* targets, int numTargets); @@ -2231,9 +2450,16 @@ void applyControlledMultiQubitNot(Qureg qureg, int control, int* targets, int nu void applyMultiControlledMultiQubitNot(Qureg qureg, int* controls, int numControls, int* targets, int numTargets); -/// @notyetdoced -/// @see -/// - applyMultiStateControlledCompMatr1() +/** @notyetdoced + * + * Applies an arbitrarily-controlled many-qubit NOT gate (or tensor product of Pauli @c X operators) upon the @p targets of @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyMultiQubitNot() for more information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiStateControlledMultiQubitNot(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets); From 4f8970f196a5b01404ce64157ed0f7d95dcc7d3f Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Mon, 6 Jul 2026 23:35:46 -0400 Subject: [PATCH 11/29] added notes about target ordering efficiency --- quest/include/operations.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/quest/include/operations.h b/quest/include/operations.h index 3b377525f..1490dc306 100644 --- a/quest/include/operations.h +++ b/quest/include/operations.h @@ -625,6 +625,9 @@ extern "C" { \hat{M}_{\text{targets}} \equiv A_{\text{targets}[0]} \cdot B_{\text{targets}[1]} \cdot C_{\text{targets}[2]} \cdot \dots * @f] * + * > [!TIP] + * > This function is sometimes more efficient when @p targets are specified in increasing order. + * * @see * - applyCompMatr1() * - leftapplyCompMatr() @@ -885,6 +888,9 @@ extern "C" { * > To efficiently apply a diagonal matrix upon _all_ targets of @p qureg, * > use applyFullStateDiagMatr(). * + * > [!TIP] + * > This function is sometimes more efficient when @p targets are specified in increasing order. + * * @see * - applyDiagMatrPower() * - applyControlledDiagMatr() @@ -926,6 +932,9 @@ void applyMultiStateControlledDiagMatr(Qureg qureg, int* controls, int* states, * > [!TIP] * > To efficiently apply an exponentiated diagonal matrix upon _all_ targets of @p qureg, * > use applyFullStateDiagMatrPower(). + * + * > [!TIP] + * > This function is sometimes more efficient when @p targets are specified in increasing order. * * @formulae * @@ -2102,6 +2111,10 @@ extern "C" { R_{\hat{Z}}(\theta) = \exp \left( - \iu \, \frac{\theta}{2} \, \bigotimes_{t \,\in\, \vec{t}} \hat{Z}_t \right). * @f] * + * > [!TIP] + * > This function is sometimes more efficient when @p targets are specified in increasing order, + * > though the effect of this function is incidentally unaffected by the ordering of @p targets. + * * @equivalences * * - This function is equivalent to calling applyPauliGadget() with a PauliStr containing only @f$ \hat{Z} @f$ and @f$ \id @f$. @@ -2293,6 +2306,10 @@ void applyTwoQubitPhaseShift(Qureg qureg, int target1, int target2, qreal angle) * @f] * effected upon the target qubits. * + * > [!TIP] + * > This function is sometimes more efficient when @p targets are specified in increasing order, + * > though the effect of this function is incidentally unaffected by the ordering of @p targets. + * * @equivalences * * - The ordering of @p targets has no affect on the effected operation. @@ -2324,6 +2341,10 @@ void applyMultiQubitPhaseFlip(Qureg qureg, int* targets, int numTargets); * @f] * effected upon the target qubits. * + * > [!TIP] + * > This function is sometimes more efficient when @p targets are specified in increasing order, + * > though the effect of this function is incidentally unaffected by the ordering of @p targets. + * * @diagram * @dot digraph { @@ -2437,6 +2458,10 @@ extern "C" { * * Applies a many-qubit NOT gate (or tensor product of Pauli @c X operators) upon the @p targets of @p qureg. * + * > [!TIP] + * > This function is sometimes more efficient when @p targets are specified in increasing order, + * > though the effect of this function is incidentally unaffected by the ordering of @p targets. + * * @author Tyson Jones */ void applyMultiQubitNot(Qureg qureg, int* targets, int numTargets); From bb24566fd352063b4b221987a797ec0ef48d9608 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Mon, 6 Jul 2026 23:41:10 -0400 Subject: [PATCH 12/29] remove "more" from "for more information" my brain is poop --- quest/include/operations.h | 100 ++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/quest/include/operations.h b/quest/include/operations.h index 1490dc306..12d0d2b4b 100644 --- a/quest/include/operations.h +++ b/quest/include/operations.h @@ -435,7 +435,7 @@ void applyCompMatr2(Qureg qureg, int target1, int target2, CompMatr2 matrix); * Applies a singly-controlled two-qubit dense unitary @p matrix to qubits * @p target1 and @p target2 (treated as increasing significance) of @p qureg. * - * > See applyControlledCompMatr1() for more information about the @p control qubit. + * > See applyControlledCompMatr1() for information about the @p control qubit. * * @diagram * @dot @@ -521,8 +521,8 @@ void applyMultiControlledCompMatr2(Qureg qureg, int* controls, int numControls, * @p target1 and @p target2 of @p qureg, * conditioned upon the @p controls being in the corresponding @p states. * - * > - See applyCompMatr2() for more information about @p target1 and @p target2. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyCompMatr2() for information about @p target1 and @p target2. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @diagram * @dot @@ -642,8 +642,8 @@ void applyCompMatr(Qureg qureg, int* targets, int numTargets, CompMatr matrix); * Applies a singly-controlled arbitrarily-sized dense unitary @p matrix to the * @p targets (treated as increasing significance) of @p qureg. * - * > - See applyCompMatr() for more information about @p targets and @p matrix. - * > - See applyControlledCompMatr1() for more information about the @p control qubit. + * > - See applyCompMatr() for information about @p targets and @p matrix. + * > - See applyControlledCompMatr1() for information about the @p control qubit. * * @author Tyson Jones */ @@ -656,8 +656,8 @@ void applyControlledCompMatr(Qureg qureg, int control, int* targets, int numTarg * @p targets (treated as increasing significance) of @p qureg, * conditioned upon all @p controls being in state @c 1. * - * > - See applyCompMatr() for more information about @p targets and @p matrix. - * > - See applyMultiControlledCompMatr1() for more information about @p controls. + * > - See applyCompMatr() for information about @p targets and @p matrix. + * > - See applyMultiControlledCompMatr1() for information about @p controls. * * @author Tyson Jones */ @@ -670,8 +670,8 @@ void applyMultiControlledCompMatr(Qureg qureg, int* controls, int numControls, i * @p targets of @p qureg, * conditioned upon the @p controls being in the corresponding @p states. * - * > - See applyCompMatr() for more information about @p targets and @p matrix. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyCompMatr() for information about @p targets and @p matrix. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. */ void applyMultiStateControlledCompMatr(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, CompMatr matrix); @@ -759,8 +759,8 @@ void applyMultiControlledDiagMatr1(Qureg qureg, int* controls, int numControls, * @p target qubit of @p qureg, * conditioned upon the @p controls being in the corresponding @p states. * - * > - See applyDiagMatr1() for more information about @p target and @p matrix. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyDiagMatr1() for information about @p target and @p matrix. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -830,8 +830,8 @@ void applyMultiControlledDiagMatr2(Qureg qureg, int* controls, int numControls, * qubits @p target1 and @p target2 of @p qureg, * conditioned upon the @p controls being in the corresponding @p states. * - * > - See applyDiagMatr2() for more information about @p target1, @p target2 and @p matrix. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyDiagMatr2() for information about @p target1, @p target2 and @p matrix. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -916,8 +916,8 @@ void applyMultiControlledDiagMatr(Qureg qureg, int* controls, int numControls, i * the @p targets of @p qureg, * conditioned upon the @p controls being in the corresponding @p states. * - * > - See applyDiagMatr() for more information about @p targets and @p matrix. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyDiagMatr() for information about @p targets and @p matrix. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -968,9 +968,9 @@ void applyMultiControlledDiagMatrPower(Qureg qureg, int* controls, int numContro * upon the @p targets of @p qureg, * conditioned upon the @p controls being in the corresponding @p states. * - * > - See applyDiagMatr() for more information about @p targets and @p matrix. - * > - See applyDiagMatrPower() for more information about @p exponent. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyDiagMatr() for information about @p targets and @p matrix. + * > - See applyDiagMatrPower() for information about @p exponent. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -1118,8 +1118,8 @@ void applyMultiControlledS(Qureg qureg, int* controls, int numControls, int targ * Applies an arbitrarily-controlled S-gate on the @p target qubit of @p qureg, * conditioned upon @p controls being in the corresponding @p states. * - * > - See applyS() for more information about the base operation. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyS() for information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -1143,8 +1143,8 @@ void applyMultiControlledT(Qureg qureg, int* controls, int numControls, int targ * Applies an arbitrarily-controlled T-gate on the @p target qubit of @p qureg, * conditioned upon @p controls being in the corresponding @p states. * - * > - See applyT() for more information about the base operation. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyT() for information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -1168,8 +1168,8 @@ void applyMultiControlledHadamard(Qureg qureg, int* controls, int numControls, i * Applies an arbitrarily-controlled Hadamard gate on the @p target qubit of @p qureg, * conditioned upon @p controls being in the corresponding @p states. * - * > - See applyHadamard() for more information about the base operation. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyHadamard() for information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -1295,8 +1295,8 @@ void applyMultiControlledSwap(Qureg qureg, int* controls, int numControls, int q * Applies an arbitrarily-controlled SWAP gate on @p qubit1 and @p qubit2 of @p qureg, * conditioned upon @p controls being in the corresponding @p states. * - * > - See applySwap() for more information about the base operation. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applySwap() for information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -1320,8 +1320,8 @@ void applyMultiControlledSqrtSwap(Qureg qureg, int* controls, int numControls, i * Applies an arbitrarily-controlled square-root-of-SWAP gate on @p qubit1 and @p qubit2 of @p qureg, * conditioned upon @p controls being in the corresponding @p states. * - * > - See applySqrtSwap() for more information about the base operation. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applySqrtSwap() for information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -1427,8 +1427,8 @@ void applyMultiControlledPauliZ(Qureg qureg, int* controls, int numControls, int * Applies an arbitrarily-controlled Pauli @c X operator (or NOT gate) upon the @p target qubit of @p qureg, * conditioned upon @p controls being in the corresponding @p states. * - * > - See applyPauliX() for more information about the base operation. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyPauliX() for information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -1440,8 +1440,8 @@ void applyMultiStateControlledPauliX(Qureg qureg, int* controls, int* states, in * Applies an arbitrarily-controlled Pauli @c Y operator upon the @p target qubit of @p qureg, * conditioned upon @p controls being in the corresponding @p states. * - * > - See applyPauliY() for more information about the base operation. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyPauliY() for information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -1453,8 +1453,8 @@ void applyMultiStateControlledPauliY(Qureg qureg, int* controls, int* states, in * Applies an arbitrarily-controlled Pauli @c Z operator upon the @p target qubit of @p qureg, * conditioned upon @p controls being in the corresponding @p states. * - * > - See applyPauliZ() for more information about the base operation. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyPauliZ() for information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -1552,8 +1552,8 @@ void applyMultiControlledPauliStr(Qureg qureg, int* controls, int numControls, P * Applies an arbitrarily-controlled tensor product of Pauli operators @p str upon @p qureg, * conditioned upon @p controls being in the corresponding @p states. * - * > - See applyPauliStr() for more information about @p str. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyPauliStr() for information about @p str. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -1749,8 +1749,8 @@ void applyMultiControlledRotateZ(Qureg qureg, int* controls, int numControls, in * upon the @p target qubit of @p qureg, * conditioned upon @p controls being in the corresponding @p states. * - * > - See applyRotateX() for more information about the base operation, and @p angle. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyRotateX() for information about the base operation, and @p angle. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -1763,8 +1763,8 @@ void applyMultiStateControlledRotateX(Qureg qureg, int* controls, int* states, i * upon the @p target qubit of @p qureg, * conditioned upon @p controls being in the corresponding @p states. * - * > - See applyRotateY() for more information about the base operation, and @p angle. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyRotateY() for information about the base operation, and @p angle. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -1777,8 +1777,8 @@ void applyMultiStateControlledRotateY(Qureg qureg, int* controls, int* states, i * upon the @p target qubit of @p qureg, * conditioned upon @p controls being in the corresponding @p states. * - * > - See applyRotateZ() for more information about the base operation, and @p angle. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyRotateZ() for information about the base operation, and @p angle. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -1861,8 +1861,8 @@ void applyMultiControlledRotateAroundAxis(Qureg qureg, int* ctrls, int numCtrls, * upon the @p target qubit of @p qureg, * conditioned upon @p controls being in the corresponding @p states. * - * > - See applyRotateAroundAxis() for more information about the base operation, @p angle, @p axisX, @p axisY and @p axisZ. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyRotateAroundAxis() for information about the base operation, @p angle, @p axisX, @p axisY and @p axisZ. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -2047,8 +2047,8 @@ void applyMultiControlledPauliGadget(Qureg qureg, int* controls, int numControls * Applies an arbitrarily-controlled many-qubit rotation upon @p qureg, generated by tensor product of Pauli operators @p str, * and conditioned upon @p controls being in the corresponding @p states. * - * > - See applyPauliGadget() for more information about the base operation, @p angle, and @p str. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyPauliGadget() for information about the base operation, @p angle, and @p str. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -2139,8 +2139,8 @@ void applyMultiControlledPhaseGadget(Qureg qureg, int* controls, int numControls * Applies an arbitrarily-controlled many-qubit @c Z rotation upon @p qureg, generated by a tensor product of Pauli @c Z operators * upon @p targets, and conditioned upon @p controls being in the corresponding @p states. * - * > - See applyPhaseGadget() for more information about the base operation, @p angle, and @p targets. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyPhaseGadget() for information about the base operation, @p angle, and @p targets. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ @@ -2480,8 +2480,8 @@ void applyMultiControlledMultiQubitNot(Qureg qureg, int* controls, int numContro * Applies an arbitrarily-controlled many-qubit NOT gate (or tensor product of Pauli @c X operators) upon the @p targets of @p qureg, * conditioned upon @p controls being in the corresponding @p states. * - * > - See applyMultiQubitNot() for more information about the base operation. - * > - See applyMultiStateControlledCompMatr1() for more information about @p controls and @p states. + * > - See applyMultiQubitNot() for information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @author Tyson Jones */ From 850226427985bd41709c4dca518d1049b732a3ba Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Mon, 6 Jul 2026 23:59:58 -0400 Subject: [PATCH 13/29] added singly-controlled doc stubs by redirecting to controlled compmatr1 --- quest/include/operations.h | 237 ++++++++++++++++++++++++++++++++----- 1 file changed, 206 insertions(+), 31 deletions(-) diff --git a/quest/include/operations.h b/quest/include/operations.h index 12d0d2b4b..6f9ffabf0 100644 --- a/quest/include/operations.h +++ b/quest/include/operations.h @@ -435,7 +435,8 @@ void applyCompMatr2(Qureg qureg, int target1, int target2, CompMatr2 matrix); * Applies a singly-controlled two-qubit dense unitary @p matrix to qubits * @p target1 and @p target2 (treated as increasing significance) of @p qureg. * - * > See applyControlledCompMatr1() for information about the @p control qubit. + * > - See applyCompMatr2() for information about the base operation. + * > - See applyControlledCompMatr1() for information about the @p control qubit. * * @diagram * @dot @@ -735,6 +736,9 @@ extern "C" { /** @notyetdoced + * + * Applies a one-qubit diagonal unitary @p matrix to the @p target qubit of @p qureg. + * * @see * - applyCompMatr1() * - leftapplyCompMatr2() @@ -743,8 +747,16 @@ extern "C" { void applyDiagMatr1(Qureg qureg, int target, DiagMatr1 matrix); -/// @notyetdoced -/// @see applyControlledCompMatr1() +/** @notyetdoced + * + * Applies a singly-controlled one-qubit diagonal unitary @p matrix to the + * @p target qubit of @p qureg. + * + * > - See applyDiagMatr1() for information about the base operation. + * > - See applyControlledCompMatr1() for information about the @p control qubit. + * + * @author Tyson Jones + */ void applyControlledDiagMatr1(Qureg qureg, int control, int target, DiagMatr1 matrix); @@ -809,13 +821,26 @@ extern "C" { #endif -/// @notyetdoced -/// @see applyCompMatr1() +/** @notyetdoced + * + * Applies a two-qubit diagonal unitary @p matrix to qubits + * @p target1 and @p target2 of @p qureg. + * + * @author Tyson Jones + */ void applyDiagMatr2(Qureg qureg, int target1, int target2, DiagMatr2 matrix); -/// @notyetdoced -/// @see applyControlledCompMatr1() +/** @notyetdoced + * + * Applies a singly-controlled two-qubit diagonal unitary @p matrix to qubits + * @p target1 and @p target2 of @p qureg. + * + * > - See applyDiagMatr2() for information about the base operation. + * > - See applyControlledCompMatr1() for information about the @p control qubit. + * + * @author Tyson Jones + */ void applyControlledDiagMatr2(Qureg qureg, int control, int target1, int target2, DiagMatr2 matrix); @@ -900,8 +925,16 @@ extern "C" { void applyDiagMatr(Qureg qureg, int* targets, int numTargets, DiagMatr matrix); -/// @notyetdoced -/// @see applyControlledCompMatr1() +/** @notyetdoced + * + * Applies a singly-controlled arbitrarily-sized diagonal unitary @p matrix + * upon the @p targets of @p qureg. + * + * > - See applyDiagMatr() for information about the base operation, @p targets and @p matrix. + * > - See applyControlledCompMatr1() for information about the @p control qubit. + * + * @author Tyson Jones + */ void applyControlledDiagMatr(Qureg qureg, int control, int* targets, int numTargets, DiagMatr matrix); @@ -947,10 +980,17 @@ void applyMultiStateControlledDiagMatr(Qureg qureg, int* controls, int* states, void applyDiagMatrPower(Qureg qureg, int* targets, int numTargets, DiagMatr matrix, qcomp exponent); -/// @notyetdoced -/// @see -/// - applyDiagMatrPower() -/// - applyControlledCompMatr1() +/** @notyetdoced + * + * Applies a singly-controlled arbitrarily-sized diagonal unitary @p matrix, + * raised to the power @p exponent, upon the @p targets of @p qureg. + * + * > - See applyDiagMatr() for information about @p targets and @p matrix. + * > - See applyDiagMatrPower() for information about @p exponent. + * > - See applyControlledCompMatr1() for information about the @p control qubit. + * + * @author Tyson Jones + */ void applyControlledDiagMatrPower(Qureg qureg, int control, int* targets, int numTargets, DiagMatr matrix, qcomp exponent); @@ -1105,7 +1145,15 @@ extern "C" { void applyS(Qureg qureg, int target); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled S gate on the @p target qubit of @p qureg. + * + * > - See applyS() for information about the base operation. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledS(Qureg qureg, int control, int target); @@ -1115,7 +1163,7 @@ void applyMultiControlledS(Qureg qureg, int* controls, int numControls, int targ /** @notyetdoced * - * Applies an arbitrarily-controlled S-gate on the @p target qubit of @p qureg, + * Applies an arbitrarily-controlled S gate on the @p target qubit of @p qureg, * conditioned upon @p controls being in the corresponding @p states. * * > - See applyS() for information about the base operation. @@ -1130,7 +1178,15 @@ void applyMultiStateControlledS(Qureg qureg, int* controls, int* states, int num void applyT(Qureg qureg, int target); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled T gate on the @p target qubit of @p qureg. + * + * > - See applyT() for information about the base operation. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledT(Qureg qureg, int control, int target); @@ -1140,7 +1196,7 @@ void applyMultiControlledT(Qureg qureg, int* controls, int numControls, int targ /** @notyetdoced * - * Applies an arbitrarily-controlled T-gate on the @p target qubit of @p qureg, + * Applies an arbitrarily-controlled T gate on the @p target qubit of @p qureg, * conditioned upon @p controls being in the corresponding @p states. * * > - See applyT() for information about the base operation. @@ -1155,7 +1211,15 @@ void applyMultiStateControlledT(Qureg qureg, int* controls, int* states, int num void applyHadamard(Qureg qureg, int target); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled Hadamard gate on the @p target qubit of @p qureg. + * + * > - See applyHadamard() for information about the base operation. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledHadamard(Qureg qureg, int control, int target); @@ -1282,7 +1346,15 @@ digraph { void applySwap(Qureg qureg, int qubit1, int qubit2); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled SWAP gate upon @p qubit1 and @p qubit2 of @p qureg. + * + * > - See applySwap() for information about the base operation. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledSwap(Qureg qureg, int control, int qubit1, int qubit2); @@ -1307,7 +1379,15 @@ void applyMultiStateControlledSwap(Qureg qureg, int* controls, int* states, int void applySqrtSwap(Qureg qureg, int qubit1, int qubit2); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled square-root-of-SWAP gate upon @p qubit1 and @p qubit2 of @p qureg. + * + * > - See applySqrtSwap() for information about the base operation. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledSqrtSwap(Qureg qureg, int control, int qubit1, int qubit2); @@ -1398,15 +1478,39 @@ void applyPauliY(Qureg qureg, int target); void applyPauliZ(Qureg qureg, int target); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled Pauli @c X operator (or NOT gate) upon the @p target qubit of @p qureg. + * + * > - See applyPauliX() for information about the base operation. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledPauliX(Qureg qureg, int control, int target); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled Pauli @c Y operator upon the @p target qubit of @p qureg. + * + * > - See applyPauliY() for information about the base operation. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledPauliY(Qureg qureg, int control, int target); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled Pauli @c Z operator upon the @p target qubit of @p qureg. + * + * > - See applyPauliZ() for information about the base operation. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledPauliZ(Qureg qureg, int control, int target); @@ -1539,7 +1643,15 @@ extern "C" { void applyPauliStr(Qureg qureg, PauliStr str); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled tensor product of Pauli operators @p str upon @p qureg. + * + * > - See applyPauliStr() for information about @p str. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledPauliStr(Qureg qureg, int control, PauliStr str); @@ -1719,15 +1831,42 @@ void applyRotateY(Qureg qureg, int target, qreal angle); void applyRotateZ(Qureg qureg, int target, qreal angle); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled one-qubit rotation of @p angle around the @c X axis, + * upon the @p target qubit of @p qureg. + * + * > - See applyRotateX() for information about the base operation, and @p angle. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledRotateX(Qureg qureg, int control, int target, qreal angle); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled one-qubit rotation of @p angle around the @c Y axis, + * upon the @p target qubit of @p qureg. + * + * > - See applyRotateY() for information about the base operation, and @p angle. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledRotateY(Qureg qureg, int control, int target, qreal angle); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled one-qubit rotation of @p angle around the @c Z axis, + * upon the @p target qubit of @p qureg. + * + * > - See applyRotateZ() for information about the base operation, and @p angle. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledRotateZ(Qureg qureg, int control, int target, qreal angle); @@ -1847,7 +1986,16 @@ void applyMultiStateControlledRotateZ(Qureg qureg, int* controls, int* states, i void applyRotateAroundAxis(Qureg qureg, int target, qreal angle, qreal axisX, qreal axisY, qreal axisZ); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled one-qubit rotation of @p angle around an arbitrary axis, + * upon the @p target qubit of @p qureg. + * + * > - See applyRotateAroundAxis() for information about the base operation, @p angle, @p axisX, @p axisY and @p axisZ. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledRotateAroundAxis(Qureg qureg, int ctrl, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ); @@ -2034,7 +2182,16 @@ void applyPauliGadget(Qureg qureg, PauliStr str, qreal angle); void applyNonUnitaryPauliGadget(Qureg qureg, PauliStr str, qcomp angle); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled many-qubit rotation upon @p qureg, + * generated by tensor product of Pauli operators @p str. + * + * > - See applyPauliGadget() for information about the base operation, @p angle, and @p str. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledPauliGadget(Qureg qureg, int control, PauliStr str, qreal angle); @@ -2126,7 +2283,16 @@ extern "C" { void applyPhaseGadget(Qureg qureg, int* targets, int numTargets, qreal angle); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled many-qubit @c Z rotation upon @p qureg, + * generated by a tensor product of Pauli @c Z operators upon @p targets. + * + * > - See applyPhaseGadget() for information about the base operation, @p angle, and @p targets. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledPhaseGadget(Qureg qureg, int control, int* targets, int numTargets, qreal angle); @@ -2467,7 +2633,16 @@ extern "C" { void applyMultiQubitNot(Qureg qureg, int* targets, int numTargets); -/// @notyetdoced +/** @notyetdoced + * + * Applies a singly-controlled many-qubit NOT gate (or tensor product of Pauli @c X operators) + * upon the @p targets of @p qureg. + * + * > - See applyMultiQubitNot() for information about the base operation. + * > - See applyControlledCompMatr1() for information about @p control. + * + * @author Tyson Jones + */ void applyControlledMultiQubitNot(Qureg qureg, int control, int* targets, int numTargets); From 6e17626dd75c14c22b75b73876b493b44a496a20 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Tue, 7 Jul 2026 00:03:32 -0400 Subject: [PATCH 14/29] remove ctrl and targ abbreviations from operations.h So that the pasted/duplicated redirections are always correct, and also for reader clarity / consistency --- quest/include/operations.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/quest/include/operations.h b/quest/include/operations.h index 6f9ffabf0..b58f5d990 100644 --- a/quest/include/operations.h +++ b/quest/include/operations.h @@ -1996,11 +1996,11 @@ void applyRotateAroundAxis(Qureg qureg, int target, qreal angle, qreal axisX, qr * * @author Tyson Jones */ -void applyControlledRotateAroundAxis(Qureg qureg, int ctrl, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ); +void applyControlledRotateAroundAxis(Qureg qureg, int control, int target, qreal angle, qreal axisX, qreal axisY, qreal axisZ); /// @notyetdoced -void applyMultiControlledRotateAroundAxis(Qureg qureg, int* ctrls, int numCtrls, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ); +void applyMultiControlledRotateAroundAxis(Qureg qureg, int* controls, int numControls, int target, qreal angle, qreal axisX, qreal axisY, qreal axisZ); /** @notyetdoced @@ -2014,7 +2014,7 @@ void applyMultiControlledRotateAroundAxis(Qureg qureg, int* ctrls, int numCtrls, * * @author Tyson Jones */ -void applyMultiStateControlledRotateAroundAxis(Qureg qureg, int* ctrls, int* states, int numCtrls, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ); +void applyMultiStateControlledRotateAroundAxis(Qureg qureg, int* controls, int* states, int numControls, int target, qreal angle, qreal axisX, qreal axisY, qreal axisZ); // end de-mangler @@ -2078,7 +2078,7 @@ void applyMultiStateControlledRotateZ(Qureg qureg, std::vector controls, st /// @notyetdoced /// @cppvectoroverload /// @see applyMultiControlledRotateAroundAxis() -void applyMultiControlledRotateAroundAxis(Qureg qureg, std::vector ctrls, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ); +void applyMultiControlledRotateAroundAxis(Qureg qureg, std::vector controls, int target, qreal angle, qreal axisX, qreal axisY, qreal axisZ); /// @notyettested @@ -2086,7 +2086,7 @@ void applyMultiControlledRotateAroundAxis(Qureg qureg, std::vector ctrls, i /// @notyetdoced /// @cppvectoroverload /// @see applyMultiStateControlledRotateAroundAxis() -void applyMultiStateControlledRotateAroundAxis(Qureg qureg, std::vector ctrls, std::vector states, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ); +void applyMultiStateControlledRotateAroundAxis(Qureg qureg, std::vector controls, std::vector states, int target, qreal angle, qreal axisX, qreal axisY, qreal axisZ); #endif // __cplusplus From 5e4ebb6d0533edc0dae49f867947db0545314dec Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Tue, 7 Jul 2026 00:18:38 -0400 Subject: [PATCH 15/29] added multi-controlled operator doc stubs by redirection to applyMultiControlledCompMatr1 --- quest/include/operations.h | 229 ++++++++++++++++++++++++++++++++----- 1 file changed, 200 insertions(+), 29 deletions(-) diff --git a/quest/include/operations.h b/quest/include/operations.h index b58f5d990..71372fe88 100644 --- a/quest/include/operations.h +++ b/quest/include/operations.h @@ -477,6 +477,9 @@ void applyControlledCompMatr2(Qureg qureg, int control, int target1, int target2 * Applies a multiply-controlled two-qubit dense unitary @p matrix to qubits * @p target1 and @p target2 (treated as increasing significance) of @p qureg. * + * > - See applyCompMatr2() for information about @p target1, @p target2 and @p matrix. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * * @diagram * @dot digraph { @@ -522,7 +525,7 @@ void applyMultiControlledCompMatr2(Qureg qureg, int* controls, int numControls, * @p target1 and @p target2 of @p qureg, * conditioned upon the @p controls being in the corresponding @p states. * - * > - See applyCompMatr2() for information about @p target1 and @p target2. + * > - See applyCompMatr2() for information about @p target1, @p target2 and @p matrix. * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. * * @diagram @@ -654,8 +657,7 @@ void applyControlledCompMatr(Qureg qureg, int control, int* targets, int numTarg /** @notyetdoced * * Applies a multiply-controlled arbitrarily-sized dense unitary @p matrix upon the - * @p targets (treated as increasing significance) of @p qureg, - * conditioned upon all @p controls being in state @c 1. + * @p targets of @p qureg. * * > - See applyCompMatr() for information about @p targets and @p matrix. * > - See applyMultiControlledCompMatr1() for information about @p controls. @@ -760,8 +762,16 @@ void applyDiagMatr1(Qureg qureg, int target, DiagMatr1 matrix); void applyControlledDiagMatr1(Qureg qureg, int control, int target, DiagMatr1 matrix); -/// @notyetdoced -/// @see applyMultiControlledCompMatr1() +/** @notyetdoced + * + * Applies a multiply-controlled one-qubit diagonal unitary @p matrix upon the + * @p target qubit of @p qureg. + * + * > - See applyDiagMatr1() for information about @p target and @p matrix. + * > - See applyMultiControlledCompMatr1() for information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiControlledDiagMatr1(Qureg qureg, int* controls, int numControls, int target, DiagMatr1 matrix); @@ -844,8 +854,16 @@ void applyDiagMatr2(Qureg qureg, int target1, int target2, DiagMatr2 matrix); void applyControlledDiagMatr2(Qureg qureg, int control, int target1, int target2, DiagMatr2 matrix); -/// @notyetdoced -/// @see applyMultiControlledCompMatr1() +/** @notyetdoced + * + * Applies a multiply-controlled two-qubit diagonal unitary @p matrix upon + * qubits @p target1 and @p target2 of @p qureg. + * + * > - See applyDiagMatr2() for information about @p target1, @p target2 and @p matrix. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledDiagMatr2(Qureg qureg, int* controls, int numControls, int target1, int target2, DiagMatr2 matrix); @@ -938,8 +956,16 @@ void applyDiagMatr(Qureg qureg, int* targets, int numTargets, DiagMatr matrix); void applyControlledDiagMatr(Qureg qureg, int control, int* targets, int numTargets, DiagMatr matrix); -/// @notyetdoced -/// @see applyMultiControlledCompMatr1() +/** @notyetdoced + * + * Applies a multiply-controlled arbitrarily-sized diagonal unitary @p matrix upon + * the @p targets of @p qureg. + * + * > - See applyDiagMatr() for information about @p targets and @p matrix. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledDiagMatr(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, DiagMatr matrix); @@ -994,10 +1020,18 @@ void applyDiagMatrPower(Qureg qureg, int* targets, int numTargets, DiagMatr matr void applyControlledDiagMatrPower(Qureg qureg, int control, int* targets, int numTargets, DiagMatr matrix, qcomp exponent); -/// @notyetdoced -/// @see -/// - applyDiagMatrPower() -/// - applyMultiControlledCompMatr1() +/** @notyetdoced + * + * Applies a multiply-controlled arbitrarily-sized diagonal unitary @p matrix, + * raised to the power @p exponent, + * upon the @p targets of @p qureg. + * + * > - See applyDiagMatr() for information about @p targets and @p matrix. + * > - See applyDiagMatrPower() for information about @p exponent. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledDiagMatrPower(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, DiagMatr matrix, qcomp exponent); @@ -1157,7 +1191,15 @@ void applyS(Qureg qureg, int target); void applyControlledS(Qureg qureg, int control, int target); -/// @notyetdoced +/** @notyetdoced + * + * Applies a multiply-controlled S gate on the @p target qubit of @p qureg. + * + * > - See applyS() for information about the base operation. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledS(Qureg qureg, int* controls, int numControls, int target); @@ -1190,7 +1232,16 @@ void applyT(Qureg qureg, int target); void applyControlledT(Qureg qureg, int control, int target); -/// @notyetdoced +/** @notyetdoced + * + * Applies an arbitrarily-controlled T gate on the @p target qubit of @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyT() for information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiControlledT(Qureg qureg, int* controls, int numControls, int target); @@ -1223,7 +1274,16 @@ void applyHadamard(Qureg qureg, int target); void applyControlledHadamard(Qureg qureg, int control, int target); -/// @notyetdoced +/** @notyetdoced + * + * Applies an arbitrarily-controlled Hadamard gate on the @p target qubit of @p qureg, + * conditioned upon @p controls being in the corresponding @p states. + * + * > - See applyHadamard() for information about the base operation. + * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. + * + * @author Tyson Jones + */ void applyMultiControlledHadamard(Qureg qureg, int* controls, int numControls, int target); @@ -1358,7 +1418,15 @@ void applySwap(Qureg qureg, int qubit1, int qubit2); void applyControlledSwap(Qureg qureg, int control, int qubit1, int qubit2); -/// @notyetdoced +/** @notyetdoced + * + * Applies a multiply-controlled SWAP gate on @p qubit1 and @p qubit2 of @p qureg. + * + * > - See applySwap() for information about the base operation. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledSwap(Qureg qureg, int* controls, int numControls, int qubit1, int qubit2); @@ -1391,7 +1459,15 @@ void applySqrtSwap(Qureg qureg, int qubit1, int qubit2); void applyControlledSqrtSwap(Qureg qureg, int control, int qubit1, int qubit2); -/// @notyetdoced +/** @notyetdoced + * + * Applies a multiply-controlled square-root-of-SWAP gate on @p qubit1 and @p qubit2 of @p qureg. + * + * > - See applySqrtSwap() for information about the base operation. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledSqrtSwap(Qureg qureg, int* controls, int numControls, int qubit1, int qubit2); @@ -1514,15 +1590,39 @@ void applyControlledPauliY(Qureg qureg, int control, int target); void applyControlledPauliZ(Qureg qureg, int control, int target); -/// @notyetdoced +/** @notyetdoced + * + * Applies a multiply-controlled Pauli @c X operator (or NOT gate) upon the @p target qubit of @p qureg. + * + * > - See applyPauliX() for information about the base operation. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledPauliX(Qureg qureg, int* controls, int numControls, int target); -/// @notyetdoced +/** @notyetdoced + * + * Applies a multiply-controlled Pauli @c Y operator (or NOT gate) upon the @p target qubit of @p qureg. + * + * > - See applyPauliY() for information about the base operation. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledPauliY(Qureg qureg, int* controls, int numControls, int target); -/// @notyetdoced +/** @notyetdoced + * + * Applies a multiply-controlled Pauli @c Z operator (or NOT gate) upon the @p target qubit of @p qureg. + * + * > - See applyPauliZ() for information about the base operation. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledPauliZ(Qureg qureg, int* controls, int numControls, int target); @@ -1655,7 +1755,15 @@ void applyPauliStr(Qureg qureg, PauliStr str); void applyControlledPauliStr(Qureg qureg, int control, PauliStr str); -/// @notyetdoced +/** @notyetdoced + * + * Applies a multiply-controlled tensor product of Pauli operators @p str upon @p qureg. + * + * > - See applyPauliStr() for information about @p str. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledPauliStr(Qureg qureg, int* controls, int numControls, PauliStr str); @@ -1870,15 +1978,42 @@ void applyControlledRotateY(Qureg qureg, int control, int target, qreal angle); void applyControlledRotateZ(Qureg qureg, int control, int target, qreal angle); -/// @notyetdoced +/** @notyetdoced + * + * Applies a multiply-controlled one-qubit rotation of @p angle around the @c X axis, + * upon the @p target qubit of @p qureg. + * + * > - See applyRotateX() for information about the base operation, and @p angle. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledRotateX(Qureg qureg, int* controls, int numControls, int target, qreal angle); -/// @notyetdoced +/** @notyetdoced + * + * Applies a multiply-controlled one-qubit rotation of @p angle around the @c Y axis, + * upon the @p target qubit of @p qureg. + * + * > - See applyRotateY() for information about the base operation, and @p angle. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledRotateY(Qureg qureg, int* controls, int numControls, int target, qreal angle); -/// @notyetdoced +/** @notyetdoced + * + * Applies a multiply-controlled one-qubit rotation of @p angle around the @c Z axis, + * upon the @p target qubit of @p qureg. + * + * > - See applyRotateZ() for information about the base operation, and @p angle. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledRotateZ(Qureg qureg, int* controls, int numControls, int target, qreal angle); @@ -1999,7 +2134,16 @@ void applyRotateAroundAxis(Qureg qureg, int target, qreal angle, qreal axisX, qr void applyControlledRotateAroundAxis(Qureg qureg, int control, int target, qreal angle, qreal axisX, qreal axisY, qreal axisZ); -/// @notyetdoced +/** @notyetdoced + * + * Applies a multiply-controlled one-qubit rotation of @p angle around an arbitrary axis, + * upon the @p target qubit of @p qureg. + * + * > - See applyRotateAroundAxis() for information about the base operation, @p angle, @p axisX, @p axisY and @p axisZ. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledRotateAroundAxis(Qureg qureg, int* controls, int numControls, int target, qreal angle, qreal axisX, qreal axisY, qreal axisZ); @@ -2195,7 +2339,16 @@ void applyNonUnitaryPauliGadget(Qureg qureg, PauliStr str, qcomp angle); void applyControlledPauliGadget(Qureg qureg, int control, PauliStr str, qreal angle); -/// @notyetdoced +/** @notyetdoced + * + * Applies a multiply-controlled many-qubit rotation upon @p qureg, + * generated by tensor product of Pauli operators @p str. + * + * > - See applyPauliGadget() for information about the base operation, @p angle, and @p str. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledPauliGadget(Qureg qureg, int* controls, int numControls, PauliStr str, qreal angle); @@ -2296,7 +2449,16 @@ void applyPhaseGadget(Qureg qureg, int* targets, int numTargets, qreal angle); void applyControlledPhaseGadget(Qureg qureg, int control, int* targets, int numTargets, qreal angle); -/// @notyetdoced +/** @notyetdoced + * + * Applies a multiply-controlled many-qubit @c Z rotation upon @p qureg, + * generated by a tensor product of Pauli @c Z operators upon @p targets. + * + * > - See applyPhaseGadget() for information about the base operation, @p angle, and @p targets. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledPhaseGadget(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, qreal angle); @@ -2646,7 +2808,16 @@ void applyMultiQubitNot(Qureg qureg, int* targets, int numTargets); void applyControlledMultiQubitNot(Qureg qureg, int control, int* targets, int numTargets); -/// @notyetdoced +/** @notyetdoced + * + * Applies a multiply-controlled many-qubit NOT gate (or tensor product of Pauli @c X operators) + * upon the @p targets of @p qureg. + * + * > - See applyMultiQubitNot() for information about the base operation. + * > - See applyMultiControlledCompMatr1() for information about @p controls. + * + * @author Tyson Jones + */ void applyMultiControlledMultiQubitNot(Qureg qureg, int* controls, int numControls, int* targets, int numTargets); From 5a351e88bebd07be75c5f502fab4495b7412082e Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Tue, 7 Jul 2026 22:33:02 -0400 Subject: [PATCH 16/29] added SuperOp and KrausMap struct doc --- quest/include/channels.h | 190 +++++++++++++++++++++++++++++++++++---- 1 file changed, 173 insertions(+), 17 deletions(-) diff --git a/quest/include/channels.h b/quest/include/channels.h index c0f5433f6..0033f7875 100644 --- a/quest/include/channels.h +++ b/quest/include/channels.h @@ -70,49 +70,205 @@ */ -/// @notyetdoced +/** A superoperator which acts upon both the ket and bra space of a + * linearised density matrix, which can represent more transformations + * than a KrausMap. + * + * An @f$n@f$-qubit superoperator is instantiated as a @f$2^{2n}\times 2^{2n}@f$ + * complex matrix, and can only be applied upon density matrices of @f$n@f$ or + * more density matrices. + * + * Like all QuEST structs, a SuperOp is safe to copy, and ergo to pass to + * functions by-value, or be returned from them. However, its destructor + * must only ever be called upon one such copy. + * + * @see + * - createSuperOp() + * - [createInlineSuperOp()](https://quest-kit.github.io/QuEST/group__channels__create.html#ga0ee76da0f63c68a2bf26c6dda973436d) + * - setSuperOp() + * - syncSuperOp() + * - reportSuperOp() + * - mixSuperOp() + * - destroySuperOp() + */ typedef struct { + /** The number of qubits of the superoperator. + * + * This is _half_ the number of qubit substates of the linearised density + * matrix upon which the superoperator acts, but is consistent with the space + * acted upon by an equivalent a channel or unitary. + * + * The total memory costs of the superoperator scale exponentially with the + * number of qubits; an @f$n@f$-qubit superoperator contains @f$16^n@f$ + * complex elements. + */ int numQubits; + + /** The dimension of the superoperator, which is a square matrix, and so + * equals both the number of rows and columns. + * + * Letting @f$n=@f$ #numQubits, then #numRows @f$=4^n@f$. + */ qindex numRows; - // 2D CPU memory, which users can manually overwrite like cpuElems[i][j], - // but which actually merely aliases the 1D cpuElemsFlat below + /** The 2D matrix elements of the CPU operator, stored in CPU host memory. + * + * It is safest to modify this matrix through setSuperOp(), but direct modification + * is possible; the matrix element of the `r`-th row and `c`-th colum is stored + * at `cpuElems[r][c]`. + * + * > [!IMPORTANT] + * > It is _critical_ to call syncSuperOp() after direct modification of + * > #cpuElems in order to update persistent superoperator properties, + * > such as its data in GPU device memory (even when not running in + * > GPU-accelerated mode). + * + * The field #cpuElems merely aliases the 1D #cpuElemsFlat field, such that + * modifications of #cpuElems also updates #cpuElemsFlat. + */ qcomp** cpuElems; - // row-major flattened elements of cpuElems, always allocated + /** A 1D row-major form of #cpuElems. + * + * Modification of the superoperator matrix should be done through #cpuElems + * for mathematical clarity, though this 1D contiguous form may be convenient + * when performing copying. + * + * > [!IMPORTANT] + * > It is _critical_ to call syncSuperOp() after direct modification of + * > #cpuElemsFlat in order to update persistent superoperator properties, + * > such as its data in GPU device memory (even when not running in + * > GPU-accelerated mode). + */ qcomp* cpuElemsFlat; - // row-major flattened elems in GPU memory, allocated - // only and always in GPU-enabled QuEST environments + /** The elements of the superoperator matrix, stored in GPU device memory, + * in a 1D row-major form. + * + * This is a copy of #cpuElemsFlat consulted by QuEST's GPU backend and should + * _never_ be modified directly. Instead, it is updated by calling syncSuperOp() + * after modifying #cpuElems or #cpuElemsFlat, which is performed automatically by + * API functions like setSuperOp(). In this way, #gpuElemsFlat and #cpuElemsFlat + * should never be out of sync with one another. + * + * Within a GPU-enabled QuEST environment, every SuperOp allocates #gpuElemsFlat + * in GPU memory, even if never ultimately consulted from the GPU backend. + */ qcomp* gpuElemsFlat; - // whether the user has ever synchronised memory to the GPU, which is performed automatically - // when calling functions like setCompMatr(), but which requires manual invocation with - // syncCompMatr() after manual modification of the cpuElem. Note this can only indicate whether - // the matrix has EVER been synced; it cannot be used to detect whether manual modifications - // made after an initial sync have been re-synched. This is a heap pointer to remain mutable. + /** Whether the superoperator matrix elements were ever synchronised. + * + * This is a heap pointer to a persistent flag which is initially @c 0 at SuperOp creation, + * but which is permanently overwritten to @c 1 when synchronisation is performed, such as + * via syncSuperOp() or setSuperOp(). The flag indicates whether the superoperator matrix + * elements have been initialised (and when QuEST is GPU-accelerated, whether they have been + * copied to GPU device memory)), and ergo whether it is valid to pass the SuperOp to a + * simulation function like mixSuperOp(). + * + * Note this flag can only indicate whether the matrix has _ever_ been synced; it cannot be + * used to detect whether manual modification of #cpuElems made after an initial sync have been + * re-synced, as required for correct behaviour in GPU mode. + */ int* wasGpuSynced; } SuperOp; -/// @notyetdoced +/** A Kraus map which can act upon density matrices, and can describe any + * physical operation or channel. + * + * A @f$t@f$-operator @f$n@f$-qubit KrausMap is described by @f$t@f$ complex matrices, + * each of dimension @f$2^n\times 2^n@f$; the equivalent size of an @f$n@f$-qubit unitary. + * A KrausMap can be applied upon density matrices of @f$n@f$ or more qubits. + * + * Due to its internal representation as a SuperOp with matrix dimension + * @f$2^{2n}\times 2^{2n}@f$, the total memory costs of a KrausMap scale exponentially + * with the number of qubits as @f$16^n@f$. + * + * Like all QuEST structs, a KrausMap is safe to copy, and ergo to pass to + * functions by-value, or be returned from them. However, its destructor + * must only ever be called upon one such copy. + * + * @see + * - createKrausMap() + * - [createInlineKrausMap()](https://quest-kit.github.io/QuEST/group__channels__create.html#gae9c49a6443896ef590ff1e4cfaa4912b) + * - setKrausMap() + * - syncKrausMap() + * - reportKrausMap() + * - mixKrausMap() + * - destroyKrausMap() + */ typedef struct { + /** The number of qubits of the Kraus map. + * + * Letting @f$n=@f$ #numQubits, each Kraus operator in the map is a @f$2^n\times 2^n@f$ + * complex matrix, and the full map is described by a @f$2^{2n}\times 2^{2n}@f$ + * superoperator; a total of @f$16^n@f$ complex elements. + */ int numQubits; - // representation of the map as a collection of Kraus operators, kept exclusively - // in CPU memory, and used only for CPTP validation and reporting the map + /** The number of Kraus operators in the map. + * + * For example, a KrausMap form of an amplitude damping channel would contain + * @c numMatrices=2, and a two-qubit depolarising channel would contain + * @c numMatrices=16. + */ int numMatrices; + + /** The dimension of each Kraus operator, which is a square matrix, and so + * equivalent to the number of rows and columns. + * + * Letting @f$n=@f$ #numQubits, then #numRows @f$=2^n@f$. + */ qindex numRows; + + /** A list of each Kraus oeprator's 2D matrix, stored in CPU host memory. + * + * It is safest to modify this matrix through setKrausMap(), but direct modification + * is possible; the matrix element of the `r`-th row and `c`-th colum of the `i`-th + * operator is stored at `matrices[i][r][c]`. + * + * > [!IMPORTANT] + * > It is _critical_ to call syncKrausMap() after direct modification of + * > #matrices in order to update persistent KrausMap properties, + * > such as its SuperOp data in GPU device memory (even when not running in + * > GPU-accelerated mode). + * + * Unlike other data structures (such as CompMatr), KrausMap has no GPU device memory + * copy of #matrices, since only the superoperator (stored within #superop) is + * needed on the device. In fact, #matrices is only used for convenient + * initialisation of a KrausMap, for validation of CPTP, and for printing by + * reportKrausMap(). + */ qcomp*** matrices; - // representation of the map as a single superoperator, used for simulation + /** A superoperator representation of the KrausMap. + * + * This is computed from #matrices during syncKrausMap() (as automatically invoked + * by setKrausMap()), and is used by QuEST's simulation backend to effect the Kraus + * map upon a density matrix. + * + * Since this is the only field of KrausMap needing synchronisation, KrausMap + * itself lacks an explicit @c wasGpuSynced field, and instead uses that attached + * to #superop. + */ SuperOp superop; - // CPTP-ness is determined at validation; 0 or 1, or -1 to indicate unknown. The flag is - // stored in heap so even copies of structs are mutable, but pointer itself is immutable. + /** Whether the Kraus map is known to be (within validation epsilon tolerance) + * completely positive and trace preserving (@c =1), or known to be non-CPTP (@c =0), + * or whether it is unknown (@c =-1). + * + * This is a heap pointer to a persistent flag which is initially @c =-1 at KrausMap + * creation, and is only ever consulted and/or updated by input validation within + * mixKrausMap(), when such validation is enabled. Calling setKrausMap() or syncKrausMap() + * restores #isApproxCPTP to @c =-1. + * + * The property of being CPTP is measured approximately, with reference to the validation + * epsilon as modified with setQuESTValidationEpsilon(). The flag will never be updated from + * @c =-1 when validation is disabled. + */ int* isApproxCPTP; } KrausMap; From 3fcf8d8ad4538400595a3b4ba5d4ff091766ca86 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Tue, 7 Jul 2026 22:35:55 -0400 Subject: [PATCH 17/29] added note about epsilon-dependent struct fields --- quest/include/channels.h | 7 ++++++- quest/include/debug.h | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/quest/include/channels.h b/quest/include/channels.h index 0033f7875..800935f66 100644 --- a/quest/include/channels.h +++ b/quest/include/channels.h @@ -267,7 +267,12 @@ typedef struct { * * The property of being CPTP is measured approximately, with reference to the validation * epsilon as modified with setQuESTValidationEpsilon(). The flag will never be updated from - * @c =-1 when validation is disabled. + * @c =-1 when validation is disabled. Like all epsilon-dependent fields, it is restored + * to @c =-1 automatically whenever setValidationEpsilon() or setValidationEpsilonToDefault() + * are called. + * + * To skip CPTP validation in mixKrausMap(), users can directly mutate this field to + * @c =1, although it is not advised. */ int* isApproxCPTP; diff --git a/quest/include/debug.h b/quest/include/debug.h index 837366221..badc15c1d 100644 --- a/quest/include/debug.h +++ b/quest/include/debug.h @@ -131,6 +131,13 @@ void setQuESTSeeds(unsigned* seeds, int numSeeds); * > In distributed simulation, only the root node's seeds are consulted (and broadcast * > to all nodes) while those passed on all other nodes are ignored. * + * Note that many data structures (e.g. CompMatr, DiagMatr, KrausMap) will assess epsilon-dependent + * validation properties such as unitarity _once_, recording the result in a persistent heap field + * (like KrausMap.isApproxCPTP) to avoid superfluous re-calculation. + * Updating the global validation epsilon via this function will update all persistent heap fields, + * marking epsilon-dependent properties as "unknown", which will be lazily re-evaluated when validation + * is next performed. Ergo, calling this function can cause later additional function overheads. + * * @myexample * ``` // make report() print only one trailing newline @@ -423,6 +430,13 @@ void setQuESTValidationEpsilonToDefault(); * The default validation epsilon, which can itself be controlled by the `QUEST_DEFAULT_VALIDATION_EPSILON` * environment variable, is restored via setQuESTValidationEpsilonToDefault(). * + * Note that many data structures (e.g. CompMatr, DiagMatr, KrausMap) will assess epsilon-dependent + * validation properties such as unitarity _once_, recording the result in a persistent heap field + * (like KrausMap.isApproxCPTP) to avoid superfluous re-calculation. + * Updating the global validation epsilon via this function will update all persistent heap fields, + * marking epsilon-dependent properties as "unknown", which will be lazily re-evaluated when validation + * is next performed. Ergo, calling this function can cause later additional function overheads. + * * @myexample * * ``` From 37c7c96af8f50c4d8e855308e71789728cd65d55 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Tue, 7 Jul 2026 22:39:17 -0400 Subject: [PATCH 18/29] linked SuperOp and KrausMap init examples --- quest/include/channels.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/quest/include/channels.h b/quest/include/channels.h index 800935f66..62949b848 100644 --- a/quest/include/channels.h +++ b/quest/include/channels.h @@ -82,6 +82,12 @@ * functions by-value, or be returned from them. However, its destructor * must only ever be called upon one such copy. * + * @myexample + * + * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_superoperators.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_superoperators.cpp) + * examples of initialising SuperOp. + * * @see * - createSuperOp() * - [createInlineSuperOp()](https://quest-kit.github.io/QuEST/group__channels__create.html#ga0ee76da0f63c68a2bf26c6dda973436d) @@ -190,6 +196,12 @@ typedef struct { * functions by-value, or be returned from them. However, its destructor * must only ever be called upon one such copy. * + * @myexample + * + * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_krausmaps.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_krausmaps.cpp) + * examples of initialising KrausMap. + * * @see * - createKrausMap() * - [createInlineKrausMap()](https://quest-kit.github.io/QuEST/group__channels__create.html#gae9c49a6443896ef590ff1e4cfaa4912b) From 74b57ffcbe0559ba5ea155710d17e9cdaba5a532 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Thu, 9 Jul 2026 21:43:38 -0400 Subject: [PATCH 19/29] added matrix struct doc --- quest/include/channels.h | 18 +- quest/include/matrices.h | 596 +++++++++++++++++++++++++++++++++++---- 2 files changed, 556 insertions(+), 58 deletions(-) diff --git a/quest/include/channels.h b/quest/include/channels.h index 62949b848..25b07de25 100644 --- a/quest/include/channels.h +++ b/quest/include/channels.h @@ -118,7 +118,7 @@ typedef struct { */ qindex numRows; - /** The 2D matrix elements of the CPU operator, stored in CPU host memory. + /** The 2D matrix elements of the operator, stored in CPU host memory. * * It is safest to modify this matrix through setSuperOp(), but direct modification * is possible; the matrix element of the `r`-th row and `c`-th colum is stored @@ -132,6 +132,9 @@ typedef struct { * * The field #cpuElems merely aliases the 1D #cpuElemsFlat field, such that * modifications of #cpuElems also updates #cpuElemsFlat. + * + * @see + * - syncSuperOp() */ qcomp** cpuElems; @@ -146,6 +149,9 @@ typedef struct { * > #cpuElemsFlat in order to update persistent superoperator properties, * > such as its data in GPU device memory (even when not running in * > GPU-accelerated mode). + * + * @see + * - syncSuperOp() */ qcomp* cpuElemsFlat; @@ -169,12 +175,15 @@ typedef struct { * but which is permanently overwritten to @c 1 when synchronisation is performed, such as * via syncSuperOp() or setSuperOp(). The flag indicates whether the superoperator matrix * elements have been initialised (and when QuEST is GPU-accelerated, whether they have been - * copied to GPU device memory)), and ergo whether it is valid to pass the SuperOp to a + * copied to GPU device memory), and ergo whether it is valid to pass the SuperOp to a * simulation function like mixSuperOp(). * * Note this flag can only indicate whether the matrix has _ever_ been synced; it cannot be * used to detect whether manual modification of #cpuElems made after an initial sync have been - * re-synced, as required for correct behaviour in GPU mode. + * re-synced, as required for correct behaviour in GPU mode. + * + * @see + * - syncSuperOp() */ int* wasGpuSynced; @@ -285,6 +294,9 @@ typedef struct { * * To skip CPTP validation in mixKrausMap(), users can directly mutate this field to * @c =1, although it is not advised. + * + * @see + * - setQuESTValidationEpsilon() */ int* isApproxCPTP; diff --git a/quest/include/matrices.h b/quest/include/matrices.h index 7fa38ab4f..cfc0b1460 100644 --- a/quest/include/matrices.h +++ b/quest/include/matrices.h @@ -64,62 +64,232 @@ */ -/// @notyetdoced +/** A one-qubit, @f$2\times 2@f$, dense complex matrix. + * + * > [!TIP] + * > This matrix is stored in stack memory, and so never needs explicit destruction, + * > and like all QuEST types, is safe to pass and return to/from functions by-value. + * + * @myexample + * + * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.cpp) + * examples of initialising CompMatr1. + * + * @see + * - getCompMatr1() + * - getInlineCompMatr1() + * - reportCompMatr1() + * - applyCompMatr1() + */ typedef struct { + /** The number of qubits upon which the matrix can act, which is always @c =1 @f$. + */ int numQubits; + + /** The matrix dimension, which is always @c =2 @f$. + */ qindex numRows; + /** The 2D matrix elements. These are safe to update at any time. + */ qcomp elems[2][2]; } CompMatr1; -/// @notyetdoced +/** A two-qubit, @f$4\times 4@f$, dense complex matrix. + * + * > [!TIP] + * > This matrix is stored in stack memory, and so never needs explicit destruction, + * > and like all QuEST types, is safe to pass and return to/from functions by-value. + * + * @myexample + * + * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.cpp) + * examples of initialising CompMatr2. + * + * @see + * - getCompMatr2() + * - getInlineCompMatr2() + * - reportCompMatr2() + * - applyCompMatr2() + */ typedef struct { + /** The number of qubits upon which the matrix can act, which is always @c =2 @f$. + */ int numQubits; + + /** The matrix dimension, which is always @c =4 @f$. + */ qindex numRows; + /** The 2D matrix elements. These are safe to update at any time. + */ qcomp elems[4][4]; } CompMatr2; -/// @notyetdoced +/** A variable-size, @f$n@f$-qubit, @f$2^n \times 2^n@f$, dense complex matrix. + * + * Unlike CompMatr1 and CompMatr2, the elements of this matrix are stored in + * heap memory. But like all QuEST structs, it is safe to copy, and ergo to pass + * to functions by-value, or be returned from them. However, its destructor + * must only ever be called upon one such copy. + * + * @myexample + * + * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.cpp) + * examples of initialising CompMatr. + * + * @see + * - createCompMatr() + * - [createInlineCompMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__create.html#gad0ac51cb08a5d0b4e0878a5fde7ca893) + * - [setInlineCompMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__setters.html#ga00993b6b571985fd04697e487a561517) + * - setCompMatr() + * - syncCompMatr() + * - reportCompMatr() + * - applyCompMatr() + * - destroyCompMatr() + */ typedef struct { // beware that CompMatr instances are sometimes 'spoofed' inside localiser.cpp, // which will set the fields from other object instances (like a SuperOp). As - // such, additional fields to this struct may require updating these spoofers. + // such, adding new fields to this struct may require updating these spoofers. + /** The number of qubits upon which the matrix can act. + * + * The total memory costs of the matrix scale exponentially with the + * number of qubits; an @f$n@f$-qubit matrix contains @f$4^n@f$ + * complex elements. + */ int numQubits; + + /** The dimension of the matrix, which is a square matrix, and so + * equals both the number of rows and columns. + * + * Letting @f$n=@f$ #numQubits, then #numRows @f$=2^n@f$. + */ qindex numRows; - // properties of the matrix (0, 1, or -1 to indicate unknown) which are lazily evaluated, - // deferred until a function actually validates them, at which point they are computed - // and the flags fixed until the user modifies the matrix (through sync() or setAmps() etc). - // flag is stored in heap so even copies of structs are mutable, but pointer is immutable. - // otherwise, the field of a user's struct could never be modified because of pass-by-copy. + /** Whether the matrix is (within validation epsilon tolerance) unitary (@c =1), or known to be + * non-unitary (@c =0), or whether it is unknown (@c =-1). + * + * This is a heap pointer to a persistent flag which is initially @c =-1 at matrix creation, and + * is only ever consulted and/or updated by input valdiation within functions like applyCompMatr(), + * when such validation is enabled. Calling setCompMatr() or syncCompMatr() restores #isApproxUnitary + * to @c -1. + * + * Unitarity is measured approximately, with reference to the validation + * epsilon as modified with setQuESTValidationEpsilon(). This flag will never be updated from + * @c =-1 when validation is disabled. Like all epsilon-dependent fields, it is restored + * to @c =-1 automatically whenever setQuESTValidationEpsilon() or setQuESTValidationEpsilonToDefault() + * are called. + * + * @see + * - setQuESTValidationEpsilon() + */ int* isApproxUnitary; - int* isApproxHermitian; /// @todo currently unused (relevant to not-yet-implemented calc-expec-val) - // whether the user has ever synchronised memory to the GPU, which is performed automatically - // when calling functions like setCompMatr(), but which requires manual invocation with - // syncCompMatr() after manual modification of the cpuElem. Note this can only indicate whether - // the matrix has EVER been synced; it cannot be used to detect whether manual modifications - // made after an initial sync have been re-synched. This is a heap pointer, as above. + /** Whether the matrix is (within validation epsilon tolerance) Hermitian (@c =1), or known to + * be non-Hermitian (@c =0), or whether it is unknown (@c =-1). + * + * This is a heap pointer to a persistent flag which is initially @c =-1 at matrix creation, and + * is only ever consulted and/or updated by input valdiation within functions which expect + * Hermiticity. Calling setCompMatr() or syncCompMatr() restores + * #isApproxHermitian to @c -1. + * + * > [!NOTE] + * > There are presently _no_ QuEST functions which expect Hermiticity of a CompMatr, + * > and so this field is presently never modified from its initial valeu of @c =-1. + * + * Hermiticity is measured approximately, with reference to the validation + * epsilon as modified with setQuESTValidationEpsilon(). This flag will never be updated from + * @c =-1 when validation is disabled. Like all epsilon-dependent fields, it is restored + * to @c =-1 automatically whenever setQuESTValidationEpsilon() or setQuESTValidationEpsilonToDefault() + * are called. + * + * @see + * - setQuESTValidationEpsilon() + */ + int* isApproxHermitian; // @todo currently unused (relevant to not-yet-implemented calc-expec-val) + + /** Whether the matrix elements were ever synchronised. + * + * This is a heap pointer to a persistent flag which is initially @c 0 at matrix creation, + * but which is permanently overwritten to @c 1 when synchronisation is performed, such as + * via syncCompMatr() or setCompmatr(). The flag indicates whether the matrix + * elements have been initialised (and when QuEST is GPU-accelerated, whether they have been + * copied to GPU device memory), and ergo whether it is valid to pass the matrix to a + * simulation function like applyCompMatr(). + * + * Note this flag can only indicate whether the matrix has _ever_ been synced; it cannot be + * used to detect whether manual modification of #cpuElems made after an initial sync have been + * re-synced, as required for correct behaviour in GPU mode. + * + * @see + * - syncCompMatr() + */ int* wasGpuSynced; - // 2D CPU memory, which users can manually overwrite like cpuElems[i][j], - // but which actually merely aliases the 1D cpuElemsFlat below + /** The 2D matrix elements, stored in CPU host memory. + * + * It is safest to modify this matrix through setCompMatr(), but direct modification + * is possible; the matrix element of the `r`-th row and `c`-th colum is stored + * at `cpuElems[r][c]`. + * + * > [!IMPORTANT] + * > It is _critical_ to call syncCompMatr() after direct modification of + * > #cpuElems in order to update persistent matrix properties, + * > such as its data in GPU device memory (even when not running in + * > GPU-accelerated mode). + * + * The field #cpuElems merely aliases the 1D #cpuElemsFlat field, such that + * modifications of #cpuElems also updates #cpuElemsFlat. + * + * @see + * - setCompMatr() + * - [setInlineCompMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__setters.html#ga00993b6b571985fd04697e487a561517) + * - syncCompMatr() + */ qcomp** cpuElems; - // row-major flattened elements of cpuElems, always allocated + /** A 1D row-major form of #cpuElems. + * + * Modification of the matrix elements should be done through #cpuElems + * for mathematical clarity, though this 1D contiguous form may be convenient + * when performing copying. + * + * > [!IMPORTANT] + * > It is _critical_ to call syncCompMatr() after direct modification of + * > #cpuElemsFlat in order to update persistent matrix properties, + * > such as its data in GPU device memory (even when not running in + * > GPU-accelerated mode). + * + * @see + * - setCompMatr() + * - [setInlineCompMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__setters.html#ga00993b6b571985fd04697e487a561517) + * - syncCompMatr() + */ qcomp* cpuElemsFlat; - // row-major flattened elems in GPU memory, allocated - // only and always in GPU-enabled QuEST environments + /** The matrix elements, stored in GPU device memory, in a 1D row-major form. + * + * This is a copy of #cpuElemsFlat consulted by QuEST's GPU backend and should + * _never_ be modified directly. Instead, it is updated by calling syncCompMatr() + * after modifying #cpuElems or #cpuElemsFlat, which is performed automatically by + * API functions like setCompMatr(). In this way, #gpuElemsFlat and #cpuElemsFlat + * should never be out of sync with one another. + * + * Within a GPU-enabled QuEST environment, every CompMatr allocates #gpuElemsFlat + * in GPU memory, even if never ultimately consulted from the GPU backend. + */ qcomp* gpuElemsFlat; } CompMatr; @@ -132,55 +302,220 @@ typedef struct { */ -/// @notyetdoced +/** A one-qubit, @f$2\times 2@f$, diagonal complex matrix, stored as a length-2 array. + * + * > [!TIP] + * > This matrix is stored in stack memory, and so never needs explicit destruction, + * > and like all QuEST types, is safe to pass and return to/from functions by-value. + * + * @myexample + * + * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.cpp) + * examples of initialising DiagMatr1. + * + * @see + * - getDiagMatr1() + * - getInlineDiagMatr1() + * - reportDiagMatr1() + * - applyDiagMatr1() + */ typedef struct { + /** The number of qubits upon which the matrix can act, which is always @c =1 @f$. + */ int numQubits; + + /** The matrix dimension, equal to the number of contained diagonal elements, which is always @c =2 @f$. + */ qindex numElems; + /** The diagonal elements of the matrix, stored as a flat array, in CPU stack memory. + * These are safe to directly modify at any time, to update the matrix. + */ qcomp elems[2]; } DiagMatr1; -/// @notyetdoced +/** A two-qubit, @f$4\times 4@f$, diagonal complex matrix, stored as a length-4 array. + * + * > [!TIP] + * > This matrix is stored in stack memory, and so never needs explicit destruction, + * > and like all QuEST types, is safe to pass and return to/from functions by-value. + * + * @myexample + * + * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.cpp) + * examples of initialising DiagMatr2. + * + * @see + * - getDiagMatr2() + * - getInlineDiagMatr2() + * - reportDiagMatr2() + * - applyDiagMatr2() + */ typedef struct { + /** The number of qubits upon which the matrix can act, which is always @c =2 @f$. + */ int numQubits; + + /** The matrix dimension, equal to the number of contained diagonal elements, which is always @c =4 @f$. + */ qindex numElems; + /** The diagonal elements of the matrix, stored as a flat array, in CPU stack memory. + * These are safe to directly modify at any time, to update the matrix. + */ qcomp elems[4]; } DiagMatr2; -/// @notyetdoced +/** A variable-size, @f$n@f$-qubit, @f$2^n \times 2^n@f$, diagonal complex matrix, + * stored as a length-@f$2^n@f$ array. + * + * This is intended for _local_ diagonal matrices, smaller than the Qureg upon + * which they operate. For a full-state diagonal matrix, see FullStateDiagMatr. + * + * Unlike DiagMatr1 and DiagMatr2, the diagonal elements of this matrix are stored in + * heap memory. But like all QuEST structs, it is safe to copy, and ergo to pass + * to functions by-value, or be returned from them. However, its destructor + * must only ever be called upon one such copy. + * + * @myexample + * + * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.cpp) + * examples of initialising DiagMatr. + * + * @see + * - createDiagMatr() + * - [createInlineDiagMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__create.html#gad0ac51cb08a5d0b4e0878a5fde7ca893) + * - [setInlineDiagMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__setters.html#ga00993b6b571985fd04697e487a561517) + * - setDiagMatr() + * - syncDiagMatr() + * - reportDiagMatr() + * - applyDiagMatr() + * - destroyDiagMatr() + */ typedef struct { + /** The number of qubits upon which the matrix can act. + * + * The total memory costs of the matrix scale exponentially with the + * number of qubits; an @f$n@f$-qubit diagonal matrix contains @f$2^n@f$ + * complex elements. + */ int numQubits; + + /** The dimension of the matrix, which is a square matrix, and so + * equals both the number of rows and columns, and the number of diagonal terms. + * + * Letting @f$n=@f$ #numQubits, then #numRows @f$=2^n@f$. + */ qindex numElems; - // properties of the matrix (0, 1, or -1 to indicate unknown) which are lazily evaluated, - // deferred until a function actually validates them, at which point they are computed - // and the flags fixed until the user modifies the matrix (through sync() or setAmps() etc). - // flag is stored in heap so even copies of structs are mutable, but pointer is immutable. - // otherwise, the field of a user's struct could never be modified because of pass-by-copy. + /** Whether the matrix is (within validation epsilon tolerance) unitary (@c =1), or known to be + * non-unitary (@c =0), or whether it is unknown (@c =-1). + * + * This is a heap pointer to a persistent flag which is initially @c =-1 at matrix creation, and + * is only ever consulted and/or updated by input valdiation within functions like applyDiagMatr(), + * when such validation is enabled. Calling setDiagMatr() or syncDiagMatr() restores #isApproxUnitary + * to @c -1. + * + * Unitarity is measured approximately, with reference to the validation + * epsilon as modified with setQuESTValidationEpsilon(). This flag will never be updated from + * @c =-1 when validation is disabled. Like all epsilon-dependent fields, it is restored + * to @c =-1 automatically whenever setQuESTValidationEpsilon() or setQuESTValidationEpsilonToDefault() + * are called. + * + * @see + * - setQuESTValidationEpsilon() + */ int* isApproxUnitary; - int* isApproxHermitian; /// @todo currently unused (relevant to not-yet-implemented calc-expec-val) - int* isApproxNonZero; /// @todo currently unused (relevant to not-yet-implemented calc-expec-val) - int* isStrictlyNonNegative; /// @todo currently unused (relevant to not-yet-implemented calc-expec-val) + + /** Whether the matrix is (within validation epsilon tolerance) Hermitian (@c =1), or known to be + * non-Hermitian (@c =0), or whether it is unknown (@c =-1). + * + * > [!NOTE] + * > There are presently _no_ QuEST functions which expect Hermiticity of a DiagMatr, + * > and so this field is presently never modified from its initial valeu of @c =-1. + * + * This field has all the same nuances and mechanisms as #isApproxUnitary. + */ + int* isApproxHermitian; // @todo currently unused (relevant to not-yet-implemented calc-expec-val) + + /** Whether all diagonal elements of the matrix are "approximately" non-zero (have a magnitude + * exceeding the validation epsilon) in which case this field @c =1, or whether the matrix is + * known to contain an approximate zero (@c =0), or whether the property is unknown (@c =-1). + * + * This property is relevant when attempting to raise the DiagMatr to a negative power, + * such as through applyDiagMatrPower(). + * + * This field has all the same nuances and mechanisms as #isApproxUnitary. + */ + int* isApproxNonZero; + + /** Whether all diagonal elements of the matrix are strictly zero or positive (@c =1), or + * whether one or more elements are known to be negative (@c =0), or whether the property is + * unknown (@c =-1). + * + * This property is relevant when attempting to raise the DiagMatr to non-integer power, + * such as through applyDiagMatrPower(). + * + * This field has similar nuances and mechanics as #isApproxUnitary, but is _not_ dependent + * upon the validation epsilon (as controlled with setQuESTValidationEpsilon()). + */ + int* isStrictlyNonNegative; - // whether the user has ever synchronised memory to the GPU, which is performed automatically - // when calling functions like setCompMatr(), but which requires manual invocation with - // syncCompMatr() after manual modification of the cpuElem. Note this can only indicate whether - // the matrix has EVER been synced; it cannot be used to detect whether manual modifications - // made after an initial sync have been re-synched. This is a heap pointer, as above. + /** Whether the matrix elements were ever synchronised. + * + * This is a heap pointer to a persistent flag which is initially @c 0 at matrix creation, + * but which is permanently overwritten to @c 1 when synchronisation is performed, such as + * via syncDiagMatr() or setDiagMatr(). The flag indicates whether the matrix + * elements have been initialised (and when QuEST is GPU-accelerated, whether they have been + * copied to GPU device memory), and ergo whether it is valid to pass the matrix to a + * simulation function like applyDiagMatr(). + * + * Note this flag can only indicate whether the matrix has _ever_ been synced; it cannot be + * used to detect whether manual modification of #cpuElems made after an initial sync have been + * re-synced, as required for correct behaviour in GPU mode. + * + * @see + * - syncDiagMatr() + */ int* wasGpuSynced; - // CPU memory; not const, so users can overwrite addresses (e.g. with nullptr) + /** The matrix diagonal elements, stored in CPU host memory. + * + * It is safest to modify this matrix through setDiagMatr(), but direct modification + * is possible. + * + * > [!IMPORTANT] + * > It is _critical_ to call syncDiagMatr() after direct modification of + * > #cpuElems in order to update persistent matrix properties, + * > such as its data in GPU device memory (even when not running in + * > GPU-accelerated mode). + * + * @see + * - syncDiagMatr() + */ qcomp* cpuElems; - // GPU memory, allocated only and always in GPU-enabled QuEST environments + /** The matrix diagonal elements, stored in GPU device memory. + * + * This is a copy of #cpuElems consulted by QuEST's GPU backend and should + * _never_ be modified directly. Instead, it is updated by calling syncDiagMatr() + * after modifying #cpuElems, which is performed automatically by + * API functions like setDiagMatr(). In this way, #gpuElems and #cpuElems + * should never be out of sync with one another. + * + * Within a GPU-enabled QuEST environment, every DiagMatr allocates #gpuElems + * in GPU memory, even if never ultimately consulted from the GPU backend. + */ qcomp* gpuElems; } DiagMatr; @@ -191,40 +526,191 @@ typedef struct { */ -/// @notyetdoced +/** A variable-size but full-state diagonal complex matrix, which can only act upon a + * Qureg of the same dimension. + * + * Unlike DiagMatr, a FullStateDiagMatr is intendedly non-local and can be distributed, + * just like a Qureg of the same dimension. + * + * @myexample + * + * See [C](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/main/examples/isolated/initialising_matrices.cpp) + * examples of initialising FullStateDiagMatr. + * + * @see + * - createFullStateDiagMatr() + * - [setInlineFullStateDiagMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__setters.html#gaa27aaa1a001a41f36a60847a19d824d4) + * - setFullStateDiagMatr() + * - setFullStateDiagMatrFromMultiVarFunc() + * - setFullStateDiagMatrFromMultiDimLists() + * - setFullStateDiagMatrFromPauliStrSum() + * - syncFullStateDiagMatr() + * - reportFullStateDiagMatr() + * - applyFullStateDiagMatr() + * - calcExpecFullStateDiagMatr() + * - destroyFullStateDiagMatr() + */ typedef struct { + /** The number of qubits in the Qureg upon which the matrix can act. + * + * The total memory costs of the matrix scale exponentially with the + * number of qubits; an @f$n@f$-qubit full-state diagonal matrix contains @f$2^n@f$ + * complex elements, which may be distributed across MPI nodes. + */ int numQubits; + + /** The total dimension of the matrix, which is a square matrix, and so + * equals both the number of rows and columns, and the number of diagonal terms. + * + * Letting @f$n=@f$ #numQubits, then #numRows @f$=2^n@f$. This is the total number + * of elements across all nodes, and so is independent of whether the matrix is + * distributed. + */ qindex numElems; - // unlike other heap-matrices, GPU memory is not always allocated when the QuEST - // env is GPU-accelerated; instead, it can be disabled by auto-deployer, or the user + /** Whether the matrix has allocated GPU memory, and so can be used by QuEST's + * GPU-accelerated backend. + * + * Unlike CompMatr and DiagMatr, a FullStateDiagMatr can opt _not_ to allocate GPU memory when + * QuEST is running in GPU-accelerated mode. + */ int isGpuAccelerated; + + /** Whether multithreading will be employed when initialising or simulating the matrix. + * + * When a QuEST function receives both a Qureg and a FullStateDiagMatr, multithreading + * is performed when _either_ or _both_ structs have multithreading enabled. + */ int isMultithreaded; + + /** Whether the matrix elements are distributed, informing the size of #cpuElems on + * every node. + * + * When distributed, each node contains only a subset of the full matrix's diagonal + * elements, in an identical fashion to how statevector Qureg are distributed. + * Unlike a Qureg however, a FullStateDiagMatr has no attached communication buffer, + * so have _half_ the total memory costs of a same-size distributed statevector Qureg. + * + * When not distributed, every node contains a duplicate copy of all elements in the matrix. + */ int isDistributed; + + /** The number of diagonal matrix elements stored on each distributed node, and the + * length of #cpuElems and #gpuElems. + * + * This differs from #numElems only when the matrix is distributed, in which case it + * equals #numElems divided by the number of nodes. + */ qindex numElemsPerNode; - // properties of the matrix (0, 1, or -1 to indicate unknown) which are lazily evaluated, - // deferred until a function actually validates them, at which point they are computed - // and the flags fixed until the user modifies the matrix (through sync() or setAmps() etc). - // flag is stored in heap so even copies of structs are mutable, but pointer is immutable. - // otherwise, the field of a user's struct could never be modified because of pass-by-copy. + /** Whether the matrix is (within validation epsilon tolerance) unitary (@c =1), or known to be + * non-unitary (@c =0), or whether it is unknown (@c =-1). + * + * This is a heap pointer to a persistent flag which is initially @c =-1 at matrix creation, and + * is only ever consulted and/or updated by input valdiation within functions like + * applyFullStateDiagMatr(), when such validation is enabled. Calling functions like + * setFullStateDiagMatr() or syncFullStateDiagMatr() restores #isApproxUnitary to @c -1. + * + * Unitarity is measured approximately, with reference to the validation + * epsilon as modified with setQuESTValidationEpsilon(). This flag will never be updated from + * @c =-1 when validation is disabled. Like all epsilon-dependent fields, it is restored + * to @c =-1 automatically whenever setQuESTValidationEpsilon() or setQuESTValidationEpsilonToDefault() + * are called. + * + * When distributed, this property reflects the _global_ state of the entire matrix across + * all nodes, and so should always be identical across nodes. + * + * @see + * - setQuESTValidationEpsilon() + */ int* isApproxUnitary; + + /** Whether the matrix is (within validation epsilon tolerance) Hermitian (@c =1), or known to be + * non-Hermitian (@c =0), or whether it is unknown (@c =-1). + * + * This field is relevant to functions like calcExpecFullStateDiagMatr(), and + * otherwise has all the same nuances and mechanisms as #isApproxUnitary. + */ int* isApproxHermitian; + + /** Whether all diagonal elements of the matrix are "approximately" non-zero (have a magnitude + * exceeding the validation epsilon) in which case this field @c =1, or whether the matrix is + * known to contain an approximate zero (@c =0), or whether the property is unknown (@c =-1). + * + * This property is relevant when attempting to raise the matrix to a negative power, + * such as through applyFullStateDiagMatrPower(). + * + * This field has all the same nuances and mechanisms as #isApproxUnitary. + */ int* isApproxNonZero; + + /** Whether all diagonal elements of the matrix are strictly zero or positive (@c =1), or + * whether one or more elements are known to be negative (@c =0), or whether the property is + * unknown (@c =-1). + * + * This property is relevant when attempting to raise the matrix to non-integer power, + * such as through applyFullStateDiagMatrPower(). + * + * This field has similar nuances and mechanics as #isApproxUnitary, but is _not_ dependent + * upon the validation epsilon (as controlled with setQuESTValidationEpsilon()). + */ int* isStrictlyNonNegative; - // whether the user has ever synchronised memory to the GPU, which is performed automatically - // when calling functions like setCompMatr(), but which requires manual invocation with - // syncCompMatr() after manual modification of the cpuElem. Note this can only indicate whether - // the matrix has EVER been synced; it cannot be used to detect whether manual modifications - // made after an initial sync have been re-synched. This is a heap pointer, as above. + /** Whether the matrix elements were ever synchronised. + * + * This is a heap pointer to a persistent flag which is initially @c 0 at matrix creation, + * but which is permanently overwritten to @c 1 when synchronisation is performed, such as + * via syncFullStateDiagMatr() or setFullStateDiagMatr(). The flag indicates whether the matrix + * elements have been initialised (and when QuEST is GPU-accelerated, whether they have been + * copied to GPU device memory), and ergo whether it is valid to pass the matrix to a + * simulation function like applyFullStateDiagMatr(). + * + * Note this flag can only indicate whether the matrix has _ever_ been synced; it cannot be + * used to detect whether manual modification of #cpuElems made after an initial sync have been + * re-synced, as required for correct behaviour in GPU mode. + * + * @see + * - syncFullStateDiagMatr() + */ int* wasGpuSynced; - // CPU memory; not const, so users can overwrite addresses (e.g. with nullptr) + /** This node's matrix diagonal elements, stored in CPU host memory. + * + * This is an array of length #numElemsPerNode, containing the diagonal elements of + * the matrix. It is safest to modify these elements through functions like + * setFullStateDiagMatr(). Direct modification is possible, but in distributed + * simulation, must be done with care. The @f$i@f$-th local element on the node + * with rank @f$r@f$ corresponds to the full matrix element @f$(m r + i, m r + i)@f$, + * where @f$m=@f$ #numElemsPerNode. + * + * > [!IMPORTANT] + * > It is _critical_ to call syncFullStateDiagMatr() after direct modification of + * > #cpuElems on any node, in order to update persistent matrix properties, + * > such as its data in GPU device memory (even when not running in + * > GPU-accelerated mode). + * + * @see + * - setFullStateDiagMatr() + * - setFullStateDiagMatrFromMultiVarFunc() + * - setFullStateDiagMatrFromMultiDimLists() + * - setFullStateDiagMatrFromPauliStrSum() + * - syncFullStateDiagMatr() + */ qcomp* cpuElems; - // GPU memory, allocated only and always in GPU-enabled QuEST environments + /** The matrix diagonal elements, stored in GPU device memory. + * + * This is a copy of #cpuElems consulted by QuEST's GPU backend and should + * _never_ be modified directly. Instead, it is updated by calling + * syncFullStateDiagMatr() + * after modifying #cpuElems, which is performed automatically by + * API functions like setFullStateDiagMatr(). In this way, #gpuElems and #cpuElems + * should never be out of sync with one another. + * + * The #gpuElems memory is only allocated when #isGpuAccelerated @c =1. + */ qcomp* gpuElems; } FullStateDiagMatr; @@ -852,7 +1338,7 @@ extern "C" { * @notyettested * * @see - * - setInlineFullStateDiagMatr() + * - [setInlineFullStateDiagMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__setters.html#gaa27aaa1a001a41f36a60847a19d824d4) * - reportFullStateDiagMatr() * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples @@ -916,7 +1402,7 @@ extern "C" { * @cpponly * * @see - * - setInlineFullStateDiagMatr() + * - [setInlineFullStateDiagMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__setters.html#gaa27aaa1a001a41f36a60847a19d824d4) * - reportFullStateDiagMatr() * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples */ From 6dba3eddadf882beddcdaf49cd81ca9fcc0267e1 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Thu, 9 Jul 2026 22:04:53 -0400 Subject: [PATCH 20/29] fix matrices.h typos --- quest/include/matrices.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/quest/include/matrices.h b/quest/include/matrices.h index cfc0b1460..42ae6b1d4 100644 --- a/quest/include/matrices.h +++ b/quest/include/matrices.h @@ -84,11 +84,11 @@ */ typedef struct { - /** The number of qubits upon which the matrix can act, which is always @c =1 @f$. + /** The number of qubits upon which the matrix can act, which is always @c =1. */ int numQubits; - /** The matrix dimension, which is always @c =2 @f$. + /** The matrix dimension, which is always @c =2. */ qindex numRows; @@ -119,11 +119,11 @@ typedef struct { */ typedef struct { - /** The number of qubits upon which the matrix can act, which is always @c =2 @f$. + /** The number of qubits upon which the matrix can act, which is always @c =2. */ int numQubits; - /** The matrix dimension, which is always @c =4 @f$. + /** The matrix dimension, which is always @c =4. */ qindex numRows; @@ -182,7 +182,7 @@ typedef struct { * non-unitary (@c =0), or whether it is unknown (@c =-1). * * This is a heap pointer to a persistent flag which is initially @c =-1 at matrix creation, and - * is only ever consulted and/or updated by input valdiation within functions like applyCompMatr(), + * is only ever consulted and/or updated by input validation within functions like applyCompMatr(), * when such validation is enabled. Calling setCompMatr() or syncCompMatr() restores #isApproxUnitary * to @c -1. * @@ -201,13 +201,13 @@ typedef struct { * be non-Hermitian (@c =0), or whether it is unknown (@c =-1). * * This is a heap pointer to a persistent flag which is initially @c =-1 at matrix creation, and - * is only ever consulted and/or updated by input valdiation within functions which expect + * is only ever consulted and/or updated by input validation within functions which expect * Hermiticity. Calling setCompMatr() or syncCompMatr() restores * #isApproxHermitian to @c -1. * * > [!NOTE] * > There are presently _no_ QuEST functions which expect Hermiticity of a CompMatr, - * > and so this field is presently never modified from its initial valeu of @c =-1. + * > and so this field is presently never modified from its initial value of @c =-1. * * Hermiticity is measured approximately, with reference to the validation * epsilon as modified with setQuESTValidationEpsilon(). This flag will never be updated from @@ -224,7 +224,7 @@ typedef struct { * * This is a heap pointer to a persistent flag which is initially @c 0 at matrix creation, * but which is permanently overwritten to @c 1 when synchronisation is performed, such as - * via syncCompMatr() or setCompmatr(). The flag indicates whether the matrix + * via syncCompMatr() or setCompMatr(). The flag indicates whether the matrix * elements have been initialised (and when QuEST is GPU-accelerated, whether they have been * copied to GPU device memory), and ergo whether it is valid to pass the matrix to a * simulation function like applyCompMatr(). @@ -241,7 +241,7 @@ typedef struct { /** The 2D matrix elements, stored in CPU host memory. * * It is safest to modify this matrix through setCompMatr(), but direct modification - * is possible; the matrix element of the `r`-th row and `c`-th colum is stored + * is possible; the matrix element of the `r`-th row and `c`-th column is stored * at `cpuElems[r][c]`. * * > [!IMPORTANT] @@ -322,11 +322,11 @@ typedef struct { */ typedef struct { - /** The number of qubits upon which the matrix can act, which is always @c =1 @f$. + /** The number of qubits upon which the matrix can act, which is always @c =1. */ int numQubits; - /** The matrix dimension, equal to the number of contained diagonal elements, which is always @c =2 @f$. + /** The matrix dimension, equal to the number of contained diagonal elements, which is always @c =2. */ qindex numElems; @@ -358,11 +358,11 @@ typedef struct { */ typedef struct { - /** The number of qubits upon which the matrix can act, which is always @c =2 @f$. + /** The number of qubits upon which the matrix can act, which is always @c =2. */ int numQubits; - /** The matrix dimension, equal to the number of contained diagonal elements, which is always @c =4 @f$. + /** The matrix dimension, equal to the number of contained diagonal elements, which is always @c =4. */ qindex numElems; @@ -422,7 +422,7 @@ typedef struct { * non-unitary (@c =0), or whether it is unknown (@c =-1). * * This is a heap pointer to a persistent flag which is initially @c =-1 at matrix creation, and - * is only ever consulted and/or updated by input valdiation within functions like applyDiagMatr(), + * is only ever consulted and/or updated by input validation within functions like applyDiagMatr(), * when such validation is enabled. Calling setDiagMatr() or syncDiagMatr() restores #isApproxUnitary * to @c -1. * @@ -442,7 +442,7 @@ typedef struct { * * > [!NOTE] * > There are presently _no_ QuEST functions which expect Hermiticity of a DiagMatr, - * > and so this field is presently never modified from its initial valeu of @c =-1. + * > and so this field is presently never modified from its initial value of @c =-1. * * This field has all the same nuances and mechanisms as #isApproxUnitary. */ @@ -607,10 +607,10 @@ typedef struct { /** Whether the matrix is (within validation epsilon tolerance) unitary (@c =1), or known to be * non-unitary (@c =0), or whether it is unknown (@c =-1). - * + * * This is a heap pointer to a persistent flag which is initially @c =-1 at matrix creation, and - * is only ever consulted and/or updated by input valdiation within functions like - * applyFullStateDiagMatr(), when such validation is enabled. Calling functions like + * is only ever consulted and/or updated by input validation within functions like + * applyFullStateDiagMatr(), when such validation is enabled. Calling functions like * setFullStateDiagMatr() or syncFullStateDiagMatr() restores #isApproxUnitary to @c -1. * * Unitarity is measured approximately, with reference to the validation From 75cde24e512a5de20a9b47aa9f209b44eb214820 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Thu, 9 Jul 2026 22:44:28 -0400 Subject: [PATCH 21/29] added doc for apply(Multi)(State)ControlledCompMatr1 since they are the "main, core" doc'd operations to which all other operators are currently hyperlinked --- quest/include/matrices.h | 4 +-- quest/include/operations.h | 74 ++++++++++++++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/quest/include/matrices.h b/quest/include/matrices.h index 42ae6b1d4..7cbc5f173 100644 --- a/quest/include/matrices.h +++ b/quest/include/matrices.h @@ -414,7 +414,7 @@ typedef struct { /** The dimension of the matrix, which is a square matrix, and so * equals both the number of rows and columns, and the number of diagonal terms. * - * Letting @f$n=@f$ #numQubits, then #numRows @f$=2^n@f$. + * Letting @f$n=@f$ #numQubits, then #numElems @f$=2^n@f$. */ qindex numElems; @@ -564,7 +564,7 @@ typedef struct { /** The total dimension of the matrix, which is a square matrix, and so * equals both the number of rows and columns, and the number of diagonal terms. * - * Letting @f$n=@f$ #numQubits, then #numRows @f$=2^n@f$. This is the total number + * Letting @f$n=@f$ #numQubits, then #numElems @f$=2^n@f$. This is the total number * of elements across all nodes, and so is independent of whether the matrix is * distributed. */ diff --git a/quest/include/operations.h b/quest/include/operations.h index 71372fe88..99a84a136 100644 --- a/quest/include/operations.h +++ b/quest/include/operations.h @@ -187,6 +187,8 @@ digraph { \dmrho \rightarrow C_c[\hat{U}_t] \, \dmrho \, {C_c[\hat{U}_t]}^\dagger. * @f] * + * The amplitudes which _are_ modified, are done so in an identical fashion as in applyCompMatr1(). + * * @constraints * * - Unitarity of @f$ \hat{U} = @f$ @p matrix requires that @@ -234,8 +236,9 @@ digraph { * - if @p qureg or @p matrix are uninitialised. * - if @p matrix is not approximately unitary. * - if @p control or @p target are an invalid qubit index. - * - if @p control and @p target overlap. + * - if @p control and @p target are equal. * @see + * - applyCompMatr1() * - applyMultiControlledCompMatr1() * - applyMultiStateControlledCompMatr1() * @author Tyson Jones @@ -243,9 +246,7 @@ digraph { void applyControlledCompMatr1(Qureg qureg, int control, int target, CompMatr1 matrix); -/** @notyetdoced - * - * Applies a multiply-controlled one-qubit dense unitary @p matrix to the specified +/** Applies a multiply-controlled one-qubit dense unitary @p matrix to the specified * @p target qubit of @p qureg. * * @diagram @@ -300,16 +301,28 @@ digraph { + \ketbra{n}{n}_{\vec{c}} \otimes \hat{U}_t * @f] * + * The amplitudes which _are_ modified, are done so in an identical fashion as in applyCompMatr1(). + * + * @param[in,out] qureg the state to modify. + * @param[in] controls a list of control qubits. + * @param[in] numControls the length of @p controls. + * @param[in] target the target qubit. + * @param[in] matrix the Z-basis unitary matrix to effect. + * @throws @validationerror + * - if @p qureg or @p matrix are uninitialised. + * - if @p matrix is not approximately unitary. + * - if @p target or any element of @p controls are an invalid qubit index. + * - if @p controls contains duplicates, or includes @p target. + * - if @p numControls is negative. * @see * - applyCompMatr1() + * - applyMultiStateControlledCompMatr1() * @author Tyson Jones */ void applyMultiControlledCompMatr1(Qureg qureg, int* controls, int numControls, int target, CompMatr1 matrix); -/** @notyetdoced - * - * Applies an arbitrarily-controlled one-qubit dense unitary @p matrix to the specified +/** Applies an arbitrarily-controlled one-qubit dense unitary @p matrix to the specified * @p target qubit of @p qureg, conditioned upon the @p controls being in the corresponding @p states. * * @diagram @@ -346,6 +359,51 @@ digraph { } * @enddot * + * @formulae + * + * Let @f$ \vec{c} = @f$ @p controls, @f$ t = @f$ @p target, @f$ \hat{U} = @f$ @p matrix and + * @f$n = 2^{|\vec{c}|}-1@f$. Let @f$ \ket{s}_{\vec{c}} @f$ be the computational substate formed by + * the qubits in @p controls being in the corresponding @p states. + * + * This function applies the operator + * + * @f[ + \sum\limits_{i=0, i \ne s}^{n} \ketbra{i}{i}_{\vec{c}} \otimes \hat{\id}_t + + \ketbra{s}{s}_{\vec{c}} \otimes \hat{U}_t + * @f] + * + * The amplitudes which _are_ modified, are done so in an identical fashion as in applyCompMatr1(). + * + * @equivalences + * + * - This function is faster than, but mathematically equivalent to, applying a Pauli @c X + * upon every zero-controlled qubit, applying the matrix with all one-controls, then undoing + * the flipped qubits. + * ```cpp + for (int i=0; i - See applyCompMatr() for information about @p targets and @p matrix. * > - See applyMultiStateControlledCompMatr1() for information about @p controls and @p states. + * + * @author Tyson Jones */ void applyMultiStateControlledCompMatr(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, CompMatr matrix); From 57525b1f04dd480c8cec3c8834ac4c0b665e5874 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Mon, 13 Jul 2026 00:03:21 -0400 Subject: [PATCH 22/29] doc channel non-inline funcs --- quest/include/channels.h | 210 ++++++++++++++++++++++++++++++++++----- 1 file changed, 187 insertions(+), 23 deletions(-) diff --git a/quest/include/channels.h b/quest/include/channels.h index 25b07de25..ed0fe5c59 100644 --- a/quest/include/channels.h +++ b/quest/include/channels.h @@ -362,44 +362,129 @@ extern "C" { /** @ingroup channels_create - * @notyetdoced * + * Creates an uninitialised Kraus map. + * + * The returned KrausMap contains @p numOperators Kraus operators, each of which + * spans @p numQubits many qubits. Before being passed to functions like + * reportKrausMap() and mixKrausMap(), its elements must be populated with + * setKrausMap() or setInlineKrausMap(), or directly modified through KrausMap::matrices, + * though any direct modification must be followed by a call to syncKrausMap(). + * + * The returned KrausMap should be later destroyed with destroyKrausMap(). + * + * > See [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.c) + * > or [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.cpp) + * > examples of initialising a KrausMap. + * + * @param[in] numQubits the number of qubits acted upon by the Kraus map. + * @param[in] numOperators the number of Kraus operators in the map. + * @returns A new KrausMap instance. + * @throws @validationerror + * - if the QuEST environment is not initialised. + * - if @p numQubits or @p numOperators are invalid. + * - if the dimensions or memory requirements overflow. + * - if any memory allocation fails. * @see - * - createInlineKrausMap + * - [createInlineKrausMap()](https://quest-kit.github.io/QuEST/group__channels__create.html#gae9c49a6443896ef590ff1e4cfaa4912b) * - createSuperOp() * - setKrausMap() - * - setInlineKrausMap + * - [setInlineKrausMap()](https://quest-kit.github.io/QuEST/group__channels__setters.html#ga3c60440fa9503c235e46d964bc58d3ec) * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.c) or * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.cpp) examples + * @author Tyson Jones */ KrausMap createKrausMap(int numQubits, int numOperators); /** @ingroup channels_sync - * @notyetdoced * + * Updates the internal state of @p map, necessary after manually modifying KrausMap::matrices. + * + * @param[in,out] map the KrausMap to synchronise. + * @throws @validationerror + * - if @p map is uninitialised. * @see * - setKrausMap() * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.c) or * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.cpp) examples + * @author Tyson Jones */ void syncKrausMap(KrausMap map); - /// @ingroup channels_destroy - /// @notyetdoced + /** @ingroup channels_destroy + * Destroys a KrausMap, freeing its Kraus operators and internal SuperOp. + * + * Since @p map is passed by value, this function cannot nullify the caller's + * copy of the KrausMap fields. The caller must not use @p map after destruction. + * + * @param[in] map the KrausMap to destroy. + * @throws @validationerror + * - if @p map is uninitialised. + * @author Tyson Jones + */ void destroyKrausMap(KrausMap map); - /// @ingroup channels_reporters - /// @notyetdoced - /// @notyettested + /** @ingroup channels_reporters + * Prints a KrausMap. + * + * @myexample + * + * ```cpp + KrausMap map = createInlineKrausMap(1, 3, { + {{1,2},{3,4}}, + {{5,5},{6,6}}, + {{1i,2i},{-3i,-4i}} + }); + reportKrausMap(map); + * ``` + * ```text + KrausMap (1 qubit, 3 2x2 matrices, 1 4x4 superoperator, 528 bytes): + [matrix 0] + 1 2 + 3 4 + [matrix 1] + 5 5 + 6 6 + [matrix 2] + i 2i + -3i -4i + * ``` + * + * @param[in] map the KrausMap to print. + * @throws @validationerror + * - if @p map is uninitialised. + * @author Tyson Jones + */ void reportKrausMap(KrausMap map); /** @ingroup channels_create - * @notyetdoced * + * Creates an uninitialised superoperator. + * + * The returned SuperOp represents an arbitrary linear map on vectorised density + * matrices, spanning @p numQubits many ket-qubits and an equal number of bra-qubits. + * Before being passed to functions + * like reportSuperOp() and mixSuperOp(), its elements must be populated with + * setSuperOp() or setInlineSuperOp(), or directly modified through SuperOp::cpuElems, + * though direct modification must be followed by a call to syncSuperOp(). + * + * The returned SuperOp should be later destroyed with destroySuperOp(). + * + * > See [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.c) + * > or [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.cpp) + * > examples of initialising a SuperOp. + * + * @param[in] numQubits the number of qubits acted upon by the superoperator. + * @returns A new SuperOp instance. + * @throws @validationerror + * - if the QuEST environment is not initialised. + * - if @p numQubits is invalid. + * - if the dimensions or memory requirements overflow. + * - if any memory allocation fails. * @see * - createInlineSuperOp() * - createKrausMap() @@ -407,29 +492,69 @@ extern "C" { * - setInlineSuperOp() * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.c) or * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.cpp) examples + * @author Tyson Jones */ SuperOp createSuperOp(int numQubits); /** @ingroup channels_sync - * @notyetdoced * + * Updates the internal state of @p op, necessary after manually modifying SuperOp::cpuElems + * or SuperOp::cpuElemsFlat. + * + * @param[in,out] op the SuperOp to synchronise. + * @throws @validationerror + * - if @p op is uninitialised. * @see * - setSuperOp() * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.c) or * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.cpp) examples + * @author Tyson Jones */ void syncSuperOp(SuperOp op); - /// @ingroup channels_destroy - /// @notyetdoced + /** @ingroup channels_destroy + * Destroys a SuperOp, freeing all its CPU and GPU memory. + * + * Since @p op is passed by value, this function cannot nullify the caller's + * copy of the SuperOp fields. The caller must not use @p op after destruction. + * + * @param[in] op the SuperOp to destroy. + * @throws @validationerror + * - if @p op is uninitialised. + * @author Tyson Jones + */ void destroySuperOp(SuperOp op); - /// @ingroup channels_reporters - /// @notyetdoced - /// @notyettested + /** @ingroup channels_reporters + * Prints a SuperOp. + * + * @myexample + * + * ```cpp + SuperOp op = createInlineSuperOp(1, { + {1,2,3,4}, + {5,-(10E-2)*3.14i,7,8}, + {9,10,11,12}, + {13,14,15,16+1.23i} + }); + reportSuperOp(op); + * ``` + * ```text + SuperOp (1 qubit, 4x4 qcomps, 304 bytes): + 1 2 3 4 + 5 -0.314i 7 8 + 9 10 11 12 + 13 14 15 16+1.23i + * ``` + * + * @param[in] op the SuperOp to print. + * @throws @validationerror + * - if @p op is uninitialised. + * @author Tyson Jones + */ void reportSuperOp(SuperOp op); @@ -456,25 +581,48 @@ extern "C" { /** @ingroup channels_setters - * @notyetdoced * + * Overwrites the Kraus operators of @p map. + * + * Argument @p matrices must be a list of KrausMap::numMatrices matrices, each of + * dimension KrausMap::numRows by KrausMap::numRows. + * + * This updates KrausMap::matrices and other internal properties. + * + * @param[in,out] map the KrausMap to overwrite. + * @param[in] matrices a 3D nested list of the above dimensions. + * @throws @validationerror + * - if @p map is uninitialised. + * @throws seg-fault + * - if @p matrices is not of the expected dimensions. * @see - * - setInlineKrausMap() + * - [setInlineKrausMap()](https://quest-kit.github.io/QuEST/group__channels__setters.html#ga3c60440fa9503c235e46d964bc58d3ec) * - syncKrausMap() * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.c) or * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.cpp) examples + * @author Tyson Jones */ void setKrausMap(KrausMap map, qcomp*** matrices); /** @ingroup channels_setters - * @notyetdoced * + * Overwrites the elements of @p op. + * + * This copies @p matrix into SuperOp::cpuElems and synchronises @p op to GPU memory + * when relevant. + * + * @param[in,out] op the SuperOp to overwrite. + * @param[in] matrix a SuperOp::numRows by SuperOp::numRows matrix of new elements. + * @throws @validationerror + * - if @p op is uninitialised. + * - if @p matrix is a null or invalid pointer. * @see * - setInlineSuperOp() * - syncSuperOp() * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.c) or * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.cpp) examples + * @author Tyson Jones */ void setSuperOp(SuperOp op, qcomp** matrix); @@ -512,7 +660,7 @@ extern "C" { * @cpponly * * @see - * - setInlineKrausMap() + * - [setInlineKrausMap()](https://quest-kit.github.io/QuEST/group__channels__setters.html#ga3c60440fa9503c235e46d964bc58d3ec) * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.cpp) examples */ void setKrausMap(KrausMap map, std::vector>> matrices); @@ -600,25 +748,41 @@ extern "C" { /** @ingroup channels_setters - * @notyetdoced + * Overwrites the Kraus operators of @p map from a @c C array. + * + * This is a @c C convenience macro equivalent to setKrausMap(). + * + * @param[in,out] map the KrausMap to overwrite. + * @param[in] matrices a 3D array. + * @throws @validationerror + * - if @p map is uninitialised. * @conly * @macrodoc * * @see - * - setInlineKrausMap() + * - [setInlineKrausMap()](https://quest-kit.github.io/QuEST/group__channels__setters.html#ga3c60440fa9503c235e46d964bc58d3ec) * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.c) examples + * @author Tyson Jones */ void setKrausMap(KrausMap map, qcomp matrices[map.numMatrices][map.numRows][map.numRows]); /** @ingroup channels_setters - * @notyetdoced + * Overwrites the elements of @p op from a @c C array. + * + * This is a @c C convenience macro equivalent to setSuperOp() + * + * @param[in,out] op the SuperOp to overwrite. + * @param[in] matrix a SuperOp::numRows by SuperOp::numRows array. + * @throws @validationerror + * - if @p op is uninitialised. * @conly * @macrodoc * * @see * - setInlineSuperOp() * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.c) examples + * @author Tyson Jones */ void setSuperOp(SuperOp op, qcomp matrix[op.numRows][op.numRows]); From e01d086036e15fd6c12b1917e9851ab89650c185 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Mon, 13 Jul 2026 00:36:38 -0400 Subject: [PATCH 23/29] doc channel inline funcs --- quest/include/channels.h | 186 +++++++++++++++++++++++++++++++++++---- 1 file changed, 168 insertions(+), 18 deletions(-) diff --git a/quest/include/channels.h b/quest/include/channels.h index ed0fe5c59..15ce44198 100644 --- a/quest/include/channels.h +++ b/quest/include/channels.h @@ -748,17 +748,37 @@ extern "C" { /** @ingroup channels_setters + * * Overwrites the Kraus operators of @p map from a @c C array. + * + * @macrodoc + * + * @conly * * This is a @c C convenience macro equivalent to setKrausMap(). + * + * @myexample + * + * ```c + qcomp arr[2][4][4] = { + { + {1,2,3,4}, + {5,6,7,8}, + {9,8,7,6}, + {5,4,3,2}, + }, { + {1i,2i,3i}, + {5i} + } + }; + KrausMap map = createKrausMap(2, 2); + setKrausMap(map, arr); + * ``` * * @param[in,out] map the KrausMap to overwrite. * @param[in] matrices a 3D array. * @throws @validationerror * - if @p map is uninitialised. - * @conly - * @macrodoc - * * @see * - [setInlineKrausMap()](https://quest-kit.github.io/QuEST/group__channels__setters.html#ga3c60440fa9503c235e46d964bc58d3ec) * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.c) examples @@ -768,18 +788,34 @@ extern "C" { /** @ingroup channels_setters + * * Overwrites the elements of @p op from a @c C array. + * + * @macrodoc + * + * @conly * - * This is a @c C convenience macro equivalent to setSuperOp() + * This is a @c C convenience macro equivalent to setSuperOp(). + * + * @myexample + * + * ```c + qcomp arr[4][4] = { + {1,2,3,4}, + {5,6,7,8}, + {9,8,7,6}, + {5,4,3,2} + }; + SuperOp a = createSuperOp(1); + setSuperOp(a, arr); + * ``` * * @param[in,out] op the SuperOp to overwrite. * @param[in] matrix a SuperOp::numRows by SuperOp::numRows array. * @throws @validationerror * - if @p op is uninitialised. - * @conly - * @macrodoc - * * @see + * - setSuperOp() * - setInlineSuperOp() * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.c) examples * @author Tyson Jones @@ -888,25 +924,77 @@ extern "C" { /** @ingroup channels_setters - * @notyetdoced - * @macrodoc * + * Overwrites the Kraus operators of @p map from an inline literal. + * + * The @c {{{matrices}}} argument is a 3D array literal, of dimensions + * @c numOps by @c 1< Date: Mon, 13 Jul 2026 00:37:38 -0400 Subject: [PATCH 24/29] fix debug doc --- quest/include/debug.h | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/quest/include/debug.h b/quest/include/debug.h index badc15c1d..731c3e13f 100644 --- a/quest/include/debug.h +++ b/quest/include/debug.h @@ -65,7 +65,7 @@ extern "C" { // seed unsigned seeds[] = {123456789u, 987654321u, 546372819u}; - setQuESTSeeds(seeds, 2); + setQuESTSeeds(seeds, 3); // randomly collapse the plus state initPlusState(qureg); @@ -74,7 +74,7 @@ extern "C" { reportScalar("outcome 2", applyQubitMeasurement(qureg, 2)); // restore RNG to state prior to collapse - setQuESTSeeds(seeds, 2); + setQuESTSeeds(seeds, 3); // randomly collapse the plus state again, obtaining same outcomes reportStr(""); @@ -319,7 +319,7 @@ int getQuESTNumSeeds(); int main() { initQuESTEnv(); - setInputErrorHandler(myErrorHandler); + setQuESTInputErrorHandler(myErrorHandler); createQureg(9999); // invokes myErrorHandler ... } @@ -857,8 +857,17 @@ void clearQuESTGpuCache(); */ -/// @notyetdoced -/// @notyettested +/** Writes a compact description of the active QuEST environment into @p str. + * + * The caller must provide a character buffer of length at least @c 200. The + * resulting string is null-terminated and summarises the current deployment. + * + * @param[out] str a character buffer of length @c 200 to overwrite. + * @throws @validationerror + * - if the QuEST environment is not initialised. + * @notyettested + * @author Tyson Jones + */ void getQuESTEnvironmentString(char str[200]); From a937ae58291676f72d5219e576b813626ec67aac Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Mon, 13 Jul 2026 00:42:44 -0400 Subject: [PATCH 25/29] fix hyperlink doxygen's inconsistent discovery of the inline links is concerning --- quest/include/decoherence.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quest/include/decoherence.h b/quest/include/decoherence.h index 4e6bfa74f..c7a9e57b4 100644 --- a/quest/include/decoherence.h +++ b/quest/include/decoherence.h @@ -601,7 +601,7 @@ void mixQureg(Qureg qureg, Qureg other, qreal prob); * qubits in @p qureg minus half log-2 of the number of processes. * @see * - createKrausMap() - * - createInlineKrausMap() + * - [createInlineKrausMap()](https://quest-kit.github.io/QuEST/group__channels__create.html#gae9c49a6443896ef590ff1e4cfaa4912b) * - setKrausMap() * @author Tyson Jones */ From 10f07d734638570a5a5afd58af4505982cc61dda Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Mon, 13 Jul 2026 00:43:06 -0400 Subject: [PATCH 26/29] bah --- quest/include/calculations.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/quest/include/calculations.h b/quest/include/calculations.h index 2ce813748..3f67e7ca8 100644 --- a/quest/include/calculations.h +++ b/quest/include/calculations.h @@ -305,6 +305,10 @@ qreal calcExpecFullStateDiagMatr(Qureg qureg, FullStateDiagMatr matr); * Hermiticity validation is relaxed and/or @p qureg is an unnormalised density matrix. * The full complex value can be obtained using calcExpecNonHermitianFullStateDiagMatrPower(). * + * @equivalences + * + * - When @p exponent is @c 1, this function is equivalent to calcExpecFullStateDiagMatr(). + * * @myexample * ``` Qureg qureg = createQureg(5); From 91832b553515671f82498527f55f5fc9c4a90ffe Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Mon, 13 Jul 2026 00:46:32 -0400 Subject: [PATCH 27/29] replace local links --- quest/include/matrices.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/quest/include/matrices.h b/quest/include/matrices.h index 7cbc5f173..894bd7422 100644 --- a/quest/include/matrices.h +++ b/quest/include/matrices.h @@ -149,8 +149,8 @@ typedef struct { * * @see * - createCompMatr() - * - [createInlineCompMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__create.html#gad0ac51cb08a5d0b4e0878a5fde7ca893) - * - [setInlineCompMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__setters.html#ga00993b6b571985fd04697e487a561517) + * - [createInlineCompMatr()](https://quest-kit.github.io/QuEST/group__matrices__create.html#gad0ac51cb08a5d0b4e0878a5fde7ca893) + * - [setInlineCompMatr()](https://quest-kit.github.io/QuEST/group__matrices__setters.html#ga00993b6b571985fd04697e487a561517) * - setCompMatr() * - syncCompMatr() * - reportCompMatr() @@ -255,7 +255,7 @@ typedef struct { * * @see * - setCompMatr() - * - [setInlineCompMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__setters.html#ga00993b6b571985fd04697e487a561517) + * - [setInlineCompMatr()](https://quest-kit.github.io/QuEST/group__matrices__setters.html#ga00993b6b571985fd04697e487a561517) * - syncCompMatr() */ qcomp** cpuElems; @@ -274,7 +274,7 @@ typedef struct { * * @see * - setCompMatr() - * - [setInlineCompMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__setters.html#ga00993b6b571985fd04697e487a561517) + * - [setInlineCompMatr()](https://quest-kit.github.io/QuEST/group__matrices__setters.html#ga00993b6b571985fd04697e487a561517) * - syncCompMatr() */ qcomp* cpuElemsFlat; @@ -393,8 +393,8 @@ typedef struct { * * @see * - createDiagMatr() - * - [createInlineDiagMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__create.html#gad0ac51cb08a5d0b4e0878a5fde7ca893) - * - [setInlineDiagMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__setters.html#ga00993b6b571985fd04697e487a561517) + * - [createInlineDiagMatr()](https://quest-kit.github.io/QuEST/group__matrices__create.html#gad0ac51cb08a5d0b4e0878a5fde7ca893) + * - [setInlineDiagMatr()](https://quest-kit.github.io/QuEST/group__matrices__setters.html#ga7b2c2e134546df6101c6001727bc6d69) * - setDiagMatr() * - syncDiagMatr() * - reportDiagMatr() @@ -540,7 +540,7 @@ typedef struct { * * @see * - createFullStateDiagMatr() - * - [setInlineFullStateDiagMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__setters.html#gaa27aaa1a001a41f36a60847a19d824d4) + * - [setInlineFullStateDiagMatr()](fhttps://quest-kit.github.io/QuEST/group__matrices__setters.html#gaa27aaa1a001a41f36a60847a19d824d4) * - setFullStateDiagMatr() * - setFullStateDiagMatrFromMultiVarFunc() * - setFullStateDiagMatrFromMultiDimLists() @@ -1338,7 +1338,7 @@ extern "C" { * @notyettested * * @see - * - [setInlineFullStateDiagMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__setters.html#gaa27aaa1a001a41f36a60847a19d824d4) + * - [setInlineFullStateDiagMatr()](fhttps://quest-kit.github.io/QuEST/group__matrices__setters.html#gaa27aaa1a001a41f36a60847a19d824d4) * - reportFullStateDiagMatr() * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples @@ -1402,7 +1402,7 @@ extern "C" { * @cpponly * * @see - * - [setInlineFullStateDiagMatr()](file:///Users/tysonjones/Desktop/GithubRepos/QuEST/Doxygen_doc/html/group__matrices__setters.html#gaa27aaa1a001a41f36a60847a19d824d4) + * - [setInlineFullStateDiagMatr()](fhttps://quest-kit.github.io/QuEST/group__matrices__setters.html#gaa27aaa1a001a41f36a60847a19d824d4) * - reportFullStateDiagMatr() * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples */ From 91d3e74b55dc1d59face85ba67f38ef4ef3d26d2 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Wed, 15 Jul 2026 21:08:33 -0400 Subject: [PATCH 28/29] added env doc --- quest/include/environment.h | 212 ++++++++++++++++++++++++++++++++++-- 1 file changed, 203 insertions(+), 9 deletions(-) diff --git a/quest/include/environment.h b/quest/include/environment.h index cdefa7d7d..e3fae7c99 100644 --- a/quest/include/environment.h +++ b/quest/include/environment.h @@ -54,36 +54,230 @@ typedef struct { } QuESTEnv; -/// @notyetdoced +/** Initialises the QuEST execution environment. + * + * This must be called before any other QuEST function, and performs tasks + * like validating the environment, reading environment variables, + * initialising external libraries like MPI or cuQuantum (when available), + * and seeding random number generators. + * + * This function prepares usage of all of QuEST's parallelisation facilities, such + * as multithreading, GPU-acceleration and distribution, provided they are compiled + * and appropriate hardware is available. The used facilities can be controlled with + * initCustomQuESTEnv(). + * + * > [!TIP] + * > The utilised facilities can be conveniently viewed with reportQuESTEnv(). + * + * When distributed execution is initialised with this function, QuEST takes control + * of MPI, including its initialisation and finalization. User-owned MPI is possible + * through initCustomMpiQuESTEnv(). + * + * Note that when cuQuantum was compiled, and a GPU is available at runtime, the + * cuQuantum backend is always used over the custom GPU backend (which, infact, was + * not compiled!). This means the GPU _must_ be compatible with cuQuantum. + * + * > [!NOTE] + * > Before exiting, the initialised QuEST environment should be finalized with + * > finalizeQuESTEnv(). This is especially important in a distributed environment + * > to avoid MPI errors. + * + * @myexample + * + * ```cpp + int main() { + initQuESTEnv(); + reportQuESTEnv(); + finalizeQuESTEnv(); + return 0; + } + * ``` + * + * @throws @validationerror + * - if the QuEST environment was already initialised, or has already been finalised. + * - if any environment variable has an invalid value. + * - if distribution is enabled but MPI was already initialised. + * - if distribution is enabled but QuEST is launched with a non-power-of-2 number of MPI processes. + * - if distribution and GPU are enabled, and a GPU is used by more than one process, unless + * explicitly enabled through environment variable QUEST_PERMIT_NODES_TO_SHARE_GPU. + * - if GPU is enabled and cuQuantum was compiled, but the GPU is not compatible with cuQuantum. + * @see + * - initCustomQuESTEnv() + * - initCustomMpiQuESTEnv() + * - initCustomMpiCommQuESTEnv() + * - finalizeQuESTEnv() + * - reportQuESTEnv() + * @author Tyson Jones + */ void initQuESTEnv(); -/** @notyetdoced - * + +/** Initialises the QuEST execution environment with the specified deployments. + * + * Each deployment flag may be @c 1 to force the deployment, @c 0 to disable it, + * or @c -1 to let QuEST choose automatically. The environment must be initialised + * exactly once, and cannot be re-initialised after finalizeQuESTEnv(). + * + * @param[in] useDistrib whether to force (@c =1), disable (@c =0), or automate (@c =-1) distribution. + * @param[in] useGpuAccel whether to force (@c =1), disable (@c =0), or automate (@c =-1) GPU acceleration. + * @param[in] useMultithread whether to force (@c =1), disable (@c =0), or automate (@c =-1) multithreading. + * @throws @validationerror + * - if any deployment flag is not @c 0, @c 1 or @c -1. + * - if the QuEST environment was already initialised, or has already been finalised. + * - if any environment variable has an invalid value. + * - if distribution is enabled but MPI was already initialised. + * - if distribution is enabled but QuEST is launched with a non-power-of-2 number of MPI processes. + * - if distribution and GPU are enabled, and a GPU is used by more than one process, unless + * explicitly enabled through environment variable QUEST_PERMIT_NODES_TO_SHARE_GPU. + * - if GPU is enabled and cuQuantum was compiled, but the GPU is not compatible with cuQuantum. * @see + * - initQuESTEnv() + * - initCustomMpiQuESTEnv() * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_environments.c) and * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_environments.cpp) examples + * @author Tyson Jones */ void initCustomQuESTEnv(int useDistrib, int useGpuAccel, int useMultithread); -/// @notyetdoced + +/** Finalises the active QuEST execution environment. + * + * This synchronises outstanding GPU/MPI work, clears QuEST's GPU cache, finalises + * cuQuantum if active, and finalises MPI if QuEST initialised it. It does not + * destroy any existing QuEST structs, such as Qureg or CompMatr, which should be + * prior destroyed to avoid a leak. + * + * @throws @validationerror + * - if the QuEST environment is not initialised. + * @see + * - initQuESTEnv() + * @author Tyson Jones + */ void finalizeQuESTEnv(); -/// @notyetdoced + +/** Synchronises QuEST across all processes and machines, waiting for outstanding work to complete. + * + * - When GPU acceleration is active, this function blocks until all outstanding GPU work is complete. + * - When distribution is active, this function blocks until all MPI ranks are synchronised. + * + * @throws @validationerror + * - if the QuEST environment is not initialised. + * @author Tyson Jones + */ void syncQuESTEnv(); -/** @notyetdoced - * @notyettested + +/** Prints a summary of the active QuEST execution environment. + * + * The report includes precision, compilation, deployment, CPU, GPU, distribution, + * Qureg size-limit and automatic-deployment information. + * + * @myexample + * + * An example output: * + * ```text + QuEST execution environment: + [precision] + qreal.................double (8 bytes) + qcomp.................std::__1::complex (16 bytes) + qindex................long long int (8 bytes) + validationEpsilon.....1e-12 + [compilation] + isOmpCompiled...............1 + isMpiCompiled...............1 + isMpiSubCommCompiled........0 + isGpuCompiled...............0 + isHipCompiled...............0 + isCuQuantumCompiled.........0 + isCheckpointingCompiled.....0 + [deployment] + isOmpEnabled...........1 + isMpiEnabled...........1 + isGpuEnabled...........0 + isCuQuantumEnabled.....0 + [cpu] + numCpuCores.......14 per machine + numOmpProcs.......14 per machine + numOmpThrds.......14 per node + cpuMemory.........36 GiB per machine + cpuMemoryFree.....unknown + [gpu] + numGpus................N/A + gpuDirect..............N/A + gpuMemPools............N/A + gpuMemory..............N/A + gpuMemoryFree..........N/A + gpuCache...............N/A + numThreadsPerBlock.....N/A + [distribution] + isMpiUserOwned..........0 + isMpiGpuAware...........0 + isGpuSharingEnabled.....N/A + numMpiNodes.............16 + [statevector limits] + minQubitsForMpi.............4 + maxQubitsForCpu.............31 + maxQubitsForGpu.............N/A + maxQubitsForMpiCpu..........34 + maxQubitsForMpiGpu..........N/A + maxQubitsForMemOverflow.....58 + maxQubitsForIndOverflow.....63 + [density matrix limits] + minQubitsForMpi.............4 + maxQubitsForCpu.............15 + maxQubitsForGpu.............N/A + maxQubitsForMpiCpu..........19 + maxQubitsForMpiGpu..........N/A + maxQubitsForMemOverflow.....28 + maxQubitsForIndOverflow.....31 + [statevector autodeployment] + 8 qubits......[omp] + 30 qubits.....[omp] [mpi] + [density matrix autodeployment] + 4 qubits......[omp] + 15 qubits.....[omp] [mpi] + * ``` + * + * @throws @validationerror + * - if the QuEST environment is not initialised. * @see * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_environments.c) and * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_environments.cpp) examples + * @author Tyson Jones */ void reportQuESTEnv(); -/// @notyetdoced +/** Indicates whether the QuEST execution environment is currently initialised. + * + * Unlike other QuEST functions, this can be called at any time, including before + * QuEST initialisation, and after finalisation. + * + * @returns @c 1 if the environment is initialised, otherwise @c 0. + * @author Tyson Jones + */ int isQuESTEnvInit(); -/// @notyetdoced +/** Returns a copy of the active QuEST execution environment. + * + * The returned QuESTEnv describes the active deployment and MPI rank information. + * This can be useful for making programmatical decisions based on the environment. + * + * @myexample + * + * ```cpp + QuESTEnv env = getQuESTEnv(); + + if (env.isDistributed && env.isGpuAccelerated && ! env.isMpiGpuAware) + printf("What a waste!\n"); + * ``` + * + * @returns A copy of the active QuESTEnv. + * @throws @validationerror + * - if the QuEST environment is not initialised. + * @author Tyson Jones + */ QuESTEnv getQuESTEnv(); From 7ff3eac209852a2831cdc67e111603f184e67bef Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Wed, 15 Jul 2026 22:32:43 -0400 Subject: [PATCH 29/29] doc'd initState funcs --- quest/include/initialisations.h | 284 +++++++++++++++++++++++++++++--- 1 file changed, 265 insertions(+), 19 deletions(-) diff --git a/quest/include/initialisations.h b/quest/include/initialisations.h index 468bb794f..8fd63c157 100644 --- a/quest/include/initialisations.h +++ b/quest/include/initialisations.h @@ -39,49 +39,295 @@ extern "C" { */ -/// @notyetdoced -/// @notyetvalidated +/** Initialises @p qureg to the unnormalised all-zero-amplitude state. + * + * Every statevector amplitude, or every density-matrix element, is set to zero. + * This is not a physical quantum state, but is useful as a blank + * workspace before manually setting amplitudes. + * + * @equivalences + * + * - This function is equivalent to (but much faster than) overwriting every + * amplitude to zero. + * ```cpp + for (int i=0; i> i) & 1) + applyPauliX(qureg, i); + * ``` + * + * @param[in,out] qureg the Qureg to overwrite. + * @param[in] stateInd the computational basis-state index. + * @throws @validationerror + * - if @p qureg is uninitialised. + * - if @p stateInd is outside the computational basis of @p qureg. + * @author Tyson Jones + */ void initClassicalState(Qureg qureg, qindex stateInd); -/// @notyetdoced -/// @notyetvalidated +/** Initialises @p qureg to the debug state. + * + * This is a non-physical, deterministic pattern useful for debugging. + * The @f$j@f$-th local amplitude becomes + * @f[ + 2j/10 + \iu(2j+1)/10, + * @f] + * even if @p qureg is a density matrix, in which case it is enumerated + * column-major. + + * @myexample + * + * ```cpp + Qureg qureg = createQureg(3); + initDebugState(qureg); + reportQureg(qureg); + * ``` + * ```text + Qureg (3 qubit statevector, 8 qcomps, 232 bytes): + 0.1i |0⟩ + 0.2+0.3i |1⟩ + 0.4+0.5i |2⟩ + 0.6+0.7i |3⟩ + 0.8+0.9i |4⟩ + 1+1.1i |5⟩ + 1.2+1.3i |6⟩ + 1.4+1.5i |7⟩ + * ``` + * + * @param[in,out] qureg the Qureg to overwrite. + * @throws @validationerror + * - if @p qureg is uninitialised. + * @author Tyson Jones + */ void initDebugState(Qureg qureg); -/// @notyetdoced -/// @notyetvalidated +/** Initialises @p qureg from the statevector amplitudes in @p amps. + * + * @formulae + * + * Let @f$N@f$ be the number of qubits in @p qureg, and let @f$\alpha_i@f$ be + * the amplitude `amps[i]`. Array @p amps must be length @f$2^N@f$. + * + * - If @p qureg is a statevector, its amplitudes are overwritten by @p amps, to become + * @f[ + \sum\limits_i \alpha_i \ket{i}. + * @f] + * + * - If @p qureg is a density matrix, it is initialised to the pure state @f$\ket{\psi}@f$ + * encoded by @p amps, i.e. + * @f[ + \ket{\psi}\bra{\psi} = + \sum\limits_i\sum\limits_j \alpha_i \,\alpha_j^* \, \ket{i}\bra{j} + * @f] + * + * There is no need for @p amps to be normalised, although @p qureg will otherwise be left + * in an unnormalised, non-physical state. + * + * @param[in,out] qureg the Qureg to overwrite. + * @param[in] amps an array of @f$2^N@f$ pure-state amplitudes. + * @throws @validationerror + * - if @p qureg is uninitialised. + * @throws seg-fault + * - if @p amps has fewer than @f$2^N@f$ elements. + * @author Tyson Jones + */ void initArbitraryPureState(Qureg qureg, qcomp* amps); -/// @notyetdoced -/// @notyetvalidated +/** Initialises @p qureg (a statevector or density matrix) to a pure state with + * uniformly random amplitudes. + * + * The resulting state is normalised, with basis state probabilities sampled + * from a chi-squared variate, as described + * [here](https://sumeetkhatri.com/wp-content/uploads/2020/05/random_pure_states.pdf). + * + * @param[in,out] qureg the Qureg to overwrite. + * @throws @validationerror + * - if @p qureg is uninitialised. + * @see + * - initRandomMixedState() + * @author Tyson Jones + */ void initRandomPureState(Qureg qureg); -/// @notyetdoced -/// @notyetvalidated +/** Initialises a density matrix to a mixture of uniformly random pure states. + * + * The resulting density matrix is the equally weighted mixture of @p numPureStates + * independently sampled random pure states, each sampled as per initRandomPureState(). + * + * @formulae + * + * Let @f$n=@f$ @p numPureStates, and let @f$\ket{\psi_i}@f$ be a random pure + * state with number of qubits as @p qureg. + * + * This function overwrites @p qureg to + * @f[ + * \sum\limits_i^n \frac{1}{n} \ket{\psi_i}\bra{\psi_i}. + * @f] + * + * @param[in,out] qureg the density matrix to overwrite. + * @param[in] numPureStates the number of random pure states in the mixture. + * @throws @validationerror + * - if @p qureg is uninitialised. + * - if @p qureg is not a density matrix. + * - if @p numPureStates is invalid. + * @see + * - initRandomPureState() + * @author Tyson Jones + */ void initRandomMixedState(Qureg qureg, qindex numPureStates);