@@ -1115,6 +1115,169 @@ TEST_CASE( "multiControlledMultiQubitUnitary", "[unitaries]" ) {
1115
1115
1116
1116
1117
1117
1118
+ /* * @sa multiControlledMultiRotatePauli
1119
+ * @ingroup unittest
1120
+ * @author Tyson Jones
1121
+ */
1122
+ TEST_CASE ( " multiControlledMultiRotatePauli" , " [unitaries]" ) {
1123
+
1124
+ PREPARE_TEST ( quregVec, quregMatr, refVec, refMatr );
1125
+ qreal param = getRandomReal (-4 *M_PI, 4 *M_PI);
1126
+
1127
+ SECTION ( " correctness" ) {
1128
+
1129
+ // try all possible numbers of targets and controls
1130
+ int numTargs = GENERATE_COPY ( range (1 ,NUM_QUBITS) ); // leave space for min 1 control qubit
1131
+ int maxNumCtrls = NUM_QUBITS - numTargs;
1132
+ int numCtrls = GENERATE_COPY ( range (1 ,maxNumCtrls+1 ) );
1133
+
1134
+ // generate all possible valid qubit arrangements
1135
+ int * targs = GENERATE_COPY ( sublists (range (0 ,NUM_QUBITS), numTargs) );
1136
+ int * ctrls = GENERATE_COPY ( sublists (range (0 ,NUM_QUBITS), numCtrls, targs, numTargs) );
1137
+
1138
+ /* it's too expensive to try ALL Pauli sequences, via
1139
+ * pauliOpType* paulis = GENERATE_COPY( pauliseqs(numTargs) );.
1140
+ * Furthermore, take(10, pauliseqs(numTargs)) will try the same pauli codes.
1141
+ * Hence, we instead opt to randomly generate pauliseqs
1142
+ */
1143
+ pauliOpType paulis[numTargs];
1144
+ for (int i=0 ; i<numTargs; i++)
1145
+ paulis[i] = (pauliOpType) getRandomInt (0 ,4 );
1146
+
1147
+ // exclude identities from reference matrix exp (they apply unwanted global phase)
1148
+ int refTargs[numTargs];
1149
+ int numRefTargs = 0 ;
1150
+
1151
+ QMatrix xMatr{{0 ,1 },{1 ,0 }};
1152
+ QMatrix yMatr{{0 ,-qcomp (0 ,1 )},{qcomp (0 ,1 ),0 }};
1153
+ QMatrix zMatr{{1 ,0 },{0 ,-1 }};
1154
+
1155
+ // build correct reference matrix by pauli-matrix exponentiation...
1156
+ QMatrix pauliProd{{1 }};
1157
+ for (int i=0 ; i<numTargs; i++) {
1158
+ QMatrix fac;
1159
+ if (paulis[i] == PAULI_I) continue ; // exclude I-targets from ref list
1160
+ if (paulis[i] == PAULI_X) fac = xMatr;
1161
+ if (paulis[i] == PAULI_Y) fac = yMatr;
1162
+ if (paulis[i] == PAULI_Z) fac = zMatr;
1163
+ pauliProd = getKroneckerProduct (fac, pauliProd);
1164
+
1165
+ // include this target in ref list
1166
+ refTargs[numRefTargs++] = targs[i];
1167
+ }
1168
+
1169
+ // produces exp(-i param/2 pauliProd), unless pauliProd = I
1170
+ QMatrix op;
1171
+ if (numRefTargs > 0 )
1172
+ op = getExponentialOfPauliMatrix (param, pauliProd);
1173
+
1174
+ SECTION ( " state-vector" ) {
1175
+
1176
+ multiControlledMultiRotatePauli (quregVec, ctrls, numCtrls, targs, paulis, numTargs, param);
1177
+ if (numRefTargs > 0 )
1178
+ applyReferenceOp (refVec, ctrls, numCtrls, refTargs, numRefTargs, op);
1179
+ REQUIRE ( areEqual (quregVec, refVec) );
1180
+ }
1181
+ SECTION ( " density-matrix" ) {
1182
+
1183
+ multiControlledMultiRotatePauli (quregMatr, ctrls, numCtrls, targs, paulis, numTargs, param);
1184
+ if (numRefTargs > 0 )
1185
+ applyReferenceOp (refMatr, ctrls, numCtrls, refTargs, numRefTargs, op);
1186
+ REQUIRE ( areEqual (quregMatr, refMatr, 10 *REAL_EPS) );
1187
+ }
1188
+ }
1189
+ SECTION ( " input validation" ) {
1190
+
1191
+ // test all validation on both state-vector and density-matrix.
1192
+ // want GENERATE_COPY( quregVec, quregMatr ), but too lazy to patch
1193
+ // using github.com/catchorg/Catch2/issues/1809
1194
+ Qureg regs[] = {quregVec, quregMatr};
1195
+ Qureg qureg = regs[GENERATE (0 ,1 )];
1196
+
1197
+ // over-sized array to prevent seg-fault in case of validation fail below
1198
+ pauliOpType paulis[NUM_QUBITS+1 ];
1199
+ for (int q=0 ; q<NUM_QUBITS+1 ; q++)
1200
+ paulis[q] = PAULI_I;
1201
+
1202
+ SECTION ( " pauli codes" ) {
1203
+
1204
+ int numCtrls = 1 ;
1205
+ int ctrls[] = {3 };
1206
+ int numTargs = 3 ;
1207
+ int targs[3 ] = {0 , 1 , 2 };
1208
+
1209
+ // make a single Pauli invalid
1210
+ paulis[GENERATE_COPY (range (0 ,numTargs))] = (pauliOpType) GENERATE ( -1 , 4 );
1211
+
1212
+ REQUIRE_THROWS_WITH ( multiControlledMultiRotatePauli (qureg, ctrls, numCtrls, targs, paulis, numTargs, param), Contains (" Invalid Pauli code" ));
1213
+ }
1214
+ SECTION ( " number of targets" ) {
1215
+
1216
+ // there cannot be more targets than qubits in register
1217
+ // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
1218
+ int numTargs = GENERATE ( -1 , 0 , NUM_QUBITS+1 );
1219
+ int numCtrls = 1 ;
1220
+ int targs[NUM_QUBITS+1 ]; // prevents seg-fault if validation doesn't trigger
1221
+ int ctrls[] = {0 };
1222
+
1223
+ REQUIRE_THROWS_WITH ( multiControlledMultiRotatePauli (qureg, ctrls, numCtrls, targs, paulis, numTargs, param), Contains (" Invalid number of target" ) );
1224
+ }
1225
+ SECTION ( " repetition in targets" ) {
1226
+
1227
+ int numCtrls = 1 ;
1228
+ int numTargs = 3 ;
1229
+ int ctrls[] = {0 };
1230
+ int targs[] = {1 ,2 ,2 };
1231
+
1232
+ REQUIRE_THROWS_WITH ( multiControlledMultiRotatePauli (qureg, ctrls, numCtrls, targs, paulis, numTargs, param), Contains (" target" ) && Contains (" unique" ));
1233
+ }
1234
+ SECTION ( " number of controls" ) {
1235
+
1236
+ int numCtrls = GENERATE ( -1 , 0 , NUM_QUBITS, NUM_QUBITS+1 );
1237
+ int numTargs = 1 ;
1238
+ int ctrls[NUM_QUBITS+1 ]; // avoids seg-fault if validation not triggered
1239
+ int targs[1 ] = {0 };
1240
+
1241
+ REQUIRE_THROWS_WITH ( multiControlledMultiRotatePauli (qureg, ctrls, numCtrls, targs, paulis, numTargs, param), Contains (" Invalid number of control" ));
1242
+ }
1243
+ SECTION ( " repetition in controls" ) {
1244
+
1245
+ int numCtrls = 3 ;
1246
+ int numTargs = 1 ;
1247
+ int ctrls[] = {0 ,1 ,1 };
1248
+ int targs[] = {3 };
1249
+
1250
+ REQUIRE_THROWS_WITH ( multiControlledMultiRotatePauli (qureg, ctrls, numCtrls, targs, paulis, numTargs, param), Contains (" control" ) && Contains (" unique" ));
1251
+ }
1252
+ SECTION ( " control and target collision" ) {
1253
+
1254
+ int numCtrls = 3 ;
1255
+ int numTargs = 3 ;
1256
+ int ctrls[] = {0 ,1 ,2 };
1257
+ int targs[] = {3 ,1 ,4 };
1258
+
1259
+ REQUIRE_THROWS_WITH ( multiControlledMultiRotatePauli (qureg, ctrls, numCtrls, targs, paulis, numTargs, param), Contains (" Control" ) && Contains (" target" ) && Contains (" disjoint" ));
1260
+ }
1261
+ SECTION ( " qubit indices" ) {
1262
+
1263
+ // valid inds
1264
+ int numQb = 2 ;
1265
+ int qb1[2 ] = {0 ,1 };
1266
+ int qb2[2 ] = {2 ,3 };
1267
+
1268
+ // make qb1 invalid
1269
+ int inv = GENERATE ( -1 , NUM_QUBITS );
1270
+ qb1[GENERATE_COPY (range (0 ,numQb))] = inv;
1271
+
1272
+ REQUIRE_THROWS_WITH ( multiControlledMultiRotatePauli (qureg, qb1, numQb, qb2, paulis, numQb, param), Contains (" Invalid control" ) );
1273
+ REQUIRE_THROWS_WITH ( multiControlledMultiRotatePauli (qureg, qb2, numQb, qb1, paulis, numQb, param), Contains (" Invalid target" ) );
1274
+ }
1275
+ }
1276
+ CLEANUP_TEST ( quregVec, quregMatr );
1277
+ }
1278
+
1279
+
1280
+
1118
1281
/* * @sa multiControlledMultiRotateZ
1119
1282
* @ingroup unittest
1120
1283
* @author Tyson Jones
0 commit comments