Maestro 0.3.1
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 // 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 if (GetSimulationType() == SimulationType::kStabilizer)
101 throw std::runtime_error("P gate not supported in stabilizer simulation");
102
103 const Types::qubits_vector qubits = {qubit};
104
105 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
106 AER::Operations::Op op;
107 op.type = AER::Operations::OpType::gate;
108 op.name = "p";
109 op.qubits = AER::reg_t{qubit};
110 op.params = {lambda};
111
112 state->buffer_op(std::move(op));
113 } else {
114 const AER::cvector_t P = {{1, 0}, std::polar(1., lambda)};
115 state->apply_diagonal_matrix(qubits, P);
116 }
117
118 NotifyObservers(qubits);
119 }
120
127 void ApplyX(Types::qubit_t qubit) override {
128 const Types::qubits_vector qubits = {qubit};
129 state->apply_x(qubit);
130 NotifyObservers(qubits);
131 }
132
139 void ApplyY(Types::qubit_t qubit) override {
140 const Types::qubits_vector qubits = {qubit};
141 state->apply_y(qubit);
142 NotifyObservers(qubits);
143 }
144
151 void ApplyZ(Types::qubit_t qubit) override {
152 const Types::qubits_vector qubits = {qubit};
153 state->apply_z(qubit);
154 NotifyObservers(qubits);
155 }
156
163 void ApplyH(Types::qubit_t qubit) override {
164 const Types::qubits_vector qubits = {qubit};
165 state->apply_h(qubit);
166 NotifyObservers(qubits);
167 }
168
175 void ApplyS(Types::qubit_t qubit) override {
176 const Types::qubits_vector qubits = {qubit};
177
178 if (GetSimulationType() == SimulationType::kStabilizer ||
179 GetSimulationType() == SimulationType::kExtendedStabilizer) {
180 AER::Operations::Op op;
181 op.type = AER::Operations::OpType::gate;
182 op.name = "s";
183 op.qubits = AER::reg_t{qubit};
184
185 state->buffer_op(std::move(op));
186 } else {
187 const AER::cvector_t S = {{1, 0}, complex_t(0.0, 1)};
188 state->apply_diagonal_matrix(qubits, S);
189 }
190
191 NotifyObservers(qubits);
192 }
193
200 void ApplySDG(Types::qubit_t qubit) override {
201 const Types::qubits_vector qubits = {qubit};
202
203 if (GetSimulationType() == SimulationType::kStabilizer ||
204 GetSimulationType() == SimulationType::kExtendedStabilizer) {
205 AER::Operations::Op op;
206 op.type = AER::Operations::OpType::gate;
207 op.name = "sdg";
208 op.qubits = AER::reg_t{qubit};
209
210 state->buffer_op(std::move(op));
211 } else {
212 const AER::cvector_t Sdg = {{1, 0}, complex_t(0.0, -1)};
213 state->apply_diagonal_matrix(qubits, Sdg);
214 }
215
216 NotifyObservers(qubits);
217 }
218
225 void ApplyT(Types::qubit_t qubit) override {
226 if (GetSimulationType() == SimulationType::kStabilizer)
227 throw std::runtime_error("T gate not supported in stabilizer simulation");
228
229 const Types::qubits_vector qubits = {qubit};
230 // state->apply_u(qubit, 0, 0, M_PI / 4.0);
231
232 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
233 AER::Operations::Op op;
234 op.type = AER::Operations::OpType::gate;
235 op.name = "t";
236 op.qubits = AER::reg_t{qubit};
237 state->buffer_op(std::move(op));
238 } else {
239 const AER::cvector_t T = {{1, 0}, std::polar<double>(1, M_PI / 4.)};
240 state->apply_diagonal_matrix(qubits, T);
241 }
242
243 NotifyObservers(qubits);
244 }
245
252 void ApplyTDG(Types::qubit_t qubit) override {
253 if (GetSimulationType() == SimulationType::kStabilizer)
254 throw std::runtime_error(
255 "TDG gate not supported in stabilizer simulation");
256
257 const Types::qubits_vector qubits = {qubit};
258 // state->apply_u(qubit, 0, 0, -M_PI / 4.0);
259
260 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
261 AER::Operations::Op op;
262 op.type = AER::Operations::OpType::gate;
263 op.name = "tdg";
264 op.qubits = AER::reg_t{qubit};
265 state->buffer_op(std::move(op));
266 } else {
267 const AER::cvector_t Tdg = {{1, 0}, std::polar<double>(1, -M_PI / 4.)};
268 state->apply_diagonal_matrix(qubits, Tdg);
269 }
270
271 NotifyObservers(qubits);
272 }
273
280 void ApplySx(Types::qubit_t qubit) override {
281 const Types::qubits_vector qubits = {qubit};
282
283 if (GetSimulationType() == SimulationType::kStabilizer ||
284 GetSimulationType() == SimulationType::kExtendedStabilizer) {
285 AER::Operations::Op op;
286 op.type = AER::Operations::OpType::gate;
287 op.name = "sx";
288 op.qubits = AER::reg_t{qubit};
289
290 state->buffer_op(std::move(op));
291 } else {
292 // there is a difference in the global phase for this
293 // changed to match qcsim behavior (and also the qiskit docs and
294 // implementation - not the one exposed in 'contrib', though)
295 // state->apply_mcrx({ qubit }, -M_PI / 4.0);
296 state->apply_unitary(qubits, AER::Linalg::Matrix::SX);
297 }
298
299 NotifyObservers(qubits);
300 }
301
308 void ApplySxDAG(Types::qubit_t qubit) override {
309 const Types::qubits_vector qubits = {qubit};
310
311 if (GetSimulationType() == SimulationType::kStabilizer ||
312 GetSimulationType() == SimulationType::kExtendedStabilizer) {
313 AER::Operations::Op op;
314 op.type = AER::Operations::OpType::gate;
315 op.name = "sxdg";
316 op.qubits = AER::reg_t{qubit};
317
318 state->buffer_op(std::move(op));
319 } else
320 state->apply_unitary(qubits, AER::Linalg::Matrix::SXDG);
321
322 NotifyObservers(qubits);
323 }
324
331 void ApplyK(Types::qubit_t qubit) override {
332 const Types::qubits_vector qubits = {qubit};
333
334 if (GetSimulationType() == SimulationType::kStabilizer ||
335 GetSimulationType() == SimulationType::kExtendedStabilizer) {
336 ApplyZ(qubit);
337 ApplyS(qubit);
338 ApplyH(qubit);
339 ApplyS(qubit);
340 } else {
341 static const cmatrix_t K = AER::Utils::make_matrix<complex_t>(
342 {{{1. / std::sqrt(2.), 0}, {0, -1. / std::sqrt(2.)}},
343 {{0, 1. / std::sqrt(2.)}, {-1. / std::sqrt(2.), 0}}});
344
345 state->apply_unitary(qubits, K);
346 }
347
348 NotifyObservers(qubits);
349 }
350
358 void ApplyRx(Types::qubit_t qubit, double theta) override {
359 if (GetSimulationType() == SimulationType::kStabilizer)
360 throw std::runtime_error(
361 "Rx gate not supported in stabilizer simulation");
362
363 const Types::qubits_vector qubits = {qubit};
364
365 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
366 ApplyH(qubit);
367 ApplyRz(qubit, theta);
368 ApplyH(qubit);
369 } else {
370 const cmatrix_t rx = AER::Linalg::Matrix::rx(theta);
371 state->apply_unitary(qubits, rx);
372 }
373
374 NotifyObservers(qubits);
375 }
376
384 void ApplyRy(Types::qubit_t qubit, double theta) override {
385 if (GetSimulationType() == SimulationType::kStabilizer)
386 throw std::runtime_error(
387 "Ry gate not supported in stabilizer simulation");
388
389 const Types::qubits_vector qubits = {qubit};
390
391 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
392 ApplySDG(qubit);
393 ApplyRx(qubit, theta);
394 ApplyS(qubit);
395 } else {
396 const cmatrix_t ry = AER::Linalg::Matrix::ry(theta);
397
398 state->apply_unitary(qubits, ry);
399 }
400
401 NotifyObservers(qubits);
402 }
403
411 void ApplyRz(Types::qubit_t qubit, double theta) override {
412 if (GetSimulationType() == SimulationType::kStabilizer)
413 throw std::runtime_error(
414 "Rz gate not supported in stabilizer simulation");
415
416 const Types::qubits_vector qubits = {qubit};
417 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
418 AER::Operations::Op op;
419 op.type = AER::Operations::OpType::gate;
420 op.name = "rz";
421 op.qubits = AER::reg_t{qubit};
422 op.params = {theta};
423
424 state->buffer_op(std::move(op));
425 } else {
426 const cmatrix_t rz = AER::Linalg::Matrix::rz(theta);
427
428 state->apply_unitary(qubits, rz);
429 }
430
431 NotifyObservers(qubits);
432 }
433
444 void ApplyU(Types::qubit_t qubit, double theta, double phi, double lambda,
445 double gamma) override {
446 if (GetSimulationType() == SimulationType::kStabilizer)
447 throw std::runtime_error("U gate not supported in stabilizer simulation");
448
449 const Types::qubits_vector qubits = {qubit};
450
451 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
452 ApplyRz(qubit, lambda);
453 ApplyRy(qubit, theta);
454 ApplyRz(qubit, phi);
455 } else {
456 const cmatrix_t u = AER::Linalg::Matrix::u4(theta, phi, lambda, gamma);
457
458 state->apply_unitary(qubits, u);
459 }
460
461 NotifyObservers(qubits);
462 }
463
471 void ApplyCX(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
472 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
473 state->apply_cx(qubits);
474 NotifyObservers(qubits);
475 }
476
484 void ApplyCY(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
485 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
486
487 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
488 ApplySDG(tgt_qubit);
489 ApplyCX(ctrl_qubit, tgt_qubit);
490 ApplyS(tgt_qubit);
491 } else {
492 state->apply_cy(qubits);
493 }
494 NotifyObservers(qubits);
495 }
496
504 void ApplyCZ(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
505 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
506 state->apply_cz(qubits);
507 NotifyObservers(qubits);
508 }
509
518 void ApplyCP(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
519 double lambda) override {
520 if (GetSimulationType() == SimulationType::kStabilizer)
521 throw std::runtime_error(
522 "CP gate not supported in stabilizer simulation");
523
524 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
525
526 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
527 const double halfAngle = lambda * 0.5;
528 ApplyP(ctrl_qubit, halfAngle);
529 ApplyCX(ctrl_qubit, tgt_qubit);
530 ApplyP(tgt_qubit, -halfAngle);
531 ApplyCX(ctrl_qubit, tgt_qubit);
532 ApplyP(tgt_qubit, halfAngle);
533 } else {
534 const cmatrix_t CP = AER::Linalg::Matrix::cphase(lambda);
535 // state->apply_mcphase(qubits, lambda);
536 state->apply_unitary(qubits, CP);
537 }
538
539 NotifyObservers(qubits);
540 }
541
550 void ApplyCRx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
551 double theta) override {
552 if (GetSimulationType() == SimulationType::kStabilizer)
553 throw std::runtime_error(
554 "CRx gate not supported in stabilizer simulation");
555
556 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
557
558 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
559 const double halfAngle = theta * 0.5;
560
561 ApplyH(tgt_qubit);
562 ApplyCX(ctrl_qubit, tgt_qubit);
563 ApplyRz(tgt_qubit, -halfAngle);
564 ApplyCX(ctrl_qubit, tgt_qubit);
565 ApplyRz(tgt_qubit, halfAngle);
566 ApplyH(tgt_qubit);
567 } else {
568 cmatrix_t mat(4, 4);
569 mat(0, 0) = 1;
570 mat(2, 2) = 1;
571
572 const double t2 = theta * 0.5;
573
574 const complex_t i(0., 1.);
575 mat(1, 1) = std::cos(t2);
576 mat(1, 3) = -i * std::sin(t2);
577 mat(3, 1) = mat(1, 3);
578 mat(3, 3) = mat(1, 1);
579
580 // state->apply_mcrx(qubits, theta);
581 state->apply_unitary(qubits, mat);
582 }
583
584 NotifyObservers(qubits);
585 }
586
595 void ApplyCRy(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
596 double theta) override {
597 if (GetSimulationType() == SimulationType::kStabilizer)
598 throw std::runtime_error(
599 "CRy gate not supported in stabilizer simulation");
600
601 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
602
603 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
604 const double halfAngle = theta * 0.5;
605
606 ApplyRy(tgt_qubit, halfAngle);
607 ApplyCX(ctrl_qubit, tgt_qubit);
608 ApplyRy(tgt_qubit, -halfAngle);
609 ApplyCX(ctrl_qubit, tgt_qubit);
610 } else {
611 cmatrix_t mat(4, 4);
612 mat(0, 0) = 1;
613 mat(2, 2) = 1;
614
615 const double t2 = theta * 0.5;
616
617 mat(1, 1) = std::complex<double>(cos(t2), 0);
618 mat(1, 3) = std::complex<double>(-sin(t2), 0);
619 mat(3, 1) = std::complex<double>(sin(t2), 0);
620 mat(3, 3) = mat(1, 1);
621
622 // state->apply_mcry(qubits, theta);
623 state->apply_unitary(qubits, mat);
624 }
625
626 NotifyObservers(qubits);
627 }
628
637 void ApplyCRz(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
638 double theta) override {
639 if (GetSimulationType() == SimulationType::kStabilizer)
640 throw std::runtime_error(
641 "CRz gate not supported in stabilizer simulation");
642
643 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
644
645 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
646 const double halfAngle = theta * 0.5;
647 ApplyRz(tgt_qubit, halfAngle);
648 ApplyCX(ctrl_qubit, tgt_qubit);
649 ApplyRz(tgt_qubit, -halfAngle);
650 ApplyCX(ctrl_qubit, tgt_qubit);
651 } else {
652 const double t2 = theta * 0.5;
653 AER::cvector_t v = {
654 {1, 0}, std::polar(1., -t2), {1, 0}, std::polar(1., t2)};
655
656 // state->apply_mcrz(qubits, theta);
657 state->apply_diagonal_matrix(qubits, v);
658 }
659
660 NotifyObservers(qubits);
661 }
662
670 void ApplyCH(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
671 if (GetSimulationType() == SimulationType::kStabilizer)
672 throw std::runtime_error(
673 "CH gate not supported in stabilizer simulation");
674
675 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
676
677 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
678 ApplyH(tgt_qubit);
679 ApplySDG(tgt_qubit);
680 ApplyCX(ctrl_qubit, tgt_qubit);
681 ApplyH(tgt_qubit);
682 ApplyT(tgt_qubit);
683 ApplyCX(ctrl_qubit, tgt_qubit);
684 ApplyT(tgt_qubit);
685 ApplyH(tgt_qubit);
686 ApplyS(tgt_qubit);
687 ApplyX(tgt_qubit);
688 ApplyS(ctrl_qubit);
689 } else {
690 const cmatrix_t CU = AER::Linalg::Matrix::cu(M_PI_2, 0, M_PI, 0);
691 state->apply_unitary(qubits, CU);
692 // state->apply_cu(qubits, M_PI_2, 0, M_PI, 0);
693 }
694 NotifyObservers(qubits);
695 }
696
704 void ApplyCSx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
705 if (GetSimulationType() == SimulationType::kStabilizer)
706 throw std::runtime_error(
707 "CSx gate not supported in stabilizer simulation");
708
709 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
710
711 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
712 ApplyH(tgt_qubit);
713 ApplyT(ctrl_qubit);
714 ApplyT(tgt_qubit);
715 ApplyCX(ctrl_qubit, tgt_qubit);
716 ApplyTDG(tgt_qubit);
717 ApplyCX(ctrl_qubit, tgt_qubit);
718 ApplyH(tgt_qubit);
719 } else {
720 static const cmatrix_t CSX = AER::Utils::make_matrix<complex_t>(
721 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}},
722 {{0, 0}, {0.5, 0.5}, {0, 0}, {0.5, -0.5}},
723 {{0, 0}, {0, 0}, {1, 0}, {0, 0}},
724 {{0, 0}, {0.5, -0.5}, {0, 0}, {0.5, 0.5}}});
725
726 state->apply_unitary(qubits, CSX);
727 }
728 NotifyObservers(qubits);
729 }
730
738 void ApplyCSxDAG(Types::qubit_t ctrl_qubit,
739 Types::qubit_t tgt_qubit) override {
740 if (GetSimulationType() == SimulationType::kStabilizer)
741 throw std::runtime_error(
742 "CSxDAG gate not supported in stabilizer simulation");
743
744 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
745
746 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
747 ApplyH(tgt_qubit);
748 ApplyCX(ctrl_qubit, tgt_qubit);
749 ApplyT(tgt_qubit);
750 ApplyCX(ctrl_qubit, tgt_qubit);
751 ApplyTDG(ctrl_qubit);
752 ApplyTDG(tgt_qubit);
753 ApplyH(tgt_qubit);
754 } else {
755 static const cmatrix_t CSXDG = AER::Utils::make_matrix<complex_t>(
756 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}},
757 {{0, 0}, {0.5, -0.5}, {0, 0}, {0.5, 0.5}},
758 {{0, 0}, {0, 0}, {1, 0}, {0, 0}},
759 {{0, 0}, {0.5, 0.5}, {0, 0}, {0.5, -0.5}}});
760
761 state->apply_unitary(qubits, CSXDG);
762 }
763
764 NotifyObservers(qubits);
765 }
766
774 void ApplySwap(Types::qubit_t qubit0, Types::qubit_t qubit1) override {
775 const Types::qubits_vector qubits = {qubit0, qubit1};
776
777 if (GetSimulationType() == SimulationType::kStabilizer ||
778 GetSimulationType() == SimulationType::kExtendedStabilizer) {
779 AER::Operations::Op op;
780 op.type = AER::Operations::OpType::gate;
781 op.name = "swap";
782 op.qubits = AER::reg_t{qubit0, qubit1};
783
784 state->buffer_op(std::move(op));
785 } else
786 // state->apply_mcswap(qubits);
787 state->apply_unitary(qubits, AER::Linalg::Matrix::SWAP);
788
789 NotifyObservers(qubits);
790 }
791
800 void ApplyCCX(Types::qubit_t qubit0, Types::qubit_t qubit1,
801 Types::qubit_t qubit2) override {
802 if (GetSimulationType() == SimulationType::kStabilizer)
803 throw std::runtime_error(
804 "CCX gate not supported in stabilizer simulation");
805
806 const Types::qubits_vector qubits = {qubit0, qubit1, qubit2};
807
808 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
809 AER::Operations::Op op;
810 op.type = AER::Operations::OpType::gate;
811 op.name = "ccx";
812 op.qubits = AER::reg_t{qubit0, qubit1, qubit2};
813
814 state->buffer_op(std::move(op));
815 } else {
816 static const cmatrix_t mat = AER::Utils::make_matrix<complex_t>(
817 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
818 {{0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
819 {{0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
820 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}},
821 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}},
822 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}},
823 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}},
824 {{0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}});
825
826 // state->apply_mcx(qubits);
827 state->apply_unitary(qubits, mat);
828 }
829
830 NotifyObservers(qubits);
831 }
832
841 void ApplyCSwap(Types::qubit_t ctrl_qubit, Types::qubit_t qubit0,
842 Types::qubit_t qubit1) override {
843 if (GetSimulationType() == SimulationType::kStabilizer)
844 throw std::runtime_error(
845 "CSwap gate not supported in stabilizer simulation");
846
847 const Types::qubits_vector qubits = {ctrl_qubit, qubit0, qubit1};
848
849 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
850 const int q1 = static_cast<int>(ctrl_qubit); // control
851 const int q2 = static_cast<int>(qubit0);
852 const int q3 = static_cast<int>(qubit1);
853
854 ApplyCX(q3, q2);
855 ApplyCSx(q2, q3);
856 ApplyCX(q1, q2);
857
858 ApplyP(q3, M_PI);
859 ApplyP(q2, -M_PI_2);
860
861 ApplyCSx(q2, q3);
862 ApplyCX(q1, q2);
863
864 ApplyP(q3, M_PI);
865 ApplyCSx(q1, q3);
866 ApplyCX(q3, q2);
867 } else {
868 static const cmatrix_t mat = AER::Utils::make_matrix<complex_t>(
869 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
870 {{0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
871 {{0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
872 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}},
873 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}},
874 {{0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
875 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}},
876 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}}});
877
878 // state->apply_mcswap(qubits);
879 state->apply_unitary(qubits, mat);
880 }
881
882 NotifyObservers(qubits);
883 }
884
896 void ApplyCU(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
897 double theta, double phi, double lambda, double gamma) override {
898 if (GetSimulationType() == SimulationType::kStabilizer)
899 throw std::runtime_error(
900 "CU gate not supported in stabilizer simulation");
901
902 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
903
904 if (GetSimulationType() == SimulationType::kExtendedStabilizer) {
905 if (gamma != 0.0) ApplyP(ctrl_qubit, gamma);
906
907 const double lambdaPlusPhiHalf = 0.5 * (lambda + phi);
908 const double halfTheta = 0.5 * theta;
909 ApplyP(tgt_qubit, 0.5 * (lambda - phi));
910 ApplyP(ctrl_qubit, lambdaPlusPhiHalf);
911 ApplyCX(ctrl_qubit, tgt_qubit);
912 ApplyU(tgt_qubit, -halfTheta, 0, -lambdaPlusPhiHalf, 0);
913 ApplyCX(ctrl_qubit, tgt_qubit);
914 ApplyU(tgt_qubit, halfTheta, phi, 0, 0);
915 } else {
916 const cmatrix_t CU = AER::Linalg::Matrix::cu(theta, phi, lambda, gamma);
917 // state->apply_mcu(qubits, theta, phi, lambda, gamma);
918 state->apply_unitary(qubits, CU);
919 }
920
921 NotifyObservers(qubits);
922 }
923
931 void ApplyNop() override {
932 AER::Operations::Op op;
933 op.type =
934 AER::Operations::OpType::barrier; // there is also 'nop' but that one
935 // doesn't work with stabilizer
936 state->buffer_op(std::move(op));
937 }
938
949 std::unique_ptr<ISimulator> Clone() override {
950 auto sim = std::make_unique<AerSimulator>();
951
952 sim->configuration = configuration; // copy the configuration
953 for (const auto& [key, value] : configuration.GetConfigMap())
954 sim->Configure(key.c_str(), value.c_str());
955
956 // the tricky part is cloning the state
957 if (simulationType == SimulationType::kMatrixProductState)
958 sim->Configure("method", "matrix_product_state");
959 else if (simulationType == SimulationType::kStabilizer)
960 sim->Configure("method", "stabilizer");
961 else if (simulationType == SimulationType::kTensorNetwork)
962 sim->Configure("method", "tensor_network");
963 else if (simulationType == SimulationType::kExtendedStabilizer)
964 sim->Configure("method", "extended_stabilizer");
965 else if (simulationType == SimulationType::kDensityMatrix)
966 sim->Configure("method", "density_matrix");
967 else
968 sim->Configure("method", "statevector");
969
970 if (simulationType == SimulationType::kMatrixProductState) {
971 std::string key = "matrix_product_state_max_bond_dimension";
972 if (configuration.IsSet(key))
973 sim->Configure(key.c_str(), configuration.GetConfiguration(key).c_str());
974
975 key = "matrix_product_state_truncation_threshold";
976 if (configuration.IsSet(key))
977 sim->Configure(key.c_str(), configuration.GetConfiguration(key).c_str());
978
979 key = "mps_sample_measure_algorithm";
980 if (configuration.IsSet(key))
981 sim->Configure(key.c_str(),
982 configuration.GetConfiguration(key).c_str());
983 }
984
985 sim->SetMultithreading(
986 enableMultithreading);
987
988 AER::Vector<complex_t> localSavedAmplitudes =
989 savedAmplitudes;
990 AER::Data localSavedState =
991 savedState;
993 AER::cmatrix_t localSavedDensityMatrix =
994 savedDensityMatrix;
995 auto localSavedExtendedStabilizerState = savedExtendedStabilizerState;
996
997 // now the tricky part
998 if (state && state->is_initialized()) {
999 SaveState(); // this also restores the state if it's destroyed in the
1000 // saving process!
1001 // now the current state is saved in savedAmplitudes or savedState, so use
1002 // it to initialize the cloned state, like this
1003 sim->savedAmplitudes = std::move(savedAmplitudes);
1004 sim->savedState = std::move(savedState);
1005 sim->savedDensityMatrix = std::move(savedDensityMatrix);
1006 sim->savedExtendedStabilizerState = savedExtendedStabilizerState;
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 sim->savedDensityMatrix = localSavedDensityMatrix;
1015 sim->savedExtendedStabilizerState = localSavedExtendedStabilizerState;
1016
1017 // those saved previously can be an older state, so put them back
1018 savedAmplitudes = std::move(localSavedAmplitudes);
1019 savedState = std::move(localSavedState);
1020 savedDensityMatrix = std::move(localSavedDensityMatrix);
1021 savedExtendedStabilizerState =
1022 std::move(localSavedExtendedStabilizerState);
1023 } else {
1024 // std::cout << "Restored from non initialized state" << std::endl;
1025 sim->savedAmplitudes = std::move(localSavedAmplitudes);
1026 sim->savedState = std::move(localSavedState);
1027 sim->savedDensityMatrix = std::move(localSavedDensityMatrix);
1028 sim->savedExtendedStabilizerState =
1029 std::move(localSavedExtendedStabilizerState);
1030
1031 sim->RestoreState(); // this might not be necessary, but sometimes, not
1032 // very often, an exception is thrown about the
1033 // state not being initialized, this might prevent
1034 // that
1035 }
1036
1037 if (configuration.IsSet("seed"))
1038 sim->SetSeed(DeriveSeed(
1039 std::stoull(configuration.GetConfiguration("seed")),
1040 nextSeedStream++));
1041
1042 return sim;
1043 }
1044};
1045
1046} // namespace Private
1047} // namespace Simulators
1048
1049#endif
1050
1051#endif
1052
1053#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