The Quantum Exact Simulation Toolkit v4.3.0
Loading...
Searching...
No Matches
operations.cpp
1/** @file
2 * API definitions for effecting operators (including
3 * unitaries, projectors, channels, Hermitians, and
4 * arbitrary matrices) upon Quregs, which can be
5 * statevectors or density matrices.
6 *
7 * @author Tyson Jones
8 */
9
10#include "quest/include/qureg.h"
11#include "quest/include/paulis.h"
12#include "quest/include/matrices.h"
13#include "quest/include/operations.h"
14#include "quest/include/calculations.h"
15
16#include "quest/src/core/validation.hpp"
17#include "quest/src/core/utilities.hpp"
18#include "quest/src/core/randomiser.hpp"
19#include "quest/src/core/localiser.hpp"
20#include "quest/src/core/bitwise.hpp"
21#include "quest/src/core/constants.hpp"
22#include "quest/src/core/paulilogic.hpp"
23
24#include <vector>
25
26using std::vector;
27
28
29
30/*
31 * PRVIATE UTILITIES
32 */
33
34// T can be CompMatr, CompMatr1, CompMatr2, DiagMatr, DiagMatr1, DiagMatr2
35template <class T>
36void validateAndApplyAnyCtrlAnyTargUnitaryMatrix(Qureg qureg, int* ctrls, int* states, int numCtrls, int* targs, int numTargs, T matr, const char* caller) {
37 validate_quregFields(qureg, caller);
38 validate_controlsAndTargets(qureg, ctrls, numCtrls, targs, numTargs, caller);
39 validate_controlStates(states, numCtrls, caller);
40 validate_matrixDimMatchesTargets(matr, numTargs, caller); // also checks fields and is-synced
41 validate_matrixIsUnitary(matr, caller); // harmlessly rechecks fields and is-synced
42 if (util_isDenseMatrixType<T>())
43 validate_mixedAmpsFitInNode(qureg, numTargs, caller);
44
45 List64 ctrlList = lists_getList64(ctrls, numCtrls);
46 List64 stateList = util_getList64OrAllOnes(states, numCtrls);
47 List64 targList = lists_getList64(targs, numTargs);
48
49 bool conj = false;
50 localiser_statevec_anyCtrlAnyTargAnyMatr(qureg, ctrlList, stateList, targList, matr, conj);
51
52 if (!qureg.isDensityMatrix)
53 return;
54
55 conj = true;
56 ctrlList = util_getBraQubits(ctrlList, qureg);
57 targList = util_getBraQubits(targList, qureg);
58 localiser_statevec_anyCtrlAnyTargAnyMatr(qureg, ctrlList, stateList, targList, matr, conj);
59
60 /// @todo
61 /// the above logic always performs two in-turn operations upon density matrices,
62 /// though when matr is diagonal (DiagMatr*), they can be trivially combined into
63 /// a single operation which enumerates the state only once. We perform this
64 /// optimisation for FullStateDiagMatr elsewhere. Consider optimising here too!
65}
66
67
68
69/*
70 * CompMatr1
71 */
72
73extern "C" {
74
75void applyCompMatr1(Qureg qureg, int target, CompMatr1 matrix) {
76
77 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, nullptr, nullptr, 0, &target, 1, matrix, __func__);
78}
79
80void applyControlledCompMatr1(Qureg qureg, int control, int target, CompMatr1 matrix) {
81
82 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, &control, nullptr, 1, &target, 1, matrix, __func__);
83}
84
85void applyMultiControlledCompMatr1(Qureg qureg, int* controls, int numControls, int target, CompMatr1 matrix) {
86
87 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, nullptr, numControls, &target, 1, matrix, __func__);
88}
89
90void applyMultiStateControlledCompMatr1(Qureg qureg, int* controls, int* states, int numControls, int target, CompMatr1 matrix) {
91
92 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matrix, __func__);
93}
94
95} // end de-mangler
96
97void applyMultiControlledCompMatr1(Qureg qureg, vector<int> controls, int target, CompMatr1 matrix) {
98
99 applyMultiControlledCompMatr1(qureg, controls.data(), controls.size(), target, matrix);
100}
101
102void applyMultiStateControlledCompMatr1(Qureg qureg, vector<int> controls, vector<int> states, int target, CompMatr1 matrix) {
103 validate_controlsMatchStates(controls.size(), states.size(), __func__);
104
105 applyMultiStateControlledCompMatr1(qureg, controls.data(), states.data(), controls.size(), target, matrix);
106}
107
108
109
110/*
111 * CompMatr2
112 */
113
114extern "C" {
115
116void applyCompMatr2(Qureg qureg, int target1, int target2, CompMatr2 matrix) {
117
118 int targs[] = {target1, target2};
119 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, nullptr, nullptr, 0, targs, 2, matrix, __func__);
120}
121
122void applyControlledCompMatr2(Qureg qureg, int control, int target1, int target2, CompMatr2 matrix) {
123
124 int targs[] = {target1, target2};
125 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, &control, nullptr, 1, targs, 2, matrix, __func__);
126}
127
128void applyMultiControlledCompMatr2(Qureg qureg, int* controls, int numControls, int target1, int target2, CompMatr2 matrix) {
129
130 int targs[] = {target1, target2};
131 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, nullptr, numControls, targs, 2, matrix, __func__);
132}
133
134void applyMultiStateControlledCompMatr2(Qureg qureg, int* controls, int* states, int numControls, int target1, int target2, CompMatr2 matrix) {
135
136 int targs[] = {target1, target2};
137 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, targs, 2, matrix, __func__);
138}
139
140} // end de-mangler
141
142void applyMultiControlledCompMatr2(Qureg qureg, vector<int> controls, int target1, int target2, CompMatr2 matr) {
143
144 applyMultiControlledCompMatr2(qureg, controls.data(), controls.size(), target1, target2, matr);
145}
146
147void applyMultiStateControlledCompMatr2(Qureg qureg, vector<int> controls, vector<int> states, int target1, int target2, CompMatr2 matr) {
148 validate_controlsMatchStates(controls.size(), states.size(), __func__);
149
150 applyMultiStateControlledCompMatr2(qureg, controls.data(), states.data(), controls.size(), target1, target2, matr);
151}
152
153
154
155/*
156 * CompMatr
157 */
158
159extern "C" {
160
161void applyCompMatr(Qureg qureg, int* targets, int numTargets, CompMatr matrix) {
162
163 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, nullptr, nullptr, 0, targets, numTargets, matrix, __func__);
164}
165
166void applyControlledCompMatr(Qureg qureg, int control, int* targets, int numTargets, CompMatr matrix) {
167
168 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, &control, nullptr, 1, targets, numTargets, matrix, __func__);
169}
170
171void applyMultiControlledCompMatr(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, CompMatr matrix) {
172
173 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, nullptr, numControls, targets, numTargets, matrix, __func__);
174}
175
176void applyMultiStateControlledCompMatr(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, CompMatr matrix) {
177
178 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, targets, numTargets, matrix, __func__);
179}
180
181} // end de-mangler
182
183void applyCompMatr(Qureg qureg, vector<int> targets, CompMatr matr) {
184
185 applyCompMatr(qureg, targets.data(), targets.size(), matr);
186}
187
188void applyControlledCompMatr(Qureg qureg, int control, vector<int> targets, CompMatr matr) {
189
190 applyControlledCompMatr(qureg, control, targets.data(), targets.size(), matr);
191}
192
193void applyMultiControlledCompMatr(Qureg qureg, vector<int> controls, vector<int> targets, CompMatr matr) {
194
195 applyMultiControlledCompMatr(qureg, controls.data(), controls.size(), targets.data(), targets.size(), matr);
196}
197
198void applyMultiStateControlledCompMatr(Qureg qureg, vector<int> controls, vector<int> states, vector<int> targets, CompMatr matr) {
199 validate_controlsMatchStates(controls.size(), states.size(), __func__);
200
201 applyMultiStateControlledCompMatr(qureg, controls.data(), states.data(), controls.size(), targets.data(), targets.size(), matr);
202}
203
204
205
206/*
207 * DiagMatr1
208 */
209
210extern "C" {
211
212void applyDiagMatr1(Qureg qureg, int target, DiagMatr1 matrix) {
213
214 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, nullptr, nullptr, 0, &target, 1, matrix, __func__);
215}
216
217void applyControlledDiagMatr1(Qureg qureg, int control, int target, DiagMatr1 matrix) {
218
219 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, &control, nullptr, 1, &target, 1, matrix, __func__);
220}
221
222void applyMultiControlledDiagMatr1(Qureg qureg, int* controls, int numControls, int target, DiagMatr1 matrix) {
223
224 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, nullptr, numControls, &target, 1, matrix, __func__);
225}
226
227void applyMultiStateControlledDiagMatr1(Qureg qureg, int* controls, int* states, int numControls, int target, DiagMatr1 matrix) {
228
229 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matrix, __func__);
230}
231
232} // end de-mangler
233
234void applyMultiControlledDiagMatr1(Qureg qureg, vector<int> controls, int target, DiagMatr1 matr) {
235
236 applyMultiControlledDiagMatr1(qureg, controls.data(), controls.size(), target, matr);
237}
238
239void applyMultiStateControlledDiagMatr1(Qureg qureg, vector<int> controls, vector<int> states, int target, DiagMatr1 matr) {
240 validate_controlsMatchStates(controls.size(), states.size(), __func__);
241
242 applyMultiStateControlledDiagMatr1(qureg, controls.data(), states.data(), controls.size(), target, matr);
243}
244
245
246
247/*
248 * DiagMatr2
249 */
250
251extern "C" {
252
253void applyDiagMatr2(Qureg qureg, int target1, int target2, DiagMatr2 matrix) {
254
255 int targs[] = {target1, target2};
256 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, nullptr, nullptr, 0, targs, 2, matrix, __func__);
257}
258
259void applyControlledDiagMatr2(Qureg qureg, int control, int target1, int target2, DiagMatr2 matrix) {
260
261 int targs[] = {target1, target2};
262 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, &control, nullptr, 1, targs, 2, matrix, __func__);
263}
264
265void applyMultiControlledDiagMatr2(Qureg qureg, int* controls, int numControls, int target1, int target2, DiagMatr2 matrix) {
266
267 int targs[] = {target1, target2};
268 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, nullptr, numControls, targs, 2, matrix, __func__);
269}
270
271void applyMultiStateControlledDiagMatr2(Qureg qureg, int* controls, int* states, int numControls, int target1, int target2, DiagMatr2 matrix) {
272
273 int targs[] = {target1, target2};
274 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, targs, 2, matrix, __func__);
275}
276
277} // end de-mangler
278
279void applyMultiControlledDiagMatr2(Qureg qureg, vector<int> controls, int target1, int target2, DiagMatr2 matr) {
280
281 applyMultiControlledDiagMatr2(qureg, controls.data(), controls.size(), target1, target2, matr);
282}
283
284void applyMultiStateControlledDiagMatr2(Qureg qureg, vector<int> controls, vector<int> states, int target1, int target2, DiagMatr2 matr) {
285 validate_controlsMatchStates(controls.size(), states.size(), __func__);
286
287 applyMultiStateControlledDiagMatr2(qureg, controls.data(), states.data(), controls.size(), target1, target2, matr);
288}
289
290
291
292/*
293 * DiagMatr
294 */
295
296extern "C" {
297
298void applyDiagMatr(Qureg qureg, int* targets, int numTargets, DiagMatr matrix) {
299
300 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, nullptr, nullptr, 0, targets, numTargets, matrix, __func__);
301}
302
303void applyControlledDiagMatr(Qureg qureg, int control, int* targets, int numTargets, DiagMatr matrix) {
304
305 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, &control, nullptr, 1, targets, numTargets, matrix, __func__);
306}
307
308void applyMultiControlledDiagMatr(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, DiagMatr matrix) {
309
310 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, nullptr, numControls, targets, numTargets, matrix, __func__);
311}
312
313void applyMultiStateControlledDiagMatr(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, DiagMatr matrix) {
314
315 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, targets, numTargets, matrix, __func__);
316}
317
318} // end de-mangler
319
320void applyDiagMatr(Qureg qureg, vector<int> targets, DiagMatr matrix) {
321
322 applyDiagMatr(qureg, targets.data(), targets.size(), matrix);
323}
324
325void applyControlledDiagMatr(Qureg qureg, int control, vector<int> targets, DiagMatr matrix) {
326
327 applyControlledDiagMatr(qureg, control, targets.data(), targets.size(), matrix);
328}
329
330void applyMultiControlledDiagMatr(Qureg qureg, vector<int> controls, vector<int> targets, DiagMatr matrix) {
331
332 applyMultiControlledDiagMatr(qureg, controls.data(), controls.size(), targets.data(), targets.size(), matrix);
333}
334
335void applyMultiStateControlledDiagMatr(Qureg qureg, vector<int> controls, vector<int> states, vector<int> targets, DiagMatr matrix) {
336 validate_controlsMatchStates(controls.size(), states.size(), __func__);
337
338 applyMultiStateControlledDiagMatr(qureg, controls.data(), states.data(), controls.size(), targets.data(), targets.size(), matrix);
339}
340
341
342
343/*
344 * DiagMatrPower
345 *
346 * which still assert unitarity despite that passing
347 * a non-real exponent is permitted
348 */
349
350extern "C" {
351
352void applyDiagMatrPower(Qureg qureg, int* targets, int numTargets, DiagMatr matrix, qcomp exponent) {
353 validate_quregFields(qureg, __func__);
354 validate_targets(qureg, targets, numTargets, __func__);
355 validate_matrixDimMatchesTargets(matrix, numTargets, __func__); // also checks fields and is-synced
356 validate_matrixIsUnitary(matrix, __func__);
357 validate_matrixExpIsNonDiverging(matrix, exponent, __func__);
358 validate_unitaryExponentIsReal(exponent, __func__);
359
360 // notice exponent is a 'qcomp' not a 'qreal' despite validation; see applyMultiStateControlledDiagMatrPower()
361
362 // harmlessly re-validates
363 applyMultiStateControlledDiagMatrPower(qureg, nullptr, nullptr, 0, targets, numTargets, matrix, exponent);
364}
365
366void applyControlledDiagMatrPower(Qureg qureg, int control, int* targets, int numTargets, DiagMatr matrix, qcomp exponent) {
367 validate_quregFields(qureg, __func__);
368 validate_controlAndTargets(qureg, control, targets, numTargets, __func__);
369 validate_matrixDimMatchesTargets(matrix, numTargets, __func__); // also checks fields and is-synced
370 validate_matrixIsUnitary(matrix, __func__);
371 validate_matrixExpIsNonDiverging(matrix, exponent, __func__);
372 validate_unitaryExponentIsReal(exponent, __func__);
373
374 // notice exponent is a 'qcomp' not a 'qreal' despite validation; see applyMultiStateControlledDiagMatrPower()
375
376 // harmlessly re-validates
377 applyMultiStateControlledDiagMatrPower(qureg, &control, nullptr, 1, targets, numTargets, matrix, exponent);
378}
379
380void applyMultiControlledDiagMatrPower(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, DiagMatr matrix, qcomp exponent) {
381 validate_quregFields(qureg, __func__);
382 validate_controlsAndTargets(qureg, controls, numControls, targets, numTargets, __func__);
383 validate_matrixDimMatchesTargets(matrix, numTargets, __func__); // also checks fields and is-synced
384 validate_matrixIsUnitary(matrix, __func__);
385 validate_matrixExpIsNonDiverging(matrix, exponent, __func__);
386 validate_unitaryExponentIsReal(exponent, __func__);
387
388 // notice exponent is a 'qcomp' not a 'qreal' despite validation; see applyMultiStateControlledDiagMatrPower()
389
390 // harmlessly re-validates
391 applyMultiStateControlledDiagMatrPower(qureg, controls, nullptr, numControls, targets, numTargets, matrix, exponent);
392}
393
394void applyMultiStateControlledDiagMatrPower(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, DiagMatr matrix, qcomp exponent) {
395 validate_quregFields(qureg, __func__);
396 validate_controlsAndTargets(qureg, controls, numControls, targets, numTargets, __func__);
397 validate_controlStates(states, numControls, __func__); // can be nullptr, ignoring numControls
398 validate_matrixDimMatchesTargets(matrix, numTargets, __func__);
399 validate_matrixIsUnitary(matrix, __func__);
400 validate_matrixExpIsNonDiverging(matrix, exponent, __func__);
401 validate_unitaryExponentIsReal(exponent, __func__);
402
403 // unlike calcExpecDiagMatrPower which accepts a 'qreal' exponent,
404 // this function accepts a 'qcomp'. This is because it always
405 // evaluates the relatively numerically unstable pow(qcomp,qcomp)
406 // overload, rather than pow(qreal,qreal), since there is no reason
407 // to think matrix is real (unitarity permits it to be complex).
408 // As such, despite unitarity requiring exponent is also real, we
409 // accept a qcomp types so that complex exponents can be passed
410 // when numerical validation is disabled without a separate func.
411
412 bool conj = false;
413 auto ctrlList = lists_getList64(controls, numControls);
414 auto stateList = util_getList64OrAllOnes(states, numControls);
415 auto targList = lists_getList64(targets, numTargets);
416 localiser_statevec_anyCtrlAnyTargDiagMatr(qureg, ctrlList, stateList, targList, matrix, exponent, conj);
417
418 if (!qureg.isDensityMatrix)
419 return;
420
421 conj = true;
422 ctrlList = util_getBraQubits(ctrlList, qureg);
423 targList = util_getBraQubits(targList, qureg);
424 localiser_statevec_anyCtrlAnyTargDiagMatr(qureg, ctrlList, stateList, targList, matrix, exponent, conj);
425}
426
427} // end de-mangler
428
429void applyDiagMatrPower(Qureg qureg, vector<int> targets, DiagMatr matrix, qcomp exponent) {
430
431 applyDiagMatrPower(qureg, targets.data(), targets.size(), matrix, exponent);
432}
433
434void applyControlledDiagMatrPower(Qureg qureg, int control, vector<int> targets, DiagMatr matrix, qcomp exponent) {
435
436 applyControlledDiagMatrPower(qureg, control, targets.data(), targets.size(), matrix, exponent);
437}
438
439void applyMultiControlledDiagMatrPower(Qureg qureg, vector<int> controls, vector<int> targets, DiagMatr matrix, qcomp exponent) {
440
441 applyMultiControlledDiagMatrPower(qureg, controls.data(), controls.size(), targets.data(), targets.size(), matrix, exponent);
442}
443
444void applyMultiStateControlledDiagMatrPower(Qureg qureg, vector<int> controls, vector<int> states, vector<int> targets, DiagMatr matrix, qcomp exponent) {
445 validate_controlsMatchStates(controls.size(), states.size(), __func__);
446
447 applyMultiStateControlledDiagMatrPower(qureg, controls.data(), states.data(), controls.size(), targets.data(), targets.size(), matrix, exponent);
448}
449
450
451
452/*
453 * FullStateDiagMatr (and power)
454 */
455
456extern "C" {
457
459 validate_quregFields(qureg, __func__);
460 validate_matrixFields(matrix, __func__);
461 validate_matrixAndQuregAreCompatible(matrix, qureg, false, __func__);
462 validate_matrixIsUnitary(matrix, __func__);
463
464 applyFullStateDiagMatrPower(qureg, matrix, 1); // harmlessly re-validates
465}
466
467void applyFullStateDiagMatrPower(Qureg qureg, FullStateDiagMatr matrix, qcomp exponent) {
468 validate_quregFields(qureg, __func__);
469 validate_matrixFields(matrix, __func__);
470 validate_matrixAndQuregAreCompatible(matrix, qureg, false, __func__);
471 validate_matrixIsUnitary(matrix, __func__);
472 validate_unitaryExponentIsReal(exponent, __func__);
473 validate_matrixExpIsNonDiverging(matrix, exponent, __func__);
474
475 // rho -> matrix^exponent rho conj(matrix^exponent)
476 bool leftMultiply = true;
477 bool rightMultiply = true;
478 bool rightConj = true;
479
480 (qureg.isDensityMatrix)?
481 localiser_densmatr_allTargDiagMatr(qureg, matrix, exponent, leftMultiply, rightMultiply, rightConj):
482 localiser_statevec_allTargDiagMatr(qureg, matrix, exponent);
483}
484
485} // end de-mangler
486
487
488
489/*
490 * S gate
491 */
492
493extern "C" {
494
495void applyS(Qureg qureg, int target) {
496 validate_quregFields(qureg, __func__);
497 validate_target(qureg, target, __func__);
498
499 // harmlessly re-validates
500 applyMultiStateControlledS(qureg, nullptr, nullptr, 0, target);
501}
502
503void applyControlledS(Qureg qureg, int control, int target) {
504 validate_quregFields(qureg, __func__);
505 validate_controlAndTarget(qureg, control, target, __func__);
506
507 // harmlessly re-validates
508 applyMultiStateControlledS(qureg, &control, nullptr, 1, target);
509}
510
511void applyMultiControlledS(Qureg qureg, int* controls, int numControls, int target) {
512 validate_quregFields(qureg, __func__);
513 validate_controlsAndTarget(qureg, controls, numControls, target, __func__);
514
515 // harmlessly re-validates
516 applyMultiStateControlledS(qureg, controls, nullptr, numControls, target);
517}
518
519void applyMultiStateControlledS(Qureg qureg, int* controls, int* states, int numControls, int target) {
520
521 static const DiagMatr1 matr = getDiagMatr1({1, 1_i});
522 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matr, __func__);
523}
524
525} // end de-mangler
526
527void applyMultiControlledS(Qureg qureg, vector<int> controls, int target) {
528
529 applyMultiControlledS(qureg, controls.data(), controls.size(), target);
530}
531
532void applyMultiStateControlledS(Qureg qureg, vector<int> controls, vector<int> states, int target) {
533 validate_controlsMatchStates(controls.size(), states.size(), __func__);
534
535 applyMultiStateControlledS(qureg, controls.data(), states.data(), controls.size(), target);
536}
537
538
539
540/*
541 * T gate
542 */
543
544extern "C" {
545
546void applyT(Qureg qureg, int target) {
547 validate_quregFields(qureg, __func__);
548 validate_target(qureg, target, __func__);
549
550 // harmlessly re-validates
551 applyMultiStateControlledT(qureg, nullptr, nullptr, 0, target);
552}
553
554void applyControlledT(Qureg qureg, int control, int target) {
555 validate_quregFields(qureg, __func__);
556 validate_controlAndTarget(qureg, control, target, __func__);
557
558 // harmlessly re-validates
559 applyMultiStateControlledT(qureg, &control, nullptr, 1, target);
560}
561
562void applyMultiControlledT(Qureg qureg, int* controls, int numControls, int target) {
563 validate_quregFields(qureg, __func__);
564 validate_controlsAndTarget(qureg, controls, numControls, target, __func__);
565
566 // harmlessly re-validates
567 applyMultiStateControlledT(qureg, controls, nullptr, numControls, target);
568}
569
570void applyMultiStateControlledT(Qureg qureg, int* controls, int* states, int numControls, int target) {
571
572 static const DiagMatr1 matr = getDiagMatr1({1, (1 + 1_i)/std::sqrt(2)});
573 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matr, __func__);
574}
575
576} // end de-mangler
577
578void applyMultiControlledT(Qureg qureg, vector<int> controls, int target) {
579
580 applyMultiControlledT(qureg, controls.data(), controls.size(), target);
581}
582
583void applyMultiStateControlledT(Qureg qureg, vector<int> controls, vector<int> states, int target) {
584 validate_controlsMatchStates(controls.size(), states.size(), __func__);
585
586 applyMultiStateControlledT(qureg, controls.data(), states.data(), controls.size(), target);
587}
588
589
590
591/*
592 * Hadamard
593 */
594
595extern "C" {
596
597void applyHadamard(Qureg qureg, int target) {
598 validate_quregFields(qureg, __func__);
599 validate_target(qureg, target, __func__);
600
601 // harmlessly re-validates
602 applyMultiStateControlledHadamard(qureg, nullptr, nullptr, 0, target);
603}
604
605void applyControlledHadamard(Qureg qureg, int control, int target) {
606 validate_quregFields(qureg, __func__);
607 validate_controlAndTarget(qureg, control, target, __func__);
608
609 // harmlessly re-validates
610 applyMultiStateControlledHadamard(qureg, &control, nullptr, 1, target);
611}
612
613void applyMultiControlledHadamard(Qureg qureg, int* controls, int numControls, int target) {
614 validate_quregFields(qureg, __func__);
615 validate_controlsAndTarget(qureg, controls, numControls, target, __func__);
616
617 // harmlessly re-validates
618 applyMultiStateControlledHadamard(qureg, controls, nullptr, numControls, target);
619}
620
621void applyMultiStateControlledHadamard(Qureg qureg, int* controls, int* states, int numControls, int target) {
622
623 static const qcomp a = 1 / std::sqrt(2);
624 static const CompMatr1 matr = getCompMatr1({
625 {a, a},
626 {a, -a}
627 });
628 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matr, __func__);
629}
630
631} // end de-mangler
632
633void applyMultiControlledHadamard(Qureg qureg, vector<int> controls, int target) {
634
635 applyMultiControlledHadamard(qureg, controls.data(), controls.size(), target);
636}
637
638void applyMultiStateControlledHadamard(Qureg qureg, vector<int> controls, vector<int> states, int target) {
639 validate_controlsMatchStates(controls.size(), states.size(), __func__);
640
641 applyMultiStateControlledHadamard(qureg, controls.data(), states.data(), controls.size(), target);
642}
643
644
645
646/*
647 * swap
648 */
649
650extern "C" {
651
652void applySwap(Qureg qureg, int qubit1, int qubit2) {
653 validate_quregFields(qureg, __func__);
654 validate_twoTargets(qureg, qubit1, qubit2, __func__);
655
656 // harmlessly re-valdiates
657 applyMultiStateControlledSwap(qureg, nullptr, nullptr, 0, qubit1, qubit2);
658}
659
660void applyControlledSwap(Qureg qureg, int control, int qubit1, int qubit2) {
661 validate_quregFields(qureg, __func__);
662 validate_controlAndTwoTargets(qureg, control, qubit1, qubit2, __func__);
663
664 // harmlessly re-valdiates
665 applyMultiStateControlledSwap(qureg, &control, nullptr, 1, qubit1, qubit2);
666}
667
668void applyMultiControlledSwap(Qureg qureg, int* controls, int numControls, int qubit1, int qubit2) {
669 validate_quregFields(qureg, __func__);
670 validate_controlsAndTwoTargets(qureg, controls, numControls, qubit1, qubit2, __func__);
671
672 // harmlessly re-valdiates
673 applyMultiStateControlledSwap(qureg, controls, nullptr, numControls, qubit1, qubit2);
674}
675
676void applyMultiStateControlledSwap(Qureg qureg, int* controls, int* states, int numControls, int qubit1, int qubit2) {
677 validate_quregFields(qureg, __func__);
678 validate_controlsAndTwoTargets(qureg, controls, numControls, qubit1, qubit2, __func__);
679 validate_controlStates(states, numControls, __func__); // permits states==nullptr
680
681 auto ctrlList = lists_getList64(controls, numControls);
682 auto stateList = util_getList64OrAllOnes(states, numControls);
683 localiser_statevec_anyCtrlSwap(qureg, ctrlList, stateList, qubit1, qubit2);
684
685 if (!qureg.isDensityMatrix)
686 return;
687
688 ctrlList = util_getBraQubits(ctrlList, qureg);
689 qubit1 = util_getBraQubit(qubit1, qureg);
690 qubit2 = util_getBraQubit(qubit2, qureg);
691 localiser_statevec_anyCtrlSwap(qureg, ctrlList, stateList, qubit1, qubit2);
692}
693
694} // end de-mangler
695
696void applyMultiControlledSwap(Qureg qureg, vector<int> controls, int qubit1, int qubit2) {
697
698 applyMultiControlledSwap(qureg, controls.data(), controls.size(), qubit1, qubit2);
699}
700
701void applyMultiStateControlledSwap(Qureg qureg, vector<int> controls, vector<int> states, int qubit1, int qubit2) {
702 validate_controlsMatchStates(controls.size(), states.size(), __func__);
703
704 applyMultiStateControlledSwap(qureg, controls.data(), states.data(), controls.size(), qubit1, qubit2);
705}
706
707
708
709/*
710 * sqrt swap
711 */
712
713extern "C" {
714
715void applySqrtSwap(Qureg qureg, int target1, int target2) {
716 validate_quregFields(qureg, __func__);
717 validate_twoTargets(qureg,target1, target2, __func__);
718
719 // harmlessly re-validates
720 applyMultiStateControlledSqrtSwap(qureg, nullptr, nullptr, 0, target1, target2);
721}
722
723void applyControlledSqrtSwap(Qureg qureg, int control, int target1, int target2) {
724 validate_quregFields(qureg, __func__);
725 validate_controlAndTwoTargets(qureg, control, target1, target2, __func__);
726
727 // harmlessly re-validates
728 applyMultiStateControlledSqrtSwap(qureg, &control, nullptr, 1, target1, target2);
729}
730
731void applyMultiControlledSqrtSwap(Qureg qureg, int* controls, int numControls, int target1, int target2) {
732 validate_quregFields(qureg, __func__);
733 validate_controlsAndTwoTargets(qureg, controls, numControls, target1, target2, __func__);
734
735 // harmlessly re-validates
736 applyMultiStateControlledSqrtSwap(qureg, controls, nullptr, numControls, target1, target2);
737}
738
739void applyMultiStateControlledSqrtSwap(Qureg qureg, int* controls, int* states, int numControls, int target1, int target2) {
740 validate_quregFields(qureg, __func__);
741 validate_controlsAndTwoTargets(qureg, controls, numControls, target1, target2, __func__);
742 validate_controlStates(states, numControls, __func__); // permits states==nullptr
743
744 /// @todo
745 /// this function exacts sqrtSwap as a dense 2-qubit matrix,
746 /// where as bespoke communication and simulation strategy is
747 /// clearly possible which we have not supported because the gate
748 /// is somewhat esoteric. As such, we must validate mixed-amps fit
749
750 validate_mixedAmpsFitInNode(qureg, 2, __func__); // to throw SqrtSwap error, not generic CompMatr2 error
751
752 static const CompMatr2 matr = getCompMatr2({
753 {1, 0, 0, 0},
754 {0, .5+.5_i, .5-.5_i, 0},
755 {0, .5-.5_i, .5+.5_i, 0},
756 {0, 0, 0, 1}});
757
758 applyMultiStateControlledCompMatr2(qureg, controls, states, numControls, target1, target2, matr);
759}
760
761} // end de-mangler
762
763void applyMultiControlledSqrtSwap(Qureg qureg, vector<int> controls, int qubit1, int qubit2) {
764
765 applyMultiControlledSqrtSwap(qureg, controls.data(), controls.size(), qubit1, qubit2);
766}
767
768void applyMultiStateControlledSqrtSwap(Qureg qureg, vector<int> controls, vector<int> states, int qubit1, int qubit2) {
769 validate_controlsMatchStates(controls.size(), states.size(), __func__);
770
771 applyMultiStateControlledSqrtSwap(qureg, controls.data(), states.data(), controls.size(), qubit1, qubit2);
772}
773
774
775
776/*
777 * individual Paulis
778 *
779 * where Y and Z are most efficiently effected as DiagMatr1,
780 * but where X is best effected as a 1-qubit PauliStr.
781 */
782
783extern "C" {
784
785void applyPauliX(Qureg qureg, int target) {
786 validate_quregFields(qureg, __func__);
787 validate_target(qureg, target, __func__);
788
789 // harmlessly re-validates
790 applyMultiStateControlledPauliX(qureg, nullptr, nullptr, 0, target);
791}
792
793void applyPauliY(Qureg qureg, int target) {
794 validate_quregFields(qureg, __func__);
795 validate_target(qureg, target, __func__);
796
797 // harmlessly re-validates
798 applyMultiStateControlledPauliY(qureg, nullptr, nullptr, 0, target);
799}
800
801void applyPauliZ(Qureg qureg, int target) {
802 validate_quregFields(qureg, __func__);
803 validate_target(qureg, target, __func__);
804
805 // harmlessly re-validates
806 applyMultiStateControlledPauliZ(qureg, nullptr, nullptr, 0, target);
807}
808
809void applyControlledPauliX(Qureg qureg, int control, int target) {
810 validate_quregFields(qureg, __func__);
811 validate_controlAndTarget(qureg, control, target, __func__);
812
813 // harmlessly re-validates
814 applyMultiStateControlledPauliX(qureg, &control, nullptr, 1, target);
815}
816
817void applyControlledPauliY(Qureg qureg, int control, int target) {
818 validate_quregFields(qureg, __func__);
819 validate_controlAndTarget(qureg, control, target, __func__);
820
821 // harmlessly re-validates
822 applyMultiStateControlledPauliY(qureg, &control, nullptr, 1, target);
823}
824
825void applyControlledPauliZ(Qureg qureg, int control, int target) {
826 validate_quregFields(qureg, __func__);
827 validate_controlAndTarget(qureg, control, target, __func__);
828
829 // harmlessly re-validates
830 applyMultiStateControlledPauliZ(qureg, &control, nullptr, 1, target);
831}
832
833void applyMultiControlledPauliX(Qureg qureg, int* controls, int numControls, int target) {
834 validate_quregFields(qureg, __func__);
835 validate_controlsAndTarget(qureg, controls, numControls, target, __func__);
836
837 // harmlessly re-validates
838 applyMultiStateControlledPauliX(qureg, controls, nullptr, numControls, target);
839}
840
841void applyMultiControlledPauliY(Qureg qureg, int* controls, int numControls, int target) {
842 validate_quregFields(qureg, __func__);
843 validate_controlsAndTarget(qureg, controls, numControls, target, __func__);
844
845 // harmlessly re-validates
846 applyMultiStateControlledPauliY(qureg, controls, nullptr, numControls, target);
847}
848
849void applyMultiControlledPauliZ(Qureg qureg, int* controls, int numControls, int target) {
850 validate_quregFields(qureg, __func__);
851 validate_controlsAndTarget(qureg, controls, numControls, target, __func__);
852
853 // harmlessly re-validates
854 applyMultiStateControlledPauliZ(qureg, controls, nullptr, numControls, target);
855}
856
857void applyMultiStateControlledPauliX(Qureg qureg, int* controls, int* states, int numControls, int target) {
858 validate_quregFields(qureg, __func__);
859 validate_controlsAndTarget(qureg, controls, numControls, target, __func__);
860 validate_controlStates(states, numControls, __func__); // permits states==nullptr
861
862 // note that for the single-target scenario, we do not call the backend of
863 // applyMultiStateControlledPauliStr() since it contains sub-optimal logic
864 // which sees the factor of every amplitude dynamically evaluated (based on
865 // index parity, etc); the dense-matrix element lookup is faster
866
867 /// @todo
868 /// a bespoke all-pauli-X function (like in QuEST v3) will be faster still
869 /// since it avoids all superfluous flops; check worthwhile for multi-qubit
870
871 // harmlessly re-validates, including hardcoded matrix unitarity
872 static const CompMatr1 matrix = util_getPauliX();
873 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matrix, __func__);
874}
875
876void applyMultiStateControlledPauliY(Qureg qureg, int* controls, int* states, int numControls, int target) {
877 validate_quregFields(qureg, __func__);
878 validate_controlsAndTarget(qureg, controls, numControls, target, __func__);
879 validate_controlStates(states, numControls, __func__); // permits states==nullptr
880
881 // harmlessly re-validates, including hardcoded matrix unitarity
882 static const CompMatr1 matrix = util_getPauliY();
883 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matrix, __func__);
884}
885
886void applyMultiStateControlledPauliZ(Qureg qureg, int* controls, int* states, int numControls, int target) {
887 validate_quregFields(qureg, __func__);
888 validate_controlsAndTarget(qureg, controls, numControls, target, __func__);
889 validate_controlStates(states, numControls, __func__); // permits states==nullptr
890
891 // harmlessly re-validates, including hardcoded matrix unitarity
892 static const DiagMatr1 matrix = util_getPauliZ();
893 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matrix, __func__);
894}
895
896} // end de-mangler
897
898void applyMultiControlledPauliX(Qureg qureg, vector<int> controls, int target) {
899
900 applyMultiControlledPauliX(qureg, controls.data(), controls.size(), target);
901}
902
903void applyMultiControlledPauliY(Qureg qureg, vector<int> controls, int target) {
904
905 applyMultiControlledPauliY(qureg, controls.data(), controls.size(), target);
906}
907
908void applyMultiControlledPauliZ(Qureg qureg, vector<int> controls, int target) {
909
910 applyMultiControlledPauliZ(qureg, controls.data(), controls.size(), target);
911}
912
913void applyMultiStateControlledPauliX(Qureg qureg, vector<int> controls, vector<int> states, int target) {
914 validate_controlsMatchStates(controls.size(), states.size(), __func__);
915
916 applyMultiStateControlledPauliX(qureg, controls.data(), states.data(), controls.size(), target);
917}
918
919void applyMultiStateControlledPauliY(Qureg qureg, vector<int> controls, vector<int> states, int target) {
920 validate_controlsMatchStates(controls.size(), states.size(), __func__);
921
922 applyMultiStateControlledPauliY(qureg, controls.data(), states.data(), controls.size(), target);
923}
924
925void applyMultiStateControlledPauliZ(Qureg qureg, vector<int> controls, vector<int> states, int target) {
926 validate_controlsMatchStates(controls.size(), states.size(), __func__);
927
928 applyMultiStateControlledPauliZ(qureg, controls.data(), states.data(), controls.size(), target);
929}
930
931
932
933/*
934 * Pauli strings
935 */
936
937extern "C" {
938
939void applyPauliStr(Qureg qureg, PauliStr str) {
940 validate_quregFields(qureg, __func__);
941 validate_pauliStrTargets(qureg, str, __func__);
942
943 // harmlessly re-validates
944 applyMultiStateControlledPauliStr(qureg, nullptr, nullptr, 0, str);
945}
946
947void applyControlledPauliStr(Qureg qureg, int control, PauliStr str) {
948 validate_quregFields(qureg, __func__);
949 validate_controlAndPauliStrTargets(qureg, control, str, __func__);
950
951 // harmlessly re-validates
952 applyMultiStateControlledPauliStr(qureg, &control, nullptr, 1, str);
953}
954
955void applyMultiControlledPauliStr(Qureg qureg, int* controls, int numControls, PauliStr str) {
956 validate_quregFields(qureg, __func__);
957 validate_controlsAndPauliStrTargets(qureg, controls, numControls, str, __func__);
958
959 // harmlessly re-validates
960 applyMultiStateControlledPauliStr(qureg, controls, nullptr, numControls, str);
961}
962
963void applyMultiStateControlledPauliStr(Qureg qureg, int* controls, int* states, int numControls, PauliStr str) {
964 validate_quregFields(qureg, __func__);
965 validate_controlsAndPauliStrTargets(qureg, controls, numControls, str, __func__);
966 validate_controlStates(states, numControls, __func__); // permits states==nullptr
967
968 qcomp factor = 1;
969 auto ctrlList = lists_getList64(controls, numControls);
970 auto stateList = util_getList64OrAllOnes(states, numControls);
971
972 // when there are no control qubits, we can merge the density matrix's
973 // operation sinto a single tensor, i.e. +- (shift(str) (x) str), to
974 // avoid superfluous re-enumeration of the state
975 if (qureg.isDensityMatrix && numControls == 0) {
976 factor = paulis_getSignOfPauliStrConj(str);
977 ctrlList = util_getConcatenated(ctrlList, util_getBraQubits(ctrlList, qureg));
978 stateList = util_getConcatenated(stateList, stateList);
979 str = paulis_getKetAndBraPauliStr(str, qureg);
980 }
981
982 localiser_statevec_anyCtrlPauliTensor(qureg, ctrlList, stateList, str, factor);
983
984 // but density-matrix control qubits require two distinct operations
985 if (qureg.isDensityMatrix && numControls > 0) {
986 factor = paulis_getSignOfPauliStrConj(str);
987 ctrlList = util_getBraQubits(ctrlList, qureg);
988 str = paulis_getShiftedPauliStr(str, qureg.numQubits);
989 localiser_statevec_anyCtrlPauliTensor(qureg, ctrlList, stateList, str, factor);
990 }
991}
992
993} // end de-mangler
994
995void applyMultiControlledPauliStr(Qureg qureg, vector<int> controls, PauliStr str) {
996
997 applyMultiControlledPauliStr(qureg, controls.data(), controls.size(), str);
998}
999
1000void applyMultiStateControlledPauliStr(Qureg qureg, vector<int> controls, vector<int> states, PauliStr str) {
1001 validate_controlsMatchStates(controls.size(), states.size(), __func__);
1002
1003 applyMultiStateControlledPauliStr(qureg, controls.data(), states.data(), controls.size(), str);
1004}
1005
1006
1007
1008/*
1009 * individual axis rotations
1010 */
1011
1012extern "C" {
1013
1014void applyRotateX(Qureg qureg, int target, qreal angle) {
1015 validate_quregFields(qureg, __func__);
1016 validate_target(qureg, target, __func__);
1017
1018 // harmlessly re-validates
1019 applyMultiStateControlledRotateX(qureg, nullptr, nullptr, 0, target, angle);
1020}
1021
1022void applyRotateY(Qureg qureg, int target, qreal angle) {
1023 validate_quregFields(qureg, __func__);
1024 validate_target(qureg, target, __func__);
1025
1026 // harmlessly re-validates
1027 applyMultiStateControlledRotateY(qureg, nullptr, nullptr, 0, target, angle);
1028}
1029
1030void applyRotateZ(Qureg qureg, int target, qreal angle) {
1031 validate_quregFields(qureg, __func__);
1032 validate_target(qureg, target, __func__);
1033
1034 // harmlessly re-validates
1035 applyMultiStateControlledRotateZ(qureg, nullptr, nullptr, 0, target, angle);
1036}
1037
1038void applyControlledRotateX(Qureg qureg, int control, int target, qreal angle) {
1039 validate_quregFields(qureg, __func__);
1040 validate_controlAndTarget(qureg, control, target, __func__);
1041
1042 // harmlessly re-validates
1043 applyMultiStateControlledRotateX(qureg, &control, nullptr, 1, target, angle);
1044}
1045
1046void applyControlledRotateY(Qureg qureg, int control, int target, qreal angle) {
1047 validate_quregFields(qureg, __func__);
1048 validate_controlAndTarget(qureg, control, target, __func__);
1049
1050 // harmlessly re-validates
1051 applyMultiStateControlledRotateY(qureg, &control, nullptr, 1, target, angle);
1052}
1053
1054void applyControlledRotateZ(Qureg qureg, int control, int target, qreal angle) {
1055 validate_quregFields(qureg, __func__);
1056 validate_controlAndTarget(qureg, control, target, __func__);
1057
1058 // harmlessly re-validates
1059 applyMultiStateControlledRotateZ(qureg, &control, nullptr, 1, target, angle);
1060}
1061
1062void applyMultiControlledRotateX(Qureg qureg, int* controls, int numControls, int target, qreal angle) {
1063 validate_quregFields(qureg, __func__);
1064 validate_controlsAndTarget(qureg, controls, numControls, target, __func__);
1065
1066 // harmlessly re-validates
1067 applyMultiStateControlledRotateX(qureg, controls, nullptr, numControls, target, angle);
1068}
1069
1070void applyMultiControlledRotateY(Qureg qureg, int* controls, int numControls, int target, qreal angle) {
1071 validate_quregFields(qureg, __func__);
1072 validate_controlsAndTarget(qureg, controls, numControls, target, __func__);
1073
1074 // harmlessly re-validates
1075 applyMultiStateControlledRotateY(qureg, controls, nullptr, numControls, target, angle);
1076}
1077
1078void applyMultiControlledRotateZ(Qureg qureg, int* controls, int numControls, int target, qreal angle) {
1079 validate_quregFields(qureg, __func__);
1080 validate_controlsAndTarget(qureg, controls, numControls, target, __func__);
1081
1082 // harmlessly re-validates
1083 applyMultiStateControlledRotateZ(qureg, controls, nullptr, numControls, target, angle);
1084}
1085
1086void applyMultiStateControlledRotateX(Qureg qureg, int* controls, int* states, int numControls, int target, qreal angle) {
1087 validate_quregFields(qureg, __func__);
1088 validate_controlsAndTarget(qureg, controls, numControls, target, __func__);
1089 validate_controlStates(states, numControls, __func__); // permits states==nullptr
1090
1091 // note that for the single-target scenario, we do not call the backend of
1092 // applyMultiStateControlledPauliGadget() since it contains sub-optimal logic
1093 // which sees the factor of every amplitude dynamically evaluated (based on
1094 // index parity, etc); the dense-matrix element lookup is faster
1095
1096 // harmlessly re-validates, including hardcoded matrix unitarity
1097 CompMatr1 matrix = util_getExpPauliX(angle);
1098 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matrix, __func__);
1099}
1100
1101void applyMultiStateControlledRotateY(Qureg qureg, int* controls, int* states, int numControls, int target, qreal angle) {
1102 validate_quregFields(qureg, __func__);
1103 validate_controlsAndTarget(qureg, controls, numControls, target, __func__);
1104 validate_controlStates(states, numControls, __func__); // permits states==nullptr
1105
1106 // note that for the single-target scenario, we do not call the backend of
1107 // applyMultiStateControlledPauliGadget() since it contains sub-optimal logic
1108 // which sees the factor of every amplitude dynamically evaluated (based on
1109 // index parity, etc); the dense-matrix element lookup is faster
1110
1111 // harmlessly re-validates, including hardcoded matrix unitarity
1112 CompMatr1 matrix = util_getExpPauliY(angle);
1113 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matrix, __func__);
1114}
1115
1116void applyMultiStateControlledRotateZ(Qureg qureg, int* controls, int* states, int numControls, int target, qreal angle) {
1117 validate_quregFields(qureg, __func__);
1118 validate_controlsAndTarget(qureg, controls, numControls, target, __func__);
1119 validate_controlStates(states, numControls, __func__); // permits states==nullptr
1120
1121 // note that for the single-target scenario, we do not call the backend of
1122 // applyMultiStateControlledPauliGadget() since it contains sub-optimal logic
1123 // which sees the factor of every amplitude dynamically evaluated (based on
1124 // index parity, etc); the dense-matrix element lookup is faster
1125
1126 // harmlessly re-validates, including hardcoded matrix unitarity
1127 DiagMatr1 matrix = util_getExpPauliZ(angle);
1128 validateAndApplyAnyCtrlAnyTargUnitaryMatrix(qureg, controls, states, numControls, &target, 1, matrix, __func__);
1129}
1130
1131} // end de-mangler
1132
1133void applyMultiControlledRotateX(Qureg qureg, vector<int> controls, int target, qreal angle) {
1134
1135 applyMultiControlledRotateX(qureg, controls.data(), controls.size(), target, angle);
1136}
1137
1138void applyMultiControlledRotateY(Qureg qureg, vector<int> controls, int target, qreal angle) {
1139
1140 applyMultiControlledRotateY(qureg, controls.data(), controls.size(), target, angle);
1141}
1142
1143void applyMultiControlledRotateZ(Qureg qureg, vector<int> controls, int target, qreal angle) {
1144
1145 applyMultiControlledRotateZ(qureg, controls.data(), controls.size(), target, angle);
1146}
1147
1148void applyMultiStateControlledRotateX(Qureg qureg, vector<int> controls, vector<int> states, int target, qreal angle) {
1149 validate_controlsMatchStates(controls.size(), states.size(), __func__);
1150
1151 applyMultiStateControlledRotateX(qureg, controls.data(), states.data(), controls.size(), target, angle);
1152}
1153
1154void applyMultiStateControlledRotateY(Qureg qureg, vector<int> controls, vector<int> states, int target, qreal angle) {
1155 validate_controlsMatchStates(controls.size(), states.size(), __func__);
1156
1157 applyMultiStateControlledRotateY(qureg, controls.data(), states.data(), controls.size(), target, angle);
1158}
1159
1160void applyMultiStateControlledRotateZ(Qureg qureg, vector<int> controls, vector<int> states, int target, qreal angle) {
1161 validate_controlsMatchStates(controls.size(), states.size(), __func__);
1162
1163 applyMultiStateControlledRotateZ(qureg, controls.data(), states.data(), controls.size(), target, angle);
1164}
1165
1166
1167
1168/*
1169 * arbitrary axis rotation
1170 */
1171
1172extern "C" {
1173
1174void applyRotateAroundAxis(Qureg qureg, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ) {
1175 validate_quregFields(qureg, __func__);
1176 validate_target(qureg, targ, __func__);
1177 validate_rotationAxisNotZeroVector(axisX, axisY, axisZ, __func__);
1178
1179 applyMultiStateControlledRotateAroundAxis(qureg, nullptr, nullptr, 0, targ, angle, axisX, axisY, axisZ);
1180}
1181
1182void applyControlledRotateAroundAxis(Qureg qureg, int ctrl, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ) {
1183 validate_quregFields(qureg, __func__);
1184 validate_controlAndTarget(qureg, ctrl, targ, __func__);
1185 validate_rotationAxisNotZeroVector(axisX, axisY, axisZ, __func__);
1186
1187 applyMultiStateControlledRotateAroundAxis(qureg, &ctrl, nullptr, 1, targ, angle, axisX, axisY, axisZ);
1188}
1189
1190void applyMultiControlledRotateAroundAxis(Qureg qureg, int* ctrls, int numCtrls, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ) {
1191 validate_quregFields(qureg, __func__);
1192 validate_controlsAndTarget(qureg, ctrls, numCtrls, targ, __func__);
1193 validate_rotationAxisNotZeroVector(axisX, axisY, axisZ, __func__);
1194
1195 applyMultiStateControlledRotateAroundAxis(qureg, ctrls, nullptr, numCtrls, targ, angle, axisX, axisY, axisZ);
1196}
1197
1198void applyMultiStateControlledRotateAroundAxis(Qureg qureg, int* ctrls, int* states, int numCtrls, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ) {
1199 validate_quregFields(qureg, __func__);
1200 validate_controlsAndTarget(qureg, ctrls, numCtrls, targ, __func__);
1201 validate_controlStates(states, numCtrls, __func__); // permits states==nullptr
1202 validate_rotationAxisNotZeroVector(axisX, axisY, axisZ, __func__);
1203
1204 // defer division of vector norm to improve numerical accuracy
1205 qreal norm = std::sqrt(std::pow(axisX,2) + std::pow(axisY,2) + std::pow(axisZ,2)); // != 0
1206
1207 // treat as generic 1-qubit matrix
1208 qreal c = std::cos(angle/2);
1209 qreal s = std::sin(angle/2);
1210 qcomp u11 = c - (s * axisZ * 1_i) / norm;
1211 qcomp u12 = - (s * (axisY + axisX * 1_i)) / norm;
1212 qcomp u21 = (s * (axisY - axisX * 1_i)) / norm;
1213 qcomp u22 = c + (s * axisZ * 1_i) / norm;
1214 auto matr = getCompMatr1({{u11,u12},{u21,u22}});
1215
1216 // harmlessly re-validates, and checks unitarity of matr
1217 applyMultiStateControlledCompMatr1(qureg, ctrls, states, numCtrls, targ, matr);
1218}
1219
1220} // end de-mangler
1221
1222void applyMultiControlledRotateAroundAxis(Qureg qureg, vector<int> ctrls, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ) {
1223
1224 applyMultiControlledRotateAroundAxis(qureg, ctrls.data(), ctrls.size(), targ, angle, axisX, axisY, axisZ);
1225}
1226
1227void applyMultiStateControlledRotateAroundAxis(Qureg qureg, vector<int> ctrls, vector<int> states, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ) {
1228 validate_controlsMatchStates(ctrls.size(), states.size(), __func__);
1229
1230 applyMultiStateControlledRotateAroundAxis(qureg, ctrls.data(), states.data(), ctrls.size(), targ, angle, axisX, axisY, axisZ);
1231}
1232
1233
1234
1235/*
1236 * Pauli gadgets
1237 */
1238
1239extern "C" {
1240
1241void applyPauliGadget(Qureg qureg, PauliStr str, qreal angle) {
1242 validate_quregFields(qureg, __func__);
1243 validate_pauliStrTargets(qureg, str, __func__);
1244
1245 applyMultiStateControlledPauliGadget(qureg, nullptr, nullptr, 0, str, angle);
1246}
1247
1248void applyNonUnitaryPauliGadget(Qureg qureg, PauliStr str, qcomp angle) {
1249 validate_quregFields(qureg, __func__);
1250 validate_pauliStrTargets(qureg, str, __func__);
1251
1252 qcomp phase = util_getPhaseFromGateAngle(angle);
1253 auto none = lists_getEmptyList64();
1254 localiser_statevec_anyCtrlPauliGadget(qureg, none, none, str, phase);
1255
1256 if (!qureg.isDensityMatrix)
1257 return;
1258
1259 // conj(e^i(a)P) = e^(-i s conj(a) P)
1260 phase = - std::conj(phase) * paulis_getSignOfPauliStrConj(str);
1261 str = paulis_getShiftedPauliStr(str, qureg.numQubits);
1262 localiser_statevec_anyCtrlPauliGadget(qureg, none, none, str, phase);
1263}
1264
1265void applyControlledPauliGadget(Qureg qureg, int control, PauliStr str, qreal angle) {
1266 validate_quregFields(qureg, __func__);
1267 validate_controlAndPauliStrTargets(qureg, control, str, __func__);
1268
1269 applyMultiStateControlledPauliGadget(qureg, &control, nullptr, 1, str, angle);
1270}
1271
1272void applyMultiControlledPauliGadget(Qureg qureg, int* controls, int numControls, PauliStr str, qreal angle) {
1273 validate_quregFields(qureg, __func__);
1274 validate_controlsAndPauliStrTargets(qureg, controls, numControls, str, __func__);
1275
1276 applyMultiStateControlledPauliGadget(qureg, controls, nullptr, numControls, str, angle);
1277}
1278
1279void applyMultiStateControlledPauliGadget(Qureg qureg, int* controls, int* states, int numControls, PauliStr str, qreal angle) {
1280 validate_quregFields(qureg, __func__);
1281 validate_controlsAndPauliStrTargets(qureg, controls, numControls, str, __func__);
1282 validate_controlStates(states, numControls, __func__); // permits states==nullptr
1283
1284 // a non-controlled str=I effects a global phase change (of -angle/2) which does not
1285 // at all change a density matrix; the subsequent dagger operation would undo it,
1286 // which we avoid to preserve numerical accuracy
1287 if (paulis_isIdentity(str) && numControls == 0 && qureg.isDensityMatrix)
1288 return;
1289
1290 // when numControls >= 1, all amps satisfying the control condition undergo a phase
1291 // change of -angle/2, as if all non-control-qubits were targeted by exp(-angle/2)I,
1292 // which is sufficiently efficient using the existing gadget backend function
1293
1294 qreal phase = util_getPhaseFromGateAngle(angle);
1295 auto ctrlList = lists_getList64(controls, numControls);
1296 auto stateList = util_getList64OrAllOnes(states, numControls);
1297 localiser_statevec_anyCtrlPauliGadget(qureg, ctrlList, stateList, str, phase);
1298
1299 if (!qureg.isDensityMatrix)
1300 return;
1301
1302 // conj(e^(i a P)) = e^(-i s a P)
1303 phase *= - paulis_getSignOfPauliStrConj(str);
1304 ctrlList = util_getBraQubits(ctrlList, qureg);
1305 str = paulis_getShiftedPauliStr(str, qureg.numQubits);
1306 localiser_statevec_anyCtrlPauliGadget(qureg, ctrlList, stateList, str, phase);
1307}
1308
1309} // end de-mangler
1310
1311void applyMultiControlledPauliGadget(Qureg qureg, vector<int> controls, PauliStr str, qreal angle) {
1312
1313 applyMultiControlledPauliGadget(qureg, controls.data(), controls.size(), str, angle);
1314}
1315
1316void applyMultiStateControlledPauliGadget(Qureg qureg, vector<int> controls, vector<int> states, PauliStr str, qreal angle) {
1317 validate_controlsMatchStates(controls.size(), states.size(), __func__);
1318
1319 applyMultiStateControlledPauliGadget(qureg, controls.data(), states.data(), controls.size(), str, angle);
1320}
1321
1322
1323
1324/*
1325 * phase gadgets
1326 */
1327
1328extern "C" {
1329
1330void applyPhaseGadget(Qureg qureg, int* targets, int numTargets, qreal angle) {
1331 validate_quregFields(qureg, __func__);
1332 validate_targets(qureg, targets, numTargets, __func__);
1333
1334 // harmlessly re-validates
1335 applyMultiStateControlledPhaseGadget(qureg, nullptr, nullptr, 0, targets, numTargets, angle);
1336}
1337
1338void applyControlledPhaseGadget(Qureg qureg, int control, int* targets, int numTargets, qreal angle) {
1339 validate_quregFields(qureg, __func__);
1340 validate_controlAndTargets(qureg, control, targets, numTargets, __func__);
1341
1342 // harmlessly re-validates
1343 applyMultiStateControlledPhaseGadget(qureg, &control, nullptr, 1, targets, numTargets, angle);
1344}
1345
1346void applyMultiControlledPhaseGadget(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, qreal angle) {
1347 validate_quregFields(qureg, __func__);
1348 validate_controlsAndTargets(qureg, controls, numControls, targets, numTargets, __func__);
1349
1350 // harmlessly re-validates
1351 applyMultiStateControlledPhaseGadget(qureg, controls, nullptr, numControls, targets, numTargets, angle);
1352}
1353
1354void applyMultiStateControlledPhaseGadget(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, qreal angle) {
1355 validate_quregFields(qureg, __func__);
1356 validate_controlsAndTargets(qureg, controls, numControls, targets, numTargets, __func__);
1357 validate_controlStates(states, numControls, __func__);
1358
1359 qreal phase = util_getPhaseFromGateAngle(angle);
1360 auto ctrlList = lists_getList64(controls, numControls);
1361 auto stateList = util_getList64OrAllOnes(states, numControls);
1362 auto targList = lists_getList64(targets, numTargets);
1363 localiser_statevec_anyCtrlPhaseGadget(qureg, ctrlList, stateList, targList, phase);
1364
1365 if (!qureg.isDensityMatrix)
1366 return;
1367
1368 phase *= -1;
1369 ctrlList = util_getBraQubits(ctrlList, qureg);
1370 targList = util_getBraQubits(targList, qureg);
1371 localiser_statevec_anyCtrlPhaseGadget(qureg, ctrlList, stateList, targList, phase);
1372}
1373
1374} // end de-mangler
1375
1376void applyPhaseGadget(Qureg qureg, vector<int> targets, qreal angle) {
1377
1378 applyPhaseGadget(qureg, targets.data(), targets.size(), angle);
1379}
1380
1381void applyControlledPhaseGadget(Qureg qureg, int control, vector<int> targets, qreal angle) {
1382
1383 applyControlledPhaseGadget(qureg, control, targets.data(), targets.size(), angle);
1384}
1385
1386void applyMultiControlledPhaseGadget(Qureg qureg, vector<int> controls, vector<int> targets, qreal angle) {
1387
1388 applyMultiControlledPhaseGadget(qureg, controls.data(), controls.size(), targets.data(), targets.size(), angle);
1389}
1390
1391void applyMultiStateControlledPhaseGadget(Qureg qureg, vector<int> controls, vector<int> states, vector<int> targets, qreal angle) {
1392 validate_controlsMatchStates(controls.size(), states.size(), __func__);
1393
1394 applyMultiStateControlledPhaseGadget(qureg, controls.data(), states.data(), controls.size(), targets.data(), targets.size(), angle);
1395}
1396
1397
1398
1399/*
1400 * phase shift
1401 */
1402
1403extern "C" {
1404
1405void applyPhaseShift(Qureg qureg, int target, qreal angle) {
1406 validate_quregFields(qureg, __func__);
1407 validate_target(qureg, target, __func__);
1408
1409 // harmlessly re-validates
1410 applyMultiQubitPhaseShift(qureg, &target, 1, angle);
1411}
1412
1413void applyTwoQubitPhaseShift(Qureg qureg, int target1, int target2, qreal angle) {
1414 validate_quregFields(qureg, __func__);
1415 validate_twoTargets(qureg, target1, target2, __func__);
1416
1417 // harmlessly re-validates
1418 int targets[] = {target1, target2};
1419 applyMultiQubitPhaseShift(qureg, targets, 2, angle);
1420}
1421
1422void applyMultiQubitPhaseShift(Qureg qureg, int* targets, int numTargets, qreal angle) {
1423 validate_quregFields(qureg, __func__);
1424 validate_targets(qureg, targets, numTargets, __func__);
1425
1426 // treat as a (numTargets-1)-controlled 1-target diagonal matrix
1427 static DiagMatr1 matr = getDiagMatr1({1, /*un-init*/ 0});
1428 matr.elems[1] = std::exp(1_i * angle); // micro-optimisation
1429
1430 // harmlessly re-validates
1431 applyMultiStateControlledDiagMatr1(qureg, &targets[1], nullptr, numTargets-1, targets[0], matr);
1432}
1433
1434} // end de-mangler
1435
1436void applyMultiQubitPhaseShift(Qureg qureg, vector<int> targets, qreal angle) {
1437
1438 applyMultiQubitPhaseShift(qureg, targets.data(), targets.size(), angle);
1439}
1440
1441
1442
1443/*
1444 * phase flips
1445 */
1446
1447extern "C" {
1448
1449void applyPhaseFlip(Qureg qureg, int target) {
1450 validate_quregFields(qureg, __func__);
1451 validate_target(qureg, target, __func__);
1452
1453 // harmlessly re-validates
1454 applyMultiQubitPhaseFlip(qureg, &target, 1);
1455}
1456
1457void applyTwoQubitPhaseFlip(Qureg qureg, int target1, int target2) {
1458 validate_quregFields(qureg, __func__);
1459 validate_twoTargets(qureg, target1, target2, __func__);
1460
1461 // harmlessly re-validates
1462 int targets[] = {target1, target2};
1463 applyMultiQubitPhaseFlip(qureg, targets, 2);
1464}
1465
1466void applyMultiQubitPhaseFlip(Qureg qureg, int* targets, int numTargets) {
1467 validate_quregFields(qureg, __func__);
1468 validate_targets(qureg, targets, numTargets, __func__);
1469
1470 // treat as a (numTargets-1)-controlled 1-target Pauli Z
1471 static const DiagMatr1 matr = getDiagMatr1({1, -1});
1472
1473 // harmlessly re-validates
1474 applyMultiStateControlledDiagMatr1(qureg, &targets[1], nullptr, numTargets-1, targets[0], matr);
1475}
1476
1477} // end de-mangler
1478
1479void applyMultiQubitPhaseFlip(Qureg qureg, vector<int> targets) {
1480
1481 applyMultiQubitPhaseFlip(qureg, targets.data(), targets.size());
1482}
1483
1484
1485
1486/*
1487 * many-qubit NOTs and CNOTs
1488 */
1489
1490extern "C" {
1491
1492void applyMultiQubitNot(Qureg qureg, int* targets, int numTargets) {
1493 validate_quregFields(qureg, __func__);
1494 validate_targets(qureg, targets, numTargets, __func__);
1495
1496 // harmlessly re-validates
1497 applyMultiStateControlledMultiQubitNot(qureg, nullptr, nullptr, 0, targets, numTargets);
1498}
1499
1500void applyControlledMultiQubitNot(Qureg qureg, int control, int* targets, int numTargets) {
1501 validate_quregFields(qureg, __func__);
1502 validate_controlAndTargets(qureg, control, targets, numTargets, __func__);
1503
1504 // harmlessly re-validates
1505 applyMultiStateControlledMultiQubitNot(qureg, &control, nullptr, 1, targets, numTargets);
1506}
1507
1508void applyMultiControlledMultiQubitNot(Qureg qureg, int* controls, int numControls, int* targets, int numTargets) {
1509 validate_quregFields(qureg, __func__);
1510 validate_controlsAndTargets(qureg, controls, numControls, targets, numTargets, __func__);
1511
1512 // harmlessly re-validates
1513 applyMultiStateControlledMultiQubitNot(qureg, controls, nullptr, numControls, targets, numTargets);
1514}
1515
1516void applyMultiStateControlledMultiQubitNot(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets) {
1517 validate_quregFields(qureg, __func__);
1518 validate_controlsAndTargets(qureg, controls, numControls, targets, numTargets, __func__);
1519 validate_controlStates(states, numControls, __func__);
1520
1521 // treat as an all-X PauliStr
1522 PauliStr str = getPauliStr(std::string(numTargets, 'X'), targets, numTargets);
1523
1524 // harmlessly re-validates
1525 applyMultiStateControlledPauliStr(qureg, controls, states, numControls, str);
1526}
1527
1528} // end de-mangler
1529
1530void applyMultiQubitNot(Qureg qureg, vector<int> targets) {
1531
1532 applyMultiQubitNot(qureg, targets.data(), targets.size());
1533}
1534
1535void applyControlledMultiQubitNot(Qureg qureg, int control, vector<int> targets) {
1536
1537 applyControlledMultiQubitNot(qureg, control, targets.data(), targets.size());
1538}
1539
1540void applyMultiControlledMultiQubitNot(Qureg qureg, vector<int> controls, vector<int> targets) {
1541
1542 applyMultiControlledMultiQubitNot(qureg, controls.data(), controls.size(), targets.data(), targets.size());
1543}
1544
1545void applyMultiStateControlledMultiQubitNot(Qureg qureg, vector<int> controls, vector<int> states, vector<int> targets) {
1546 validate_controlsMatchStates(controls.size(), states.size(), __func__);
1547
1548 applyMultiStateControlledMultiQubitNot(qureg, controls.data(), states.data(), controls.size(), targets.data(), targets.size());
1549}
1550
1551
1552
1553/*
1554 * projectors
1555 */
1556
1557extern "C" {
1558
1559void applyQubitProjector(Qureg qureg, int target, int outcome) {
1560 validate_quregFields(qureg, __func__);
1561 validate_target(qureg, target, __func__);
1562 validate_measurementOutcomeIsValid(outcome, __func__);
1563
1564 qreal prob = 1;
1565
1566 auto targList = lists_getList64({target});
1567 auto outcomeList = lists_getList64({outcome});
1568
1569 // density matrix has an optimised func in lieu of calling the statevector func twice
1570 (qureg.isDensityMatrix)?
1571 localiser_densmatr_multiQubitProjector(qureg, targList, outcomeList, prob):
1572 localiser_statevec_multiQubitProjector(qureg, targList, outcomeList, prob);
1573}
1574
1575void applyMultiQubitProjector(Qureg qureg, int* qubits, int* outcomes, int numQubits) {
1576 validate_quregFields(qureg, __func__);
1577 validate_targets(qureg, qubits, numQubits, __func__);
1578 validate_measurementOutcomesAreValid(outcomes, numQubits, __func__);
1579
1580 qreal prob = 1;
1581 auto qubitList = lists_getList64(qubits, numQubits);
1582 auto outcomeList = lists_getList64(outcomes, numQubits);
1583
1584 // density matrix has an optimised func in lieu of calling the statevector func twice
1585 (qureg.isDensityMatrix)?
1586 localiser_densmatr_multiQubitProjector(qureg, qubitList, outcomeList, prob):
1587 localiser_statevec_multiQubitProjector(qureg, qubitList, outcomeList, prob);
1588}
1589
1590} // end de-mangler
1591
1592void applyMultiQubitProjector(Qureg qureg, vector<int> qubits, vector<int> outcomes) {
1593 validate_measurementOutcomesMatchTargets(qubits.size(), outcomes.size(), __func__);
1594
1595 applyMultiQubitProjector(qureg, qubits.data(), outcomes.data(), outcomes.size());
1596}
1597
1598
1599
1600/*
1601 * measurement
1602 */
1603
1604extern "C" {
1605
1606int applyQubitMeasurement(Qureg qureg, int target) {
1607 validate_quregFields(qureg, __func__);
1608 validate_target(qureg, target, __func__);
1609
1610 qreal prob = 0; // ignored
1611 return applyQubitMeasurementAndGetProb(qureg, target, &prob); // harmlessly re-validates
1612}
1613
1614int applyQubitMeasurementAndGetProb(Qureg qureg, int target, qreal* probability) {
1615 validate_quregFields(qureg, __func__);
1616 validate_target(qureg, target, __func__);
1617
1618 // we do not assume state normalisation (that is posteriori checked),
1619 // so we must perform two reductions; one for each outcome. We choose
1620 // to re-enumerate the state (potentially doubling caching costs) to
1621 // avoid the nuisances/race-cons of parallel adding to two scalars.
1622 vector<qreal> probs(2);
1623 probs[0] = calcProbOfQubitOutcome(qureg, target, 0); // harmlessly re-validates
1624 probs[1] = calcProbOfQubitOutcome(qureg, target, 1); // " "
1625 validate_measurementProbsAreNormalised(probs, __func__);
1626
1627 // randomly choose the outcome
1628 int outcome = rand_getRandomSingleQubitOutcome(probs[0]);
1629 *probability = probs[outcome];
1630
1631 auto targList = lists_getList64({target});
1632 auto outcomeList = lists_getList64({outcome});
1633
1634 // collapse to the outcome
1635 (qureg.isDensityMatrix)?
1636 localiser_densmatr_multiQubitProjector(qureg, targList, outcomeList, *probability):
1637 localiser_statevec_multiQubitProjector(qureg, targList, outcomeList, *probability);
1638
1639 return outcome;
1640}
1641
1642qreal applyForcedQubitMeasurement(Qureg qureg, int target, int outcome) {
1643 validate_quregFields(qureg, __func__);
1644 validate_target(qureg, target, __func__);
1645 validate_measurementOutcomeIsValid(outcome, __func__);
1646
1647 // note that we do not merely invoke applyForcedMultiQubitMeasurement()
1648 // because we must validate the renormalising probability and
1649 // report this function's name during the error message
1650 qreal prob = calcProbOfQubitOutcome(qureg, target, outcome); // harmlessly re-validates
1651 validate_measurementOutcomeProbNotZero(outcome, prob, __func__);
1652
1653 auto targList = lists_getList64({target});
1654 auto outcomeList = lists_getList64({outcome});
1655
1656 // project to the outcome, renormalising the surviving states
1657 (qureg.isDensityMatrix)?
1658 localiser_densmatr_multiQubitProjector(qureg, targList, outcomeList, prob):
1659 localiser_statevec_multiQubitProjector(qureg, targList, outcomeList, prob);
1660
1661 return prob;
1662}
1663
1664qindex applyMultiQubitMeasurement(Qureg qureg, int* qubits, int numQubits) {
1665 validate_quregFields(qureg, __func__);
1666 validate_targets(qureg, qubits, numQubits, __func__);
1667
1668 qreal prob = 0; // ignored
1669
1670 // below validates post-measurement and would report 'AndGetProb' function suffix. Eh!
1671 return applyMultiQubitMeasurementAndGetProb(qureg, qubits, numQubits, &prob);
1672}
1673
1674qindex applyMultiQubitMeasurementAndGetProb(Qureg qureg, int* qubits, int numQubits, qreal* probability) {
1675 validate_quregFields(qureg, __func__);
1676 validate_targets(qureg, qubits, numQubits, __func__);
1677
1678 // find the probability of all possible outcomes...
1679 qindex numProbs = powerOf2(numQubits);
1680
1681 // by allocating a temp vector, and validating successful (since exponentially big!)
1682 vector<qreal> probs;
1683 auto callback = [&]() { validate_tempListAllocSucceeded(false, numProbs, sizeof(qreal), __func__); };
1684 util_tryAllocVector(probs, numProbs, callback);
1685
1686 // populate probs
1687 calcProbsOfAllMultiQubitOutcomes(probs.data(), qureg, qubits, numQubits); // harmlessly re-validates
1688
1689 // we cannot meaningfully sample these probs if not normalised
1690 validate_measurementProbsAreNormalised(probs, __func__);
1691
1692 // randomly choose an outcome
1693 qindex outcome = rand_getRandomMultiQubitOutcome(probs);
1694 *probability = probs[outcome];
1695
1696 // map outcome to individual qubit outcomes
1697 auto qubitList = lists_getList64(qubits, numQubits);
1698 auto outcomeList = util_getConstantList(-1, numQubits);
1699 setToBitsOfInteger(outcomeList.data(), outcome, numQubits);
1700
1701 // project to the outcomes, renormalising the surviving states
1702 (qureg.isDensityMatrix)?
1703 localiser_densmatr_multiQubitProjector(qureg, qubitList, outcomeList, *probability):
1704 localiser_statevec_multiQubitProjector(qureg, qubitList, outcomeList, *probability);
1705
1706 return outcome;
1707}
1708
1709qreal applyForcedMultiQubitMeasurement(Qureg qureg, int* qubits, int* outcomes, int numQubits) {
1710 validate_quregFields(qureg, __func__);
1711 validate_targets(qureg, qubits, numQubits, __func__);
1712 validate_measurementOutcomesAreValid(outcomes, numQubits, __func__);
1713
1714 auto qubitList = lists_getList64(qubits, numQubits);
1715 auto outcomeList = lists_getList64(outcomes, numQubits);
1716
1717 // ensure probability of the forced measurement outcome is not negligible
1718 qreal prob = calcProbOfMultiQubitOutcome(qureg, qubits, outcomes, numQubits); // harmlessly re-validates
1719 validate_measurementOutcomesProbNotZero(outcomes, numQubits, prob, __func__);
1720
1721 // project to the outcome, renormalising the surviving states
1722 (qureg.isDensityMatrix)?
1723 localiser_densmatr_multiQubitProjector(qureg, qubitList, outcomeList, prob):
1724 localiser_statevec_multiQubitProjector(qureg, qubitList, outcomeList, prob);
1725
1726 return prob;
1727}
1728
1729} // end de-mangler
1730
1731qindex applyMultiQubitMeasurement(Qureg qureg, vector<int> qubits) {
1732
1733 return applyMultiQubitMeasurement(qureg, qubits.data(), qubits.size());
1734}
1735
1736qindex applyMultiQubitMeasurementAndGetProb(Qureg qureg, vector<int> qubits, qreal* probability) {
1737
1738 return applyMultiQubitMeasurementAndGetProb(qureg, qubits.data(), qubits.size(), probability);
1739}
1740
1741qreal applyForcedMultiQubitMeasurement(Qureg qureg, vector<int> qubits, vector<int> outcomes) {
1742 validate_measurementOutcomesMatchTargets(qubits.size(), outcomes.size(), __func__);
1743
1744 return applyForcedMultiQubitMeasurement(qureg, qubits.data(), outcomes.data(), outcomes.size());
1745}
1746
1747
1748
1749/*
1750 * QFT
1751 */
1752
1753extern "C" {
1754
1755void applyQuantumFourierTransform(Qureg qureg, int* targets, int numTargets, bool inverse) {
1756 validate_quregFields(qureg, __func__);
1757 validate_targets(qureg, targets, numTargets, __func__);
1758
1759 /// @todo
1760 /// change this placeholder implementation to the bespoke, optimised routine,
1761 /// wherein each contiguous controlled-phase gate is merged
1762
1763 int mid = numTargets/2; // floors
1764
1765 // don't think it is worth overcomplicating this to avoid slight repetition
1766 if (inverse) {
1767 for (int n=0; n<mid; n++)
1768 applySwap(qureg, targets[n], targets[numTargets-1-n]);
1769
1770 for (int n=0; n<numTargets; n++) {
1771 for (int m=0; m<n; m++) {
1772 qreal arg = - const_PI / powerOf2(m+1);
1773 applyTwoQubitPhaseShift(qureg, targets[n], targets[n-m-1], arg);
1774 }
1775 applyHadamard(qureg, targets[n]);
1776 }
1777
1778 } else {
1779 for (int n=numTargets-1; n>=0; n--) {
1780 applyHadamard(qureg, targets[n]);
1781
1782 for (int m=0; m<n; m++) {
1783 qreal arg = const_PI / powerOf2(m+1);
1784 applyTwoQubitPhaseShift(qureg, targets[n], targets[n-m-1], arg);
1785 }
1786 }
1787
1788 for (int n=0; n<mid; n++)
1789 applySwap(qureg, targets[n], targets[numTargets-1-n]);
1790 }
1791}
1792
1793void applyFullQuantumFourierTransform(Qureg qureg, bool inverse) {
1794 validate_quregFields(qureg, __func__);
1795
1796 auto targets = util_getRange(qureg.numQubits);
1797 applyQuantumFourierTransform(qureg, targets.data(), targets.size(), inverse);
1798}
1799
1800} // end de-mangler
1801
1802void applyQuantumFourierTransform(Qureg qureg, vector<int> targets, bool inverse) {
1803
1804 applyQuantumFourierTransform(qureg, targets.data(), targets.size(), inverse);
1805}
qreal calcProbOfQubitOutcome(Qureg qureg, int qubit, int outcome)
void calcProbsOfAllMultiQubitOutcomes(qreal *outcomeProbs, Qureg qureg, int *qubits, int numQubits)
qreal calcProbOfMultiQubitOutcome(Qureg qureg, int *qubits, int *outcomes, int numQubits)
static CompMatr2 getCompMatr2(qcomp **in)
Definition matrices.h:837
static CompMatr1 getCompMatr1(qcomp **in)
Definition matrices.h:811
static DiagMatr1 getDiagMatr1(qcomp *in)
Definition matrices.h:864
void applyCompMatr1(Qureg qureg, int target, CompMatr1 matrix)
void applyMultiControlledCompMatr1(Qureg qureg, int *controls, int numControls, int target, CompMatr1 matrix)
void applyControlledCompMatr1(Qureg qureg, int control, int target, CompMatr1 matrix)
void applyMultiStateControlledCompMatr1(Qureg qureg, int *controls, int *states, int numControls, int target, CompMatr1 matrix)
void applyMultiStateControlledCompMatr2(Qureg qureg, int *controls, int *states, int numControls, int target1, int target2, CompMatr2 matrix)
void applyMultiControlledCompMatr2(Qureg qureg, int *controls, int numControls, int target1, int target2, CompMatr2 matrix)
void applyControlledCompMatr2(Qureg qureg, int control, int target1, int target2, CompMatr2 matrix)
void applyCompMatr2(Qureg qureg, int target1, int target2, CompMatr2 matrix)
void applyMultiStateControlledCompMatr(Qureg qureg, int *controls, int *states, int numControls, int *targets, int numTargets, CompMatr matrix)
void applyControlledCompMatr(Qureg qureg, int control, int *targets, int numTargets, CompMatr matrix)
void applyCompMatr(Qureg qureg, int *targets, int numTargets, CompMatr matrix)
void applyMultiControlledCompMatr(Qureg qureg, int *controls, int numControls, int *targets, int numTargets, CompMatr matrix)
void applyDiagMatr1(Qureg qureg, int target, DiagMatr1 matrix)
void applyMultiControlledDiagMatr1(Qureg qureg, int *controls, int numControls, int target, DiagMatr1 matrix)
void applyControlledDiagMatr1(Qureg qureg, int control, int target, DiagMatr1 matrix)
void applyMultiStateControlledDiagMatr1(Qureg qureg, int *controls, int *states, int numControls, int target, DiagMatr1 matrix)
void applyDiagMatr2(Qureg qureg, int target1, int target2, DiagMatr2 matrix)
void applyMultiControlledDiagMatr2(Qureg qureg, int *controls, int numControls, int target1, int target2, DiagMatr2 matrix)
void applyControlledDiagMatr2(Qureg qureg, int control, int target1, int target2, DiagMatr2 matrix)
void applyMultiStateControlledDiagMatr2(Qureg qureg, int *controls, int *states, int numControls, int target1, int target2, DiagMatr2 matrix)
void applyDiagMatr(Qureg qureg, int *targets, int numTargets, DiagMatr matrix)
void applyMultiControlledDiagMatrPower(Qureg qureg, int *controls, int numControls, int *targets, int numTargets, DiagMatr matrix, qcomp exponent)
void applyMultiStateControlledDiagMatrPower(Qureg qureg, int *controls, int *states, int numControls, int *targets, int numTargets, DiagMatr matrix, qcomp exponent)
void applyDiagMatrPower(Qureg qureg, int *targets, int numTargets, DiagMatr matrix, qcomp exponent)
void applyControlledDiagMatr(Qureg qureg, int control, int *targets, int numTargets, DiagMatr matrix)
void applyMultiControlledDiagMatr(Qureg qureg, int *controls, int numControls, int *targets, int numTargets, DiagMatr matrix)
void applyControlledDiagMatrPower(Qureg qureg, int control, int *targets, int numTargets, DiagMatr matrix, qcomp exponent)
void applyMultiStateControlledDiagMatr(Qureg qureg, int *controls, int *states, int numControls, int *targets, int numTargets, DiagMatr matrix)
void applyControlledT(Qureg qureg, int control, int target)
void applyControlledS(Qureg qureg, int control, int target)
void applyMultiStateControlledHadamard(Qureg qureg, int *controls, int *states, int numControls, int target)
void applyMultiControlledHadamard(Qureg qureg, int *controls, int numControls, int target)
void applyS(Qureg qureg, int target)
void applyMultiControlledT(Qureg qureg, int *controls, int numControls, int target)
void applyMultiControlledS(Qureg qureg, int *controls, int numControls, int target)
void applyT(Qureg qureg, int target)
void applyMultiStateControlledS(Qureg qureg, int *controls, int *states, int numControls, int target)
void applyHadamard(Qureg qureg, int target)
void applyControlledHadamard(Qureg qureg, int control, int target)
void applyMultiStateControlledT(Qureg qureg, int *controls, int *states, int numControls, int target)
void applyFullStateDiagMatr(Qureg qureg, FullStateDiagMatr matrix)
void applyFullStateDiagMatrPower(Qureg qureg, FullStateDiagMatr matrix, qcomp exponent)
qreal applyForcedQubitMeasurement(Qureg qureg, int target, int outcome)
qindex applyMultiQubitMeasurement(Qureg qureg, int *qubits, int numQubits)
int applyQubitMeasurement(Qureg qureg, int target)
qreal applyForcedMultiQubitMeasurement(Qureg qureg, int *qubits, int *outcomes, int numQubits)
qindex applyMultiQubitMeasurementAndGetProb(Qureg qureg, int *qubits, int numQubits, qreal *probability)
int applyQubitMeasurementAndGetProb(Qureg qureg, int target, qreal *probability)
void applyMultiStateControlledMultiQubitNot(Qureg qureg, int *controls, int *states, int numControls, int *targets, int numTargets)
void applyMultiControlledMultiQubitNot(Qureg qureg, int *controls, int numControls, int *targets, int numTargets)
void applyMultiQubitNot(Qureg qureg, int *targets, int numTargets)
void applyControlledMultiQubitNot(Qureg qureg, int control, int *targets, int numTargets)
void applyMultiControlledPauliZ(Qureg qureg, int *controls, int numControls, int target)
void applyPauliX(Qureg qureg, int target)
void applyControlledPauliX(Qureg qureg, int control, int target)
void applyMultiStateControlledPauliY(Qureg qureg, int *controls, int *states, int numControls, int target)
void applyMultiControlledPauliY(Qureg qureg, int *controls, int numControls, int target)
void applyControlledPauliZ(Qureg qureg, int control, int target)
void applyMultiControlledPauliX(Qureg qureg, int *controls, int numControls, int target)
void applyPauliZ(Qureg qureg, int target)
void applyMultiStateControlledPauliZ(Qureg qureg, int *controls, int *states, int numControls, int target)
void applyPauliY(Qureg qureg, int target)
void applyControlledPauliY(Qureg qureg, int control, int target)
void applyMultiStateControlledPauliX(Qureg qureg, int *controls, int *states, int numControls, int target)
void applyMultiControlledPauliGadget(Qureg qureg, int *controls, int numControls, PauliStr str, qreal angle)
void applyControlledPauliGadget(Qureg qureg, int control, PauliStr str, qreal angle)
void applyMultiStateControlledPauliGadget(Qureg qureg, int *controls, int *states, int numControls, PauliStr str, qreal angle)
void applyNonUnitaryPauliGadget(Qureg qureg, PauliStr str, qcomp angle)
void applyPauliGadget(Qureg qureg, PauliStr str, qreal angle)
void applyMultiControlledPauliStr(Qureg qureg, int *controls, int numControls, PauliStr str)
void applyPauliStr(Qureg qureg, PauliStr str)
void applyMultiStateControlledPauliStr(Qureg qureg, int *controls, int *states, int numControls, PauliStr str)
void applyControlledPauliStr(Qureg qureg, int control, PauliStr str)
void applyControlledPhaseGadget(Qureg qureg, int control, int *targets, int numTargets, qreal angle)
void applyMultiControlledPhaseGadget(Qureg qureg, int *controls, int numControls, int *targets, int numTargets, qreal angle)
void applyMultiQubitPhaseShift(Qureg qureg, int *targets, int numTargets, qreal angle)
void applyTwoQubitPhaseShift(Qureg qureg, int target1, int target2, qreal angle)
void applyTwoQubitPhaseFlip(Qureg qureg, int target1, int target2)
void applyMultiStateControlledPhaseGadget(Qureg qureg, int *controls, int *states, int numControls, int *targets, int numTargets, qreal angle)
void applyPhaseShift(Qureg qureg, int target, qreal angle)
void applyPhaseFlip(Qureg qureg, int target)
void applyMultiQubitPhaseFlip(Qureg qureg, int *targets, int numTargets)
void applyPhaseGadget(Qureg qureg, int *targets, int numTargets, qreal angle)
void applyMultiQubitProjector(Qureg qureg, int *qubits, int *outcomes, int numQubits)
void applyQubitProjector(Qureg qureg, int target, int outcome)
void applyQuantumFourierTransform(Qureg qureg, int *targets, int numTargets, bool inverse)
void applyFullQuantumFourierTransform(Qureg qureg, bool inverse)
void applyMultiStateControlledRotateY(Qureg qureg, int *controls, int *states, int numControls, int target, qreal angle)
void applyControlledRotateZ(Qureg qureg, int control, int target, qreal angle)
void applyMultiControlledRotateX(Qureg qureg, int *controls, int numControls, int target, qreal angle)
void applyMultiStateControlledRotateX(Qureg qureg, int *controls, int *states, int numControls, int target, qreal angle)
void applyMultiControlledRotateZ(Qureg qureg, int *controls, int numControls, int target, qreal angle)
void applyMultiStateControlledRotateZ(Qureg qureg, int *controls, int *states, int numControls, int target, qreal angle)
void applyControlledRotateAroundAxis(Qureg qureg, int ctrl, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ)
void applyRotateZ(Qureg qureg, int target, qreal angle)
void applyControlledRotateX(Qureg qureg, int control, int target, qreal angle)
void applyRotateY(Qureg qureg, int target, qreal angle)
void applyRotateX(Qureg qureg, int target, qreal angle)
void applyRotateAroundAxis(Qureg qureg, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ)
void applyMultiControlledRotateAroundAxis(Qureg qureg, int *ctrls, int numCtrls, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ)
void applyMultiStateControlledRotateAroundAxis(Qureg qureg, int *ctrls, int *states, int numCtrls, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ)
void applyMultiControlledRotateY(Qureg qureg, int *controls, int numControls, int target, qreal angle)
void applyControlledRotateY(Qureg qureg, int control, int target, qreal angle)
void applyMultiControlledSwap(Qureg qureg, int *controls, int numControls, int qubit1, int qubit2)
void applyControlledSwap(Qureg qureg, int control, int qubit1, int qubit2)
void applyMultiStateControlledSwap(Qureg qureg, int *controls, int *states, int numControls, int qubit1, int qubit2)
void applySwap(Qureg qureg, int qubit1, int qubit2)
void applyControlledSqrtSwap(Qureg qureg, int control, int target1, int target2)
void applySqrtSwap(Qureg qureg, int target1, int target2)
void applyMultiControlledSqrtSwap(Qureg qureg, int *controls, int numControls, int target1, int target2)
void applyMultiStateControlledSqrtSwap(Qureg qureg, int *controls, int *states, int numControls, int target1, int target2)
PauliStr getPauliStr(const char *paulis, int *indices, int numPaulis)
Definition paulis.cpp:76
qcomp elems[2]
Definition matrices.h:336
Definition qureg.h:49