Maestro 0.3.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{
26// TODO: Maybe use the pimpl idiom
27// https://en.cppreference.com/w/cpp/language/pimpl to hide the implementation
28// for good but during development this should be good enough
29namespace Private
30{
31
43class AerSimulator : public AerState
44{
45 public:
46 AerSimulator() = default;
47 // allow no copy or assignment
48 AerSimulator(const AerSimulator &) = delete;
49 AerSimulator &operator=(const AerSimulator &) = delete;
50
51 // but allow moving
52 AerSimulator(AerSimulator &&other) = default;
53 AerSimulator &operator=(AerSimulator &&other) = default;
54
60 void ApplyGenericOneQubitGate(Types::qubit_t qubit, const Eigen::Matrix2cd &gate) override
61 {
62 const AER::reg_t qubits = {qubit};
63 AER::cmatrix_t gate_matrix(2, 2);
64 gate_matrix(0, 0) = gate(0, 0);
65 gate_matrix(0, 1) = gate(0, 1);
66 gate_matrix(1, 0) = gate(1, 0);
67 gate_matrix(1, 1) = gate(1, 1);
68
69 state->apply_unitary(qubits, gate_matrix);
70 NotifyObservers(qubits);
71 }
72
79 void ApplyGenericTwoQubitGate(Types::qubit_t qubit0, Types::qubit_t qubit1, const Eigen::Matrix4cd &gate) override
80 {
81 // Aer, like QCSim, maps the first entry to local matrix bit zero.
82 const AER::reg_t qubits = {qubit0, qubit1};
83 AER::cmatrix_t gate_matrix(4, 4);
84 for (size_t i = 0; i < 4; ++i)
85 for (size_t j = 0; j < 4; ++j)
86 gate_matrix(i, j) = gate(i, j);
87
88 state->apply_unitary(qubits, gate_matrix);
89 NotifyObservers(qubits);
90 }
91
99 void ApplyP(Types::qubit_t qubit, double lambda) override
100 {
101 if (GetSimulationType() == SimulationType::kStabilizer)
102 throw std::runtime_error("P gate not supported in stabilizer simulation");
103
104 const Types::qubits_vector qubits = {qubit};
105
106 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
107 {
108 AER::Operations::Op op;
109 op.type = AER::Operations::OpType::gate;
110 op.name = "p";
111 op.qubits = AER::reg_t{qubit};
112 op.params = {lambda};
113
114 state->buffer_op(std::move(op));
115 }
116 else
117 {
118 const AER::cvector_t P = {{1, 0}, std::polar(1., lambda)};
119 state->apply_diagonal_matrix(qubits, P);
120 }
121
122 NotifyObservers(qubits);
123 }
124
131 void ApplyX(Types::qubit_t qubit) override
132 {
133 const Types::qubits_vector qubits = {qubit};
134 state->apply_x(qubit);
135 NotifyObservers(qubits);
136 }
137
144 void ApplyY(Types::qubit_t qubit) override
145 {
146 const Types::qubits_vector qubits = {qubit};
147 state->apply_y(qubit);
148 NotifyObservers(qubits);
149 }
150
157 void ApplyZ(Types::qubit_t qubit) override
158 {
159 const Types::qubits_vector qubits = {qubit};
160 state->apply_z(qubit);
161 NotifyObservers(qubits);
162 }
163
170 void ApplyH(Types::qubit_t qubit) override
171 {
172 const Types::qubits_vector qubits = {qubit};
173 state->apply_h(qubit);
174 NotifyObservers(qubits);
175 }
176
183 void ApplyS(Types::qubit_t qubit) override
184 {
185 const Types::qubits_vector qubits = {qubit};
186
187 if (GetSimulationType() == SimulationType::kStabilizer || GetSimulationType() == SimulationType::kExtendedStabilizer)
188 {
189 AER::Operations::Op op;
190 op.type = AER::Operations::OpType::gate;
191 op.name = "s";
192 op.qubits = AER::reg_t{qubit};
193
194 state->buffer_op(std::move(op));
195 }
196 else
197 {
198 const AER::cvector_t S = {{1, 0}, complex_t(0.0, 1)};
199 state->apply_diagonal_matrix(qubits, S);
200 }
201
202 NotifyObservers(qubits);
203 }
204
211 void ApplySDG(Types::qubit_t qubit) override
212 {
213 const Types::qubits_vector qubits = {qubit};
214
215 if (GetSimulationType() == SimulationType::kStabilizer || GetSimulationType() == SimulationType::kExtendedStabilizer)
216 {
217 AER::Operations::Op op;
218 op.type = AER::Operations::OpType::gate;
219 op.name = "sdg";
220 op.qubits = AER::reg_t{qubit};
221
222 state->buffer_op(std::move(op));
223 }
224 else
225 {
226 const AER::cvector_t Sdg = {{1, 0}, complex_t(0.0, -1)};
227 state->apply_diagonal_matrix(qubits, Sdg);
228 }
229
230 NotifyObservers(qubits);
231 }
232
239 void ApplyT(Types::qubit_t qubit) override
240 {
241 if (GetSimulationType() == SimulationType::kStabilizer)
242 throw std::runtime_error("T gate not supported in stabilizer simulation");
243
244 const Types::qubits_vector qubits = {qubit};
245 // state->apply_u(qubit, 0, 0, M_PI / 4.0);
246
247 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
248 {
249 AER::Operations::Op op;
250 op.type = AER::Operations::OpType::gate;
251 op.name = "t";
252 op.qubits = AER::reg_t{qubit};
253 state->buffer_op(std::move(op));
254 }
255 else
256 {
257 const AER::cvector_t T = {{1, 0}, std::polar<double>(1, M_PI / 4.)};
258 state->apply_diagonal_matrix(qubits, T);
259 }
260
261 NotifyObservers(qubits);
262 }
263
270 void ApplyTDG(Types::qubit_t qubit) override
271 {
272 if (GetSimulationType() == SimulationType::kStabilizer)
273 throw std::runtime_error("TDG gate not supported in stabilizer simulation");
274
275 const Types::qubits_vector qubits = {qubit};
276 // state->apply_u(qubit, 0, 0, -M_PI / 4.0);
277
278 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
279 {
280 AER::Operations::Op op;
281 op.type = AER::Operations::OpType::gate;
282 op.name = "tdg";
283 op.qubits = AER::reg_t{qubit};
284 state->buffer_op(std::move(op));
285 }
286 else
287 {
288 const AER::cvector_t Tdg = {{1, 0}, std::polar<double>(1, -M_PI / 4.)};
289 state->apply_diagonal_matrix(qubits, Tdg);
290 }
291
292 NotifyObservers(qubits);
293 }
294
301 void ApplySx(Types::qubit_t qubit) override
302 {
303 const Types::qubits_vector qubits = {qubit};
304
305 if (GetSimulationType() == SimulationType::kStabilizer || GetSimulationType() == SimulationType::kExtendedStabilizer)
306 {
307 AER::Operations::Op op;
308 op.type = AER::Operations::OpType::gate;
309 op.name = "sx";
310 op.qubits = AER::reg_t{qubit};
311
312 state->buffer_op(std::move(op));
313 }
314 else
315 {
316 // there is a difference in the global phase for this
317 // changed to match qcsim behavior (and also the qiskit docs and
318 // implementation - not the one exposed in 'contrib', though)
319 // state->apply_mcrx({ qubit }, -M_PI / 4.0);
320 state->apply_unitary(qubits, AER::Linalg::Matrix::SX);
321 }
322
323 NotifyObservers(qubits);
324 }
325
332 void ApplySxDAG(Types::qubit_t qubit) override
333 {
334 const Types::qubits_vector qubits = {qubit};
335
336 if (GetSimulationType() == SimulationType::kStabilizer || GetSimulationType() == SimulationType::kExtendedStabilizer)
337 {
338 AER::Operations::Op op;
339 op.type = AER::Operations::OpType::gate;
340 op.name = "sxdg";
341 op.qubits = AER::reg_t{qubit};
342
343 state->buffer_op(std::move(op));
344 }
345 else
346 state->apply_unitary(qubits, AER::Linalg::Matrix::SXDG);
347
348 NotifyObservers(qubits);
349 }
350
357 void ApplyK(Types::qubit_t qubit) override
358 {
359 const Types::qubits_vector qubits = {qubit};
360
361 if (GetSimulationType() == SimulationType::kStabilizer || GetSimulationType() == SimulationType::kExtendedStabilizer)
362 {
363 ApplyZ(qubit);
364 ApplyS(qubit);
365 ApplyH(qubit);
366 ApplyS(qubit);
367 }
368 else
369 {
370 static const cmatrix_t K =
371 AER::Utils::make_matrix<complex_t>({{{1. / std::sqrt(2.), 0}, {0, -1. / std::sqrt(2.)}}, {{0, 1. / std::sqrt(2.)}, {-1. / std::sqrt(2.), 0}}});
372
373 state->apply_unitary(qubits, K);
374 }
375
376 NotifyObservers(qubits);
377 }
378
386 void ApplyRx(Types::qubit_t qubit, double theta) override
387 {
388 if (GetSimulationType() == SimulationType::kStabilizer)
389 throw std::runtime_error("Rx gate not supported in stabilizer simulation");
390
391 const Types::qubits_vector qubits = {qubit};
392
393 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
394 {
395 ApplyH(qubit);
396 ApplyRz(qubit, theta);
397 ApplyH(qubit);
398 }
399 else
400 {
401 const cmatrix_t rx = AER::Linalg::Matrix::rx(theta);
402 state->apply_unitary(qubits, rx);
403 }
404
405 NotifyObservers(qubits);
406 }
407
415 void ApplyRy(Types::qubit_t qubit, double theta) override
416 {
417 if (GetSimulationType() == SimulationType::kStabilizer)
418 throw std::runtime_error("Ry gate not supported in stabilizer simulation");
419
420 const Types::qubits_vector qubits = {qubit};
421
422 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
423 {
424 ApplySDG(qubit);
425 ApplyRx(qubit, theta);
426 ApplyS(qubit);
427 }
428 else
429 {
430 const cmatrix_t ry = AER::Linalg::Matrix::ry(theta);
431
432 state->apply_unitary(qubits, ry);
433 }
434
435 NotifyObservers(qubits);
436 }
437
445 void ApplyRz(Types::qubit_t qubit, double theta) override
446 {
447 if (GetSimulationType() == SimulationType::kStabilizer)
448 throw std::runtime_error("Rz gate not supported in stabilizer simulation");
449
450 const Types::qubits_vector qubits = {qubit};
451 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
452 {
453 AER::Operations::Op op;
454 op.type = AER::Operations::OpType::gate;
455 op.name = "rz";
456 op.qubits = AER::reg_t{qubit};
457 op.params = {theta};
458
459 state->buffer_op(std::move(op));
460 }
461 else
462 {
463 const cmatrix_t rz = AER::Linalg::Matrix::rz(theta);
464
465 state->apply_unitary(qubits, rz);
466 }
467
468 NotifyObservers(qubits);
469 }
470
481 void ApplyU(Types::qubit_t qubit, double theta, double phi, double lambda, double gamma) override
482 {
483 if (GetSimulationType() == SimulationType::kStabilizer)
484 throw std::runtime_error("U gate not supported in stabilizer simulation");
485
486 const Types::qubits_vector qubits = {qubit};
487
488 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
489 {
490 ApplyRz(qubit, lambda);
491 ApplyRy(qubit, theta);
492 ApplyRz(qubit, phi);
493 }
494 else
495 {
496 const cmatrix_t u = AER::Linalg::Matrix::u4(theta, phi, lambda, gamma);
497
498 state->apply_unitary(qubits, u);
499 }
500
501 NotifyObservers(qubits);
502 }
503
511 void ApplyCX(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
512 {
513 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
514 state->apply_cx(qubits);
515 NotifyObservers(qubits);
516 }
517
525 void ApplyCY(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
526 {
527 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
528
529 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
530 {
531 ApplySDG(tgt_qubit);
532 ApplyCX(ctrl_qubit, tgt_qubit);
533 ApplyS(tgt_qubit);
534 }
535 else
536 {
537 state->apply_cy(qubits);
538 }
539 NotifyObservers(qubits);
540 }
541
549 void ApplyCZ(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
550 {
551 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
552 state->apply_cz(qubits);
553 NotifyObservers(qubits);
554 }
555
564 void ApplyCP(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double lambda) override
565 {
566 if (GetSimulationType() == SimulationType::kStabilizer)
567 throw std::runtime_error("CP gate not supported in stabilizer simulation");
568
569 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
570
571 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
572 {
573 const double halfAngle = lambda * 0.5;
574 ApplyP(ctrl_qubit, halfAngle);
575 ApplyCX(ctrl_qubit, tgt_qubit);
576 ApplyP(tgt_qubit, -halfAngle);
577 ApplyCX(ctrl_qubit, tgt_qubit);
578 ApplyP(tgt_qubit, halfAngle);
579 }
580 else
581 {
582 const cmatrix_t CP = AER::Linalg::Matrix::cphase(lambda);
583 // state->apply_mcphase(qubits, lambda);
584 state->apply_unitary(qubits, CP);
585 }
586
587 NotifyObservers(qubits);
588 }
589
598 void ApplyCRx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta) override
599 {
600 if (GetSimulationType() == SimulationType::kStabilizer)
601 throw std::runtime_error("CRx gate not supported in stabilizer simulation");
602
603 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
604
605 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
606 {
607 const double halfAngle = theta * 0.5;
608
609 ApplyH(tgt_qubit);
610 ApplyCX(ctrl_qubit, tgt_qubit);
611 ApplyRz(tgt_qubit, -halfAngle);
612 ApplyCX(ctrl_qubit, tgt_qubit);
613 ApplyRz(tgt_qubit, halfAngle);
614 ApplyH(tgt_qubit);
615 }
616 else
617 {
618 cmatrix_t mat(4, 4);
619 mat(0, 0) = 1;
620 mat(2, 2) = 1;
621
622 const double t2 = theta * 0.5;
623
624 const complex_t i(0., 1.);
625 mat(1, 1) = std::cos(t2);
626 mat(1, 3) = -i * std::sin(t2);
627 mat(3, 1) = mat(1, 3);
628 mat(3, 3) = mat(1, 1);
629
630 // state->apply_mcrx(qubits, theta);
631 state->apply_unitary(qubits, mat);
632 }
633
634 NotifyObservers(qubits);
635 }
636
645 void ApplyCRy(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta) override
646 {
647 if (GetSimulationType() == SimulationType::kStabilizer)
648 throw std::runtime_error("CRy gate not supported in stabilizer simulation");
649
650 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
651
652 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
653 {
654 const double halfAngle = theta * 0.5;
655
656 ApplyRy(tgt_qubit, halfAngle);
657 ApplyCX(ctrl_qubit, tgt_qubit);
658 ApplyRy(tgt_qubit, -halfAngle);
659 ApplyCX(ctrl_qubit, tgt_qubit);
660 }
661 else
662 {
663 cmatrix_t mat(4, 4);
664 mat(0, 0) = 1;
665 mat(2, 2) = 1;
666
667 const double t2 = theta * 0.5;
668
669 mat(1, 1) = std::complex<double>(cos(t2), 0);
670 mat(1, 3) = std::complex<double>(-sin(t2), 0);
671 mat(3, 1) = std::complex<double>(sin(t2), 0);
672 mat(3, 3) = mat(1, 1);
673
674 // state->apply_mcry(qubits, theta);
675 state->apply_unitary(qubits, mat);
676 }
677
678 NotifyObservers(qubits);
679 }
680
689 void ApplyCRz(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta) override
690 {
691 if (GetSimulationType() == SimulationType::kStabilizer)
692 throw std::runtime_error("CRz gate not supported in stabilizer simulation");
693
694 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
695
696 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
697 {
698 const double halfAngle = theta * 0.5;
699 ApplyRz(tgt_qubit, halfAngle);
700 ApplyCX(ctrl_qubit, tgt_qubit);
701 ApplyRz(tgt_qubit, -halfAngle);
702 ApplyCX(ctrl_qubit, tgt_qubit);
703 }
704 else
705 {
706 const double t2 = theta * 0.5;
707 AER::cvector_t v = {{1, 0}, std::polar(1., -t2), {1, 0}, std::polar(1., t2)};
708
709 // state->apply_mcrz(qubits, theta);
710 state->apply_diagonal_matrix(qubits, v);
711 }
712
713 NotifyObservers(qubits);
714 }
715
723 void ApplyCH(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
724 {
725 if (GetSimulationType() == SimulationType::kStabilizer)
726 throw std::runtime_error("CH gate not supported in stabilizer simulation");
727
728 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
729
730 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
731 {
732 ApplyH(tgt_qubit);
733 ApplySDG(tgt_qubit);
734 ApplyCX(ctrl_qubit, tgt_qubit);
735 ApplyH(tgt_qubit);
736 ApplyT(tgt_qubit);
737 ApplyCX(ctrl_qubit, tgt_qubit);
738 ApplyT(tgt_qubit);
739 ApplyH(tgt_qubit);
740 ApplyS(tgt_qubit);
741 ApplyX(tgt_qubit);
742 ApplyS(ctrl_qubit);
743 }
744 else
745 {
746 const cmatrix_t CU = AER::Linalg::Matrix::cu(M_PI_2, 0, M_PI, 0);
747 state->apply_unitary(qubits, CU);
748 // state->apply_cu(qubits, M_PI_2, 0, M_PI, 0);
749 }
750 NotifyObservers(qubits);
751 }
752
760 void ApplyCSx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
761 {
762 if (GetSimulationType() == SimulationType::kStabilizer)
763 throw std::runtime_error("CSx gate not supported in stabilizer simulation");
764
765 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
766
767 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
768 {
769 ApplyH(tgt_qubit);
770 ApplyT(ctrl_qubit);
771 ApplyT(tgt_qubit);
772 ApplyCX(ctrl_qubit, tgt_qubit);
773 ApplyTDG(tgt_qubit);
774 ApplyCX(ctrl_qubit, tgt_qubit);
775 ApplyH(tgt_qubit);
776 }
777 else
778 {
779 static const cmatrix_t CSX = AER::Utils::make_matrix<complex_t>({{{1, 0}, {0, 0}, {0, 0}, {0, 0}},
780 {{0, 0}, {0.5, 0.5}, {0, 0}, {0.5, -0.5}},
781 {{0, 0}, {0, 0}, {1, 0}, {0, 0}},
782 {{0, 0}, {0.5, -0.5}, {0, 0}, {0.5, 0.5}}});
783
784 state->apply_unitary(qubits, CSX);
785 }
786 NotifyObservers(qubits);
787 }
788
796 void ApplyCSxDAG(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
797 {
798 if (GetSimulationType() == SimulationType::kStabilizer)
799 throw std::runtime_error("CSxDAG gate not supported in stabilizer simulation");
800
801 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
802
803 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
804 {
805 ApplyH(tgt_qubit);
806 ApplyCX(ctrl_qubit, tgt_qubit);
807 ApplyT(tgt_qubit);
808 ApplyCX(ctrl_qubit, tgt_qubit);
809 ApplyTDG(ctrl_qubit);
810 ApplyTDG(tgt_qubit);
811 ApplyH(tgt_qubit);
812 }
813 else
814 {
815 static const cmatrix_t CSXDG = AER::Utils::make_matrix<complex_t>({{{1, 0}, {0, 0}, {0, 0}, {0, 0}},
816 {{0, 0}, {0.5, -0.5}, {0, 0}, {0.5, 0.5}},
817 {{0, 0}, {0, 0}, {1, 0}, {0, 0}},
818 {{0, 0}, {0.5, 0.5}, {0, 0}, {0.5, -0.5}}});
819
820 state->apply_unitary(qubits, CSXDG);
821 }
822
823 NotifyObservers(qubits);
824 }
825
833 void ApplySwap(Types::qubit_t qubit0, Types::qubit_t qubit1) override
834 {
835 const Types::qubits_vector qubits = {qubit0, qubit1};
836
837 if (GetSimulationType() == SimulationType::kStabilizer || GetSimulationType() == SimulationType::kExtendedStabilizer)
838 {
839 AER::Operations::Op op;
840 op.type = AER::Operations::OpType::gate;
841 op.name = "swap";
842 op.qubits = AER::reg_t{qubit0, qubit1};
843
844 state->buffer_op(std::move(op));
845 }
846 else
847 // state->apply_mcswap(qubits);
848 state->apply_unitary(qubits, AER::Linalg::Matrix::SWAP);
849
850 NotifyObservers(qubits);
851 }
852
861 void ApplyCCX(Types::qubit_t qubit0, Types::qubit_t qubit1, Types::qubit_t qubit2) override
862 {
863 if (GetSimulationType() == SimulationType::kStabilizer)
864 throw std::runtime_error("CCX gate not supported in stabilizer simulation");
865
866 const Types::qubits_vector qubits = {qubit0, qubit1, qubit2};
867
868 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
869 {
870 AER::Operations::Op op;
871 op.type = AER::Operations::OpType::gate;
872 op.name = "ccx";
873 op.qubits = AER::reg_t{qubit0, qubit1, qubit2};
874
875 state->buffer_op(std::move(op));
876 }
877 else
878 {
879 static const cmatrix_t mat = AER::Utils::make_matrix<complex_t>({{{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}, {0, 0}, {0, 0}, {1, 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}, {0, 0}, {0, 0}, {1, 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}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}});
887
888 // state->apply_mcx(qubits);
889 state->apply_unitary(qubits, mat);
890 }
891
892 NotifyObservers(qubits);
893 }
894
903 void ApplyCSwap(Types::qubit_t ctrl_qubit, Types::qubit_t qubit0, Types::qubit_t qubit1) override
904 {
905 if (GetSimulationType() == SimulationType::kStabilizer)
906 throw std::runtime_error("CSwap gate not supported in stabilizer simulation");
907
908 const Types::qubits_vector qubits = {ctrl_qubit, qubit0, qubit1};
909
910 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
911 {
912 const int q1 = static_cast<int>(ctrl_qubit); // control
913 const int q2 = static_cast<int>(qubit0);
914 const int q3 = static_cast<int>(qubit1);
915
916 ApplyCX(q3, q2);
917 ApplyCSx(q2, q3);
918 ApplyCX(q1, q2);
919
920 ApplyP(q3, M_PI);
921 ApplyP(q2, -M_PI_2);
922
923 ApplyCSx(q2, q3);
924 ApplyCX(q1, q2);
925
926 ApplyP(q3, M_PI);
927 ApplyCSx(q1, q3);
928 ApplyCX(q3, q2);
929 }
930 else
931 {
932 static const cmatrix_t mat = AER::Utils::make_matrix<complex_t>({{{1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
933 {{0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
934 {{0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
935 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}},
936 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}},
937 {{0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
938 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}},
939 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}}});
940
941 // state->apply_mcswap(qubits);
942 state->apply_unitary(qubits, mat);
943 }
944
945 NotifyObservers(qubits);
946 }
947
959 void ApplyCU(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta, double phi, double lambda, double gamma) override
960 {
961 if (GetSimulationType() == SimulationType::kStabilizer)
962 throw std::runtime_error("CU gate not supported in stabilizer simulation");
963
964 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
965
966 if (GetSimulationType() == SimulationType::kExtendedStabilizer)
967 {
968 if (gamma != 0.0)
969 ApplyP(ctrl_qubit, gamma);
970
971 const double lambdaPlusPhiHalf = 0.5 * (lambda + phi);
972 const double halfTheta = 0.5 * theta;
973 ApplyP(tgt_qubit, 0.5 * (lambda - phi));
974 ApplyP(ctrl_qubit, lambdaPlusPhiHalf);
975 ApplyCX(ctrl_qubit, tgt_qubit);
976 ApplyU(tgt_qubit, -halfTheta, 0, -lambdaPlusPhiHalf, 0);
977 ApplyCX(ctrl_qubit, tgt_qubit);
978 ApplyU(tgt_qubit, halfTheta, phi, 0, 0);
979 }
980 else
981 {
982 const cmatrix_t CU = AER::Linalg::Matrix::cu(theta, phi, lambda, gamma);
983 // state->apply_mcu(qubits, theta, phi, lambda, gamma);
984 state->apply_unitary(qubits, CU);
985 }
986
987 NotifyObservers(qubits);
988 }
989
997 void ApplyNop() override
998 {
999 AER::Operations::Op op;
1000 op.type = AER::Operations::OpType::barrier; // there is also 'nop' but that one
1001 // doesn't work with stabilizer
1002 state->buffer_op(std::move(op));
1003 }
1004
1015 std::unique_ptr<ISimulator> Clone() override
1016 {
1017 auto sim = std::make_unique<AerSimulator>();
1018
1019 sim->configuration = configuration; // copy the configuration
1020 for (const auto &[key, value] : configuration.GetConfigMap())
1021 sim->Configure(key.c_str(), value.c_str());
1022
1023 // the tricky part is cloning the state
1024 if (simulationType == SimulationType::kMatrixProductState)
1025 sim->Configure("method", "matrix_product_state");
1026 else if (simulationType == SimulationType::kStabilizer)
1027 sim->Configure("method", "stabilizer");
1028 else if (simulationType == SimulationType::kTensorNetwork)
1029 sim->Configure("method", "tensor_network");
1030 else if (simulationType == SimulationType::kExtendedStabilizer)
1031 sim->Configure("method", "extended_stabilizer");
1032 else if (simulationType == SimulationType::kDensityMatrix)
1033 sim->Configure("method", "density_matrix");
1034 else
1035 sim->Configure("method", "statevector");
1036
1037 if (simulationType == SimulationType::kMatrixProductState)
1038 {
1039 std::string key = "matrix_product_state_max_bond_dimension";
1040 if (configuration.IsSet(key))
1041 sim->Configure(key.c_str(), configuration.GetConfiguration(key).c_str());
1042
1043 key = "matrix_product_state_truncation_threshold";
1044 if (configuration.IsSet(key))
1045 sim->Configure(key.c_str(), configuration.GetConfiguration(key).c_str());
1046
1047 key = "mps_sample_measure_algorithm";
1048 if (configuration.IsSet(key))
1049 sim->Configure(key.c_str(), configuration.GetConfiguration(key).c_str());
1050 }
1051
1052 sim->SetMultithreading(enableMultithreading);
1053
1054 AER::Vector<complex_t> localSavedAmplitudes = savedAmplitudes;
1055 AER::Data localSavedState = savedState;
1057 AER::cmatrix_t localSavedDensityMatrix = savedDensityMatrix;
1058 auto localSavedExtendedStabilizerState = savedExtendedStabilizerState;
1059
1060 // now the tricky part
1061 if (state && state->is_initialized())
1062 {
1063 SaveState(); // this also restores the state if it's destroyed in the
1064 // saving process!
1065 // now the current state is saved in savedAmplitudes or savedState, so use
1066 // it to initialize the cloned state, like this
1067 sim->savedAmplitudes = std::move(savedAmplitudes);
1068 sim->savedState = std::move(savedState);
1069 sim->savedDensityMatrix = std::move(savedDensityMatrix);
1070 sim->savedExtendedStabilizerState = savedExtendedStabilizerState;
1071
1072 sim->RestoreState(); // now the state is loaded in the cloned simulator
1073
1074 // those saved previously can be an older state, so put them in the clone,
1075 // too
1076 sim->savedAmplitudes = localSavedAmplitudes;
1077 sim->savedState = localSavedState;
1078 sim->savedDensityMatrix = localSavedDensityMatrix;
1079 sim->savedExtendedStabilizerState = localSavedExtendedStabilizerState;
1080
1081 // those saved previously can be an older state, so put them back
1082 savedAmplitudes = std::move(localSavedAmplitudes);
1083 savedState = std::move(localSavedState);
1084 savedDensityMatrix = std::move(localSavedDensityMatrix);
1085 savedExtendedStabilizerState = std::move(localSavedExtendedStabilizerState);
1086 }
1087 else
1088 {
1089 // std::cout << "Restored from non initialized state" << std::endl;
1090 sim->savedAmplitudes = std::move(localSavedAmplitudes);
1091 sim->savedState = std::move(localSavedState);
1092 sim->savedDensityMatrix = std::move(localSavedDensityMatrix);
1093 sim->savedExtendedStabilizerState = std::move(localSavedExtendedStabilizerState);
1094
1095 sim->RestoreState(); // this might not be necessary, but sometimes, not
1096 // very often, an exception is thrown about the
1097 // state not being initialized, this might prevent
1098 // that
1099 }
1100
1101 if (configuration.IsSet("seed"))
1102 sim->SetSeed(DeriveSeed(std::stoull(configuration.GetConfiguration("seed")), nextSeedStream++));
1103
1104 return sim;
1105 }
1106};
1107
1108} // namespace Private
1109} // namespace Simulators
1110
1111#endif
1112
1113#endif
1114
1115#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 ApplyGenericOneQubitGate(void *sim, unsigned long q0, const double *buffer)
int ApplyGenericTwoQubitGate(void *sim, unsigned long q0, unsigned long q1, const double *buffer)
int SaveState(void *sim)
Bounded online routing based on current physical bond dimensions.
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
Definition Types.h:24
uint_fast64_t qubit_t
The type of a qubit.
Definition Types.h:23