MCPcopy Create free account
hub / github.com/QuEST-Kit/QuEST / localiser_statevec_calcExpecPauliStrSum

Function localiser_statevec_calcExpecPauliStrSum

quest/src/core/localiser.cpp:2078–2151  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

2076
2077
2078qcomp localiser_statevec_calcExpecPauliStrSum(Qureg qureg, PauliStrSum sum) {
2079 assert_localiserGivenStateVec(qureg);
2080
2081 // this function does not process each PauliStr within sum independently; instead, we
2082 // leverage that strings differing only by I <-> Z and X <-> Y in the prefix qubits
2083 // have identical communication patterns, and so can all be processed after one round
2084 // of amps exchange.
2085
2086 /// @todo
2087 /// We can optimise further in a similar spirit to above by grouping identically-
2088 /// communicating strings into those which differ only by suffix I <-> Z and X <-> Y,
2089 /// which have identical amplitude-mixing patterns, to avoid repeated enumeration of
2090 /// all amplitudes and reduce the associated memory-movement / caching costs.
2091 /// (This is facilitated "for free" by cuStateVec in GPU settings, although we do not
2092 /// wish to here differentiate localiser logic based on CPU vs GPU deployment)
2093
2094 qcomp totalValue = 0;
2095
2096 using Key = PAULI_MASK_TYPE;
2097 using Term = tuple<PauliStr,qcomp>;
2098 std::unordered_map<Key, vector<Term>> groups;
2099
2100 // group sum's terms into those with identical communication patterns
2101 for (int i=0; i<sum.numTerms; i++) {
2102 Term term = tuple{sum.strings[i], sum.coeffs[i]};
2103 Key totalKey = paulis_getKeyOfSameMixedAmpsGroup(sum.strings[i]);
2104 Key prefixKey = getBitsLeftOfIndex(totalKey, qureg.logNumAmpsPerNode - 1); // 0 if !qureg.isDistributed
2105
2106 groups[prefixKey].push_back(term);
2107 }
2108
2109 // process each group in-turn
2110 for (auto& [key, terms] : groups) {
2111
2112 // perform communication once per-group, if necessary
2113 int pairRank = flipBits(qureg.rank, key);
2114 if (pairRank != qureg.rank)
2115 comm_exchangeAmpsToBuffers(qureg, pairRank);
2116
2117 // determine backend function to invoke upon all terms in group (likely _subB)
2118 auto termFunc = (pairRank == qureg.rank)?
2119 getStateVecExpecAllSuffixPauliStr :
2120 accel_statevec_calcExpecPauliStr_subB;
2121
2122 // for each term within the current group...
2123 for (auto& [str, coeff] : terms) {
2124 auto [targsX, targsY, targsZ] = paulis_getSeparateInds(str);
2125 auto [prefixX, suffixX] = util_getPrefixAndSuffixQubits(targsX, qureg);
2126 auto [prefixY, suffixY] = util_getPrefixAndSuffixQubits(targsY, qureg);
2127 auto [prefixZ, suffixZ] = util_getPrefixAndSuffixQubits(targsZ, qureg);
2128
2129 // contribute coeff * prefix-coeff * suffix-sum
2130 qcomp termFactor = paulis_getPrefixPaulisElem(qureg, prefixY, prefixZ);
2131 qcomp termValue = termFactor * termFunc(qureg, suffixX, suffixY, suffixZ);
2132
2133 /// @todo
2134 /// use Kahan summation to improve (for free) the accuracy of totalValue
2135 /// here! This sum is always serial, so we should always use it! It is

Callers 2

calcExpecPauliStrSumFunction · 0.85

Calls 9

getBitsLeftOfIndexFunction · 0.85
flipBitsFunction · 0.85
paulis_getSeparateIndsFunction · 0.85
comm_reduceAmpFunction · 0.85

Tested by

no test coverage detected