The Quantum Exact Simulation Toolkit v4.2.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 auto ctrlVec = util_getVector(ctrls, numCtrls);
46 auto stateVec = util_getVector(states, numCtrls);
47 auto targVec = util_getVector(targs, numTargs);
48
49 bool conj = false;
50 localiser_statevec_anyCtrlAnyTargAnyMatr(qureg, ctrlVec, stateVec, targVec, matr, conj);
51
52 if (!qureg.isDensityMatrix)
53 return;
54
55 conj = true;
56 ctrlVec = util_getBraQubits(ctrlVec, qureg);
57 targVec = util_getBraQubits(targVec, qureg);
58 localiser_statevec_anyCtrlAnyTargAnyMatr(qureg, ctrlVec, stateVec, targVec, 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 numControls, 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 ctrlVec = util_getVector(controls, numControls);
414 auto stateVec = util_getVector(states, numControls); // empty if states==nullptr
415 auto targVec = util_getVector(targets, numTargets);
416 localiser_statevec_anyCtrlAnyTargDiagMatr(qureg, ctrlVec, stateVec, targVec, matrix, exponent, conj);
417
418 if (!qureg.isDensityMatrix)
419 return;
420
421 conj = true;
422 ctrlVec = util_getBraQubits(ctrlVec, qureg);
423 targVec = util_getBraQubits(targVec, qureg);
424 localiser_statevec_anyCtrlAnyTargDiagMatr(qureg, ctrlVec, stateVec, targVec, 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 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 DiagMatr1 matr = getDiagMatr1({1, 1/std::sqrt(2) + 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 qcomp a = 1/std::sqrt(2);
624 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 ctrlVec = util_getVector(controls, numControls);
682 auto stateVec = util_getVector(states, numControls); // empty if states==nullptr
683 localiser_statevec_anyCtrlSwap(qureg, ctrlVec, stateVec, qubit1, qubit2);
684
685 if (!qureg.isDensityMatrix)
686 return;
687
688 ctrlVec = util_getBraQubits(ctrlVec, qureg);
689 qubit1 = util_getBraQubit(qubit1, qureg);
690 qubit2 = util_getBraQubit(qubit2, qureg);
691 localiser_statevec_anyCtrlSwap(qureg, ctrlVec, stateVec, 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 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 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 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 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 ctrlVec = util_getVector(controls, numControls);
970 auto stateVec = util_getVector(states, numControls); // empty if states==nullptr
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 ctrlVec = util_getConcatenated(ctrlVec, util_getBraQubits(ctrlVec, qureg));
978 stateVec = util_getConcatenated(stateVec, stateVec);
979 str = paulis_getKetAndBraPauliStr(str, qureg);
980 }
981
982 localiser_statevec_anyCtrlPauliTensor(qureg, ctrlVec, stateVec, 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 ctrlVec = util_getBraQubits(ctrlVec, qureg);
988 str = paulis_getShiftedPauliStr(str, qureg.numQubits);
989 localiser_statevec_anyCtrlPauliTensor(qureg, ctrlVec, stateVec, 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 localiser_statevec_anyCtrlPauliGadget(qureg, {}, {}, str, phase);
1254
1255 if (!qureg.isDensityMatrix)
1256 return;
1257
1258 // conj(e^i(a)P) = e^(-i s conj(a) P)
1259 phase = - std::conj(phase) * paulis_getSignOfPauliStrConj(str);
1260 str = paulis_getShiftedPauliStr(str, qureg.numQubits);
1261 localiser_statevec_anyCtrlPauliGadget(qureg, {}, {}, str, phase);
1262}
1263
1264void applyControlledPauliGadget(Qureg qureg, int control, PauliStr str, qreal angle) {
1265 validate_quregFields(qureg, __func__);
1266 validate_controlAndPauliStrTargets(qureg, control, str, __func__);
1267
1268 applyMultiStateControlledPauliGadget(qureg, &control, nullptr, 1, str, angle);
1269}
1270
1271void applyMultiControlledPauliGadget(Qureg qureg, int* controls, int numControls, PauliStr str, qreal angle) {
1272 validate_quregFields(qureg, __func__);
1273 validate_controlsAndPauliStrTargets(qureg, controls, numControls, str, __func__);
1274
1275 applyMultiStateControlledPauliGadget(qureg, controls, nullptr, numControls, str, angle);
1276}
1277
1278void 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
1310void applyMultiControlledPauliGadget(Qureg qureg, vector<int> controls, PauliStr str, qreal angle) {
1311
1312 applyMultiControlledPauliGadget(qureg, controls.data(), controls.size(), str, angle);
1313}
1314
1315void applyMultiStateControlledPauliGadget(Qureg qureg, vector<int> controls, vector<int> states, PauliStr str, qreal angle) {
1316 validate_controlsMatchStates(controls.size(), states.size(), __func__);
1317
1318 applyMultiStateControlledPauliGadget(qureg, controls.data(), states.data(), controls.size(), str, angle);
1319}
1320
1321
1322
1323/*
1324 * phase gadgets
1325 */
1326
1327extern "C" {
1328
1329void applyPhaseGadget(Qureg qureg, int* targets, int numTargets, qreal angle) {
1330 validate_quregFields(qureg, __func__);
1331 validate_targets(qureg, targets, numTargets, __func__);
1332
1333 // harmlessly re-validates
1334 applyMultiStateControlledPhaseGadget(qureg, nullptr, nullptr, 0, targets, numTargets, angle);
1335}
1336
1337void applyControlledPhaseGadget(Qureg qureg, int control, int* targets, int numTargets, qreal angle) {
1338 validate_quregFields(qureg, __func__);
1339 validate_controlAndTargets(qureg, control, targets, numTargets, __func__);
1340
1341 // harmlessly re-validates
1342 applyMultiStateControlledPhaseGadget(qureg, &control, nullptr, 1, targets, numTargets, angle);
1343}
1344
1345void applyMultiControlledPhaseGadget(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, qreal angle) {
1346 validate_quregFields(qureg, __func__);
1347 validate_controlsAndTargets(qureg, controls, numControls, targets, numTargets, __func__);
1348
1349 // harmlessly re-validates
1350 applyMultiStateControlledPhaseGadget(qureg, controls, nullptr, numControls, targets, numTargets, angle);
1351}
1352
1353void applyMultiStateControlledPhaseGadget(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, qreal angle) {
1354 validate_quregFields(qureg, __func__);
1355 validate_controlsAndTargets(qureg, controls, numControls, targets, numTargets, __func__);
1356 validate_controlStates(states, numControls, __func__);
1357
1358 qreal phase = util_getPhaseFromGateAngle(angle);
1359 auto ctrlVec = util_getVector(controls, numControls);
1360 auto targVec = util_getVector(targets, numTargets);
1361 auto stateVec = util_getVector(states, numControls); // empty if states==nullptr
1362 localiser_statevec_anyCtrlPhaseGadget(qureg, ctrlVec, stateVec, targVec, phase);
1363
1364 if (!qureg.isDensityMatrix)
1365 return;
1366
1367 phase *= -1;
1368 ctrlVec = util_getBraQubits(ctrlVec, qureg);
1369 targVec = util_getBraQubits(targVec, qureg);
1370 localiser_statevec_anyCtrlPhaseGadget(qureg, ctrlVec, stateVec, targVec, phase);
1371}
1372
1373} // end de-mangler
1374
1375void applyPhaseGadget(Qureg qureg, vector<int> targets, qreal angle) {
1376
1377 applyPhaseGadget(qureg, targets.data(), targets.size(), angle);
1378}
1379
1380void applyControlledPhaseGadget(Qureg qureg, int control, vector<int> targets, qreal angle) {
1381
1382 applyControlledPhaseGadget(qureg, control, targets.data(), targets.size(), angle);
1383}
1384
1385void applyMultiControlledPhaseGadget(Qureg qureg, vector<int> controls, vector<int> targets, qreal angle) {
1386
1387 applyMultiControlledPhaseGadget(qureg, controls.data(), controls.size(), targets.data(), targets.size(), angle);
1388}
1389
1390void applyMultiStateControlledPhaseGadget(Qureg qureg, vector<int> controls, vector<int> states, vector<int> targets, qreal angle) {
1391 validate_controlsMatchStates(controls.size(), states.size(), __func__);
1392
1393 applyMultiStateControlledPhaseGadget(qureg, controls.data(), states.data(), controls.size(), targets.data(), targets.size(), angle);
1394}
1395
1396
1397
1398/*
1399 * phase shift
1400 */
1401
1402extern "C" {
1403
1404void applyPhaseShift(Qureg qureg, int target, qreal angle) {
1405 validate_quregFields(qureg, __func__);
1406 validate_target(qureg, target, __func__);
1407
1408 // harmlessly re-validates
1409 applyMultiQubitPhaseShift(qureg, &target, 1, angle);
1410}
1411
1412void applyTwoQubitPhaseShift(Qureg qureg, int target1, int target2, qreal angle) {
1413 validate_quregFields(qureg, __func__);
1414 validate_twoTargets(qureg, target1, target2, __func__);
1415
1416 // harmlessly re-validates
1417 int targets[] = {target1, target2};
1418 applyMultiQubitPhaseShift(qureg, targets, 2, angle);
1419}
1420
1421void applyMultiQubitPhaseShift(Qureg qureg, int* targets, int numTargets, qreal angle) {
1422 validate_quregFields(qureg, __func__);
1423 validate_targets(qureg, targets, numTargets, __func__);
1424
1425 // treat as a (numTargets-1)-controlled 1-target diagonal matrix
1426 DiagMatr1 matr = getDiagMatr1({1, std::exp(1_i * angle)});
1427
1428 // harmlessly re-validates
1429 applyMultiStateControlledDiagMatr1(qureg, &targets[1], nullptr, numTargets-1, targets[0], matr);
1430}
1431
1432} // end de-mangler
1433
1434void applyMultiQubitPhaseShift(Qureg qureg, vector<int> targets, qreal angle) {
1435
1436 applyMultiQubitPhaseShift(qureg, targets.data(), targets.size(), angle);
1437}
1438
1439
1440
1441/*
1442 * phase flips
1443 */
1444
1445extern "C" {
1446
1447void applyPhaseFlip(Qureg qureg, int target) {
1448 validate_quregFields(qureg, __func__);
1449 validate_target(qureg, target, __func__);
1450
1451 // harmlessly re-validates
1452 applyMultiQubitPhaseFlip(qureg, &target, 1);
1453}
1454
1455void applyTwoQubitPhaseFlip(Qureg qureg, int target1, int target2) {
1456 validate_quregFields(qureg, __func__);
1457 validate_twoTargets(qureg, target1, target2, __func__);
1458
1459 // harmlessly re-validates
1460 int targets[] = {target1, target2};
1461 applyMultiQubitPhaseFlip(qureg, targets, 2);
1462}
1463
1464void applyMultiQubitPhaseFlip(Qureg qureg, int* targets, int numTargets) {
1465 validate_quregFields(qureg, __func__);
1466 validate_targets(qureg, targets, numTargets, __func__);
1467
1468 // treat as a (numTargets-1)-controlled 1-target Pauli Z
1469 DiagMatr1 matr = getDiagMatr1({1, -1});
1470
1471 // harmlessly re-validates
1472 applyMultiStateControlledDiagMatr1(qureg, &targets[1], nullptr, numTargets-1, targets[0], matr);
1473}
1474
1475} // end de-mangler
1476
1477void applyMultiQubitPhaseFlip(Qureg qureg, vector<int> targets) {
1478
1479 applyMultiQubitPhaseFlip(qureg, targets.data(), targets.size());
1480}
1481
1482
1483
1484/*
1485 * many-qubit NOTs and CNOTs
1486 */
1487
1488extern "C" {
1489
1490void applyMultiQubitNot(Qureg qureg, int* targets, int numTargets) {
1491 validate_quregFields(qureg, __func__);
1492 validate_targets(qureg, targets, numTargets, __func__);
1493
1494 // harmlessly re-validates
1495 applyMultiStateControlledMultiQubitNot(qureg, nullptr, nullptr, 0, targets, numTargets);
1496}
1497
1498void applyControlledMultiQubitNot(Qureg qureg, int control, int* targets, int numTargets) {
1499 validate_quregFields(qureg, __func__);
1500 validate_controlAndTargets(qureg, control, targets, numTargets, __func__);
1501
1502 // harmlessly re-validates
1503 applyMultiStateControlledMultiQubitNot(qureg, &control, nullptr, 1, targets, numTargets);
1504}
1505
1506void applyMultiControlledMultiQubitNot(Qureg qureg, int* controls, int numControls, int* targets, int numTargets) {
1507 validate_quregFields(qureg, __func__);
1508 validate_controlsAndTargets(qureg, controls, numControls, targets, numTargets, __func__);
1509
1510 // harmlessly re-validates
1511 applyMultiStateControlledMultiQubitNot(qureg, controls, nullptr, numControls, targets, numTargets);
1512}
1513
1514void applyMultiStateControlledMultiQubitNot(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets) {
1515 validate_quregFields(qureg, __func__);
1516 validate_controlsAndTargets(qureg, controls, numControls, targets, numTargets, __func__);
1517 validate_controlStates(states, numControls, __func__);
1518
1519 // treat as an all-X PauliStr
1520 PauliStr str = getPauliStr(std::string(numTargets, 'X'), targets, numTargets);
1521
1522 // harmlessly re-validates
1523 applyMultiStateControlledPauliStr(qureg, controls, states, numControls, str);
1524}
1525
1526} // end de-mangler
1527
1528void applyMultiQubitNot(Qureg qureg, vector<int> targets) {
1529
1530 applyMultiQubitNot(qureg, targets.data(), targets.size());
1531}
1532
1533void applyControlledMultiQubitNot(Qureg qureg, int control, vector<int> targets) {
1534
1535 applyControlledMultiQubitNot(qureg, control, targets.data(), targets.size());
1536}
1537
1538void applyMultiControlledMultiQubitNot(Qureg qureg, vector<int> controls, vector<int> targets) {
1539
1540 applyMultiControlledMultiQubitNot(qureg, controls.data(), controls.size(), targets.data(), targets.size());
1541}
1542
1543void applyMultiStateControlledMultiQubitNot(Qureg qureg, vector<int> controls, vector<int> states, vector<int> targets) {
1544 validate_controlsMatchStates(controls.size(), states.size(), __func__);
1545
1546 applyMultiStateControlledMultiQubitNot(qureg, controls.data(), states.data(), controls.size(), targets.data(), targets.size());
1547}
1548
1549
1550
1551/*
1552 * projectors
1553 */
1554
1555extern "C" {
1556
1557void applyQubitProjector(Qureg qureg, int target, int outcome) {
1558 validate_quregFields(qureg, __func__);
1559 validate_target(qureg, target, __func__);
1560 validate_measurementOutcomeIsValid(outcome, __func__);
1561
1562 qreal prob = 1;
1563
1564 // density matrix has an optimised func in lieu of calling the statevector func twice
1565 (qureg.isDensityMatrix)?
1566 localiser_densmatr_multiQubitProjector(qureg, {target}, {outcome}, prob):
1567 localiser_statevec_multiQubitProjector(qureg, {target}, {outcome}, prob);
1568}
1569
1570void applyMultiQubitProjector(Qureg qureg, int* qubits, int* outcomes, int numQubits) {
1571 validate_quregFields(qureg, __func__);
1572 validate_targets(qureg, qubits, numQubits, __func__);
1573 validate_measurementOutcomesAreValid(outcomes, numQubits, __func__);
1574
1575 qreal prob = 1;
1576 auto qubitVec = util_getVector(qubits, numQubits);
1577 auto outcomeVec = util_getVector(outcomes, numQubits);
1578
1579 // density matrix has an optimised func in lieu of calling the statevector func twice
1580 (qureg.isDensityMatrix)?
1581 localiser_densmatr_multiQubitProjector(qureg, qubitVec, outcomeVec, prob):
1582 localiser_statevec_multiQubitProjector(qureg, qubitVec, outcomeVec, prob);
1583}
1584
1585} // end de-mangler
1586
1587void applyMultiQubitProjector(Qureg qureg, vector<int> qubits, vector<int> outcomes) {
1588 validate_measurementOutcomesMatchTargets(qubits.size(), outcomes.size(), __func__);
1589
1590 applyMultiQubitProjector(qureg, qubits.data(), outcomes.data(), outcomes.size());
1591}
1592
1593
1594
1595/*
1596 * measurement
1597 */
1598
1599extern "C" {
1600
1601int applyQubitMeasurement(Qureg qureg, int target) {
1602 validate_quregFields(qureg, __func__);
1603 validate_target(qureg, target, __func__);
1604
1605 qreal prob = 0; // ignored
1606 return applyQubitMeasurementAndGetProb(qureg, target, &prob); // harmlessly re-validates
1607}
1608
1609int applyQubitMeasurementAndGetProb(Qureg qureg, int target, qreal* probability) {
1610 validate_quregFields(qureg, __func__);
1611 validate_target(qureg, target, __func__);
1612
1613 // we do not assume state normalisation (that is posteriori checked),
1614 // so we must perform two reductions; one for each outcome. We choose
1615 // to re-enumerate the state (potentially doubling caching costs) to
1616 // avoid the nuisances/race-cons of parallel adding to two scalars.
1617 vector<qreal> probs(2);
1618 probs[0] = calcProbOfQubitOutcome(qureg, target, 0); // harmlessly re-validates
1619 probs[1] = calcProbOfQubitOutcome(qureg, target, 1); // " "
1620 validate_measurementProbsAreNormalised(probs, __func__);
1621
1622 // randomly choose the outcome
1623 int outcome = rand_getRandomSingleQubitOutcome(probs[0]);
1624 *probability = probs[outcome];
1625
1626 // collapse to the outcome
1627 (qureg.isDensityMatrix)?
1628 localiser_densmatr_multiQubitProjector(qureg, {target}, {outcome}, *probability):
1629 localiser_statevec_multiQubitProjector(qureg, {target}, {outcome}, *probability);
1630
1631 return outcome;
1632}
1633
1634qreal applyForcedQubitMeasurement(Qureg qureg, int target, int outcome) {
1635 validate_quregFields(qureg, __func__);
1636 validate_target(qureg, target, __func__);
1637 validate_measurementOutcomeIsValid(outcome, __func__);
1638
1639 // note that we do not merely invoke applyForcedMultiQubitMeasurement()
1640 // because we must validate the renormalising probability and
1641 // report this function's name during the error message
1642 qreal prob = calcProbOfQubitOutcome(qureg, target, outcome); // harmlessly re-validates
1643 validate_measurementOutcomeProbNotZero(outcome, prob, __func__);
1644
1645 // project to the outcome, renormalising the surviving states
1646 (qureg.isDensityMatrix)?
1647 localiser_densmatr_multiQubitProjector(qureg, {target}, {outcome}, prob):
1648 localiser_statevec_multiQubitProjector(qureg, {target}, {outcome}, prob);
1649
1650 return prob;
1651}
1652
1653qindex applyMultiQubitMeasurement(Qureg qureg, int* qubits, int numQubits) {
1654 validate_quregFields(qureg, __func__);
1655 validate_targets(qureg, qubits, numQubits, __func__);
1656
1657 qreal prob = 0; // ignored
1658
1659 // below validates post-measurement and would report 'AndGetProb' function suffix. Eh!
1660 return applyMultiQubitMeasurementAndGetProb(qureg, qubits, numQubits, &prob);
1661}
1662
1663qindex applyMultiQubitMeasurementAndGetProb(Qureg qureg, int* qubits, int numQubits, qreal* probability) {
1664 validate_quregFields(qureg, __func__);
1665 validate_targets(qureg, qubits, numQubits, __func__);
1666
1667 // find the probability of all possible outcomes...
1668 qindex numProbs = powerOf2(numQubits);
1669
1670 // by allocating a temp vector, and validating successful (since exponentially big!)
1671 vector<qreal> probs;
1672 auto callback = [&]() { validate_tempAllocSucceeded(false, numProbs, sizeof(qreal), __func__); };
1673 util_tryAllocVector(probs, numProbs, callback);
1674
1675 // populate probs
1676 calcProbsOfAllMultiQubitOutcomes(probs.data(), qureg, qubits, numQubits); // harmlessly re-validates
1677
1678 // we cannot meaningfully sample these probs if not normalised
1679 validate_measurementProbsAreNormalised(probs, __func__);
1680
1681 // randomly choose an outcome
1682 qindex outcome = rand_getRandomMultiQubitOutcome(probs);
1683 *probability = probs[outcome];
1684
1685 // map outcome to individual qubit outcomes
1686 auto qubitVec = util_getVector(qubits, numQubits);
1687 auto outcomeVec = vector<int>(numQubits);
1688 getBitsFromInteger(outcomeVec.data(), outcome, numQubits);
1689
1690 // project to the outcomes, renormalising the surviving states
1691 (qureg.isDensityMatrix)?
1692 localiser_densmatr_multiQubitProjector(qureg, qubitVec, outcomeVec, *probability):
1693 localiser_statevec_multiQubitProjector(qureg, qubitVec, outcomeVec, *probability);
1694
1695 return outcome;
1696}
1697
1698qreal applyForcedMultiQubitMeasurement(Qureg qureg, int* qubits, int* outcomes, int numQubits) {
1699 validate_quregFields(qureg, __func__);
1700 validate_targets(qureg, qubits, numQubits, __func__);
1701 validate_measurementOutcomesAreValid(outcomes, numQubits, __func__);
1702
1703 auto qubitVec = util_getVector(qubits, numQubits);
1704 auto outcomeVec = util_getVector(outcomes, numQubits);
1705
1706 // ensure probability of the forced measurement outcome is not negligible
1707 qreal prob = calcProbOfMultiQubitOutcome(qureg, qubits, outcomes, numQubits); // harmlessly re-validates
1708 validate_measurementOutcomesProbNotZero(outcomes, numQubits, prob, __func__);
1709
1710 // project to the outcome, renormalising the surviving states
1711 (qureg.isDensityMatrix)?
1712 localiser_densmatr_multiQubitProjector(qureg, qubitVec, outcomeVec, prob):
1713 localiser_statevec_multiQubitProjector(qureg, qubitVec, outcomeVec, prob);
1714
1715 return prob;
1716}
1717
1718} // end de-mangler
1719
1720qindex applyMultiQubitMeasurementAndGetProb(Qureg qureg, vector<int> qubits, qreal* probability) {
1721
1722 return applyMultiQubitMeasurementAndGetProb(qureg, qubits.data(), qubits.size(), probability);
1723}
1724
1725qreal applyForcedMultiQubitMeasurement(Qureg qureg, vector<int> qubits, vector<int> outcomes) {
1726 validate_measurementOutcomesMatchTargets(qubits.size(), outcomes.size(), __func__);
1727
1728 return applyForcedMultiQubitMeasurement(qureg, qubits.data(), outcomes.data(), outcomes.size());
1729}
1730
1731
1732
1733/*
1734 * QFT
1735 */
1736
1737extern "C" {
1738
1739void applyQuantumFourierTransform(Qureg qureg, int* targets, int numTargets) {
1740 validate_quregFields(qureg, __func__);
1741 validate_targets(qureg, targets, numTargets, __func__);
1742
1743 /// @todo
1744 /// change this placeholder implementation to the bespoke, optimised routine,
1745 /// wherein each contiguous controlled-phase gate is merged
1746
1747 for (int n=numTargets-1; n>=0; n--) {
1748 applyHadamard(qureg, targets[n]);
1749 for (int m=0; m<n; m++) {
1750 qreal arg = const_PI / powerOf2(m+1);
1751 applyTwoQubitPhaseShift(qureg, targets[n], targets[n-m-1], arg);
1752 }
1753 }
1754
1755 int mid = numTargets/2; // floors
1756 for (int n=0; n<mid; n++)
1757 applySwap(qureg, targets[n], targets[numTargets-1-n]);
1758}
1759
1761 validate_quregFields(qureg, __func__);
1762
1763 // tiny; no need to validate alloc
1764 vector<int> targets(qureg.numQubits);
1765 for (size_t i=0; i<targets.size(); i++)
1766 targets[i] = i;
1767
1768 applyQuantumFourierTransform(qureg, targets.data(), targets.size());
1769}
1770
1771} // end de-mangler
1772
1773void applyQuantumFourierTransform(Qureg qureg, vector<int> targets) {
1774
1775 applyQuantumFourierTransform(qureg, targets.data(), targets.size());
1776}
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:351
static CompMatr1 getCompMatr1(qcomp **in)
Definition matrices.h:325
static DiagMatr1 getDiagMatr1(qcomp *in)
Definition matrices.h:378
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 applyCompMatr2(Qureg qureg, int target1, int target2, CompMatr2 matrix)
void applyControlledCompMatr2(Qureg qureg, int control, int target1, int target2, CompMatr2 matrix)
void applyMultiStateControlledCompMatr(Qureg qureg, int *controls, int *states, int numControls, int *targets, int numTargets, CompMatr matrix)
void applyMultiControlledCompMatr(Qureg qureg, int *controls, 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 applyControlledDiagMatr1(Qureg qureg, int control, int target, DiagMatr1 matrix)
void applyDiagMatr1(Qureg qureg, int target, DiagMatr1 matrix)
void applyMultiStateControlledDiagMatr1(Qureg qureg, int *controls, int *states, int numControls, int target, DiagMatr1 matrix)
void applyMultiControlledDiagMatr1(Qureg qureg, int *controls, int numControls, int target, DiagMatr1 matrix)
void applyMultiStateControlledDiagMatr2(Qureg qureg, int *controls, int *states, int numControls, int target1, int target2, DiagMatr2 matrix)
void applyMultiControlledDiagMatr2(Qureg qureg, int *controls, int numControls, int target1, int target2, DiagMatr2 matrix)
void applyDiagMatr2(Qureg qureg, int target1, int target2, DiagMatr2 matrix)
void applyControlledDiagMatr2(Qureg qureg, int control, 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 applyFullQuantumFourierTransform(Qureg qureg)
void applyQuantumFourierTransform(Qureg qureg, int *targets, int numTargets)
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 applyRotateZ(Qureg qureg, int target, qreal angle)
void applyMultiStateControlledRotateAroundAxis(Qureg qureg, int *ctrls, int *states, int numCtrls, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ)
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 applyMultiControlledRotateY(Qureg qureg, int *controls, int numControls, int target, qreal angle)
void applyControlledRotateAroundAxis(Qureg qureg, int ctrl, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ)
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
Definition qureg.h:49