32 #ifndef CLASSES_GATES_H_ 33 #define CLASSES_GATES_H_ 40 class Gates final :
public internal::Singleton<const Gates>
42 friend class internal::Singleton<const Gates>;
46 cmat Id2{cmat::Identity(2, 2)};
47 cmat H{cmat::Zero(2, 2)};
48 cmat X{cmat::Zero(2, 2)};
49 cmat Y{cmat::Zero(2, 2)};
50 cmat Z{cmat::Zero(2, 2)};
51 cmat S{cmat::Zero(2, 2)};
52 cmat T{cmat::Zero(2, 2)};
55 cmat CNOT{cmat::Identity(4, 4)};
56 cmat CZ{cmat::Identity(4, 4)};
57 cmat CNOTba{cmat::Zero(4, 4)};
58 cmat SWAP{cmat::Identity(4, 4)};
61 cmat TOF{cmat::Identity(8, 8)};
62 cmat FRED{cmat::Identity(8, 8)};
68 H << 1 / std::sqrt(2.), 1 / std::sqrt(2.), 1 / std::sqrt(2.),
74 T << 1, 0, 0, std::exp(1_i * pi / 4.0);
75 CNOT.block(2, 2, 2, 2) = X;
82 SWAP.block(1, 1, 2, 2) = X;
83 TOF.block(6, 6, 2, 2) = X;
84 FRED.block(4, 4, 4, 4) = SWAP;
105 cmat Rn(
double theta,
const std::vector<double>& n)
const {
110 throw exception::CustomException(
111 "qpp::Gates::Rn()",
"n is not a 3-dimensional vector!");
115 result = std::cos(theta / 2) * Id2 -
116 1_i * std::sin(theta / 2) * (n[0] * X + n[1] * Y + n[2] * Z);
127 cmat RX(
double theta)
const {
132 return Rn(theta, {1, 0, 0});
141 cmat RY(
double theta)
const {
146 return Rn(theta, {0, 1, 0});
155 cmat RZ(
double theta)
const {
160 return Rn(theta, {0, 0, 1});
174 cmat Zd(idx D = 2)
const {
179 throw exception::DimsInvalid(
"qpp::Gates::Zd()");
182 cmat result = cmat::Zero(D, D);
183 for (idx i = 0; i < D; ++i)
184 result(i, i) = std::pow(omega(D), static_cast<double>(i));
195 cmat SWAPd(idx D = 2)
const {
200 throw exception::DimsInvalid(
"qpp::Gates::SWAPd()");
203 cmat result = cmat::Zero(D * D, D * D);
206 #pragma omp parallel for collapse(2) 207 #endif // WITH_OPENMP_ 209 for (idx j = 0; j < D; ++j)
210 for (idx i = 0; i < D; ++i)
211 result(D * i + j, i + D * j) = 1;
226 cmat Fd(idx D = 2)
const {
231 throw exception::DimsInvalid(
"qpp::Gates::Fd()");
237 #pragma omp parallel for collapse(2) 238 #endif // WITH_OPENMP_ 240 for (idx j = 0; j < D; ++j)
241 for (idx i = 0; i < D; ++i)
242 result(i, j) = 1 / std::sqrt(D) *
243 std::pow(omega(D), static_cast<double>(i * j));
263 cmat MODMUL(idx a, idx N, idx n)
const {
267 assert(gcd(a, N) == 1);
272 if (N < 3 || a >= N) {
273 throw exception::OutOfRange(
"qpp::Gates::MODMUL()");
277 if (n < static_cast<idx>(std::ceil(std::log2(N)))) {
278 throw exception::OutOfRange(
"qpp::Gates::MODMUL()");
283 idx D =
static_cast<idx
>(std::llround(std::pow(2, n)));
285 cmat result = cmat::Zero(D, D);
288 #pragma omp parallel for collapse(2) 289 #endif // WITH_OPENMP_ 291 for (idx j = 0; j < N; ++j)
292 for (idx i = 0; i < N; ++i)
293 if (static_cast<idx>(modmul(j, a, N)) == i)
297 #pragma omp parallel for 298 #endif // WITH_OPENMP_ 300 for (idx i = N; i < D; ++i)
315 cmat Xd(idx D = 2)
const {
320 throw exception::DimsInvalid(
"qpp::Gates::Xd()");
323 return Fd(D).inverse() * Zd(D) * Fd(D);
335 template <
typename Derived = Eigen::MatrixXcd>
336 Derived Id(idx D = 2)
const {
341 throw exception::DimsInvalid(
"qpp::Gates::Id()");
344 return Derived::Identity(D, D);
365 template <
typename Derived>
366 dyn_mat<typename Derived::Scalar>
367 CTRL(
const Eigen::MatrixBase<Derived>& A,
const std::vector<idx>& ctrl,
368 const std::vector<idx>& target, idx n, idx d = 2,
369 std::vector<idx> shift = {})
const {
370 const dyn_mat<typename Derived::Scalar>& rA = A.derived();
375 if (!internal::check_nonzero_size(rA))
376 throw exception::ZeroSize(
"qpp::Gates::CTRL()");
379 if (!internal::check_square_mat(rA))
380 throw exception::MatrixNotSquare(
"qpp::Gates::CTRL()");
384 throw exception::ZeroSize(
"qpp::Gates::CTRL()");
386 throw exception::ZeroSize(
"qpp::Gates::CTRL()");
390 throw exception::OutOfRange(
"qpp::Gates::CTRL()");
394 throw exception::DimsInvalid(
"qpp::Gates::CTRL()");
397 std::vector<idx> ctrlgate = ctrl;
398 ctrlgate.insert(std::end(ctrlgate), std::begin(target),
400 std::sort(std::begin(ctrlgate), std::end(ctrlgate));
402 std::vector<idx> dims(n, d);
406 if (!internal::check_subsys_match_dims(ctrlgate, dims))
407 throw exception::SubsysMismatchDims(
"qpp::Gates::CTRL()");
410 using Index =
typename dyn_mat<typename Derived::Scalar>::Index;
412 static_cast<Index
>(std::llround(std::pow(d, target.size()))))
413 throw exception::DimsMismatchMatrix(
"qpp::Gates::CTRL()");
416 if (!shift.empty() && (shift.size() != ctrl.size()))
417 throw exception::SizeMismatch(
"qpp::Gates::CTRL()");
419 for (
auto&& elem : shift)
421 throw exception::OutOfRange(
"qpp::Gates::CTRL()");
425 shift = std::vector<idx>(ctrl.size(), 0);
437 idx Csubsys_bar[maxn];
440 idx n_gate = target.size();
441 idx n_ctrl = ctrl.size();
442 idx n_subsys_bar = n - ctrlgate.size();
443 idx D =
static_cast<idx
>(std::llround(std::pow(d, n)));
444 idx DA =
static_cast<idx
>(rA.rows());
446 static_cast<idx
>(std::llround(std::pow(d, n_subsys_bar)));
449 std::vector<idx> subsys_bar = complement(ctrlgate, n);
450 std::copy(std::begin(subsys_bar), std::end(subsys_bar),
451 std::begin(Csubsys_bar));
453 for (idx k = 0; k < n; ++k) {
454 midx_row[k] = midx_col[k] = 0;
458 for (idx k = 0; k < n_subsys_bar; ++k) {
463 for (idx k = 0; k < n_gate; ++k) {
464 midxA_row[k] = midxA_col[k] = 0;
468 dyn_mat<typename Derived::Scalar> result =
469 dyn_mat<typename Derived::Scalar>::Identity(D, D);
470 dyn_mat<typename Derived::Scalar> Ak;
473 for (idx i = 0; i < Dsubsys_bar; ++i) {
475 internal::n2multiidx(i, n_subsys_bar, Cdims_bar, midx_bar);
476 for (idx k = 0; k < d; ++k) {
479 for (idx a = 0; a < DA; ++a) {
481 internal::n2multiidx(a, n_gate, CdimsA, midxA_row);
486 for (idx c = 0; c < n_ctrl; ++c)
487 midx_row[ctrl[c]] = midx_col[ctrl[c]] =
488 (k + d - shift[c]) % d;
491 for (idx c = 0; c < n_subsys_bar; ++c)
492 midx_row[Csubsys_bar[c]] = midx_col[Csubsys_bar[c]] =
496 for (idx c = 0; c < n_gate; ++c)
497 midx_row[target[c]] = midxA_row[c];
500 for (idx b = 0; b < DA; ++b) {
502 internal::n2multiidx(b, n_gate, CdimsA, midxA_col);
505 for (idx c = 0; c < n_gate; ++c)
506 midx_col[target[c]] = midxA_col[c];
509 result(internal::multiidx2n(midx_row, n, Cdims),
510 internal::multiidx2n(midx_col, n, Cdims)) =
535 template <
typename Derived>
536 dyn_mat<typename Derived::Scalar>
537 expandout(
const Eigen::MatrixBase<Derived>& A, idx pos,
538 const std::vector<idx>& dims)
const {
539 const dyn_mat<typename Derived::Scalar>& rA = A.derived();
544 if (!internal::check_nonzero_size(rA))
545 throw exception::ZeroSize(
"qpp::Gates::expandout()");
548 if (!internal::check_dims(dims))
549 throw exception::DimsInvalid(
"qpp::Gates::expandout()");
552 if (!internal::check_square_mat(rA))
553 throw exception::MatrixNotSquare(
"qpp::Gates::expandout()");
556 if (pos + 1 > dims.size())
557 throw exception::OutOfRange(
"qpp::Gates::expandout()");
560 if (static_cast<idx>(rA.rows()) != dims[pos])
561 throw exception::DimsMismatchMatrix(
"qpp::Gates::expandout()");
564 idx D = std::accumulate(std::begin(dims), std::end(dims),
565 static_cast<idx>(1), std::multiplies<idx>());
566 dyn_mat<typename Derived::Scalar> result =
567 dyn_mat<typename Derived::Scalar>::Identity(D, D);
573 for (idx k = 0; k < dims.size(); ++k) {
574 midx_row[k] = midx_col[k] = 0;
579 for (idx i = 0; i < D; ++i) {
581 internal::n2multiidx(i, dims.size(), Cdims, midx_row);
583 internal::n2multiidx(i, dims.size(), Cdims, midx_col);
585 for (idx a = 0; a < static_cast<idx>(rA.rows()); ++a) {
590 for (idx b = 0; b < static_cast<idx>(rA.cols()); ++b) {
595 result(internal::multiidx2n(midx_row, dims.size(), Cdims),
596 internal::multiidx2n(midx_col, dims.size(), Cdims)) =
626 template <
typename Derived>
627 dyn_mat<typename Derived::Scalar>
628 expandout(
const Eigen::MatrixBase<Derived>& A, idx pos,
629 const std::initializer_list<idx>& dims)
const {
630 return expandout(A, pos, std::vector<idx>(dims));
649 template <
typename Derived>
650 dyn_mat<typename Derived::Scalar>
651 expandout(
const Eigen::MatrixBase<Derived>& A, idx pos, idx n,
656 if (!internal::check_nonzero_size(A))
657 throw exception::ZeroSize(
"qpp::Gates::expandout()");
661 throw exception::DimsInvalid(
"qpp::Gates::expandout()");
664 std::vector<idx> dims(n, d);
666 return expandout(A, pos, dims);
680 std::string get_name(
const cmat& U)
const {
684 if (!internal::check_nonzero_size(U))
685 throw exception::ZeroSize(
"qpp::Gates::get_name()");
688 if (!internal::check_square_mat(U))
693 const idx D =
static_cast<idx
>(U.rows());
721 else if (U == CNOTba)
Quantum++ main namespace.
Definition: circuits.h:35