Maestro 0.1.0
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 {
42public:
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 const Types::qubits_vector qubits = {qubit};
61
62 const AER::cvector_t P = {{1, 0}, std::polar(1., lambda)};
63 state->apply_diagonal_matrix(qubits, P);
64
65 NotifyObservers(qubits);
66 }
67
74 void ApplyX(Types::qubit_t qubit) override {
75 const Types::qubits_vector qubits = {qubit};
76 state->apply_x(qubit);
77 NotifyObservers(qubits);
78 }
79
86 void ApplyY(Types::qubit_t qubit) override {
87 const Types::qubits_vector qubits = {qubit};
88 state->apply_y(qubit);
89 NotifyObservers(qubits);
90 }
91
98 void ApplyZ(Types::qubit_t qubit) override {
99 const Types::qubits_vector qubits = {qubit};
100 state->apply_z(qubit);
101 NotifyObservers(qubits);
102 }
103
110 void ApplyH(Types::qubit_t qubit) override {
111 const Types::qubits_vector qubits = {qubit};
112 state->apply_h(qubit);
113 NotifyObservers(qubits);
114 }
115
122 void ApplyS(Types::qubit_t qubit) override {
123 const Types::qubits_vector qubits = {qubit};
124
125 if (GetSimulationType() == SimulationType::kStabilizer) {
126 AER::Operations::Op op;
127 op.type = AER::Operations::OpType::gate;
128 op.name = "s";
129 op.qubits = AER::reg_t{qubit};
130
131 state->buffer_op(std::move(op));
132 } else {
133 const AER::cvector_t S = {{1, 0}, complex_t(0.0, 1)};
134 state->apply_diagonal_matrix(qubits, S);
135 }
136
137 NotifyObservers(qubits);
138 }
139
146 void ApplySDG(Types::qubit_t qubit) override {
147 const Types::qubits_vector qubits = {qubit};
148
149 if (GetSimulationType() == SimulationType::kStabilizer) {
150 AER::Operations::Op op;
151 op.type = AER::Operations::OpType::gate;
152 op.name = "sdg";
153 op.qubits = AER::reg_t{qubit};
154
155 state->buffer_op(std::move(op));
156 } else {
157 const AER::cvector_t Sdg = {{1, 0}, complex_t(0.0, -1)};
158 state->apply_diagonal_matrix(qubits, Sdg);
159 }
160
161 NotifyObservers(qubits);
162 }
163
170 void ApplyT(Types::qubit_t qubit) override {
171 if (GetSimulationType() == SimulationType::kStabilizer)
172 throw std::runtime_error("T gate not supported in stabilizer simulation");
173
174 const Types::qubits_vector qubits = {qubit};
175 // state->apply_u(qubit, 0, 0, M_PI / 4.0);
176
177 const AER::cvector_t T = {{1, 0}, std::polar<double>(1, M_PI / 4.)};
178 state->apply_diagonal_matrix(qubits, T);
179
180 NotifyObservers(qubits);
181 }
182
189 void ApplyTDG(Types::qubit_t qubit) override {
190 if (GetSimulationType() == SimulationType::kStabilizer)
191 throw std::runtime_error(
192 "TDG gate not supported in stabilizer simulation");
193
194 const Types::qubits_vector qubits = {qubit};
195 // state->apply_u(qubit, 0, 0, -M_PI / 4.0);
196
197 const AER::cvector_t Tdg = {{1, 0}, std::polar<double>(1, -M_PI / 4.)};
198 state->apply_diagonal_matrix(qubits, Tdg);
199
200 NotifyObservers(qubits);
201 }
202
209 void ApplySx(Types::qubit_t qubit) override {
210 const Types::qubits_vector qubits = {qubit};
211
212 if (GetSimulationType() == SimulationType::kStabilizer) {
213 AER::Operations::Op op;
214 op.type = AER::Operations::OpType::gate;
215 op.name = "sx";
216 op.qubits = AER::reg_t{qubit};
217
218 state->buffer_op(std::move(op));
219 } else {
220 // there is a difference in the global phase for this
221 // changed to match qcsim behavior (and also the qiskit docs and
222 // implementation - not the one exposed in 'contrib', though)
223 // state->apply_mcrx({ qubit }, -M_PI / 4.0);
224 state->apply_unitary(qubits, AER::Linalg::Matrix::SX);
225 }
226
227 NotifyObservers(qubits);
228 }
229
236 void ApplySxDAG(Types::qubit_t qubit) override {
237 const Types::qubits_vector qubits = {qubit};
238
239 if (GetSimulationType() == SimulationType::kStabilizer) {
240 AER::Operations::Op op;
241 op.type = AER::Operations::OpType::gate;
242 op.name = "sxdg";
243 op.qubits = AER::reg_t{qubit};
244
245 state->buffer_op(std::move(op));
246 } else
247 state->apply_unitary(qubits, AER::Linalg::Matrix::SXDG);
248
249 NotifyObservers(qubits);
250 }
251
258 void ApplyK(Types::qubit_t qubit) override {
259 const Types::qubits_vector qubits = {qubit};
260
261 if (GetSimulationType() == SimulationType::kStabilizer) {
262 ApplyZ(qubit);
263 ApplyS(qubit);
264 ApplyH(qubit);
265 ApplyS(qubit);
266 } else {
267 static const cmatrix_t K = AER::Utils::make_matrix<complex_t>(
268 {{{1. / std::sqrt(2.), 0}, {0, -1. / std::sqrt(2.)}},
269 {{0, 1. / std::sqrt(2.)}, {-1. / std::sqrt(2.), 0}}});
270
271 state->apply_unitary(qubits, K);
272 }
273
274 NotifyObservers(qubits);
275 }
276
284 void ApplyRx(Types::qubit_t qubit, double theta) override {
285 if (GetSimulationType() == SimulationType::kStabilizer)
286 throw std::runtime_error(
287 "Rx gate not supported in stabilizer simulation");
288
289 const Types::qubits_vector qubits = {qubit};
290 const cmatrix_t rx = AER::Linalg::Matrix::rx(theta);
291
292 state->apply_unitary(qubits, rx);
293
294 NotifyObservers(qubits);
295 }
296
304 void ApplyRy(Types::qubit_t qubit, double theta) override {
305 if (GetSimulationType() == SimulationType::kStabilizer)
306 throw std::runtime_error(
307 "Ry gate not supported in stabilizer simulation");
308
309 const Types::qubits_vector qubits = {qubit};
310 const cmatrix_t ry = AER::Linalg::Matrix::ry(theta);
311
312 state->apply_unitary(qubits, ry);
313
314 NotifyObservers(qubits);
315 }
316
324 void ApplyRz(Types::qubit_t qubit, double theta) override {
325 if (GetSimulationType() == SimulationType::kStabilizer)
326 throw std::runtime_error(
327 "Rz gate not supported in stabilizer simulation");
328
329 const Types::qubits_vector qubits = {qubit};
330 const cmatrix_t rz = AER::Linalg::Matrix::rz(theta);
331
332 state->apply_unitary(qubits, rz);
333
334 NotifyObservers(qubits);
335 }
336
347 void ApplyU(Types::qubit_t qubit, double theta, double phi, double lambda,
348 double gamma) override {
349 if (GetSimulationType() == SimulationType::kStabilizer)
350 throw std::runtime_error("U gate not supported in stabilizer simulation");
351
352 const Types::qubits_vector qubits = {qubit};
353 const cmatrix_t u = AER::Linalg::Matrix::u4(theta, phi, lambda, gamma);
354
355 state->apply_unitary(qubits, u);
356
357 NotifyObservers(qubits);
358 }
359
367 void ApplyCX(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
368 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
369 state->apply_cx(qubits);
370 NotifyObservers(qubits);
371 }
372
380 void ApplyCY(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
381 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
382 state->apply_cy(qubits);
383 NotifyObservers(qubits);
384 }
385
393 void ApplyCZ(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
394 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
395 state->apply_cz(qubits);
396 NotifyObservers(qubits);
397 }
398
407 void ApplyCP(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
408 double lambda) override {
409 if (GetSimulationType() == SimulationType::kStabilizer)
410 throw std::runtime_error(
411 "CP gate not supported in stabilizer simulation");
412
413 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
414 const cmatrix_t CP = AER::Linalg::Matrix::cphase(lambda);
415 // state->apply_mcphase(qubits, lambda);
416 state->apply_unitary(qubits, CP);
417
418 NotifyObservers(qubits);
419 }
420
429 void ApplyCRx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
430 double theta) override {
431 if (GetSimulationType() == SimulationType::kStabilizer)
432 throw std::runtime_error(
433 "CRx gate not supported in stabilizer simulation");
434
435 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
436
437 cmatrix_t mat(4, 4);
438 mat(0, 0) = 1;
439 mat(2, 2) = 1;
440
441 const double t2 = theta * 0.5;
442
443 const complex_t i(0., 1.);
444 mat(1, 1) = std::cos(t2);
445 mat(1, 3) = -i * std::sin(t2);
446 mat(3, 1) = mat(1, 3);
447 mat(3, 3) = mat(1, 1);
448
449 // state->apply_mcrx(qubits, theta);
450 state->apply_unitary(qubits, mat);
451
452 NotifyObservers(qubits);
453 }
454
463 void ApplyCRy(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
464 double theta) override {
465 if (GetSimulationType() == SimulationType::kStabilizer)
466 throw std::runtime_error(
467 "CRy gate not supported in stabilizer simulation");
468
469 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
470
471 cmatrix_t mat(4, 4);
472 mat(0, 0) = 1;
473 mat(2, 2) = 1;
474
475 const double t2 = theta * 0.5;
476
477 mat(1, 1) = std::complex<double>(cos(t2), 0);
478 mat(1, 3) = std::complex<double>(-sin(t2), 0);
479 mat(3, 1) = std::complex<double>(sin(t2), 0);
480 mat(3, 3) = mat(1, 1);
481
482 // state->apply_mcry(qubits, theta);
483 state->apply_unitary(qubits, mat);
484
485 NotifyObservers(qubits);
486 }
487
496 void ApplyCRz(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
497 double theta) override {
498 if (GetSimulationType() == SimulationType::kStabilizer)
499 throw std::runtime_error(
500 "CRz gate not supported in stabilizer simulation");
501
502 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
503
504 const double t2 = theta * 0.5;
505 AER::cvector_t v = {
506 {1, 0}, std::polar(1., -t2), {1, 0}, std::polar(1., t2)};
507
508 // state->apply_mcrz(qubits, theta);
509 state->apply_diagonal_matrix(qubits, v);
510
511 NotifyObservers(qubits);
512 }
513
521 void ApplyCH(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
522 if (GetSimulationType() == SimulationType::kStabilizer)
523 throw std::runtime_error(
524 "CH gate not supported in stabilizer simulation");
525
526 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
527 const cmatrix_t CU = AER::Linalg::Matrix::cu(M_PI_2, 0, M_PI, 0);
528 state->apply_unitary(qubits, CU);
529 // state->apply_cu(qubits, M_PI_2, 0, M_PI, 0);
530
531 NotifyObservers(qubits);
532 }
533
541 void ApplyCSx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
542 if (GetSimulationType() == SimulationType::kStabilizer)
543 throw std::runtime_error(
544 "CSx gate not supported in stabilizer simulation");
545
546 static const cmatrix_t CSX = AER::Utils::make_matrix<complex_t>(
547 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}},
548 {{0, 0}, {0.5, 0.5}, {0, 0}, {0.5, -0.5}},
549 {{0, 0}, {0, 0}, {1, 0}, {0, 0}},
550 {{0, 0}, {0.5, -0.5}, {0, 0}, {0.5, 0.5}}});
551
552 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
553 state->apply_unitary(qubits, CSX);
554 NotifyObservers(qubits);
555 }
556
564 void ApplyCSxDAG(Types::qubit_t ctrl_qubit,
565 Types::qubit_t tgt_qubit) override {
566 if (GetSimulationType() == SimulationType::kStabilizer)
567 throw std::runtime_error(
568 "CSxDAG gate not supported in stabilizer simulation");
569
570 static const cmatrix_t CSXDG = AER::Utils::make_matrix<complex_t>(
571 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}},
572 {{0, 0}, {0.5, -0.5}, {0, 0}, {0.5, 0.5}},
573 {{0, 0}, {0, 0}, {1, 0}, {0, 0}},
574 {{0, 0}, {0.5, 0.5}, {0, 0}, {0.5, -0.5}}});
575
576 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
577 state->apply_unitary(qubits, CSXDG);
578 NotifyObservers(qubits);
579 }
580
588 void ApplySwap(Types::qubit_t qubit0, Types::qubit_t qubit1) override {
589 const Types::qubits_vector qubits = {qubit0, qubit1};
590
591 if (GetSimulationType() == SimulationType::kStabilizer) {
592 AER::Operations::Op op;
593 op.type = AER::Operations::OpType::gate;
594 op.name = "swap";
595 op.qubits = AER::reg_t{qubit0, qubit1};
596
597 state->buffer_op(std::move(op));
598 } else
599 // state->apply_mcswap(qubits);
600 state->apply_unitary(qubits, AER::Linalg::Matrix::SWAP);
601
602 NotifyObservers(qubits);
603 }
604
613 void ApplyCCX(Types::qubit_t qubit0, Types::qubit_t qubit1,
614 Types::qubit_t qubit2) override {
615 if (GetSimulationType() == SimulationType::kStabilizer)
616 throw std::runtime_error(
617 "CCX gate not supported in stabilizer simulation");
618
619 const Types::qubits_vector qubits = {qubit0, qubit1, qubit2};
620
621 static const cmatrix_t mat = AER::Utils::make_matrix<complex_t>(
622 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
623 {{0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
624 {{0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
625 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}},
626 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}},
627 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}},
628 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}},
629 {{0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}});
630
631 // state->apply_mcx(qubits);
632 state->apply_unitary(qubits, mat);
633
634 NotifyObservers(qubits);
635 }
636
645 void ApplyCSwap(Types::qubit_t ctrl_qubit, Types::qubit_t qubit0,
646 Types::qubit_t qubit1) override {
647 if (GetSimulationType() == SimulationType::kStabilizer)
648 throw std::runtime_error(
649 "CSwap gate not supported in stabilizer simulation");
650
651 const Types::qubits_vector qubits = {ctrl_qubit, qubit0, qubit1};
652
653 static const cmatrix_t mat = AER::Utils::make_matrix<complex_t>(
654 {{{1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
655 {{0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
656 {{0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
657 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}},
658 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}},
659 {{0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
660 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}, {0, 0}},
661 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 0}}});
662
663 // state->apply_mcswap(qubits);
664 state->apply_unitary(qubits, mat);
665
666 NotifyObservers(qubits);
667 }
668
680 void ApplyCU(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
681 double theta, double phi, double lambda, double gamma) override {
682 if (GetSimulationType() == SimulationType::kStabilizer)
683 throw std::runtime_error(
684 "CU gate not supported in stabilizer simulation");
685
686 const Types::qubits_vector qubits = {ctrl_qubit, tgt_qubit};
687
688 const cmatrix_t CU = AER::Linalg::Matrix::cu(theta, phi, lambda, gamma);
689 // state->apply_mcu(qubits, theta, phi, lambda, gamma);
690 state->apply_unitary(qubits, CU);
691
692 NotifyObservers(qubits);
693 }
694
702 void ApplyNop() override {
703 AER::Operations::Op op;
704 op.type =
705 AER::Operations::OpType::barrier; // there is also 'nop' but that one
706 // doesn't work with stabilizer
707 state->buffer_op(std::move(op));
708 }
709
720 std::unique_ptr<ISimulator> Clone() override {
721 auto sim = std::make_unique<AerSimulator>();
722
723 // the tricky part is cloning the state
724 if (simulationType == SimulationType::kMatrixProductState)
725 sim->Configure("method", "matrix_product_state");
726 else if (simulationType == SimulationType::kStabilizer)
727 sim->Configure("method", "stabilizer");
728 else if (simulationType == SimulationType::kTensorNetwork)
729 sim->Configure("method", "tensor_network");
730 else
731 sim->Configure("method", "statevector");
732
733 if (simulationType == SimulationType::kMatrixProductState) {
734 if (limitSize)
735 sim->Configure("matrix_product_state_max_bond_dimension",
736 std::to_string(chi).c_str());
737 if (limitEntanglement)
738 sim->Configure("matrix_product_state_truncation_threshold",
739 std::to_string(singularValueThreshold).c_str());
740 sim->Configure("mps_sample_measure_algorithm", useMPSMeasureNoCollapse
741 ? "mps_probabilities"
742 : "mps_apply_measure");
743 }
744
745 sim->SetMultithreading(
746 enableMultithreading);
747
748 AER::Vector<complex_t> localSavedAmplitudes =
749 savedAmplitudes;
750 AER::Data localSavedState =
751 savedState;
753
754 // now the tricky part
755 if (state && state->is_initialized()) {
756 SaveState(); // this also restores the state if it's destroyed in the
757 // saving process!
758 // now the current state is saved in savedAmplitudes or savedState, so use
759 // it to initialize the cloned state, like this
760 sim->savedAmplitudes = std::move(savedAmplitudes);
761 sim->savedState = std::move(savedState);
762
763 sim->RestoreState(); // now the state is loaded in the cloned simulator
764
765 // those saved previously can be an older state, so put them in the clone,
766 // too
767 sim->savedAmplitudes = localSavedAmplitudes;
768 sim->savedState = localSavedState;
769
770 // those saved previously can be an older state, so put them back
771 savedAmplitudes = std::move(localSavedAmplitudes);
772 savedState = std::move(localSavedState);
773 } else {
774 // std::cout << "Restored from non initialized state" << std::endl;
775 sim->savedAmplitudes = std::move(localSavedAmplitudes);
776 sim->savedState = std::move(localSavedState);
777
778 sim->RestoreState(); // this might not be necessary, but sometimes, not
779 // very often, an exception is thrown about the state
780 // not being initialized, this might prevent that
781 }
782
783 return sim;
784 }
785};
786
787} // namespace Private
788} // namespace Simulators
789
790#endif
791
792#endif
793
794#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:21
uint_fast64_t qubit_t
The type of a qubit.
Definition Types.h:20