Maestro 0.2.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
AerSimulator.h
Go to the documentation of this file.
1
12
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
57 void ApplyGenericOneQubitGate(Types::qubit_t qubit,
58 const Eigen::Matrix2cd& gate) override
59 {
60 const AER::reg_t qubits = {qubit};
61 AER::cmatrix_t gate_matrix(2, 2);
62 gate_matrix(0, 0) = gate(0, 0);
63 gate_matrix(0, 1) = gate(0, 1);
64 gate_matrix(1, 0) = gate(1, 0);
65 gate_matrix(1, 1) = gate(1, 1);
66
67 state->apply_unitary(qubits, gate_matrix);
68 NotifyObservers(qubits);
69 }
70
77 void ApplyGenericTwoQubitGate(Types::qubit_t qubit0,
78 Types::qubit_t qubit1,
79 const Eigen::Matrix4cd& gate) override
80 {
81 const AER::reg_t qubits = {qubit1, qubit0};
82 AER::cmatrix_t gate_matrix(4, 4);
83 for (size_t i = 0; i < 4; ++i)
84 for (size_t j = 0; j < 4; ++j)
85 gate_matrix(i, j) = gate(i, j);
86
87 state->apply_unitary(qubits, gate_matrix);
88 NotifyObservers(qubits);
89 }
90
98 void ApplyP(Types::qubit_t qubit, double lambda) override {
99 if (GetSimulationType() == SimulationType::kStabilizer)
100 throw std::runtime_error("P gate not supported in stabilizer simulation");
101
102 const Types::qubits_vector qubits = {qubit};
103
104 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
105 AER::Operations::Op op;
106 op.type = AER::Operations::OpType::gate;
107 op.name = "p";
108 op.qubits = AER::reg_t{qubit};
109 op.params = {lambda};
110
111 state->buffer_op(std::move(op));
112 } else {
113 const AER::cvector_t P = {{1, 0}, std::polar(1., lambda)};
114 state->apply_diagonal_matrix(qubits, P);
115 }
116
117 NotifyObservers(qubits);
118 }
119
126 void ApplyX(Types::qubit_t qubit) override {
127 const Types::qubits_vector qubits = {qubit};
128 state->apply_x(qubit);
129 NotifyObservers(qubits);
130 }
131
138 void ApplyY(Types::qubit_t qubit) override {
139 const Types::qubits_vector qubits = {qubit};
140 state->apply_y(qubit);
141 NotifyObservers(qubits);
142 }
143
150 void ApplyZ(Types::qubit_t qubit) override {
151 const Types::qubits_vector qubits = {qubit};
152 state->apply_z(qubit);
153 NotifyObservers(qubits);
154 }
155
162 void ApplyH(Types::qubit_t qubit) override {
163 const Types::qubits_vector qubits = {qubit};
164 state->apply_h(qubit);
165 NotifyObservers(qubits);
166 }
167
174 void ApplyS(Types::qubit_t qubit) override {
175 const Types::qubits_vector qubits = {qubit};
176
177 if (GetSimulationType() == SimulationType::kStabilizer ||
178 GetSimulationType() == SimulationType::kExtendedStabilizer) {
179 AER::Operations::Op op;
180 op.type = AER::Operations::OpType::gate;
181 op.name = "s";
182 op.qubits = AER::reg_t{qubit};
183
184 state->buffer_op(std::move(op));
185 } else {
186 const AER::cvector_t S = {{1, 0}, complex_t(0.0, 1)};
187 state->apply_diagonal_matrix(qubits, S);
188 }
189
190 NotifyObservers(qubits);
191 }
192
199 void ApplySDG(Types::qubit_t qubit) override {
200 const Types::qubits_vector qubits = {qubit};
201
202 if (GetSimulationType() == SimulationType::kStabilizer ||
203 GetSimulationType() == SimulationType::kExtendedStabilizer) {
204 AER::Operations::Op op;
205 op.type = AER::Operations::OpType::gate;
206 op.name = "sdg";
207 op.qubits = AER::reg_t{qubit};
208
209 state->buffer_op(std::move(op));
210 } else {
211 const AER::cvector_t Sdg = {{1, 0}, complex_t(0.0, -1)};
212 state->apply_diagonal_matrix(qubits, Sdg);
213 }
214
215 NotifyObservers(qubits);
216 }
217
224 void ApplyT(Types::qubit_t qubit) override {
225 if (GetSimulationType() == SimulationType::kStabilizer)
226 throw std::runtime_error("T gate not supported in stabilizer simulation");
227
228 const Types::qubits_vector qubits = {qubit};
229 // state->apply_u(qubit, 0, 0, M_PI / 4.0);
230
231 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
232 AER::Operations::Op op;
233 op.type = AER::Operations::OpType::gate;
234 op.name = "t";
235 op.qubits = AER::reg_t{qubit};
236 state->buffer_op(std::move(op));
237 } else {
238 const AER::cvector_t T = {{1, 0}, std::polar<double>(1, M_PI / 4.)};
239 state->apply_diagonal_matrix(qubits, T);
240 }
241
242 NotifyObservers(qubits);
243 }
244
251 void ApplyTDG(Types::qubit_t qubit) override {
252 if (GetSimulationType() == SimulationType::kStabilizer)
253 throw std::runtime_error(
254 "TDG gate not supported in stabilizer simulation");
255
256 const Types::qubits_vector qubits = {qubit};
257 // state->apply_u(qubit, 0, 0, -M_PI / 4.0);
258
259 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
260 AER::Operations::Op op;
261 op.type = AER::Operations::OpType::gate;
262 op.name = "tdg";
263 op.qubits = AER::reg_t{qubit};
264 state->buffer_op(std::move(op));
265 } else {
266 const AER::cvector_t Tdg = {{1, 0}, std::polar<double>(1, -M_PI / 4.)};
267 state->apply_diagonal_matrix(qubits, Tdg);
268 }
269
270 NotifyObservers(qubits);
271 }
272
279 void ApplySx(Types::qubit_t qubit) override {
280 const Types::qubits_vector qubits = {qubit};
281
282 if (GetSimulationType() == SimulationType::kStabilizer ||
283 GetSimulationType() == SimulationType::kExtendedStabilizer) {
284 AER::Operations::Op op;
285 op.type = AER::Operations::OpType::gate;
286 op.name = "sx";
287 op.qubits = AER::reg_t{qubit};
288
289 state->buffer_op(std::move(op));
290 } else {
291 // there is a difference in the global phase for this
292 // changed to match qcsim behavior (and also the qiskit docs and
293 // implementation - not the one exposed in 'contrib', though)
294 // state->apply_mcrx({ qubit }, -M_PI / 4.0);
295 state->apply_unitary(qubits, AER::Linalg::Matrix::SX);
296 }
297
298 NotifyObservers(qubits);
299 }
300
307 void ApplySxDAG(Types::qubit_t qubit) override {
308 const Types::qubits_vector qubits = {qubit};
309
310 if (GetSimulationType() == SimulationType::kStabilizer ||
311 GetSimulationType() == SimulationType::kExtendedStabilizer) {
312 AER::Operations::Op op;
313 op.type = AER::Operations::OpType::gate;
314 op.name = "sxdg";
315 op.qubits = AER::reg_t{qubit};
316
317 state->buffer_op(std::move(op));
318 } else
319 state->apply_unitary(qubits, AER::Linalg::Matrix::SXDG);
320
321 NotifyObservers(qubits);
322 }
323
330 void ApplyK(Types::qubit_t qubit) override {
331 const Types::qubits_vector qubits = {qubit};
332
333 if (GetSimulationType() == SimulationType::kStabilizer ||
334 GetSimulationType() == SimulationType::kExtendedStabilizer) {
335 ApplyZ(qubit);
336 ApplyS(qubit);
337 ApplyH(qubit);
338 ApplyS(qubit);
339 } else {
340 static const cmatrix_t K = AER::Utils::make_matrix<complex_t>(
341 {{{1. / std::sqrt(2.), 0}, {0, -1. / std::sqrt(2.)}},
342 {{0, 1. / std::sqrt(2.)}, {-1. / std::sqrt(2.), 0}}});
343
344 state->apply_unitary(qubits, K);
345 }
346
347 NotifyObservers(qubits);
348 }
349
357 void ApplyRx(Types::qubit_t qubit, double theta) override {
358 if (GetSimulationType() == SimulationType::kStabilizer)
359 throw std::runtime_error(
360 "Rx gate not supported in stabilizer simulation");
361
362 const Types::qubits_vector qubits = {qubit};
363
364 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
365 ApplyH(qubit);
366 ApplyRz(qubit, theta);
367 ApplyH(qubit);
368 } else {
369 const cmatrix_t rx = AER::Linalg::Matrix::rx(theta);
370 state->apply_unitary(qubits, rx);
371 }
372
373 NotifyObservers(qubits);
374 }
375
383 void ApplyRy(Types::qubit_t qubit, double theta) override {
384 if (GetSimulationType() == SimulationType::kStabilizer)
385 throw std::runtime_error(
386 "Ry gate not supported in stabilizer simulation");
387
388 const Types::qubits_vector qubits = {qubit};
389
390 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
391 ApplySDG(qubit);
392 ApplyRx(qubit, theta);
393 ApplyS(qubit);
394 } else {
395 const cmatrix_t ry = AER::Linalg::Matrix::ry(theta);
396
397 state->apply_unitary(qubits, ry);
398 }
399
400 NotifyObservers(qubits);
401 }
402
410 void ApplyRz(Types::qubit_t qubit, double theta) override {
411 if (GetSimulationType() == SimulationType::kStabilizer)
412 throw std::runtime_error(
413 "Rz gate not supported in stabilizer simulation");
414
415 const Types::qubits_vector qubits = {qubit};
416 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
417 // this does not suffice, as it is implemented only for pi/4 multiples by
418 // qiskit aer... use p instead, which is implemented for any angle...
419 // there is a phase difference, but it is not important for the stabilizer
420 // simulation
421
422 // it's very important as many other non-clifford gates are implemented
423 // based on rotations!
424
425 /*
426 AER::Operations::Op op;
427 op.type = AER::Operations::OpType::gate;
428 op.name = "rz";
429 op.qubits = AER::reg_t{qubit};
430 op.params = {theta};
431
432 state->buffer_op(std::move(op));
433 */
434 ApplyP(qubit, theta);
435 } else {
436 const cmatrix_t rz = AER::Linalg::Matrix::rz(theta);
437
438 state->apply_unitary(qubits, rz);
439 }
440
441 NotifyObservers(qubits);
442 }
443
454 void ApplyU(Types::qubit_t qubit, double theta, double phi, double lambda,
455 double gamma) override {
456 if (GetSimulationType() == SimulationType::kStabilizer)
457 throw std::runtime_error("U gate not supported in stabilizer simulation");
458
459 const Types::qubits_vector qubits = {qubit};
460
461 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
462 ApplyRz(qubit, lambda);
463 ApplyRy(qubit, theta);
464 ApplyRz(qubit, phi);
465 } else {
466 const cmatrix_t u = AER::Linalg::Matrix::u4(theta, phi, lambda, gamma);
467
468 state->apply_unitary(qubits, u);
469 }
470
471 NotifyObservers(qubits);
472 }
473
481 void ApplyCX(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
482 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
483 state->apply_cx(qubits);
484 NotifyObservers(qubits);
485 }
486
494 void ApplyCY(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
495 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
496
497 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
498 ApplySDG(tgt_qubit);
499 ApplyCX(ctrl_qubit, tgt_qubit);
500 ApplyS(tgt_qubit);
501 } else {
502 state->apply_cy(qubits);
503 }
504 NotifyObservers(qubits);
505 }
506
514 void ApplyCZ(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
515 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
516 state->apply_cz(qubits);
517 NotifyObservers(qubits);
518 }
519
528 void ApplyCP(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
529 double lambda) override {
530 if (GetSimulationType() == SimulationType::kStabilizer)
531 throw std::runtime_error(
532 "CP gate not supported in stabilizer simulation");
533
534 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
535
536 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
537 const double halfAngle = lambda * 0.5;
538 ApplyP(ctrl_qubit, halfAngle);
539 ApplyCX(ctrl_qubit, tgt_qubit);
540 ApplyP(tgt_qubit, -halfAngle);
541 ApplyCX(ctrl_qubit, tgt_qubit);
542 ApplyP(tgt_qubit, halfAngle);
543 } else {
544 const cmatrix_t CP = AER::Linalg::Matrix::cphase(lambda);
545 // state->apply_mcphase(qubits, lambda);
546 state->apply_unitary(qubits, CP);
547 }
548
549 NotifyObservers(qubits);
550 }
551
560 void ApplyCRx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
561 double theta) override {
562 if (GetSimulationType() == SimulationType::kStabilizer)
563 throw std::runtime_error(
564 "CRx gate not supported in stabilizer simulation");
565
566 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
567
568 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
569 const double halfAngle = theta * 0.5;
570
571 ApplyH(tgt_qubit);
572 ApplyCX(ctrl_qubit, tgt_qubit);
573 ApplyRz(tgt_qubit, -halfAngle);
574 ApplyCX(ctrl_qubit, tgt_qubit);
575 ApplyRz(tgt_qubit, halfAngle);
576 ApplyH(tgt_qubit);
577 } else {
578 cmatrix_t mat(4, 4);
579 mat(0, 0) = 1;
580 mat(2, 2) = 1;
581
582 const double t2 = theta * 0.5;
583
584 const complex_t i(0., 1.);
585 mat(1, 1) = std::cos(t2);
586 mat(1, 3) = -i * std::sin(t2);
587 mat(3, 1) = mat(1, 3);
588 mat(3, 3) = mat(1, 1);
589
590 // state->apply_mcrx(qubits, theta);
591 state->apply_unitary(qubits, mat);
592 }
593
594 NotifyObservers(qubits);
595 }
596
605 void ApplyCRy(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
606 double theta) override {
607 if (GetSimulationType() == SimulationType::kStabilizer)
608 throw std::runtime_error(
609 "CRy gate not supported in stabilizer simulation");
610
611 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
612
613 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
614 const double halfAngle = theta * 0.5;
615
616 ApplyRy(tgt_qubit, halfAngle);
617 ApplyCX(ctrl_qubit, tgt_qubit);
618 ApplyRy(tgt_qubit, -halfAngle);
619 ApplyCX(ctrl_qubit, tgt_qubit);
620 } else {
621 cmatrix_t mat(4, 4);
622 mat(0, 0) = 1;
623 mat(2, 2) = 1;
624
625 const double t2 = theta * 0.5;
626
627 mat(1, 1) = std::complex<double>(cos(t2), 0);
628 mat(1, 3) = std::complex<double>(-sin(t2), 0);
629 mat(3, 1) = std::complex<double>(sin(t2), 0);
630 mat(3, 3) = mat(1, 1);
631
632 // state->apply_mcry(qubits, theta);
633 state->apply_unitary(qubits, mat);
634 }
635
636 NotifyObservers(qubits);
637 }
638
647 void ApplyCRz(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
648 double theta) override {
649 if (GetSimulationType() == SimulationType::kStabilizer)
650 throw std::runtime_error(
651 "CRz gate not supported in stabilizer simulation");
652
653 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
654
655 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
656 const double halfAngle = theta * 0.5;
657 ApplyRz(tgt_qubit, halfAngle);
658 ApplyCX(ctrl_qubit, tgt_qubit);
659 ApplyRz(tgt_qubit, -halfAngle);
660 ApplyCX(ctrl_qubit, tgt_qubit);
661 } else {
662 const double t2 = theta * 0.5;
663 AER::cvector_t v = {
664 {1, 0}, std::polar(1., -t2), {1, 0}, std::polar(1., t2)};
665
666 // state->apply_mcrz(qubits, theta);
667 state->apply_diagonal_matrix(qubits, v);
668 }
669
670 NotifyObservers(qubits);
671 }
672
680 void ApplyCH(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
681 if (GetSimulationType() == SimulationType::kStabilizer)
682 throw std::runtime_error(
683 "CH gate not supported in stabilizer simulation");
684
685 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
686
687 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
688 ApplyH(tgt_qubit);
689 ApplySDG(tgt_qubit);
690 ApplyCX(ctrl_qubit, tgt_qubit);
691 ApplyH(tgt_qubit);
692 ApplyT(tgt_qubit);
693 ApplyCX(ctrl_qubit, tgt_qubit);
694 ApplyT(tgt_qubit);
695 ApplyH(tgt_qubit);
696 ApplyS(tgt_qubit);
697 ApplyX(tgt_qubit);
698 ApplyS(ctrl_qubit);
699 } else {
700 const cmatrix_t CU = AER::Linalg::Matrix::cu(M_PI_2, 0, M_PI, 0);
701 state->apply_unitary(qubits, CU);
702 // state->apply_cu(qubits, M_PI_2, 0, M_PI, 0);
703 }
704 NotifyObservers(qubits);
705 }
706
714 void ApplyCSx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
715 if (GetSimulationType() == SimulationType::kStabilizer)
716 throw std::runtime_error(
717 "CSx gate not supported in stabilizer simulation");
718
719 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
720
721 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
722 ApplyH(tgt_qubit);
723 ApplyT(ctrl_qubit);
724 ApplyT(tgt_qubit);
725 ApplyCX(ctrl_qubit, tgt_qubit);
726 ApplyTDG(tgt_qubit);
727 ApplyCX(ctrl_qubit, tgt_qubit);
728 ApplyH(tgt_qubit);
729 } else {
730 static const cmatrix_t CSX = AER::Utils::make_matrix<complex_t>(
731 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}},
732 {{0, 0}, {0.5, 0.5}, {0, 0}, {0.5, -0.5}},
733 {{0, 0}, {0, 0}, {1, 0}, {0, 0}},
734 {{0, 0}, {0.5, -0.5}, {0, 0}, {0.5, 0.5}}});
735
736 state->apply_unitary(qubits, CSX);
737 }
738 NotifyObservers(qubits);
739 }
740
748 void ApplyCSxDAG(Types::qubit_t ctrl_qubit,
749 Types::qubit_t tgt_qubit) override {
750 if (GetSimulationType() == SimulationType::kStabilizer)
751 throw std::runtime_error(
752 "CSxDAG gate not supported in stabilizer simulation");
753
754 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
755
756 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
757 ApplyH(tgt_qubit);
758 ApplyCX(ctrl_qubit, tgt_qubit);
759 ApplyT(tgt_qubit);
760 ApplyCX(ctrl_qubit, tgt_qubit);
761 ApplyTDG(ctrl_qubit);
762 ApplyTDG(tgt_qubit);
763 ApplyH(tgt_qubit);
764 } else {
765 static const cmatrix_t CSXDG = AER::Utils::make_matrix<complex_t>(
766 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}},
767 {{0, 0}, {0.5, -0.5}, {0, 0}, {0.5, 0.5}},
768 {{0, 0}, {0, 0}, {1, 0}, {0, 0}},
769 {{0, 0}, {0.5, 0.5}, {0, 0}, {0.5, -0.5}}});
770
771 state->apply_unitary(qubits, CSXDG);
772 }
773
774 NotifyObservers(qubits);
775 }
776
784 void ApplySwap(Types::qubit_t qubit0, Types::qubit_t qubit1) override {
785 const Types::qubits_vector qubits = {qubit0, qubit1};
786
787 if (GetSimulationType() == SimulationType::kStabilizer ||
788 GetSimulationType() == SimulationType::kExtendedStabilizer) {
789 AER::Operations::Op op;
790 op.type = AER::Operations::OpType::gate;
791 op.name = "swap";
792 op.qubits = AER::reg_t{qubit0, qubit1};
793
794 state->buffer_op(std::move(op));
795 } else
796 // state->apply_mcswap(qubits);
797 state->apply_unitary(qubits, AER::Linalg::Matrix::SWAP);
798
799 NotifyObservers(qubits);
800 }
801
810 void ApplyCCX(Types::qubit_t qubit0, Types::qubit_t qubit1,
811 Types::qubit_t qubit2) override {
812 if (GetSimulationType() == SimulationType::kStabilizer)
813 throw std::runtime_error(
814 "CCX gate not supported in stabilizer simulation");
815
816 const Types::qubits_vector qubits = {qubit0, qubit1, qubit2};
817
818 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
819 AER::Operations::Op op;
820 op.type = AER::Operations::OpType::gate;
821 op.name = "ccx";
822 op.qubits = AER::reg_t{qubit0, qubit1, qubit2};
823
824 state->buffer_op(std::move(op));
825 } else {
826 static const cmatrix_t mat = AER::Utils::make_matrix<complex_t>(
827 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
828 {{0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
829 {{0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
830 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}},
831 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}},
832 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}},
833 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}},
834 {{0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}});
835
836 // state->apply_mcx(qubits);
837 state->apply_unitary(qubits, mat);
838 }
839
840 NotifyObservers(qubits);
841 }
842
851 void ApplyCSwap(Types::qubit_t ctrl_qubit, Types::qubit_t qubit0,
852 Types::qubit_t qubit1) override {
853 if (GetSimulationType() == SimulationType::kStabilizer)
854 throw std::runtime_error(
855 "CSwap gate not supported in stabilizer simulation");
856
857 const Types::qubits_vector qubits = {ctrl_qubit, qubit0, qubit1};
858
859 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
860 const int q1 = static_cast<int>(ctrl_qubit); // control
861 const int q2 = static_cast<int>(qubit0);
862 const int q3 = static_cast<int>(qubit1);
863
864 ApplyCX(q3, q2);
865 ApplyCSx(q2, q3);
866 ApplyCX(q1, q2);
867
868 ApplyP(q3, M_PI);
869 ApplyP(q2, -M_PI_2);
870
871 ApplyCSx(q2, q3);
872 ApplyCX(q1, q2);
873
874 ApplyP(q3, M_PI);
875 ApplyCSx(q1, q3);
876 ApplyCX(q3, q2);
877 } else {
878 static const cmatrix_t mat = AER::Utils::make_matrix<complex_t>(
879 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
880 {{0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
881 {{0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
882 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}},
883 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}},
884 {{0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
885 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}},
886 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}}});
887
888 // state->apply_mcswap(qubits);
889 state->apply_unitary(qubits, mat);
890 }
891
892 NotifyObservers(qubits);
893 }
894
906 void ApplyCU(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
907 double theta, double phi, double lambda, double gamma) override {
908 if (GetSimulationType() == SimulationType::kStabilizer)
909 throw std::runtime_error(
910 "CU gate not supported in stabilizer simulation");
911
912 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
913
914 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
915 if (gamma != 0.0) ApplyP(ctrl_qubit, gamma);
916
917 const double lambdaPlusPhiHalf = 0.5 * (lambda + phi);
918 const double halfTheta = 0.5 * theta;
919 ApplyP(tgt_qubit, 0.5 * (lambda - phi));
920 ApplyP(ctrl_qubit, lambdaPlusPhiHalf);
921 ApplyCX(ctrl_qubit, tgt_qubit);
922 ApplyU(tgt_qubit, -halfTheta, 0, -lambdaPlusPhiHalf, 0);
923 ApplyCX(ctrl_qubit, tgt_qubit);
924 ApplyU(tgt_qubit, halfTheta, phi, 0, 0);
925 } else {
926 const cmatrix_t CU = AER::Linalg::Matrix::cu(theta, phi, lambda, gamma);
927 // state->apply_mcu(qubits, theta, phi, lambda, gamma);
928 state->apply_unitary(qubits, CU);
929 }
930
931 NotifyObservers(qubits);
932 }
933
941 void ApplyNop() override {
942 AER::Operations::Op op;
943 op.type =
944 AER::Operations::OpType::barrier; // there is also 'nop' but that one
945 // doesn't work with stabilizer
946 state->buffer_op(std::move(op));
947 }
948
959 std::unique_ptr<ISimulator> Clone() override {
960 auto sim = std::make_unique<AerSimulator>();
961
962 // the tricky part is cloning the state
963 if (simulationType == SimulationType::kMatrixProductState)
964 sim->Configure("method", "matrix_product_state");
965 else if (simulationType == SimulationType::kStabilizer)
966 sim->Configure("method", "stabilizer");
967 else if (simulationType == SimulationType::kTensorNetwork)
968 sim->Configure("method", "tensor_network");
969 else if (simulationType == SimulationType::kExtendedStabilizer)
970 sim->Configure("method", "extended_stabilizer");
971 else
972 sim->Configure("method", "statevector");
973
974 if (simulationType == SimulationType::kMatrixProductState) {
975 if (limitSize)
976 sim->Configure("matrix_product_state_max_bond_dimension",
977 std::to_string(chi).c_str());
978 if (limitEntanglement) {
979 std::ostringstream oss;
980 oss << std::setprecision(std::numeric_limits<double>::max_digits10)
981 << singularValueThreshold;
982 sim->Configure("matrix_product_state_truncation_threshold",
983 oss.str().c_str());
984 }
985 sim->Configure("mps_sample_measure_algorithm", useMPSMeasureNoCollapse
986 ? "mps_probabilities"
987 : "mps_apply_measure");
988 }
989
990 sim->SetMultithreading(
991 enableMultithreading);
992
993 AER::Vector<complex_t> localSavedAmplitudes =
994 savedAmplitudes;
995 AER::Data localSavedState =
996 savedState;
998
999 // now the tricky part
1000 if (state && state->is_initialized()) {
1001 SaveState(); // this also restores the state if it's destroyed in the
1002 // saving process!
1003 // now the current state is saved in savedAmplitudes or savedState, so use
1004 // it to initialize the cloned state, like this
1005 sim->savedAmplitudes = std::move(savedAmplitudes);
1006 sim->savedState = std::move(savedState);
1007
1008 sim->RestoreState(); // now the state is loaded in the cloned simulator
1009
1010 // those saved previously can be an older state, so put them in the clone,
1011 // too
1012 sim->savedAmplitudes = localSavedAmplitudes;
1013 sim->savedState = localSavedState;
1014
1015 // those saved previously can be an older state, so put them back
1016 savedAmplitudes = std::move(localSavedAmplitudes);
1017 savedState = std::move(localSavedState);
1018 } else {
1019 // std::cout << "Restored from non initialized state" << std::endl;
1020 sim->savedAmplitudes = std::move(localSavedAmplitudes);
1021 sim->savedState = std::move(localSavedState);
1022
1023 sim->RestoreState(); // this might not be necessary, but sometimes, not
1024 // very often, an exception is thrown about the
1025 // state not being initialized, this might prevent
1026 // that
1027 }
1028
1029 return sim;
1030 }
1031};
1032
1033} // namespace Private
1034} // namespace Simulators
1035
1036#endif
1037
1038#endif
1039
1040#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)
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
Definition Types.h:22
uint_fast64_t qubit_t
The type of a qubit.
Definition Types.h:21