diff --git a/quest/include/paulis.h b/quest/include/paulis.h
index e4645923..275b0036 100644
--- a/quest/include/paulis.h
+++ b/quest/include/paulis.h
@@ -66,11 +66,16 @@ typedef struct {
qindex numTerms;
- // arbitrarily-sized collection of Pauli strings and their
- // coefficients are stored in heap memory.
+ // numTerms-sized collection of Pauli strings and their
+ // corresponding coefficients, stored in heap memory.
PauliStr* strings;
qcomp* coeffs;
+ // numTerms-sized list of term indices, consulted by some
+ // routines (such as Trotter functions) to effectively
+ // reorder the terms (strings and coeffs)
+ qindex* ordering;
+
// whether the sum constitutes a Hermitian operator (0, 1, or -1 to indicate unknown),
// which is lazily evaluated when a function validates Hermiticity them. The flag is
// stored in heap so even copies of structs are mutable, but the pointer is immutable;
@@ -101,7 +106,7 @@ typedef struct {
* @brief Functions for printing Pauli data structures.
*
* @defgroup paulis_setters Setters
- * @brief Functions for overwriting the elements of Pauli data structures.
+ * @brief Functions for modifying existing Pauli data structures.
*/
@@ -435,27 +440,26 @@ extern "C" {
/** @ingroup paulis_setters
*
- * Reorders the terms within a @p sum of weighted Pauli strings to sort Pauli
- * strings into lexicographic (dictionary) ordering.
+ * Reorders the terms within a @p sum of weighted Pauli strings so that Pauli strings
+ * are ordered lexicographically.
+ *
+ * This affects @p sum.ordering, and will change the behaviour of functions like
+ * applyTrotterizedPauliStrSumGadget() when randomised ordering is disabled.
*
* @formulae
- * Let @f$ H = @f$ @p sum, which can be represented as
+ *
+ * Let @f$ H = @f$ @p sum, satisfying
* @f[
H = \sum\limits_j c_j \, \hat{\sigma}_j
* @f]
* where @f$ c_j @f$ is the coefficient of the @f$ j @f$-th PauliStr @f$ \hat{\sigma}_j @f$.
*
- * This function constructs and applies the permutation @f$ \pi @f$ to @f$ H @f$
- * @f[
- H = \sum\limits_j c_{\pi(j)} \, \hat{\sigma}_{\pi(j)}
- * @f]
- * such that
+ * This function modifies @p sum.ordering to the permutation @f$ \pi @f$ such that
* @f[
* \hat{\sigma}_{\pi(i)} <_{lex} \hat{\sigma}_{\pi(j)} \ \forall \ \pi(i) < \pi(j).
* @f]
*
- *
- * @param[in,out] sum a weighted sum of Pauli strings to reorder.
+ * @param[in,out] sum a weighted sum of Pauli strings to reorder (via @p sum.ordering)
*
* @throws @validationerror
* - if @p sum is not initialised.
@@ -469,21 +473,21 @@ extern "C" {
/** @ingroup paulis_setters
*
- * Reorders the terms within a @p sum of weighted Pauli strings to sort Pauli
- * strings into decreasing magnitude weights.
+ * Reorders the terms within a @p sum of weighted Pauli strings such that
+ * coefficients are ordered with decreasing magnitude.
+ *
+ * This affects only @p sum.ordering, and will change the behaviour of functions like
+ * applyTrotterizedPauliStrSumGadget() when randomised ordering is disabled.
*
* @formulae
- * Let @f$ H = @f$ @p sum, represented as the weighted sum
+ *
+ * Let @f$ H = @f$ @p sum, satisfying
* @f[
H = \sum\limits_j c_j \, \hat{\sigma}_j
* @f]
* where @f$ c_j @f$ is the coefficient of the @f$ j @f$-th PauliStr @f$ \hat{\sigma}_j @f$.
*
- * This function constructs and applies the permutation @f$ \pi @f$ to @f$ H @f$
- * @f[
- H = \sum\limits_j c_{\pi(j)} \, \hat{\sigma}_{\pi(j)}
- * @f]
- * such that
+ * This function modifies @p sum.ordering to the permutation @f$ \pi @f$ such that
* @f[
* |c_{\pi(i)}| > |c_{\pi(j)}| \, \forall \, \pi(i) < \pi(j).
* @f]
diff --git a/quest/include/trotterisation.h b/quest/include/trotterisation.h
index 9e7cad25..3bfc9191 100644
--- a/quest/include/trotterisation.h
+++ b/quest/include/trotterisation.h
@@ -109,14 +109,16 @@ 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
+ * 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.
+ * where @f$ \pi @f$ is a randomly selected permutation. When @p permutePaulis=false, the fixed
+ * ordering @f$ \pi = @f$ @p sum.ordering is used.
*
* @important
- * Using @p permutePaulis=true will cause @p sum to be mutated by the Trotterisation.
+ * Using @p permutePaulis=true will mutate the ordering of @p sum (specifically @p sum.ordering).
*
* @equivalences
*
@@ -153,7 +155,8 @@ extern "C" {
* 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,out] sum a weighted sum of Pauli strings to approximately exponentiate,
+ * with ordering mutated when @p permutePaulis=true.
* @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.
@@ -248,7 +251,8 @@ void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, int* con
* 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,out] sum a weighted sum of Pauli strings to approximately exponentiate,
+ * with ordering mutated when @p permutePaulis=true.
* @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.
@@ -391,7 +395,8 @@ extern "C" {
* - applyTrotterizedNonUnitaryPauliStrSumGadget()
*
* @param[in,out] qureg the state to modify.
- * @param[in] hamil the Hamiltonian as a a weighted sum of Pauli strings.
+ * @param[in,out] hamil the Hamiltonian as a a weighted sum of Pauli strings,
+ * with ordering mutated when @p permutePaulis=true.
* @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.
@@ -522,7 +527,8 @@ void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal
* - applyTrotterizedNonUnitaryPauliStrSumGadget()
*
* @param[in,out] qureg the state to modify.
- * @param[in] hamil the Hamiltonian as a a weighted sum of Pauli strings.
+ * @param[in,out] hamil the Hamiltonian as a a weighted sum of Pauli strings,
+ * with ordering mutated when @p permutePaulis=true.
* @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.
@@ -548,6 +554,11 @@ void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qrea
* evolution approximated by symmetrized Trotterisation of the specified @p order and number of cycles
* @p reps.
*
+ * Note the ordering of all passed PauliStrSum (through functions like sortPauliStrSumMagnitude()) will
+ * affect that of the internally created super-propagator and ergo the Trotter accuracy. This is overridden
+ * by passing @p permutePaulis=true, whereby the super-propagator order is randomised every Trotter repetition.
+ * This never mutates the ordering of all passed PauliStrSum.
+ *
* @formulae
*
* Let @f$ \rho = @f$ @p qureg, @f$ \hat{H} = @f$ @p hamil, @f$ t = @f$ @p time, and denote the @f$ i @f$-th
diff --git a/quest/src/api/paulis.cpp b/quest/src/api/paulis.cpp
index e7f85a88..7853af5b 100644
--- a/quest/src/api/paulis.cpp
+++ b/quest/src/api/paulis.cpp
@@ -20,6 +20,8 @@
#include
#include
+#include
+#include
using std::string;
using std::vector;
@@ -34,8 +36,9 @@ using std::vector;
bool didAnyAllocsFailOnAnyNode(PauliStrSum sum) {
bool anyFail = (
- ! mem_isAllocated(sum.strings) ||
- ! mem_isAllocated(sum.coeffs) ||
+ ! mem_isAllocated(sum.strings) ||
+ ! mem_isAllocated(sum.coeffs) ||
+ ! mem_isAllocated(sum.ordering) ||
! mem_isAllocated(sum.isApproxHermitian) );
if (comm_isInit())
@@ -50,6 +53,7 @@ void freePauliStrSum(PauliStrSum sum) {
// these do not need to be allocated (freeing nullptr is legal)
cpu_deallocPauliStrings(sum.strings);
cpu_deallocArray(sum.coeffs);
+ cpu_deallocIndices(sum.ordering);
util_deallocEpsilonSensitiveHeapFlag(sum.isApproxHermitian);
}
@@ -173,6 +177,7 @@ extern "C" PauliStrSum createPauliStrSum(PauliStr* strings, qcomp* coeffs, qinde
out.numTerms = numTerms;
out.strings = cpu_allocPauliStrings(numTerms); // nullptr if failed
out.coeffs = cpu_allocArray(numTerms); // nullptr if failed
+ out.ordering = cpu_allocIndices(numTerms); // nullptr if failed
out.isApproxHermitian = util_allocEpsilonSensitiveHeapFlag(); // nullptr if failed
// if either alloc failed, clear both before validation to avoid leak
@@ -182,6 +187,7 @@ extern "C" PauliStrSum createPauliStrSum(PauliStr* strings, qcomp* coeffs, qinde
// otherwise copy given data into new heap structure, and set initial flags
cpu_copyPauliStrSum(out, strings, coeffs);
util_setFlagToUnknown(out.isApproxHermitian);
+ std::iota(out.ordering, out.ordering + out.numTerms, 0);
return out;
}
@@ -308,7 +314,8 @@ extern "C" void sortPauliStrSumLexicographic(PauliStrSum sum) {
return std::tie(strI.highPaulis, strI.lowPaulis) < std::tie(strJ.highPaulis, strJ.lowPaulis);
};
- paulis_sortTermsViaComparator(sum, lexSort);
+ std::iota(sum.ordering, sum.ordering + sum.numTerms, 0);
+ std::stable_sort(sum.ordering, sum.ordering + sum.numTerms, lexSort);
}
@@ -319,5 +326,6 @@ extern "C" void sortPauliStrSumMagnitude(PauliStrSum sum) {
return std::norm(sum.coeffs[i]) > std::norm(sum.coeffs[j]);
};
- paulis_sortTermsViaComparator(sum, magSort);
+ std::iota(sum.ordering, sum.ordering + sum.numTerms, 0);
+ std::stable_sort(sum.ordering, sum.ordering + sum.numTerms, magSort);
}
diff --git a/quest/src/api/trotterisation.cpp b/quest/src/api/trotterisation.cpp
index 700077aa..cf0583f5 100644
--- a/quest/src/api/trotterisation.cpp
+++ b/quest/src/api/trotterisation.cpp
@@ -18,6 +18,7 @@
#include "quest/src/core/randomiser.hpp"
#include
+#include
using std::vector;
@@ -33,9 +34,12 @@ void internal_applyFirstOrderTrotterRepetition(
) {
// apply each sum term as a gadget, in forward or reverse order
for (qindex i=0; i -> exp(i angle * coeff * term)|psi>
qcomp arg = angle * coeff;
@@ -100,16 +104,18 @@ void internal_applyAllTrotterRepetitions(
// perform carefully-ordered sequence of gadgets
for (int r=0; r superStrings;
vector superCoeffs;
- auto callbackString = [&]() { validate_tempAllocSucceeded(false, numSuperTerms, sizeof(PauliStr), __func__); };
- auto callbackCoeff = [&]() { validate_tempAllocSucceeded(false, numSuperTerms, sizeof(qcomp), __func__); };
- util_tryAllocVector(superStrings, numSuperTerms, callbackString);
- util_tryAllocVector(superCoeffs, numSuperTerms, callbackCoeff);
-
+ vector superOrdering;
+ auto callbackString = [&]() { validate_tempAllocSucceeded(false, numSuperTerms, sizeof(PauliStr), __func__); };
+ auto callbackCoeff = [&]() { validate_tempAllocSucceeded(false, numSuperTerms, sizeof(qcomp), __func__); };
+ auto callbackOrdering = [&]() { validate_tempAllocSucceeded(false, numSuperTerms, sizeof(qindex), __func__); };
+ util_tryAllocVector(superStrings, numSuperTerms, callbackString);
+ util_tryAllocVector(superCoeffs, numSuperTerms, callbackCoeff);
+ util_tryAllocVector(superOrdering, numSuperTerms, callbackOrdering);
+
+ // construct super-propagator term by term, in an order affected by
+ // both hamil.ordering and jumps[].ordering (inside paulis_setters())
qindex superTermInd = 0;
// collect -i[H,rho] terms
for (qindex n=0; n
#include
#include
-#include
-#include
using std::vector;
@@ -310,37 +308,6 @@ qindex paulis_getTargetBitMask(PauliStrSum sum) {
}
-void paulis_applyPermutationToTerms(PauliStrSum sum, vector scatterPermutation) {
- // permutation passed by value since we modify it
-
- // scatterPermutation[i] = destination index for element originally at i
- for (qindex i = 0; i < sum.numTerms; i++) {
- while (scatterPermutation[i] != i) {
- qindex j = scatterPermutation[i];
- std::swap(sum.strings[i], sum.strings[j]);
- std::swap(sum.coeffs[i], sum.coeffs[j]);
- std::swap(scatterPermutation[i], scatterPermutation[j]);
- }
- }
-}
-
-
-void paulis_sortTermsViaComparator(PauliStrSum sum, std::function comparator) {
-
- // TODO: below is an unguarded vector alloc, forgiven since a subsequent
- // change (giving PauliStrSum an 'ordering' list) supersedes it
-
- // gatherPermutation[j] = source index of element placed at j
- vector gatherPermutation(sum.numTerms);
- std::iota(gatherPermutation.begin(), gatherPermutation.end(), 0);
- std::stable_sort(gatherPermutation.begin(), gatherPermutation.end(), comparator);
-
- // invert permutation and apply
- vector scatterPermutation = util_getInversePermutation(gatherPermutation);
- paulis_applyPermutationToTerms(sum, scatterPermutation);
-}
-
-
void paulis_setPauliStrSumToScaledTensorProdOfConjWithSelf(PauliStrSum out, qreal factor, PauliStrSum in, int numQubits) {
// sets out = factor * conj(in) (x) in, where in has dim of numQubits
@@ -354,9 +321,13 @@ void paulis_setPauliStrSumToScaledTensorProdOfConjWithSelf(PauliStrSum out, qrea
for (qindex j=0; j
#include
#include
-#include
using std::vector;
@@ -77,10 +76,6 @@ int paulis_getIndOfLefmostNonIdentityPauli(PauliStrSum sum);
qindex paulis_getTargetBitMask(PauliStrSum sum);
-void paulis_applyPermutationToTerms(PauliStrSum sum, vector permutation);
-
-void paulis_sortTermsViaComparator(PauliStrSum sum, std::function comparator);
-
// below are used exclusively by Trotterisation
diff --git a/quest/src/core/randomiser.cpp b/quest/src/core/randomiser.cpp
index 1e9b4a94..554d929d 100644
--- a/quest/src/core/randomiser.cpp
+++ b/quest/src/core/randomiser.cpp
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
using std::vector;
@@ -271,18 +272,13 @@ qcomp rand_getThreadPrivateRandomAmp(std::mt19937_64 &gen, std::normal_distribut
/*
- * PAULI STRINGS
+ * PAULI STRING SUM PERMUTATION
*/
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]);
- }
+ // reset ordering to a valid [0,numTerms) before shuffling
+ std::iota(sum.ordering, sum.ordering + sum.numTerms, 0);
+ std::shuffle(sum.ordering, sum.ordering + sum.numTerms, mainGenerator);
}
diff --git a/quest/src/core/utilities.cpp b/quest/src/core/utilities.cpp
index a5ca635b..e7265fd5 100644
--- a/quest/src/core/utilities.cpp
+++ b/quest/src/core/utilities.cpp
@@ -387,20 +387,6 @@ qreal util_getSum(vector list) {
return sum;
}
-vector util_getInversePermutation(vector permutation) {
-
- // TODO: below is an unguarded vector alloc, forgiven since a subsequent
- // change (giving PauliStrSum an 'ordering' list) supersedes it
-
- qindex numTerms = permutation.size();
- vector out(numTerms);
-
- for (qindex i = 0; i < numTerms; i++)
- out[permutation[i]] = i;
-
- return out;
-}
-
/*
@@ -1211,6 +1197,7 @@ void tryAllocVector(vector &vec, qindex size, std::function errFunc)
void util_tryAllocVector(vector &vec, qindex size, std::function errFunc) { tryAllocVector(vec, size, errFunc); }
void util_tryAllocVector(vector &vec, qindex size, std::function errFunc) { tryAllocVector(vec, size, errFunc); }
void util_tryAllocVector(vector &vec, qindex size, std::function errFunc) { tryAllocVector(vec, size, errFunc); }
+void util_tryAllocVector(vector &vec, qindex size, std::function errFunc) { tryAllocVector(vec, size, errFunc); }
void util_tryAllocVector(vector &vec, qindex size, std::function errFunc) { tryAllocVector(vec, size, errFunc); }
void util_tryAllocVector(vector &vec, qindex size, std::function errFunc) { tryAllocVector(vec, size, errFunc); }
diff --git a/quest/src/core/utilities.hpp b/quest/src/core/utilities.hpp
index f2d7087e..181d4bec 100644
--- a/quest/src/core/utilities.hpp
+++ b/quest/src/core/utilities.hpp
@@ -245,8 +245,6 @@ qcomp* util_getGpuMemPtr(T matr) {
qreal util_getSum(vector list);
-vector util_getInversePermutation(vector permutation);
-
/*
@@ -420,6 +418,7 @@ vector util_getVector(Qureg* ptr, int length);
void util_tryAllocVector(vector &vec, qindex size, std::function errFunc);
void util_tryAllocVector(vector &vec, qindex size, std::function errFunc);
void util_tryAllocVector(vector &vec, qindex size, std::function errFunc);
+void util_tryAllocVector(vector &vec, qindex size, std::function errFunc);
void util_tryAllocVector(vector &vec, qindex size, std::function errFunc);
void util_tryAllocVector(vector &vec, qindex size, std::function errFunc);
diff --git a/quest/src/core/validation.cpp b/quest/src/core/validation.cpp
index 3ac48505..649840a0 100644
--- a/quest/src/core/validation.cpp
+++ b/quest/src/core/validation.cpp
@@ -3339,8 +3339,9 @@ void validate_pauliStrSumFields(PauliStrSum sum, const char* caller) {
assertThat(sum.numTerms > 0, report::INVALID_PAULI_STR_SUM_FIELDS, {{"${NUM_TERMS}", sum.numTerms}}, caller);
- assertThat(mem_isAllocated(sum.coeffs), report::INVALID_PAULI_STR_HEAP_PTR, caller);
- assertThat(mem_isAllocated(sum.strings), report::INVALID_PAULI_STR_HEAP_PTR, caller);
+ assertThat(mem_isAllocated(sum.coeffs), report::INVALID_PAULI_STR_HEAP_PTR, caller);
+ assertThat(mem_isAllocated(sum.strings), report::INVALID_PAULI_STR_HEAP_PTR, caller);
+ assertThat(mem_isAllocated(sum.ordering), report::INVALID_PAULI_STR_HEAP_PTR, caller);
assertThat(mem_isAllocated(sum.isApproxHermitian), report::INVALID_HEAP_FLAG_PTR, caller);
@@ -3350,6 +3351,9 @@ void validate_pauliStrSumFields(PauliStrSum sum, const char* caller) {
{"${BAD_FLAG}", flag},
{"${UNKNOWN_FLAG}", validate_STRUCT_PROPERTY_UNKNOWN_FLAG}};
assertThat(flag == 0 || flag == 1 || flag == validate_STRUCT_PROPERTY_UNKNOWN_FLAG, report::INVALID_HEAP_FLAG_VALUE, vars, caller);
+
+ // note we DO NOT check whether sum.ordering is valid, i.e. whether it is a unique list of
+ // integers from 0 to sum.numTerms (exclusive) in an arbitrary order
}
void validate_pauliStrSumIsHermitian(PauliStrSum sum, const char* caller) {
diff --git a/quest/src/cpu/cpu_config.cpp b/quest/src/cpu/cpu_config.cpp
index c11ec224..cd1ab084 100644
--- a/quest/src/cpu/cpu_config.cpp
+++ b/quest/src/cpu/cpu_config.cpp
@@ -412,6 +412,16 @@ void cpu_deallocPauliStrings(PauliStr* strings) {
free(strings);
}
+qindex* cpu_allocIndices(qindex length) {
+ return (qindex*) calloc(length, sizeof(qindex));
+}
+
+void cpu_deallocIndices(qindex* indices) {
+
+ // safe to free if nullptr
+ free(indices);
+}
+
/*
diff --git a/quest/src/cpu/cpu_config.hpp b/quest/src/cpu/cpu_config.hpp
index 21d39e35..5b422362 100644
--- a/quest/src/cpu/cpu_config.hpp
+++ b/quest/src/cpu/cpu_config.hpp
@@ -43,6 +43,8 @@ int cpu_getCurrentNumThreads();
* MEMORY ALLOCATION
*/
+long cpu_getPageSize();
+
qcomp* cpu_allocArray(qindex length);
void cpu_deallocArray(qcomp* arr);
@@ -64,8 +66,9 @@ void cpu_deallocHeapFlag(int* ptr);
PauliStr* cpu_allocPauliStrings(qindex numStrings);
void cpu_deallocPauliStrings(PauliStr* strings);
+qindex* cpu_allocIndices(qindex length);
+void cpu_deallocIndices(qindex* indices);
-long cpu_getPageSize();
/*
diff --git a/tests/unit/paulis.cpp b/tests/unit/paulis.cpp
index e3339100..86a620ad 100644
--- a/tests/unit/paulis.cpp
+++ b/tests/unit/paulis.cpp
@@ -591,10 +591,11 @@ TEST_CASE( "sortPauliStrSumLexicographic", TEST_CATEGORY ) {
SECTION( LABEL_CORRECTNESS ) {
- vector coeffs = {0.1_i, 2+1_i, 5, 3+4_i};
+ vector coeffs = {0.1_i, 2+1_i, 5, 3+4_i, .3}; // ignored
vector strings = {
getPauliStr("XY", {31,32}),
getPauliStr("YX", {0,1}),
+ getPauliStr("YX", {1,0}),
getPauliStr("II", {0,1}),
getPauliStr("YY", {31,32})
};
@@ -602,14 +603,15 @@ TEST_CASE( "sortPauliStrSumLexicographic", TEST_CATEGORY ) {
PauliStrSum sum = createPauliStrSum(strings, coeffs);
sortPauliStrSumLexicographic(sum);
- REQUIRE(sum.coeffs[0] == 5+0_i);
- REQUIRE(sum.coeffs[1] == 2+1_i);
- REQUIRE(sum.coeffs[3] == 3+4_i);
-
- REQUIRE(sum.strings[0].lowPaulis == 0);
- REQUIRE(sum.strings[1].lowPaulis == 2 + 1*4);
- REQUIRE(sum.strings[3].highPaulis == 2);
- REQUIRE(sum.strings[3].lowPaulis == 2*std::pow(4, 31));
+ vector refOrder = {
+ 3, // I1 I0
+ 1, // X1 Y0
+ 2, // Y1 X0
+ 0, // Y32 X31
+ 4 // Y32 Y31
+ };
+ vector apiOrder = vector(sum.ordering, sum.ordering + sum.numTerms);
+ REQUIRE( refOrder == apiOrder );
destroyPauliStrSum(sum);
}
@@ -630,13 +632,10 @@ TEST_CASE( "sortPauliStrSumMagnitude", TEST_CATEGORY ) {
PauliStrSum sum = createPauliStrSum(strings, coeffs);
sortPauliStrSumMagnitude(sum);
- REQUIRE(sum.coeffs[0] == 5+0_i);
- REQUIRE(sum.coeffs[1] == 3+4_i);
- REQUIRE(sum.coeffs[3] == 0+0.1_i);
-
- REQUIRE(sum.strings[0].lowPaulis == 0);
- REQUIRE(sum.strings[1].lowPaulis == 2 + 3*4);
- REQUIRE(sum.strings[3].lowPaulis == 1 + 2*4);
+ // sorting is stable, so coeff=5 precedes coeff=3+4i
+ vector refOrder = {2, 3, 1, 0};
+ vector apiOrder = vector(sum.ordering, sum.ordering + sum.numTerms);
+ REQUIRE( refOrder == apiOrder );
destroyPauliStrSum(sum);
}