From 7b8860afde8d9d3d49fda8b0555906af5b8726f4 Mon Sep 17 00:00:00 2001 From: Vasco Ferreira Date: Mon, 10 Nov 2025 13:16:53 +0000 Subject: [PATCH 1/4] Implement PauliStrSum random permutations --- quest/src/core/randomiser.cpp | 20 ++++++++++++++++++++ quest/src/core/randomiser.hpp | 10 +++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/quest/src/core/randomiser.cpp b/quest/src/core/randomiser.cpp index 45668fd30..1e9b4a94f 100644 --- a/quest/src/core/randomiser.cpp +++ b/quest/src/core/randomiser.cpp @@ -5,6 +5,7 @@ * * @author Tyson Jones * @author Balint Koczor (patched v3 MSVC seeding) + * @author Vasco Ferreira (PauliStrSum permutation) */ #include "quest/include/types.h" @@ -266,3 +267,22 @@ qcomp rand_getThreadPrivateRandomAmp(std::mt19937_64 &gen, std::normal_distribut qcomp amp = std::sqrt(prob) * std::exp(phase * 1_i); return amp; } + + + +/* + * PAULI STRINGS + */ + + +void rand_permutePauliStrSum(PauliStrSum &sum) { + + // permute ordering of terms inplace using Fisher-Yates + for (qindex i = sum.numTerms - 1; i > 0; --i) { + std::uniform_int_distribution distrib(0, i); + qindex j = distrib(mainGenerator); + + std::swap(sum.coeffs[i], sum.coeffs[j]); + std::swap(sum.strings[i], sum.strings[j]); + } +} diff --git a/quest/src/core/randomiser.hpp b/quest/src/core/randomiser.hpp index 179e5ccbe..b867fae74 100644 --- a/quest/src/core/randomiser.hpp +++ b/quest/src/core/randomiser.hpp @@ -4,6 +4,7 @@ * quantum measurements and randomly initialising Quregs. * * @author Tyson Jones + * @author Vasco Ferreira (PauliStrSum permutation) */ #ifndef RANDOMISER_HPP @@ -61,4 +62,11 @@ qcomp rand_getThreadPrivateRandomAmp(std::mt19937_64 &gen, std::normal_distribut -#endif // RANDOMISER_HPP \ No newline at end of file +/* + * PAULI STRINGS + */ + + +void rand_permutePauliStrSum(PauliStrSum &sum); + +#endif // RANDOMISER_HPP From 141d56e45d02f21529378f7952f8cfcbb4b44aa1 Mon Sep 17 00:00:00 2001 From: Vasco Ferreira Date: Mon, 10 Nov 2025 16:46:15 +0000 Subject: [PATCH 2/4] Add randomisation to Trotter functions --- examples/extended/dynamics.c | 5 ++- examples/extended/dynamics.cpp | 5 ++- quest/include/trotterisation.h | 23 ++++++----- quest/src/api/trotterisation.cpp | 66 +++++++++++++++++++++----------- 4 files changed, 63 insertions(+), 36 deletions(-) diff --git a/examples/extended/dynamics.c b/examples/extended/dynamics.c index 0d6763c1d..03abcc16c 100644 --- a/examples/extended/dynamics.c +++ b/examples/extended/dynamics.c @@ -153,11 +153,12 @@ int main() { int order = 4; int reps = 5; int steps = 20; + bool randomise = true; for (int i=0; i qreal time = dt * (i+1); @@ -187,7 +188,7 @@ int main() { // verify results by uninterrupted higher-order simulation to target time initPlusState(qureg); - applyTrotterizedUnitaryTimeEvolution(qureg, hamil, dt*steps, order+2, reps*steps); + applyTrotterizedUnitaryTimeEvolution(qureg, hamil, dt*steps, order+2, reps*steps, randomise); reportScalar("final ", calcExpecPauliStrSum(qureg, observ)); // clean up diff --git a/examples/extended/dynamics.cpp b/examples/extended/dynamics.cpp index 95245fb87..636145387 100644 --- a/examples/extended/dynamics.cpp +++ b/examples/extended/dynamics.cpp @@ -150,11 +150,12 @@ int main() { int order = 4; int reps = 5; int steps = 20; + bool randomise = true; for (int i=0; i qreal time = dt * (i+1); @@ -181,7 +182,7 @@ int main() { // verify results by uninterrupted higher-order simulation to target time initPlusState(qureg); - applyTrotterizedUnitaryTimeEvolution(qureg, hamil, dt*steps, order+2, reps*steps); + applyTrotterizedUnitaryTimeEvolution(qureg, hamil, dt*steps, order+2, reps*steps, randomise); reportScalar("final ", calcExpecPauliStrSum(qureg, observ)); // clean up diff --git a/quest/include/trotterisation.h b/quest/include/trotterisation.h index 667eedd91..46039fde3 100644 --- a/quest/include/trotterisation.h +++ b/quest/include/trotterisation.h @@ -10,9 +10,12 @@ * @{ */ + #ifndef TROTTERISATION_H #define TROTTERISATION_H +#include + #include "quest/include/qureg.h" #include "quest/include/paulis.h" #include "quest/include/matrices.h" @@ -157,7 +160,7 @@ extern "C" { * * @author Tyson Jones */ -void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle, int order, int reps); +void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle, int order, int reps, bool randomiseString); /// @notyetdoced @@ -165,7 +168,7 @@ void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle /// @see /// - applyTrotterizedPauliStrSumGadget() /// - applyControlledCompMatr1() -void applyTrotterizedControlledPauliStrSumGadget(Qureg qureg, int control, PauliStrSum sum, qreal angle, int order, int reps); +void applyTrotterizedControlledPauliStrSumGadget(Qureg qureg, int control, PauliStrSum sum, qreal angle, int order, int reps, bool randomiseString); /// @notyetdoced @@ -173,7 +176,7 @@ void applyTrotterizedControlledPauliStrSumGadget(Qureg qureg, int control, Pauli /// @see /// - applyTrotterizedPauliStrSumGadget() /// - applyMultiControlledCompMatr1() -void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, int* controls, int numControls, PauliStrSum sum, qreal angle, int order, int reps); +void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, int* controls, int numControls, PauliStrSum sum, qreal angle, int order, int reps, bool randomiseString); /// @notyetdoced @@ -181,7 +184,7 @@ void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, int* controls /// @see /// - applyTrotterizedPauliStrSumGadget() /// - applyMultiStateControlledCompMatr1() -void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, int* controls, int* states, int numControls, PauliStrSum sum, qreal angle, int order, int reps); +void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, int* controls, int* states, int numControls, PauliStrSum sum, qreal angle, int order, int reps, bool randomiseString); /** @notyettested @@ -232,7 +235,7 @@ void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, int* con * * @author Tyson Jones */ -void applyTrotterizedNonUnitaryPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qcomp angle, int order, int reps); +void applyTrotterizedNonUnitaryPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qcomp angle, int order, int reps, bool randomiseString); // end de-mangler @@ -248,7 +251,7 @@ void applyTrotterizedNonUnitaryPauliStrSumGadget(Qureg qureg, PauliStrSum sum, q /// @notyetdoced /// @cppvectoroverload /// @see applyTrotterizedMultiControlledPauliStrSumGadget() -void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, std::vector controls, PauliStrSum sum, qreal angle, int order, int reps); +void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, std::vector controls, PauliStrSum sum, qreal angle, int order, int reps, bool randomiseString); /// @notyettested @@ -256,7 +259,7 @@ void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, std::vector controls, std::vector states, PauliStrSum sum, qreal angle, int order, int reps); +void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, std::vector controls, std::vector states, PauliStrSum sum, qreal angle, int order, int reps, bool randomiseString); #endif // __cplusplus @@ -368,7 +371,7 @@ extern "C" { * * @author Tyson Jones */ -void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal time, int order, int reps); +void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal time, int order, int reps, bool randomiseString); /** @notyettested @@ -499,7 +502,7 @@ void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal * * @author Tyson Jones */ -void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal tau, int order, int reps); +void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal tau, int order, int reps, bool randomiseString); /** @notyettested @@ -646,7 +649,7 @@ void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qrea * * @author Tyson Jones */ -void applyTrotterizedNoisyTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal* damps, PauliStrSum* jumps, int numJumps, qreal time, int order, int reps); +void applyTrotterizedNoisyTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal* damps, PauliStrSum* jumps, int numJumps, qreal time, int order, int reps, bool randomiseString); // end de-mangler diff --git a/quest/src/api/trotterisation.cpp b/quest/src/api/trotterisation.cpp index af25b9615..a57dfc325 100644 --- a/quest/src/api/trotterisation.cpp +++ b/quest/src/api/trotterisation.cpp @@ -15,6 +15,7 @@ #include "quest/src/core/localiser.hpp" #include "quest/src/core/paulilogic.hpp" #include "quest/src/core/errors.hpp" +#include "quest/src/core/randomiser.hpp" #include @@ -84,7 +85,7 @@ void internal_applyHigherOrderTrotterRepetition( void internal_applyAllTrotterRepetitions( Qureg qureg, int* controls, int* states, int numControls, - PauliStrSum sum, qcomp angle, int order, int reps, bool onlyLeftApply + PauliStrSum sum, qcomp angle, int order, int reps, bool onlyLeftApply, bool randomiseString ) { // exp(i angle sum) = identity when angle=0 if (angle == qcomp(0,0)) @@ -98,9 +99,12 @@ void internal_applyAllTrotterRepetitions( qcomp arg = angle / reps; // perform carefully-ordered sequence of gadgets - for (int r=0; r -> U |psi>, rho -> U rho U^dagger bool onlyLeftApply = false; - internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, sum, angle, order, reps, onlyLeftApply); + internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, sum, angle, order, reps, onlyLeftApply, randomiseString); } -void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle, int order, int reps) { +void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle, int order, int reps, bool randomiseString) { validate_quregFields(qureg, __func__); validate_pauliStrSumFields(sum, __func__); validate_pauliStrSumTargets(sum, qureg, __func__); @@ -167,10 +171,13 @@ void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle validate_trotterParams(qureg, order, reps, __func__); bool onlyLeftApply = false; - internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, sum, angle, order, reps, onlyLeftApply); + internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, sum, angle, order, reps, onlyLeftApply, randomiseString); } -void applyTrotterizedControlledPauliStrSumGadget(Qureg qureg, int control, PauliStrSum sum, qreal angle, int order, int reps) { +void applyTrotterizedControlledPauliStrSumGadget( + Qureg qureg, int control, PauliStrSum sum, + qreal angle, int order, int reps, bool randomiseString +) { validate_quregFields(qureg, __func__); validate_pauliStrSumFields(sum, __func__); validate_pauliStrSumIsHermitian(sum, __func__); @@ -178,10 +185,13 @@ void applyTrotterizedControlledPauliStrSumGadget(Qureg qureg, int control, Pauli validate_trotterParams(qureg, order, reps, __func__); bool onlyLeftApply = false; - internal_applyAllTrotterRepetitions(qureg, &control, nullptr, 1, sum, angle, order, reps, onlyLeftApply); + internal_applyAllTrotterRepetitions(qureg, &control, nullptr, 1, sum, angle, order, reps, onlyLeftApply, randomiseString); } -void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, int* controls, int numControls, PauliStrSum sum, qreal angle, int order, int reps) { +void applyTrotterizedMultiControlledPauliStrSumGadget( + Qureg qureg, int* controls, int numControls, PauliStrSum sum, + qreal angle, int order, int reps, bool randomiseString +) { validate_quregFields(qureg, __func__); validate_pauliStrSumFields(sum, __func__); validate_pauliStrSumIsHermitian(sum, __func__); @@ -189,10 +199,13 @@ void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, int* controls validate_trotterParams(qureg, order, reps, __func__); bool onlyLeftApply = false; - internal_applyAllTrotterRepetitions(qureg, controls, nullptr, numControls, sum, angle, order, reps, onlyLeftApply); + internal_applyAllTrotterRepetitions(qureg, controls, nullptr, numControls, sum, angle, order, reps, onlyLeftApply, randomiseString); } -void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, int* controls, int* states, int numControls, PauliStrSum sum, qreal angle, int order, int reps) { +void applyTrotterizedMultiStateControlledPauliStrSumGadget( + Qureg qureg, int* controls, int* states, int numControls, PauliStrSum sum, + qreal angle, int order, int reps, bool randomiseString +) { validate_quregFields(qureg, __func__); validate_pauliStrSumFields(sum, __func__); validate_pauliStrSumIsHermitian(sum, __func__); @@ -201,20 +214,26 @@ void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, int* con validate_trotterParams(qureg, order, reps, __func__); bool onlyLeftApply = false; - internal_applyAllTrotterRepetitions(qureg, controls, states, numControls, sum, angle, order, reps, onlyLeftApply); + internal_applyAllTrotterRepetitions(qureg, controls, states, numControls, sum, angle, order, reps, onlyLeftApply, randomiseString); } } // end de-mangler -void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, vector controls, PauliStrSum sum, qreal angle, int order, int reps) { +void applyTrotterizedMultiControlledPauliStrSumGadget( + Qureg qureg, vector controls, PauliStrSum sum, + qreal angle, int order, int reps, bool randomiseString +) { - applyTrotterizedMultiControlledPauliStrSumGadget(qureg, controls.data(), controls.size(), sum, angle, order, reps); + applyTrotterizedMultiControlledPauliStrSumGadget(qureg, controls.data(), controls.size(), sum, angle, order, reps, randomiseString); } -void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, vector controls, vector states, PauliStrSum sum, qreal angle, int order, int reps) { +void applyTrotterizedMultiStateControlledPauliStrSumGadget( + Qureg qureg, vector controls, vector states, PauliStrSum sum, + qreal angle, int order, int reps, bool randomiseString +) { validate_controlsMatchStates(controls.size(), states.size(), __func__); - applyTrotterizedMultiStateControlledPauliStrSumGadget(qureg, controls.data(), states.data(), controls.size(), sum, angle, order, reps); + applyTrotterizedMultiStateControlledPauliStrSumGadget(qureg, controls.data(), states.data(), controls.size(), sum, angle, order, reps, randomiseString); } @@ -225,7 +244,7 @@ void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, vector Date: Wed, 3 Dec 2025 11:48:29 +0000 Subject: [PATCH 3/4] Document random Pauli permutations for Trotterisation --- quest/include/trotterisation.h | 95 +++++++++++++++++++------------- quest/src/api/trotterisation.cpp | 44 +++++++-------- 2 files changed, 78 insertions(+), 61 deletions(-) diff --git a/quest/include/trotterisation.h b/quest/include/trotterisation.h index 46039fde3..7173c11b3 100644 --- a/quest/include/trotterisation.h +++ b/quest/include/trotterisation.h @@ -43,9 +43,12 @@ extern "C" { * * Effects an approximation to the exponential of @p sum, weighted by @p angle times @f$ i @f$, upon @p qureg, * via the symmetrized Trotter-Suzuki decomposition (arXiv). + * * Increasing @p reps (the number of Trotter repetitions) or @p order (an even, positive integer or one) * improves the accuracy of the approximation by reducing the "Trotter error" due to non-commuting - * terms of @p sum, though increases the runtime linearly and exponentially respectively. + * terms of @p sum, though increases the runtime linearly and exponentially respectively. + * Using @p permutePaulis the ordering of terms in the sum can also be randomised, which generally + * improves the accuracy of the approximation for low order decompositions (arXiv). * * @formulae * @@ -106,6 +109,15 @@ extern "C" { * > These formulations are taken from 'Finding Exponential Product Formulas * > of Higher Orders', Naomichi Hatano and Masuo Suzuki (2005) (arXiv). * + * When @p permutePaulis=true the terms of @p sum are effected in a random order at each repetition. That is, each repetition of the Trotter-Suzuki decomposition is evaluated with the sum + * @f[ + \hat{H} = \sum\limits_j^T c_{\pi(j)} \, \hat{\sigma}_{\pi(j)} + * @f] + * where @f$ \pi @f$ is a randomly selected permutation. + * + * @important + * Using @p permutePaulis=true will cause @p sum to be mutated by the Trotterisation. + * * @equivalences * * - By passing @f$ \theta = - \Delta t / \hbar @f$, this function approximates unitary time evolution of a closed @@ -140,11 +152,12 @@ extern "C" { * - This function only ever effects @f$ \exp \left(\iu \, \theta \, \hat{H} \right) @f$ exactly * when all PauliStr in @p sum = @f$ \hat{H} @f$ commute, or @p reps @f$ \rightarrow \infty @f$. * - * @param[in,out] qureg the state to modify. - * @param[in] sum a weighted sum of Pauli strings to approximately exponentiate. - * @param[in] angle the prefactor of @p sum times @f$ i @f$ in the exponent. - * @param[in] order the order of the Trotter-Suzuki decomposition (e.g. @p 1, @p 2, @p 4, ...). - * @param[in] reps the number of Trotter repetitions. + * @param[in,out] qureg the state to modify. + * @param[in] sum a weighted sum of Pauli strings to approximately exponentiate. + * @param[in] angle the prefactor of @p sum times @f$ i @f$ in the exponent. + * @param[in] order the order of the Trotter-Suzuki decomposition (e.g. @p 1, @p 2, @p 4, ...). + * @param[in] reps the number of Trotter repetitions. + * @param[in] permutePaulis whether to randomly reorder Pauli strings at each repetition. * * @throws @validationerror * - if @p qureg or @p sum are uninitialised. @@ -160,7 +173,7 @@ extern "C" { * * @author Tyson Jones */ -void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle, int order, int reps, bool randomiseString); +void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle, int order, int reps, bool permutePaulis); /// @notyetdoced @@ -168,7 +181,7 @@ void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle /// @see /// - applyTrotterizedPauliStrSumGadget() /// - applyControlledCompMatr1() -void applyTrotterizedControlledPauliStrSumGadget(Qureg qureg, int control, PauliStrSum sum, qreal angle, int order, int reps, bool randomiseString); +void applyTrotterizedControlledPauliStrSumGadget(Qureg qureg, int control, PauliStrSum sum, qreal angle, int order, int reps, bool permutePaulis); /// @notyetdoced @@ -176,7 +189,7 @@ void applyTrotterizedControlledPauliStrSumGadget(Qureg qureg, int control, Pauli /// @see /// - applyTrotterizedPauliStrSumGadget() /// - applyMultiControlledCompMatr1() -void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, int* controls, int numControls, PauliStrSum sum, qreal angle, int order, int reps, bool randomiseString); +void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, int* controls, int numControls, PauliStrSum sum, qreal angle, int order, int reps, bool permutePaulis); /// @notyetdoced @@ -184,7 +197,7 @@ void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, int* controls /// @see /// - applyTrotterizedPauliStrSumGadget() /// - applyMultiStateControlledCompMatr1() -void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, int* controls, int* states, int numControls, PauliStrSum sum, qreal angle, int order, int reps, bool randomiseString); +void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, int* controls, int* states, int numControls, PauliStrSum sum, qreal angle, int order, int reps, bool permutePaulis); /** @notyettested @@ -221,11 +234,12 @@ void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, int* con * - This function only ever effects @f$ \exp \left(\iu \, \theta \, \hat{H} \right) @f$ exactly * when all PauliStr in @p sum = @f$ \hat{H} @f$ commute. * - * @param[in,out] qureg the state to modify. - * @param[in] sum a weighted sum of Pauli strings to approximately exponentiate. - * @param[in] angle an effective prefactor of @p sum in the exponent. - * @param[in] order the order of the Trotter-Suzuki decomposition (e.g. @p 1, @p 2, @p 4, ...). - * @param[in] reps the number of Trotter repetitions. + * @param[in,out] qureg the state to modify. + * @param[in] sum a weighted sum of Pauli strings to approximately exponentiate. + * @param[in] angle an effective prefactor of @p sum in the exponent. + * @param[in] order the order of the Trotter-Suzuki decomposition (e.g. @p 1, @p 2, @p 4, ...). + * @param[in] reps the number of Trotter repetitions. + * @param[in] permutePaulis whether to randomly reorder Pauli strings at each repetition. * * @throws @validationerror * - if @p qureg or @p sum are uninitialised. @@ -235,7 +249,7 @@ void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, int* con * * @author Tyson Jones */ -void applyTrotterizedNonUnitaryPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qcomp angle, int order, int reps, bool randomiseString); +void applyTrotterizedNonUnitaryPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qcomp angle, int order, int reps, bool permutePaulis); // end de-mangler @@ -251,7 +265,7 @@ void applyTrotterizedNonUnitaryPauliStrSumGadget(Qureg qureg, PauliStrSum sum, q /// @notyetdoced /// @cppvectoroverload /// @see applyTrotterizedMultiControlledPauliStrSumGadget() -void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, std::vector controls, PauliStrSum sum, qreal angle, int order, int reps, bool randomiseString); +void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, std::vector controls, PauliStrSum sum, qreal angle, int order, int reps, bool permutePaulis); /// @notyettested @@ -259,7 +273,7 @@ void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, std::vector controls, std::vector states, PauliStrSum sum, qreal angle, int order, int reps, bool randomiseString); +void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, std::vector controls, std::vector states, PauliStrSum sum, qreal angle, int order, int reps, bool permutePaulis); #endif // __cplusplus @@ -356,11 +370,12 @@ extern "C" { * - applyTrotterizedNoisyTimeEvolution() * - applyTrotterizedNonUnitaryPauliStrSumGadget() * - * @param[in,out] qureg the state to modify. - * @param[in] hamil the Hamiltonian as a a weighted sum of Pauli strings. - * @param[in] time the duration over which to simulate evolution. - * @param[in] order the order of the Trotter-Suzuki decomposition (e.g. @p 1, @p 2, @p 4, ...). - * @param[in] reps the number of Trotter repetitions. + * @param[in,out] qureg the state to modify. + * @param[in] hamil the Hamiltonian as a a weighted sum of Pauli strings. + * @param[in] time the duration over which to simulate evolution. + * @param[in] order the order of the Trotter-Suzuki decomposition (e.g. @p 1, @p 2, @p 4, ...). + * @param[in] reps the number of Trotter repetitions. + * @param[in] permutePaulis whether to randomly reorder Pauli strings at each repetition. * * @throws @validationerror * - if @p qureg or @p hamil are uninitialised. @@ -371,7 +386,7 @@ extern "C" { * * @author Tyson Jones */ -void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal time, int order, int reps, bool randomiseString); +void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal time, int order, int reps, bool permutePaulis); /** @notyettested @@ -487,11 +502,12 @@ void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal * - applyTrotterizedUnitaryTimeEvolution() * - applyTrotterizedNonUnitaryPauliStrSumGadget() * - * @param[in,out] qureg the state to modify. - * @param[in] hamil the Hamiltonian as a a weighted sum of Pauli strings. - * @param[in] tau the duration over which to simulate imaginary-time evolution. - * @param[in] order the order of the Trotter-Suzuki decomposition (e.g. @p 1, @p 2, @p 4, ...). - * @param[in] reps the number of Trotter repetitions. + * @param[in,out] qureg the state to modify. + * @param[in] hamil the Hamiltonian as a a weighted sum of Pauli strings. + * @param[in] tau the duration over which to simulate imaginary-time evolution. + * @param[in] order the order of the Trotter-Suzuki decomposition (e.g. @p 1, @p 2, @p 4, ...). + * @param[in] reps the number of Trotter repetitions. + * @param[in] permutePaulis whether to randomly reorder Pauli strings at each repetition. * * @throws @validationerror * - if @p qureg or @p hamil are uninitialised. @@ -502,7 +518,7 @@ void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal * * @author Tyson Jones */ -void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal tau, int order, int reps, bool randomiseString); +void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal tau, int order, int reps, bool permutePaulis); /** @notyettested @@ -625,14 +641,15 @@ void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qrea * - applyTrotterizedUnitaryTimeEvolution() * - applyTrotterizedImaginaryTimeEvolution() * - * @param[in,out] qureg the density-matrix state to evolve and modify. - * @param[in] hamil the Hamiltonian of the qubit system (excludes any environment). - * @param[in] damps the damping rates of each jump operator in @p jumps. - * @param[in] jumps the jump operators specified as PauliStrSum. - * @param[in] numJumps the length of list @p jumps (and @p damps). - * @param[in] time the duration through which to evolve the state. - * @param[in] order the order of the Trotter-Suzuki decomposition (e.g. @p 1, @p 2, @p 4, ...). - * @param[in] reps the number of Trotter repetitions. + * @param[in,out] qureg the density-matrix state to evolve and modify. + * @param[in] hamil the Hamiltonian of the qubit system (excludes any environment). + * @param[in] damps the damping rates of each jump operator in @p jumps. + * @param[in] jumps the jump operators specified as PauliStrSum. + * @param[in] numJumps the length of list @p jumps (and @p damps). + * @param[in] time the duration through which to evolve the state. + * @param[in] order the order of the Trotter-Suzuki decomposition (e.g. @p 1, @p 2, @p 4, ...). + * @param[in] reps the number of Trotter repetitions. + * @param[in] permutePaulis whether to randomly reorder Pauli strings at each repetition. * * @throws @validationerror * - if @p qureg, @p hamil or any element of @p jumps are uninitialised. @@ -649,7 +666,7 @@ void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qrea * * @author Tyson Jones */ -void applyTrotterizedNoisyTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal* damps, PauliStrSum* jumps, int numJumps, qreal time, int order, int reps, bool randomiseString); +void applyTrotterizedNoisyTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal* damps, PauliStrSum* jumps, int numJumps, qreal time, int order, int reps, bool permutePaulis); // end de-mangler diff --git a/quest/src/api/trotterisation.cpp b/quest/src/api/trotterisation.cpp index a57dfc325..700077aa8 100644 --- a/quest/src/api/trotterisation.cpp +++ b/quest/src/api/trotterisation.cpp @@ -85,7 +85,7 @@ void internal_applyHigherOrderTrotterRepetition( void internal_applyAllTrotterRepetitions( Qureg qureg, int* controls, int* states, int numControls, - PauliStrSum sum, qcomp angle, int order, int reps, bool onlyLeftApply, bool randomiseString + PauliStrSum sum, qcomp angle, int order, int reps, bool onlyLeftApply, bool permutePaulis ) { // exp(i angle sum) = identity when angle=0 if (angle == qcomp(0,0)) @@ -100,7 +100,7 @@ void internal_applyAllTrotterRepetitions( // perform carefully-ordered sequence of gadgets for (int r=0; r -> U |psi>, rho -> U rho U^dagger bool onlyLeftApply = false; - internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, sum, angle, order, reps, onlyLeftApply, randomiseString); + internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, sum, angle, order, reps, onlyLeftApply, permutePaulis); } -void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle, int order, int reps, bool randomiseString) { +void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle, int order, int reps, bool permutePaulis) { validate_quregFields(qureg, __func__); validate_pauliStrSumFields(sum, __func__); validate_pauliStrSumTargets(sum, qureg, __func__); @@ -171,12 +171,12 @@ void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle validate_trotterParams(qureg, order, reps, __func__); bool onlyLeftApply = false; - internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, sum, angle, order, reps, onlyLeftApply, randomiseString); + internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, sum, angle, order, reps, onlyLeftApply, permutePaulis); } void applyTrotterizedControlledPauliStrSumGadget( Qureg qureg, int control, PauliStrSum sum, - qreal angle, int order, int reps, bool randomiseString + qreal angle, int order, int reps, bool permutePaulis ) { validate_quregFields(qureg, __func__); validate_pauliStrSumFields(sum, __func__); @@ -185,12 +185,12 @@ void applyTrotterizedControlledPauliStrSumGadget( validate_trotterParams(qureg, order, reps, __func__); bool onlyLeftApply = false; - internal_applyAllTrotterRepetitions(qureg, &control, nullptr, 1, sum, angle, order, reps, onlyLeftApply, randomiseString); + internal_applyAllTrotterRepetitions(qureg, &control, nullptr, 1, sum, angle, order, reps, onlyLeftApply, permutePaulis); } void applyTrotterizedMultiControlledPauliStrSumGadget( Qureg qureg, int* controls, int numControls, PauliStrSum sum, - qreal angle, int order, int reps, bool randomiseString + qreal angle, int order, int reps, bool permutePaulis ) { validate_quregFields(qureg, __func__); validate_pauliStrSumFields(sum, __func__); @@ -199,12 +199,12 @@ void applyTrotterizedMultiControlledPauliStrSumGadget( validate_trotterParams(qureg, order, reps, __func__); bool onlyLeftApply = false; - internal_applyAllTrotterRepetitions(qureg, controls, nullptr, numControls, sum, angle, order, reps, onlyLeftApply, randomiseString); + internal_applyAllTrotterRepetitions(qureg, controls, nullptr, numControls, sum, angle, order, reps, onlyLeftApply, permutePaulis); } void applyTrotterizedMultiStateControlledPauliStrSumGadget( Qureg qureg, int* controls, int* states, int numControls, PauliStrSum sum, - qreal angle, int order, int reps, bool randomiseString + qreal angle, int order, int reps, bool permutePaulis ) { validate_quregFields(qureg, __func__); validate_pauliStrSumFields(sum, __func__); @@ -214,26 +214,26 @@ void applyTrotterizedMultiStateControlledPauliStrSumGadget( validate_trotterParams(qureg, order, reps, __func__); bool onlyLeftApply = false; - internal_applyAllTrotterRepetitions(qureg, controls, states, numControls, sum, angle, order, reps, onlyLeftApply, randomiseString); + internal_applyAllTrotterRepetitions(qureg, controls, states, numControls, sum, angle, order, reps, onlyLeftApply, permutePaulis); } } // end de-mangler void applyTrotterizedMultiControlledPauliStrSumGadget( Qureg qureg, vector controls, PauliStrSum sum, - qreal angle, int order, int reps, bool randomiseString + qreal angle, int order, int reps, bool permutePaulis ) { - applyTrotterizedMultiControlledPauliStrSumGadget(qureg, controls.data(), controls.size(), sum, angle, order, reps, randomiseString); + applyTrotterizedMultiControlledPauliStrSumGadget(qureg, controls.data(), controls.size(), sum, angle, order, reps, permutePaulis); } void applyTrotterizedMultiStateControlledPauliStrSumGadget( Qureg qureg, vector controls, vector states, PauliStrSum sum, - qreal angle, int order, int reps, bool randomiseString + qreal angle, int order, int reps, bool permutePaulis ) { validate_controlsMatchStates(controls.size(), states.size(), __func__); - applyTrotterizedMultiStateControlledPauliStrSumGadget(qureg, controls.data(), states.data(), controls.size(), sum, angle, order, reps, randomiseString); + applyTrotterizedMultiStateControlledPauliStrSumGadget(qureg, controls.data(), states.data(), controls.size(), sum, angle, order, reps, permutePaulis); } @@ -244,7 +244,7 @@ void applyTrotterizedMultiStateControlledPauliStrSumGadget( extern "C" { -void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal time, int order, int reps, bool randomiseString) { +void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal time, int order, int reps, bool permutePaulis) { validate_quregFields(qureg, __func__); validate_pauliStrSumFields(hamil, __func__); validate_pauliStrSumTargets(hamil, qureg, __func__); @@ -254,10 +254,10 @@ void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal // exp(-i t H) = exp(x i H) | x=-t qcomp angle = - time; bool onlyLeftApply = false; - internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, hamil, angle, order, reps, onlyLeftApply, randomiseString); + internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, hamil, angle, order, reps, onlyLeftApply, permutePaulis); } -void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal tau, int order, int reps, bool randomiseString) { +void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal tau, int order, int reps, bool permutePaulis) { validate_quregFields(qureg, __func__); validate_pauliStrSumFields(hamil, __func__); validate_pauliStrSumTargets(hamil, qureg, __func__); @@ -267,7 +267,7 @@ void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qrea // exp(-tau H) = exp(x i H) | x=tau*i qcomp angle = qcomp(0, tau); bool onlyLeftApply = false; - internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, hamil, angle, order, reps, onlyLeftApply, randomiseString); + internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, hamil, angle, order, reps, onlyLeftApply, permutePaulis); } } // end de-mangler @@ -282,7 +282,7 @@ extern "C" { void applyTrotterizedNoisyTimeEvolution( Qureg qureg, PauliStrSum hamil, qreal* damps, PauliStrSum* jumps, - int numJumps, qreal time, int order, int reps, bool randomiseString + int numJumps, qreal time, int order, int reps, bool permutePaulis ) { validate_quregFields(qureg, __func__); validate_quregIsDensityMatrix(qureg, __func__); @@ -368,7 +368,7 @@ void applyTrotterizedNoisyTimeEvolution( // effect exp(t S) = exp(x i S) | x=-i*time, left-multiplying only qcomp angle = qcomp(0, -time); bool onlyLeftApply = true; - internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, superSum, angle, order, reps, onlyLeftApply, randomiseString); + internal_applyAllTrotterRepetitions(qureg, nullptr, nullptr, 0, superSum, angle, order, reps, onlyLeftApply, permutePaulis); } } // end de-mangler From eacf599c9928edfd4bc754554b61bb5ced6c9f56 Mon Sep 17 00:00:00 2001 From: Vasco Ferreira Date: Wed, 3 Dec 2025 11:49:46 +0000 Subject: [PATCH 4/4] Add test for Trotter randomisation --- tests/unit/trotterisation.cpp | 80 +++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 8 deletions(-) diff --git a/tests/unit/trotterisation.cpp b/tests/unit/trotterisation.cpp index cc6914027..dbf16786e 100644 --- a/tests/unit/trotterisation.cpp +++ b/tests/unit/trotterisation.cpp @@ -9,6 +9,11 @@ #include "quest.h" +#include + +#include "tests/utils/cache.hpp" +#include "tests/utils/random.hpp" + /* @@ -19,24 +24,83 @@ LABEL_UNIT_TAG "[trotterisation]" +void TEST_ON_CACHED_QUREGS(quregCache quregs, auto& refFunc, auto& regularFunc, auto& randFunc) { + + for (auto& [label, refQureg]: quregs) { + + DYNAMIC_SECTION( label ) { + initDebugState(refQureg); + + Qureg regularQureg = createCloneQureg(refQureg); + Qureg randQureg = createCloneQureg(refQureg); + + refFunc(refQureg); + regularFunc(regularQureg); + randFunc(randQureg); + + double regularDistance = calcDistance(regularQureg, refQureg); + double randDistance = calcDistance(randQureg, refQureg); + + REQUIRE( randDistance < regularDistance ); + + destroyQureg(regularQureg); + destroyQureg(randQureg); + } + } +} + +/** + * @todo + * Basic validation for randomisation, should be expanded and merged + * once the Trotterisation function tests have been implemented. + */ + +TEST_CASE( "randomisedTrotter", TEST_CATEGORY ) { + + SECTION( LABEL_CORRECTNESS ) { + + int numQubits = getNumCachedQubits(); + int numTerms = 25; + int reps = 50; + double time = 1.0; + + int refOrder = 4; + int order = GENERATE_COPY(1, 2); + + GENERATE( range(0, 10) ); + PauliStrSum sum = createRandomPauliStrSum(numQubits, numTerms); + + auto refFunc = [&](Qureg qureg) { applyTrotterizedUnitaryTimeEvolution(qureg, sum, time, refOrder, reps, false); }; + auto regularFunc = [&](Qureg qureg) { applyTrotterizedUnitaryTimeEvolution(qureg, sum, time, order, reps, false); }; + auto randFunc = [&](Qureg qureg) { applyTrotterizedUnitaryTimeEvolution(qureg, sum, time, order, reps, true); }; + + TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), refFunc, regularFunc, randFunc); + TEST_ON_CACHED_QUREGS(getCachedStatevecs(), refFunc, regularFunc, randFunc); + + destroyPauliStrSum(sum); + + } + +} + /** * @todo * UNTESTED FUNCTIONS */ -void applyTrotterizedNonUnitaryPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qcomp angle, int order, int reps); +void applyTrotterizedNonUnitaryPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qcomp angle, int order, int reps, bool permutePaulis); -void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle, int order, int reps); +void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle, int order, int reps, bool permutePaulis); -void applyTrotterizedControlledPauliStrSumGadget(Qureg qureg, int control, PauliStrSum sum, qreal angle, int order, int reps); +void applyTrotterizedControlledPauliStrSumGadget(Qureg qureg, int control, PauliStrSum sum, qreal angle, int order, int reps, bool permutePaulis); -void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, int* controls, int numControls, PauliStrSum sum, qreal angle, int order, int reps); +void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, int* controls, int numControls, PauliStrSum sum, qreal angle, int order, int reps, bool permutePaulis); -void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, int* controls, int* states, int numControls, PauliStrSum sum, qreal angle, int order, int reps); +void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, int* controls, int* states, int numControls, PauliStrSum sum, qreal angle, int order, int reps, bool permutePaulis); -void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal time, int order, int reps); +void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal time, int order, int reps, bool permutePaulis); -void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal tau, int order, int reps); +void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal tau, int order, int reps, bool permutePaulis); -void applyTrotterizedNoisyTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal* damps, PauliStr* jumps, int numJumps, qreal time, int order, int reps); +void applyTrotterizedNoisyTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal* damps, PauliStr* jumps, int numJumps, qreal time, int order, int reps, bool permutePaulis);