| 2024 | |
| 2025 | |
| 2026 | qcomp localiser_statevec_calcExpecPauliStr(Qureg qureg, PauliStr str) { |
| 2027 | assert_localiserGivenStateVec(qureg); |
| 2028 | |
| 2029 | qcomp value = 0; |
| 2030 | |
| 2031 | // partition non-Id Paulis into prefix and suffix, since... |
| 2032 | // - prefix X,Y determine communication, because they apply bit-not to rank |
| 2033 | // - prefix Y,Z determine node-wide coefficient, because they contain rank-determined !=1 elements |
| 2034 | // - suffix X,Y,Z determine local amp coefficients |
| 2035 | // noting that when !qureg.isDistributed, all paulis will be in suffix |
| 2036 | auto [targsX, targsY, targsZ] = paulis_getSeparateInds(str); |
| 2037 | auto [prefixX, suffixX] = util_getPrefixAndSuffixQubits(targsX, qureg); |
| 2038 | auto [prefixY, suffixY] = util_getPrefixAndSuffixQubits(targsY, qureg); |
| 2039 | auto [prefixZ, suffixZ] = util_getPrefixAndSuffixQubits(targsZ, qureg); |
| 2040 | |
| 2041 | // embarrassingly parallel when there is only Z's in prefix (which themselves are handled afterward) |
| 2042 | if (prefixX.empty() && prefixY.empty()) { |
| 2043 | value = getStateVecExpecAllSuffixPauliStr(qureg, suffixX, suffixY, suffixZ); |
| 2044 | |
| 2045 | // otherwise, communication is pairwise exchange |
| 2046 | } else { |
| 2047 | auto prefixXY = util_getConcatenated(prefixX, prefixY); |
| 2048 | int pairRank = util_getRankWithQubitsFlipped(prefixXY, qureg); |
| 2049 | comm_exchangeAmpsToBuffers(qureg, pairRank); |
| 2050 | |
| 2051 | value = accel_statevec_calcExpecPauliStr_subB(qureg, suffixX, suffixY, suffixZ); |
| 2052 | } |
| 2053 | |
| 2054 | // apply this node's pre-factor |
| 2055 | value *= paulis_getPrefixPaulisElem(qureg, prefixY, prefixZ); |
| 2056 | |
| 2057 | // combine contributions from each node |
| 2058 | if (qureg.isDistributed) |
| 2059 | comm_reduceAmp(&value); |
| 2060 | |
| 2061 | return value; |
| 2062 | } |
| 2063 | |
| 2064 | |
| 2065 | qcomp localiser_densmatr_calcExpecPauliStr(Qureg qureg, PauliStr str) { |
no test coverage detected