From 38048c73f1bb61b6514f456dd91b755017de83cc Mon Sep 17 00:00:00 2001 From: TysonRayJones Date: Fri, 29 Aug 2025 00:59:58 +0200 Subject: [PATCH] redirect one-qubit Pauli to CompMatr1 as per #638 Before merging, the performance impact of these changes must be measured in all settings. --- quest/src/api/operations.cpp | 55 +++++++++++++++++++++++++++--------- quest/src/core/utilities.cpp | 48 +++++++++++++++++++++++++++++++ quest/src/core/utilities.hpp | 8 ++++++ 3 files changed, 98 insertions(+), 13 deletions(-) diff --git a/quest/src/api/operations.cpp b/quest/src/api/operations.cpp index a2b09d84..e458605a 100644 --- a/quest/src/api/operations.cpp +++ b/quest/src/api/operations.cpp @@ -859,8 +859,18 @@ void applyMultiStateControlledPauliX(Qureg qureg, int* controls, int* states, in validate_controlsAndTarget(qureg, controls, numControls, target, __func__); validate_controlStates(states, numControls, __func__); // permits states==nullptr - // harmlessly re-validates - applyMultiStateControlledPauliStr(qureg, controls, states, numControls, getPauliStr("X", {target})); + // note that for the single-target scenario, we do not call the backend of + // applyMultiStateControlledPauliStr() since it contains sub-optimal logic + // which sees the factor of every amplitude dynamically evaluated (based on + // index parity, etc); the dense-matrix element lookup is faster + + /// @todo + /// a bespoke all-pauli-X function (like in QuEST v3) will be faster still + /// since it avoids all superfluous flops; check worthwhile for multi-qubit + + // harmlessly re-validates, including hardcoded matrix unitarity + CompMatr1 matrix = util_getPauliX(); + validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matrix, __func__); } void applyMultiStateControlledPauliY(Qureg qureg, int* controls, int* states, int numControls, int target) { @@ -868,8 +878,9 @@ void applyMultiStateControlledPauliY(Qureg qureg, int* controls, int* states, in validate_controlsAndTarget(qureg, controls, numControls, target, __func__); validate_controlStates(states, numControls, __func__); // permits states==nullptr - // harmlessly re-validates - applyMultiStateControlledPauliStr(qureg, controls, states, numControls, getPauliStr("Y", {target})); + // harmlessly re-validates, including hardcoded matrix unitarity + CompMatr1 matrix = util_getPauliY(); + validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matrix, __func__); } void applyMultiStateControlledPauliZ(Qureg qureg, int* controls, int* states, int numControls, int target) { @@ -877,9 +888,9 @@ void applyMultiStateControlledPauliZ(Qureg qureg, int* controls, int* states, in validate_controlsAndTarget(qureg, controls, numControls, target, __func__); validate_controlStates(states, numControls, __func__); // permits states==nullptr - // harmlessly re-validates - DiagMatr1 matr = getDiagMatr1({1, -1}); - applyMultiStateControlledDiagMatr1(qureg, controls, states, numControls, target, matr); + // harmlessly re-validates, including hardcoded matrix unitarity + DiagMatr1 matrix = util_getPauliZ(); + validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matrix, __func__); } } // end de-mangler @@ -1077,8 +1088,14 @@ void applyMultiStateControlledRotateX(Qureg qureg, int* controls, int* states, i validate_controlsAndTarget(qureg, controls, numControls, target, __func__); validate_controlStates(states, numControls, __func__); // permits states==nullptr - // harmlessly re-validates - applyMultiStateControlledPauliGadget(qureg, controls, states, numControls, getPauliStr("X", {target}), angle); + // note that for the single-target scenario, we do not call the backend of + // applyMultiStateControlledPauliGadget() since it contains sub-optimal logic + // which sees the factor of every amplitude dynamically evaluated (based on + // index parity, etc); the dense-matrix element lookup is faster + + // harmlessly re-validates, including hardcoded matrix unitarity + CompMatr1 matrix = util_getExpPauliX(angle); + validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matrix, __func__); } void applyMultiStateControlledRotateY(Qureg qureg, int* controls, int* states, int numControls, int target, qreal angle) { @@ -1086,8 +1103,14 @@ void applyMultiStateControlledRotateY(Qureg qureg, int* controls, int* states, i validate_controlsAndTarget(qureg, controls, numControls, target, __func__); validate_controlStates(states, numControls, __func__); // permits states==nullptr - // harmlessly re-validates - applyMultiStateControlledPauliGadget(qureg, controls, states, numControls, getPauliStr("Y", {target}), angle); + // note that for the single-target scenario, we do not call the backend of + // applyMultiStateControlledPauliGadget() since it contains sub-optimal logic + // which sees the factor of every amplitude dynamically evaluated (based on + // index parity, etc); the dense-matrix element lookup is faster + + // harmlessly re-validates, including hardcoded matrix unitarity + CompMatr1 matrix = util_getExpPauliY(angle); + validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matrix, __func__); } void applyMultiStateControlledRotateZ(Qureg qureg, int* controls, int* states, int numControls, int target, qreal angle) { @@ -1095,8 +1118,14 @@ void applyMultiStateControlledRotateZ(Qureg qureg, int* controls, int* states, i validate_controlsAndTarget(qureg, controls, numControls, target, __func__); validate_controlStates(states, numControls, __func__); // permits states==nullptr - // harmlessly re-validates - applyMultiStateControlledPauliGadget(qureg, controls, states, numControls, getPauliStr("Z", {target}), angle); + // note that for the single-target scenario, we do not call the backend of + // applyMultiStateControlledPauliGadget() since it contains sub-optimal logic + // which sees the factor of every amplitude dynamically evaluated (based on + // index parity, etc); the dense-matrix element lookup is faster + + // harmlessly re-validates, including hardcoded matrix unitarity + DiagMatr1 matrix = util_getExpPauliZ(angle); + validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matrix, __func__); } } // end de-mangler diff --git a/quest/src/core/utilities.cpp b/quest/src/core/utilities.cpp index aba32ef0..4966d191 100644 --- a/quest/src/core/utilities.cpp +++ b/quest/src/core/utilities.cpp @@ -1007,6 +1007,54 @@ qcomp util_getPhaseFromGateAngle(qcomp angle) { return - angle / 2; } +CompMatr1 util_getPauliX() { + return getCompMatr1({ + {0,1}, + {1,0} + }); +} +CompMatr1 util_getPauliY() { + return getCompMatr1({ + {0,qcomp(0,-1)}, + {qcomp(0,1),0} + }); +} +DiagMatr1 util_getPauliZ() { + return getDiagMatr1({1,-1}); +} + +CompMatr1 util_getExpPauliX(qreal angle) { + + qreal x = util_getPhaseFromGateAngle(angle); + qreal c = std::cos(x); + qreal s = std::sin(x); + + return getCompMatr1({ + {qcomp(c,0), qcomp(0,s)}, + {qcomp(0,s), qcomp(c,0)} + }); +} + +CompMatr1 util_getExpPauliY(qreal angle) { + + qreal x = util_getPhaseFromGateAngle(angle); + qreal c = std::cos(x); + qreal s = std::sin(x); + + return getCompMatr1({ + { c, s}, + {-s, c} + }); +} + +DiagMatr1 util_getExpPauliZ(qreal angle) { + + qreal x = util_getPhaseFromGateAngle(angle); + qcomp y = qcomp(0, x); + + return getDiagMatr1({std::exp(y), std::exp(-y)}); +} + /* diff --git a/quest/src/core/utilities.hpp b/quest/src/core/utilities.hpp index e3a92a12..cb2d8e71 100644 --- a/quest/src/core/utilities.hpp +++ b/quest/src/core/utilities.hpp @@ -365,6 +365,14 @@ std::pair util_getBlockMultipleSubRange(qindex rangeLen, qindex qreal util_getPhaseFromGateAngle(qreal angle); qcomp util_getPhaseFromGateAngle(qcomp angle); +CompMatr1 util_getPauliX(); +CompMatr1 util_getPauliY(); +DiagMatr1 util_getPauliZ(); + +CompMatr1 util_getExpPauliX(qreal angle); +CompMatr1 util_getExpPauliY(qreal angle); +DiagMatr1 util_getExpPauliZ(qreal angle); + /*