Maestro 0.2.5
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
AerSimulator.h
Go to the documentation of this file.
1
13#pragma once
14
15#ifndef _AER_SIMULATOR_H_
16#define _AER_SIMULATOR_H_
17
18#ifndef NO_QISKIT_AER
19
20#ifdef INCLUDED_BY_FACTORY
21
22#include "AerState.h"
23
24namespace Simulators {
25// TODO: Maybe use the pimpl idiom
26// https://en.cppreference.com/w/cpp/language/pimpl to hide the implementation
27// for good but during development this should be good enough
28namespace Private {
29
41class AerSimulator : public AerState {
42 public:
43 AerSimulator() = default;
44 // allow no copy or assignment
45 AerSimulator(const AerSimulator &) = delete;
46 AerSimulator &operator=(const AerSimulator &) = delete;
47
48 // but allow moving
49 AerSimulator(AerSimulator &&other) = default;
50 AerSimulator &operator=(AerSimulator &&other) = default;
51
59 void ApplyP(Types::qubit_t qubit, double lambda) override {
60 if (GetSimulationType() == SimulationType::kStabilizer)
61 throw std::runtime_error("P gate not supported in stabilizer simulation");
62
63 const Types::qubits_vector qubits = {qubit};
64
65 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
66 AER::Operations::Op op;
67 op.type = AER::Operations::OpType::gate;
68 op.name = "p";
69 op.qubits = AER::reg_t{qubit};
70 op.params = {lambda};
71
72 state->buffer_op(std::move(op));
73 } else {
74 const AER::cvector_t P = {{1, 0}, std::polar(1., lambda)};
75 state->apply_diagonal_matrix(qubits, P);
76 }
77
78 NotifyObservers(qubits);
79 }
80
87 void ApplyX(Types::qubit_t qubit) override {
88 const Types::qubits_vector qubits = {qubit};
89 state->apply_x(qubit);
90 NotifyObservers(qubits);
91 }
92
99 void ApplyY(Types::qubit_t qubit) override {
100 const Types::qubits_vector qubits = {qubit};
101 state->apply_y(qubit);
102 NotifyObservers(qubits);
103 }
104
111 void ApplyZ(Types::qubit_t qubit) override {
112 const Types::qubits_vector qubits = {qubit};
113 state->apply_z(qubit);
114 NotifyObservers(qubits);
115 }
116
123 void ApplyH(Types::qubit_t qubit) override {
124 const Types::qubits_vector qubits = {qubit};
125 state->apply_h(qubit);
126 NotifyObservers(qubits);
127 }
128
135 void ApplyS(Types::qubit_t qubit) override {
136 const Types::qubits_vector qubits = {qubit};
137
138 if (GetSimulationType() == SimulationType::kStabilizer ||
139 GetSimulationType() == SimulationType::kExtendedStabilizer) {
140 AER::Operations::Op op;
141 op.type = AER::Operations::OpType::gate;
142 op.name = "s";
143 op.qubits = AER::reg_t{qubit};
144
145 state->buffer_op(std::move(op));
146 } else {
147 const AER::cvector_t S = {{1, 0}, complex_t(0.0, 1)};
148 state->apply_diagonal_matrix(qubits, S);
149 }
150
151 NotifyObservers(qubits);
152 }
153
160 void ApplySDG(Types::qubit_t qubit) override {
161 const Types::qubits_vector qubits = {qubit};
162
163 if (GetSimulationType() == SimulationType::kStabilizer ||
164 GetSimulationType() == SimulationType::kExtendedStabilizer) {
165 AER::Operations::Op op;
166 op.type = AER::Operations::OpType::gate;
167 op.name = "sdg";
168 op.qubits = AER::reg_t{qubit};
169
170 state->buffer_op(std::move(op));
171 } else {
172 const AER::cvector_t Sdg = {{1, 0}, complex_t(0.0, -1)};
173 state->apply_diagonal_matrix(qubits, Sdg);
174 }
175
176 NotifyObservers(qubits);
177 }
178
185 void ApplyT(Types::qubit_t qubit) override {
186 if (GetSimulationType() == SimulationType::kStabilizer)
187 throw std::runtime_error("T gate not supported in stabilizer simulation");
188
189 const Types::qubits_vector qubits = {qubit};
190 // state->apply_u(qubit, 0, 0, M_PI / 4.0);
191
192 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
193 AER::Operations::Op op;
194 op.type = AER::Operations::OpType::gate;
195 op.name = "t";
196 op.qubits = AER::reg_t{qubit};
197 state->buffer_op(std::move(op));
198 } else {
199 const AER::cvector_t T = {{1, 0}, std::polar<double>(1, M_PI / 4.)};
200 state->apply_diagonal_matrix(qubits, T);
201 }
202
203 NotifyObservers(qubits);
204 }
205
212 void ApplyTDG(Types::qubit_t qubit) override {
213 if (GetSimulationType() == SimulationType::kStabilizer)
214 throw std::runtime_error(
215 "TDG gate not supported in stabilizer simulation");
216
217 const Types::qubits_vector qubits = {qubit};
218 // state->apply_u(qubit, 0, 0, -M_PI / 4.0);
219
220 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
221 AER::Operations::Op op;
222 op.type = AER::Operations::OpType::gate;
223 op.name = "tdg";
224 op.qubits = AER::reg_t{qubit};
225 state->buffer_op(std::move(op));
226 } else {
227 const AER::cvector_t Tdg = {{1, 0}, std::polar<double>(1, -M_PI / 4.)};
228 state->apply_diagonal_matrix(qubits, Tdg);
229 }
230
231 NotifyObservers(qubits);
232 }
233
240 void ApplySx(Types::qubit_t qubit) override {
241 const Types::qubits_vector qubits = {qubit};
242
243 if (GetSimulationType() == SimulationType::kStabilizer ||
244 GetSimulationType() == SimulationType::kExtendedStabilizer) {
245 AER::Operations::Op op;
246 op.type = AER::Operations::OpType::gate;
247 op.name = "sx";
248 op.qubits = AER::reg_t{qubit};
249
250 state->buffer_op(std::move(op));
251 } else {
252 // there is a difference in the global phase for this
253 // changed to match qcsim behavior (and also the qiskit docs and
254 // implementation - not the one exposed in 'contrib', though)
255 // state->apply_mcrx({ qubit }, -M_PI / 4.0);
256 state->apply_unitary(qubits, AER::Linalg::Matrix::SX);
257 }
258
259 NotifyObservers(qubits);
260 }
261
268 void ApplySxDAG(Types::qubit_t qubit) override {
269 const Types::qubits_vector qubits = {qubit};
270
271 if (GetSimulationType() == SimulationType::kStabilizer ||
272 GetSimulationType() == SimulationType::kExtendedStabilizer) {
273 AER::Operations::Op op;
274 op.type = AER::Operations::OpType::gate;
275 op.name = "sxdg";
276 op.qubits = AER::reg_t{qubit};
277
278 state->buffer_op(std::move(op));
279 } else
280 state->apply_unitary(qubits, AER::Linalg::Matrix::SXDG);
281
282 NotifyObservers(qubits);
283 }
284
291 void ApplyK(Types::qubit_t qubit) override {
292 const Types::qubits_vector qubits = {qubit};
293
294 if (GetSimulationType() == SimulationType::kStabilizer ||
295 GetSimulationType() == SimulationType::kExtendedStabilizer) {
296 ApplyZ(qubit);
297 ApplyS(qubit);
298 ApplyH(qubit);
299 ApplyS(qubit);
300 } else {
301 static const cmatrix_t K = AER::Utils::make_matrix<complex_t>(
302 {{{1. / std::sqrt(2.), 0}, {0, -1. / std::sqrt(2.)}},
303 {{0, 1. / std::sqrt(2.)}, {-1. / std::sqrt(2.), 0}}});
304
305 state->apply_unitary(qubits, K);
306 }
307
308 NotifyObservers(qubits);
309 }
310
318 void ApplyRx(Types::qubit_t qubit, double theta) override {
319 if (GetSimulationType() == SimulationType::kStabilizer)
320 throw std::runtime_error(
321 "Rx gate not supported in stabilizer simulation");
322
323 const Types::qubits_vector qubits = {qubit};
324
325 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
326 ApplyH(qubit);
327 ApplyRz(qubit, theta);
328 ApplyH(qubit);
329 } else {
330 const cmatrix_t rx = AER::Linalg::Matrix::rx(theta);
331 state->apply_unitary(qubits, rx);
332 }
333
334 NotifyObservers(qubits);
335 }
336
344 void ApplyRy(Types::qubit_t qubit, double theta) override {
345 if (GetSimulationType() == SimulationType::kStabilizer)
346 throw std::runtime_error(
347 "Ry gate not supported in stabilizer simulation");
348
349 const Types::qubits_vector qubits = {qubit};
350
351 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
352 ApplySDG(qubit);
353 ApplyRx(qubit, theta);
354 ApplyS(qubit);
355 } else {
356 const cmatrix_t ry = AER::Linalg::Matrix::ry(theta);
357
358 state->apply_unitary(qubits, ry);
359 }
360
361 NotifyObservers(qubits);
362 }
363
371 void ApplyRz(Types::qubit_t qubit, double theta) override {
372 if (GetSimulationType() == SimulationType::kStabilizer)
373 throw std::runtime_error(
374 "Rz gate not supported in stabilizer simulation");
375
376 const Types::qubits_vector qubits = {qubit};
377 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
378 // this does not suffice, as it is implemented only for pi/4 multiples by
379 // qiskit aer... use p instead, which is implemented for any angle...
380 // there is a phase difference, but it is not important for the stabilizer
381 // simulation
382
383 // it's very important as many other non-clifford gates are implemented
384 // based on rotations!
385
386 /*
387 AER::Operations::Op op;
388 op.type = AER::Operations::OpType::gate;
389 op.name = "rz";
390 op.qubits = AER::reg_t{qubit};
391 op.params = {theta};
392
393 state->buffer_op(std::move(op));
394 */
395 ApplyP(qubit, theta);
396 } else {
397 const cmatrix_t rz = AER::Linalg::Matrix::rz(theta);
398
399 state->apply_unitary(qubits, rz);
400 }
401
402 NotifyObservers(qubits);
403 }
404
415 void ApplyU(Types::qubit_t qubit, double theta, double phi, double lambda,
416 double gamma) override {
417 if (GetSimulationType() == SimulationType::kStabilizer)
418 throw std::runtime_error("U gate not supported in stabilizer simulation");
419
420 const Types::qubits_vector qubits = {qubit};
421
422 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
423 ApplyRz(qubit, lambda);
424 ApplyRy(qubit, theta);
425 ApplyRz(qubit, phi);
426 } else {
427 const cmatrix_t u = AER::Linalg::Matrix::u4(theta, phi, lambda, gamma);
428
429 state->apply_unitary(qubits, u);
430 }
431
432 NotifyObservers(qubits);
433 }
434
442 void ApplyCX(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
443 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
444 state->apply_cx(qubits);
445 NotifyObservers(qubits);
446 }
447
455 void ApplyCY(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
456 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
457
458 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
459 ApplySDG(tgt_qubit);
460 ApplyCX(ctrl_qubit, tgt_qubit);
461 ApplyS(tgt_qubit);
462 } else {
463 state->apply_cy(qubits);
464 }
465 NotifyObservers(qubits);
466 }
467
475 void ApplyCZ(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
476 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
477 state->apply_cz(qubits);
478 NotifyObservers(qubits);
479 }
480
489 void ApplyCP(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
490 double lambda) override {
491 if (GetSimulationType() == SimulationType::kStabilizer)
492 throw std::runtime_error(
493 "CP gate not supported in stabilizer simulation");
494
495 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
496
497 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
498 const double halfAngle = lambda * 0.5;
499 ApplyP(ctrl_qubit, halfAngle);
500 ApplyCX(ctrl_qubit, tgt_qubit);
501 ApplyP(tgt_qubit, -halfAngle);
502 ApplyCX(ctrl_qubit, tgt_qubit);
503 ApplyP(tgt_qubit, halfAngle);
504 } else {
505 const cmatrix_t CP = AER::Linalg::Matrix::cphase(lambda);
506 // state->apply_mcphase(qubits, lambda);
507 state->apply_unitary(qubits, CP);
508 }
509
510 NotifyObservers(qubits);
511 }
512
521 void ApplyCRx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
522 double theta) override {
523 if (GetSimulationType() == SimulationType::kStabilizer)
524 throw std::runtime_error(
525 "CRx gate not supported in stabilizer simulation");
526
527 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
528
529 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
530 const double halfAngle = theta * 0.5;
531
532 ApplyH(tgt_qubit);
533 ApplyCX(ctrl_qubit, tgt_qubit);
534 ApplyRz(tgt_qubit, -halfAngle);
535 ApplyCX(ctrl_qubit, tgt_qubit);
536 ApplyRz(tgt_qubit, halfAngle);
537 ApplyH(tgt_qubit);
538 } else {
539 cmatrix_t mat(4, 4);
540 mat(0, 0) = 1;
541 mat(2, 2) = 1;
542
543 const double t2 = theta * 0.5;
544
545 const complex_t i(0., 1.);
546 mat(1, 1) = std::cos(t2);
547 mat(1, 3) = -i * std::sin(t2);
548 mat(3, 1) = mat(1, 3);
549 mat(3, 3) = mat(1, 1);
550
551 // state->apply_mcrx(qubits, theta);
552 state->apply_unitary(qubits, mat);
553 }
554
555 NotifyObservers(qubits);
556 }
557
566 void ApplyCRy(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
567 double theta) override {
568 if (GetSimulationType() == SimulationType::kStabilizer)
569 throw std::runtime_error(
570 "CRy gate not supported in stabilizer simulation");
571
572 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
573
574 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
575 const double halfAngle = theta * 0.5;
576
577 ApplyRy(tgt_qubit, halfAngle);
578 ApplyCX(ctrl_qubit, tgt_qubit);
579 ApplyRy(tgt_qubit, -halfAngle);
580 ApplyCX(ctrl_qubit, tgt_qubit);
581 } else {
582 cmatrix_t mat(4, 4);
583 mat(0, 0) = 1;
584 mat(2, 2) = 1;
585
586 const double t2 = theta * 0.5;
587
588 mat(1, 1) = std::complex<double>(cos(t2), 0);
589 mat(1, 3) = std::complex<double>(-sin(t2), 0);
590 mat(3, 1) = std::complex<double>(sin(t2), 0);
591 mat(3, 3) = mat(1, 1);
592
593 // state->apply_mcry(qubits, theta);
594 state->apply_unitary(qubits, mat);
595 }
596
597 NotifyObservers(qubits);
598 }
599
608 void ApplyCRz(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
609 double theta) override {
610 if (GetSimulationType() == SimulationType::kStabilizer)
611 throw std::runtime_error(
612 "CRz gate not supported in stabilizer simulation");
613
614 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
615
616 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
617 const double halfAngle = theta * 0.5;
618 ApplyRz(tgt_qubit, halfAngle);
619 ApplyCX(ctrl_qubit, tgt_qubit);
620 ApplyRz(tgt_qubit, -halfAngle);
621 ApplyCX(ctrl_qubit, tgt_qubit);
622 } else {
623 const double t2 = theta * 0.5;
624 AER::cvector_t v = {
625 {1, 0}, std::polar(1., -t2), {1, 0}, std::polar(1., t2)};
626
627 // state->apply_mcrz(qubits, theta);
628 state->apply_diagonal_matrix(qubits, v);
629 }
630
631 NotifyObservers(qubits);
632 }
633
641 void ApplyCH(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
642 if (GetSimulationType() == SimulationType::kStabilizer)
643 throw std::runtime_error(
644 "CH gate not supported in stabilizer simulation");
645
646 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
647
648 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
649 ApplyH(tgt_qubit);
650 ApplySDG(tgt_qubit);
651 ApplyCX(ctrl_qubit, tgt_qubit);
652 ApplyH(tgt_qubit);
653 ApplyT(tgt_qubit);
654 ApplyCX(ctrl_qubit, tgt_qubit);
655 ApplyT(tgt_qubit);
656 ApplyH(tgt_qubit);
657 ApplyS(tgt_qubit);
658 ApplyX(tgt_qubit);
659 ApplyS(ctrl_qubit);
660 } else {
661 const cmatrix_t CU = AER::Linalg::Matrix::cu(M_PI_2, 0, M_PI, 0);
662 state->apply_unitary(qubits, CU);
663 // state->apply_cu(qubits, M_PI_2, 0, M_PI, 0);
664 }
665 NotifyObservers(qubits);
666 }
667
675 void ApplyCSx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
676 if (GetSimulationType() == SimulationType::kStabilizer)
677 throw std::runtime_error(
678 "CSx gate not supported in stabilizer simulation");
679
680 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
681
682 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
683 ApplyH(tgt_qubit);
684 ApplyT(ctrl_qubit);
685 ApplyT(tgt_qubit);
686 ApplyCX(ctrl_qubit, tgt_qubit);
687 ApplyTDG(tgt_qubit);
688 ApplyCX(ctrl_qubit, tgt_qubit);
689 ApplyH(tgt_qubit);
690 } else {
691 static const cmatrix_t CSX = AER::Utils::make_matrix<complex_t>(
692 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}},
693 {{0, 0}, {0.5, 0.5}, {0, 0}, {0.5, -0.5}},
694 {{0, 0}, {0, 0}, {1, 0}, {0, 0}},
695 {{0, 0}, {0.5, -0.5}, {0, 0}, {0.5, 0.5}}});
696
697 state->apply_unitary(qubits, CSX);
698 }
699 NotifyObservers(qubits);
700 }
701
709 void ApplyCSxDAG(Types::qubit_t ctrl_qubit,
710 Types::qubit_t tgt_qubit) override {
711 if (GetSimulationType() == SimulationType::kStabilizer)
712 throw std::runtime_error(
713 "CSxDAG gate not supported in stabilizer simulation");
714
715 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
716
717 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
718 ApplyH(tgt_qubit);
719 ApplyCX(ctrl_qubit, tgt_qubit);
720 ApplyT(tgt_qubit);
721 ApplyCX(ctrl_qubit, tgt_qubit);
722 ApplyTDG(ctrl_qubit);
723 ApplyTDG(tgt_qubit);
724 ApplyH(tgt_qubit);
725 } else {
726 static const cmatrix_t CSXDG = AER::Utils::make_matrix<complex_t>(
727 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}},
728 {{0, 0}, {0.5, -0.5}, {0, 0}, {0.5, 0.5}},
729 {{0, 0}, {0, 0}, {1, 0}, {0, 0}},
730 {{0, 0}, {0.5, 0.5}, {0, 0}, {0.5, -0.5}}});
731
732 state->apply_unitary(qubits, CSXDG);
733 }
734
735 NotifyObservers(qubits);
736 }
737
745 void ApplySwap(Types::qubit_t qubit0, Types::qubit_t qubit1) override {
746 const Types::qubits_vector qubits = {qubit0, qubit1};
747
748 if (GetSimulationType() == SimulationType::kStabilizer ||
749 GetSimulationType() == SimulationType::kExtendedStabilizer) {
750 AER::Operations::Op op;
751 op.type = AER::Operations::OpType::gate;
752 op.name = "swap";
753 op.qubits = AER::reg_t{qubit0, qubit1};
754
755 state->buffer_op(std::move(op));
756 } else
757 // state->apply_mcswap(qubits);
758 state->apply_unitary(qubits, AER::Linalg::Matrix::SWAP);
759
760 NotifyObservers(qubits);
761 }
762
771 void ApplyCCX(Types::qubit_t qubit0, Types::qubit_t qubit1,
772 Types::qubit_t qubit2) override {
773 if (GetSimulationType() == SimulationType::kStabilizer)
774 throw std::runtime_error(
775 "CCX gate not supported in stabilizer simulation");
776
777 const Types::qubits_vector qubits = {qubit0, qubit1, qubit2};
778
779 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
780 AER::Operations::Op op;
781 op.type = AER::Operations::OpType::gate;
782 op.name = "ccx";
783 op.qubits = AER::reg_t{qubit0, qubit1, qubit2};
784
785 state->buffer_op(std::move(op));
786 } else {
787 static const cmatrix_t mat = AER::Utils::make_matrix<complex_t>(
788 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
789 {{0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
790 {{0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
791 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}},
792 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}},
793 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}},
794 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}},
795 {{0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}});
796
797 // state->apply_mcx(qubits);
798 state->apply_unitary(qubits, mat);
799 }
800
801 NotifyObservers(qubits);
802 }
803
812 void ApplyCSwap(Types::qubit_t ctrl_qubit, Types::qubit_t qubit0,
813 Types::qubit_t qubit1) override {
814 if (GetSimulationType() == SimulationType::kStabilizer)
815 throw std::runtime_error(
816 "CSwap gate not supported in stabilizer simulation");
817
818 const Types::qubits_vector qubits = {ctrl_qubit, qubit0, qubit1};
819
820 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
821 const int q1 = ctrl_qubit; // control
822 const int q2 = qubit0;
823 const int q3 = qubit1;
824
825 ApplyCX(q3, q2);
826 ApplyCSx(q2, q3);
827 ApplyCX(q1, q2);
828
829 ApplyP(q3, M_PI);
830 ApplyP(q2, -M_PI_2);
831
832 ApplyCSx(q2, q3);
833 ApplyCX(q1, q2);
834
835 ApplyP(q3, M_PI);
836 ApplyCSx(q1, q3);
837 ApplyCX(q3, q2);
838 } else {
839 static const cmatrix_t mat = AER::Utils::make_matrix<complex_t>(
840 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
841 {{0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
842 {{0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
843 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}},
844 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}},
845 {{0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
846 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}},
847 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}}});
848
849 // state->apply_mcswap(qubits);
850 state->apply_unitary(qubits, mat);
851 }
852
853 NotifyObservers(qubits);
854 }
855
867 void ApplyCU(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
868 double theta, double phi, double lambda, double gamma) override {
869 if (GetSimulationType() == SimulationType::kStabilizer)
870 throw std::runtime_error(
871 "CU gate not supported in stabilizer simulation");
872
873 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
874
875 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
876 if (gamma != 0.0) ApplyP(ctrl_qubit, gamma);
877
878 const double lambdaPlusPhiHalf = 0.5 * (lambda + phi);
879 const double halfTheta = 0.5 * theta;
880 ApplyP(tgt_qubit, 0.5 * (lambda - phi));
881 ApplyP(ctrl_qubit, lambdaPlusPhiHalf);
882 ApplyCX(ctrl_qubit, tgt_qubit);
883 ApplyU(tgt_qubit, -halfTheta, 0, -lambdaPlusPhiHalf, 0);
884 ApplyCX(ctrl_qubit, tgt_qubit);
885 ApplyU(tgt_qubit, halfTheta, phi, 0, 0);
886 } else {
887 const cmatrix_t CU = AER::Linalg::Matrix::cu(theta, phi, lambda, gamma);
888 // state->apply_mcu(qubits, theta, phi, lambda, gamma);
889 state->apply_unitary(qubits, CU);
890 }
891
892 NotifyObservers(qubits);
893 }
894
902 void ApplyNop() override {
903 AER::Operations::Op op;
904 op.type =
905 AER::Operations::OpType::barrier; // there is also 'nop' but that one
906 // doesn't work with stabilizer
907 state->buffer_op(std::move(op));
908 }
909
920 std::unique_ptr<ISimulator> Clone() override {
921 auto sim = std::make_unique<AerSimulator>();
922
923 // the tricky part is cloning the state
924 if (simulationType == SimulationType::kMatrixProductState)
925 sim->Configure("method", "matrix_product_state");
926 else if (simulationType == SimulationType::kStabilizer)
927 sim->Configure("method", "stabilizer");
928 else if (simulationType == SimulationType::kTensorNetwork)
929 sim->Configure("method", "tensor_network");
930 else if (simulationType == SimulationType::kExtendedStabilizer)
931 sim->Configure("method", "extended_stabilizer");
932 else
933 sim->Configure("method", "statevector");
934
935 if (simulationType == SimulationType::kMatrixProductState) {
936 if (limitSize)
937 sim->Configure("matrix_product_state_max_bond_dimension",
938 std::to_string(chi).c_str());
939 if (limitEntanglement)
940 sim->Configure("matrix_product_state_truncation_threshold",
941 std::to_string(singularValueThreshold).c_str());
942 sim->Configure("mps_sample_measure_algorithm", useMPSMeasureNoCollapse
943 ? "mps_probabilities"
944 : "mps_apply_measure");
945 }
946
947 sim->SetMultithreading(
948 enableMultithreading);
950 AER::Vector<complex_t> localSavedAmplitudes =
951 savedAmplitudes;
952 AER::Data localSavedState =
953 savedState;
956 // now the tricky part
957 if (state && state->is_initialized()) {
958 SaveState(); // this also restores the state if it's destroyed in the
959 // saving process!
960 // now the current state is saved in savedAmplitudes or savedState, so use
961 // it to initialize the cloned state, like this
962 sim->savedAmplitudes = std::move(savedAmplitudes);
963 sim->savedState = std::move(savedState);
964
965 sim->RestoreState(); // now the state is loaded in the cloned simulator
966
967 // those saved previously can be an older state, so put them in the clone,
968 // too
969 sim->savedAmplitudes = localSavedAmplitudes;
970 sim->savedState = localSavedState;
971
972 // those saved previously can be an older state, so put them back
973 savedAmplitudes = std::move(localSavedAmplitudes);
974 savedState = std::move(localSavedState);
975 } else {
976 // std::cout << "Restored from non initialized state" << std::endl;
977 sim->savedAmplitudes = std::move(localSavedAmplitudes);
978 sim->savedState = std::move(localSavedState);
979
980 sim->RestoreState(); // this might not be necessary, but sometimes, not
981 // very often, an exception is thrown about the
982 // state not being initialized, this might prevent
983 // that
984 }
985
986 return sim;
987 }
988};
989
990} // namespace Private
991} // namespace Simulators
992
993#endif
994
995#endif
996
997#endif
int ApplyK(void *sim, int qubit)
int ApplyRx(void *sim, int qubit, double theta)
int ApplyX(void *sim, int qubit)
int ApplyU(void *sim, int qubit, double theta, double phi, double lambda, double gamma)
int ApplyCRy(void *sim, int controlQubit, int targetQubit, double theta)
int ApplyTDG(void *sim, int qubit)
int ApplyS(void *sim, int qubit)
int ApplyCX(void *sim, int controlQubit, int targetQubit)
int ApplyCRz(void *sim, int controlQubit, int targetQubit, double theta)
int ApplyCP(void *sim, int controlQubit, int targetQubit, double theta)
int ApplySDG(void *sim, int qubit)
int ApplyCSwap(void *sim, int controlQubit, int qubit1, int qubit2)
int ApplyCCX(void *sim, int controlQubit1, int controlQubit2, int targetQubit)
int ApplyY(void *sim, int qubit)
int ApplyZ(void *sim, int qubit)
int ApplyH(void *sim, int qubit)
int ApplyCY(void *sim, int controlQubit, int targetQubit)
int ApplyCU(void *sim, int controlQubit, int targetQubit, double theta, double phi, double lambda, double gamma)
int ApplySwap(void *sim, int qubit1, int qubit2)
int ApplyRy(void *sim, int qubit, double theta)
int ApplyP(void *sim, int qubit, double theta)
int ApplyCH(void *sim, int controlQubit, int targetQubit)
int GetSimulationType(void *sim)
int ApplyCZ(void *sim, int controlQubit, int targetQubit)
int ApplyRz(void *sim, int qubit, double theta)
int ApplyT(void *sim, int qubit)
int ApplyCRx(void *sim, int controlQubit, int targetQubit, double theta)
int SaveState(void *sim)
uint_fast64_t qubit_t
The type of a qubit.
Definition Types.h:21
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
Definition Types.h:23