| 1276 | } |
| 1277 | |
| 1278 | void applyMultiStateControlledPauliGadget(Qureg qureg, int* controls, int* states, int numControls, PauliStr str, qreal angle) { |
| 1279 | validate_quregFields(qureg, __func__); |
| 1280 | validate_controlsAndPauliStrTargets(qureg, controls, numControls, str, __func__); |
| 1281 | validate_controlStates(states, numControls, __func__); // permits states==nullptr |
| 1282 | |
| 1283 | // a non-controlled str=I effects a global phase change (of -angle/2) which does not |
| 1284 | // at all change a density matrix; the subsequent dagger operation would undo it, |
| 1285 | // which we avoid to preserve numerical accuracy |
| 1286 | if (paulis_isIdentity(str) && numControls == 0 && qureg.isDensityMatrix) |
| 1287 | return; |
| 1288 | |
| 1289 | // when numControls >= 1, all amps satisfying the control condition undergo a phase |
| 1290 | // change of -angle/2, as if all non-control-qubits were targeted by exp(-angle/2)I, |
| 1291 | // which is sufficiently efficient using the existing gadget backend function |
| 1292 | |
| 1293 | qreal phase = util_getPhaseFromGateAngle(angle); |
| 1294 | auto ctrlVec = util_getVector(controls, numControls); |
| 1295 | auto stateVec = util_getVector(states, numControls); // empty if states==nullptr |
| 1296 | localiser_statevec_anyCtrlPauliGadget(qureg, ctrlVec, stateVec, str, phase); |
| 1297 | |
| 1298 | if (!qureg.isDensityMatrix) |
| 1299 | return; |
| 1300 | |
| 1301 | // conj(e^(i a P)) = e^(-i s a P) |
| 1302 | phase *= - paulis_getSignOfPauliStrConj(str); |
| 1303 | ctrlVec = util_getBraQubits(ctrlVec, qureg); |
| 1304 | str = paulis_getShiftedPauliStr(str, qureg.numQubits); |
| 1305 | localiser_statevec_anyCtrlPauliGadget(qureg, ctrlVec, stateVec, str, phase); |
| 1306 | } |
| 1307 | |
| 1308 | } // end de-mangler |
| 1309 |
no test coverage detected