Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions quest/include/paulis.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -99,6 +99,9 @@ typedef struct {
*
* @defgroup paulis_reporters Reporters
* @brief Functions for printing Pauli data structures.
*
* @defgroup paulis_setters Setters
* @brief Functions for overwriting the elements of Pauli data structures.
*/


Expand DownExpand Up@@ -420,6 +423,91 @@ extern "C" {



/*
* SETTERS
*/

// enable invocation by both C and C++ binaries
#ifdef __cplusplus
extern "C" {
#endif


/** @ingroup paulis_setters
*
* Reorders the terms within a @p sum of weighted Pauli strings to sort Pauli
* strings into lexicographic (dictionary) ordering.
*
* @formulae
* Let @f$ H = @f$ @p sum, which can be represented as
* @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
* @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.
*
* @throws @validationerror
* - if @p sum is not initialised.
*
* @see
* - sortPauliStrSumMagnitude()
* @author Vasco Ferreira
*/
void sortPauliStrSumLexicographic(PauliStrSum sum);


/** @ingroup paulis_setters
*
* Reorders the terms within a @p sum of weighted Pauli strings to sort Pauli
* strings into decreasing magnitude weights.
*
* @formulae
* Let @f$ H = @f$ @p sum, represented as the weighted sum
* @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
* @f[
* |c_{\pi(i)}| > |c_{\pi(j)}| \, \forall \, \pi(i) < \pi(j).
* @f]
*
* @param[in,out] sum a weighted sum of Pauli strings to reorder.
*
* @throws @validationerror
* - if @p sum is not initialised.
*
* @see
* - sortPauliStrSumLexicographic()
*
* @author Vasco Ferreira
*/
void sortPauliStrSumMagnitude(PauliStrSum sum);


// end de-mangler
#ifdef __cplusplus
}
#endif



#endif // PAULIS_H

/** @} */ // (end file-wide doxygen defgroup)
30 changes: 30 additions & 0 deletions quest/src/api/paulis.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -291,3 +291,33 @@ extern "C" void reportPauliStrSum(PauliStrSum sum) {
// exclude mandatory newline above
print_oneFewerNewlines();
}



/*
* SORTING
*/


extern "C" void sortPauliStrSumLexicographic(PauliStrSum sum) {
validate_pauliStrSumFields(sum, __func__);

auto lexSort = [&](qindex i, qindex j) {
PauliStr strI = sum.strings[i];
PauliStr strJ = sum.strings[j];
return std::tie(strI.highPaulis, strI.lowPaulis) < std::tie(strJ.highPaulis, strJ.lowPaulis);
};

paulis_sortTermsViaComparator(sum, lexSort);
}


extern "C" void sortPauliStrSumMagnitude(PauliStrSum sum) {
validate_pauliStrSumFields(sum, __func__);

auto magSort = [&](qindex i, qindex j) {
return std::norm(sum.coeffs[i]) > std::norm(sum.coeffs[j]);
};

paulis_sortTermsViaComparator(sum, magSort);
}
34 changes: 34 additions & 0 deletions quest/src/core/paulilogic.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,9 +13,12 @@
#include "quest/src/core/bitwise.hpp"
#include "quest/src/core/errors.hpp"

#include <numeric>
#include <utility>
#include <vector>
#include <array>
#include <functional>
#include <algorithm>

using std::vector;

Expand DownExpand Up@@ -307,6 +310,37 @@ qindex paulis_getTargetBitMask(PauliStrSum sum) {
}


void paulis_applyPermutationToTerms(PauliStrSum sum, vector<qindex> 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<bool(qindex, qindex)> 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<qindex> gatherPermutation(sum.numTerms);
std::iota(gatherPermutation.begin(), gatherPermutation.end(), 0);
std::stable_sort(gatherPermutation.begin(), gatherPermutation.end(), comparator);

// invert permutation and apply
vector<qindex> 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
Expand Down
7 changes: 6 additions & 1 deletion quest/src/core/paulilogic.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,6 +15,7 @@
#include <utility>
#include <vector>
#include <array>
#include <functional>

using std::vector;

Expand DownExpand Up@@ -76,6 +77,10 @@ int paulis_getIndOfLefmostNonIdentityPauli(PauliStrSum sum);

qindex paulis_getTargetBitMask(PauliStrSum sum);

void paulis_applyPermutationToTerms(PauliStrSum sum, vector<qindex> permutation);

void paulis_sortTermsViaComparator(PauliStrSum sum, std::function<bool(qindex, qindex)> comparator);


// below are used exclusively by Trotterisation

Expand All@@ -88,4 +93,4 @@ void paulis_setPauliStrSumToScaledProdOfAdjointWithSelf(PauliStrSum out, qreal f
void paulis_setPauliStrSumToShiftedConj(PauliStrSum out, PauliStrSum in, int numQubits);


#endif // PAULILOGIC_HPP
#endif // PAULILOGIC_HPP
16 changes: 15 additions & 1 deletion quest/src/core/utilities.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -368,7 +368,7 @@ bool util_willSumOverflow(vector<qindex> terms) {


/*
* VECTOR REDUCTION
* LIST PROCESSING
*/

qreal util_getSum(vector<qreal> list) {
Expand All@@ -387,6 +387,20 @@ qreal util_getSum(vector<qreal> list) {
return sum;
}

vector<qindex> util_getInversePermutation(vector<qindex> 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<qindex> out(numTerms);

for (qindex i = 0; i < numTerms; i++)
out[permutation[i]] = i;

return out;
}



/*
Expand Down
6 changes: 4 additions & 2 deletions quest/src/core/utilities.hpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -240,11 +240,13 @@ qcomp* util_getGpuMemPtr(T matr) {


/*
* VECTOR REDUCTION
* LIST PROCESSING
*/

qreal util_getSum(vector<qreal> list);

vector<qindex> util_getInversePermutation(vector<qindex> permutation);



/*
Expand DownExpand Up@@ -430,4 +432,4 @@ void util_tryAllocMatrix(vector<vector<qcomp>> &vec, qindex numRows, qindex numC



#endif // UTILITIES_HPP
#endif // UTILITIES_HPP
55 changes: 55 additions & 0 deletions tests/unit/paulis.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -587,6 +587,61 @@ TEST_CASE( "destroyPauliStrSum", TEST_CATEGORY ) {
}
}

TEST_CASE( "sortPauliStrSumLexicographic", TEST_CATEGORY ) {

SECTION( LABEL_CORRECTNESS ) {

vector<qcomp> coeffs = {0.1_i, 2+1_i, 5, 3+4_i};
vector<PauliStr> strings = {
getPauliStr("XY", {31,32}),
getPauliStr("YX", {0,1}),
getPauliStr("II", {0,1}),
getPauliStr("YY", {31,32})
};

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));

destroyPauliStrSum(sum);
}
}

TEST_CASE( "sortPauliStrSumMagnitude", TEST_CATEGORY ) {

SECTION( LABEL_CORRECTNESS ) {

vector<qcomp> coeffs = {0.1_i, 2+1_i, 5, 3+4_i};
vector<PauliStr> strings = {
getPauliStr("XY", {0,1}),
getPauliStr("ZX", {0,1}),
getPauliStr("II", {0,1}),
getPauliStr("YZ", {0,1})
};

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);

destroyPauliStrSum(sum);
}
}


/** @} (end defgroup) */

Expand Down
Loading