55 template <
typename Derived1,
typename Derived2>
56 dyn_mat<typename Derived1::Scalar>
57 applyCTRL(
const Eigen::MatrixBase<Derived1>& state,
58 const Eigen::MatrixBase<Derived2>& A,
const std::vector<idx>& ctrl,
59 const std::vector<idx>& target,
const std::vector<idx>& dims,
60 std::vector<idx> shift = {}) {
61 const typename Eigen::MatrixBase<Derived1>::EvalReturnType& rstate =
63 const dyn_mat<typename Derived2::Scalar>& rA = A.derived();
68 if (!std::is_same<
typename Derived1::Scalar,
69 typename Derived2::Scalar>::value)
70 throw exception::TypeMismatch(
"qpp::applyCTRL()");
73 if (!internal::check_nonzero_size(rA))
74 throw exception::ZeroSize(
"qpp::applyCTRL()");
77 if (!internal::check_nonzero_size(rstate))
78 throw exception::ZeroSize(
"qpp::applyCTRL()");
81 if (!internal::check_nonzero_size(target))
82 throw exception::ZeroSize(
"qpp::applyCTRL()");
85 if (!internal::check_square_mat(rA))
86 throw exception::MatrixNotSquare(
"qpp::applyCTRL()");
89 if (internal::check_cvector(rstate)) {
90 if (!internal::check_dims_match_cvect(dims, state))
91 throw exception::DimsMismatchCvector(
"qpp::applyCTRL()");
92 }
else if (internal::check_square_mat(rstate)) {
93 if (!internal::check_dims_match_mat(dims, state))
94 throw exception::DimsMismatchMatrix(
"qpp::applyCTRL()");
96 throw exception::MatrixNotSquareNorCvector(
"qpp::applyCTRL()");
99 if (!internal::check_subsys_match_dims(ctrl, dims))
100 throw exception::SubsysMismatchDims(
"qpp::applyCTRL()");
103 idx d = ctrl.size() > 0 ? dims[ctrl[0]] : 1;
104 for (idx i = 1; i < ctrl.size(); ++i)
105 if (dims[ctrl[i]] != d)
106 throw exception::DimsNotEqual(
"qpp::applyCTRL()");
109 if (!internal::check_dims(dims))
110 throw exception::DimsInvalid(
"qpp::applyCTRL()");
113 if (!internal::check_subsys_match_dims(target, dims))
114 throw exception::SubsysMismatchDims(
"qpp::applyCTRL()");
117 std::vector<idx> target_dims(target.size());
118 for (idx i = 0; i < target.size(); ++i)
119 target_dims[i] = dims[target[i]];
120 if (!internal::check_dims_match_mat(target_dims, rA))
121 throw exception::MatrixMismatchSubsys(
"qpp::applyCTRL()");
123 std::vector<idx> ctrlgate = ctrl;
124 ctrlgate.insert(std::end(ctrlgate), std::begin(target), std::end(target));
125 std::sort(std::begin(ctrlgate), std::end(ctrlgate));
129 if (!internal::check_subsys_match_dims(ctrlgate, dims))
130 throw exception::SubsysMismatchDims(
"qpp::applyCTRL()");
133 if (!shift.empty() && (shift.size() != ctrl.size()))
134 throw exception::SizeMismatch(
"qpp::applyCTRL()");
136 for (
auto&& elem : shift)
138 throw exception::OutOfRange(
"qpp::applyCTRL()");
142 shift = std::vector<idx>(ctrl.size(), 0);
145 std::vector<dyn_mat<typename Derived1::Scalar>> Ai;
146 std::vector<dyn_mat<typename Derived1::Scalar>> Aidagger;
147 for (idx i = 0; i < std::max(d, static_cast<idx>(2)); ++i) {
148 Ai.emplace_back(powm(rA, i));
149 Aidagger.emplace_back(powm(adjoint(rA), i));
152 idx D =
static_cast<idx
>(rstate.rows());
154 idx ctrlsize = ctrl.size();
155 idx ctrlgatesize = ctrlgate.size();
156 idx targetsize = target.size();
158 idx Dctrl =
static_cast<idx
>(std::llround(std::pow(d, ctrlsize)));
159 idx DA =
static_cast<idx
>(rA.rows());
164 idx CdimsCTRLA_bar[maxn];
167 std::vector<idx> ctrlgate_bar = complement(ctrlgate, n);
169 idx ctrlgate_barsize = ctrlgate_bar.size();
172 for (idx i = 0; i < ctrlgate_barsize; ++i)
173 DCTRLA_bar *= dims[ctrlgate_bar[i]];
175 for (idx k = 0; k < n; ++k)
177 for (idx k = 0; k < targetsize; ++k)
178 CdimsA[k] = dims[target[k]];
179 for (idx k = 0; k < ctrlsize; ++k)
181 for (idx k = 0; k < ctrlgate_barsize; ++k)
182 CdimsCTRLA_bar[k] = dims[ctrlgate_bar[k]];
186 auto coeff_idx_ket = [&](idx i_, idx m_, idx r_) noexcept
187 ->std::pair<typename Derived1::Scalar, idx> {
189 typename Derived1::Scalar coeff = 0;
193 idx CmidxCTRLA_bar[maxn];
198 for (idx k = 0; k < ctrlsize; ++k) {
199 Cmidx[ctrl[k]] = (i_ + d - shift[k]) % d;
203 internal::n2multiidx(r_, n - ctrlgatesize, CdimsCTRLA_bar,
205 for (idx k = 0; k < n - ctrlgatesize; ++k) {
206 Cmidx[ctrlgate_bar[k]] = CmidxCTRLA_bar[k];
210 internal::n2multiidx(m_, targetsize, CdimsA, CmidxA);
211 for (idx k = 0; k < targetsize; ++k) {
212 Cmidx[target[k]] = CmidxA[k];
216 indx = internal::multiidx2n(Cmidx, n, Cdims);
219 for (idx n_ = 0; n_ < DA; ++n_) {
220 internal::n2multiidx(n_, targetsize, CdimsA, CmidxA);
221 for (idx k = 0; k < targetsize; ++k) {
222 Cmidx[target[k]] = CmidxA[k];
225 Ai[i_](m_, n_) * rstate(internal::multiidx2n(Cmidx, n, Cdims));
228 return std::make_pair(coeff, indx);
234 auto coeff_idx_rho = [&](idx i1_, idx m1_, idx r1_, idx i2_, idx m2_,
236 ->std::tuple<typename Derived1::Scalar, idx, idx> {
239 typename Derived1::Scalar coeff = 0, lhs = 1, rhs = 1;
245 idx CmidxCTRLrow[maxn];
246 idx CmidxCTRLcol[maxn];
247 idx CmidxCTRLA_barrow[maxn];
248 idx CmidxCTRLA_barcol[maxn];
253 internal::n2multiidx(i1_, ctrlsize, CdimsCTRL, CmidxCTRLrow);
254 internal::n2multiidx(i2_, ctrlsize, CdimsCTRL, CmidxCTRLcol);
256 for (idx k = 0; k < ctrlsize; ++k) {
257 Cmidxrow[ctrl[k]] = CmidxCTRLrow[k];
258 Cmidxcol[ctrl[k]] = CmidxCTRLcol[k];
262 internal::n2multiidx(r1_, n - ctrlgatesize, CdimsCTRLA_bar,
264 internal::n2multiidx(r2_, n - ctrlgatesize, CdimsCTRLA_bar,
266 for (idx k = 0; k < n - ctrlgatesize; ++k) {
267 Cmidxrow[ctrlgate_bar[k]] = CmidxCTRLA_barrow[k];
268 Cmidxcol[ctrlgate_bar[k]] = CmidxCTRLA_barcol[k];
272 internal::n2multiidx(m1_, targetsize, CdimsA, CmidxArow);
273 internal::n2multiidx(m2_, targetsize, CdimsA, CmidxAcol);
274 for (idx k = 0; k < target.size(); ++k) {
275 Cmidxrow[target[k]] = CmidxArow[k];
276 Cmidxcol[target[k]] = CmidxAcol[k];
280 idxrow = internal::multiidx2n(Cmidxrow, n, Cdims);
281 idxcol = internal::multiidx2n(Cmidxcol, n, Cdims);
284 bool all_ctrl_rows_equal =
true;
285 bool all_ctrl_cols_equal =
true;
287 idx first_ctrl_row, first_ctrl_col;
289 first_ctrl_row = (CmidxCTRLrow[0] + shift[0]) % d;
290 first_ctrl_col = (CmidxCTRLcol[0] + shift[0]) % d;
292 first_ctrl_row = first_ctrl_col = 1;
295 for (idx k = 1; k < ctrlsize; ++k) {
296 if ((CmidxCTRLrow[k] + shift[k]) % d != first_ctrl_row) {
297 all_ctrl_rows_equal =
false;
301 for (idx k = 1; k < ctrlsize; ++k) {
302 if ((CmidxCTRLcol[k] + shift[k]) % d != first_ctrl_col) {
303 all_ctrl_cols_equal =
false;
309 for (idx n1_ = 0; n1_ < DA; ++n1_) {
310 internal::n2multiidx(n1_, targetsize, CdimsA, CmidxArow);
311 for (idx k = 0; k < targetsize; ++k) {
312 Cmidxrow[target[k]] = CmidxArow[k];
314 idx idxrowtmp = internal::multiidx2n(Cmidxrow, n, Cdims);
316 if (all_ctrl_rows_equal) {
317 lhs = Ai[first_ctrl_row](m1_, n1_);
319 lhs = (m1_ == n1_) ? 1 : 0;
322 for (idx n2_ = 0; n2_ < DA; ++n2_) {
323 internal::n2multiidx(n2_, targetsize, CdimsA, CmidxAcol);
324 for (idx k = 0; k < targetsize; ++k) {
325 Cmidxcol[target[k]] = CmidxAcol[k];
328 if (all_ctrl_cols_equal) {
329 rhs = Aidagger[first_ctrl_col](n2_, m2_);
331 rhs = (n2_ == m2_) ? 1 : 0;
334 idx idxcoltmp = internal::multiidx2n(Cmidxcol, n, Cdims);
336 coeff += lhs * rstate(idxrowtmp, idxcoltmp) * rhs;
340 return std::make_tuple(coeff, idxrow, idxcol);
344 if (internal::check_cvector(rstate))
347 if (!internal::check_dims_match_cvect(dims, rstate))
348 throw exception::DimsMismatchCvector(
"qpp::applyCTRL()");
352 dyn_mat<typename Derived1::Scalar> result = rstate;
355 #pragma omp parallel for collapse(2) 356 #endif // WITH_OPENMP_ 357 for (idx m = 0; m < DA; ++m)
358 for (idx r = 0; r < DCTRLA_bar; ++r) {
361 result(coeff_idx_ket(1, m, r).second) =
362 coeff_idx_ket(1, m, r).first;
364 for (idx i = 0; i < d; ++i) {
365 result(coeff_idx_ket(i, m, r).second) =
366 coeff_idx_ket(i, m, r).first;
376 if (!internal::check_dims_match_mat(dims, rstate))
377 throw exception::DimsMismatchMatrix(
"qpp::applyCTRL()");
382 dyn_mat<typename Derived1::Scalar> result = rstate;
385 #pragma omp parallel for collapse(4) 386 #endif // WITH_OPENMP_ 387 for (idx m1 = 0; m1 < DA; ++m1)
388 for (idx r1 = 0; r1 < DCTRLA_bar; ++r1)
389 for (idx m2 = 0; m2 < DA; ++m2)
390 for (idx r2 = 0; r2 < DCTRLA_bar; ++r2)
394 coeff_idx_rho(1, m1, r1, 1, m2, r2);
395 result(std::get<1>(coeff_idxes),
396 std::get<2>(coeff_idxes)) =
397 std::get<0>(coeff_idxes);
399 for (idx i1 = 0; i1 < Dctrl; ++i1)
400 for (idx i2 = 0; i2 < Dctrl; ++i2) {
402 coeff_idx_rho(i1, m1, r1, i2, m2, r2);
403 result(std::get<1>(coeff_idxes),
404 std::get<2>(coeff_idxes)) =
405 std::get<0>(coeff_idxes);
431 template <
typename Derived1,
typename Derived2>
432 dyn_mat<typename Derived1::Scalar>
433 applyCTRL(
const Eigen::MatrixBase<Derived1>& state,
434 const Eigen::MatrixBase<Derived2>& A,
const std::vector<idx>& ctrl,
435 const std::vector<idx>& target, idx d = 2,
436 const std::vector<idx>& shift = {}) {
437 const typename Eigen::MatrixBase<Derived1>::EvalReturnType& rstate =
439 const dyn_mat<typename Derived1::Scalar>& rA = A.derived();
444 if (!internal::check_nonzero_size(rstate))
445 throw exception::ZeroSize(
"qpp::applyCTRL()");
449 throw exception::DimsInvalid(
"qpp::applyCTRL()");
452 idx n = internal::get_num_subsys(static_cast<idx>(rstate.rows()), d);
453 std::vector<idx> dims(n, d);
455 return applyCTRL(rstate, rA, ctrl, target, dims, shift);
470 template <
typename Derived1,
typename Derived2>
471 dyn_mat<typename Derived1::Scalar>
472 apply(
const Eigen::MatrixBase<Derived1>& state,
473 const Eigen::MatrixBase<Derived2>& A,
const std::vector<idx>& target,
474 const std::vector<idx>& dims) {
475 const typename Eigen::MatrixBase<Derived1>::EvalReturnType& rstate =
477 const dyn_mat<typename Derived2::Scalar>& rA = A.derived();
482 if (!std::is_same<
typename Derived1::Scalar,
483 typename Derived2::Scalar>::value)
484 throw exception::TypeMismatch(
"qpp::apply()");
487 if (!internal::check_nonzero_size(rA))
488 throw exception::ZeroSize(
"qpp::apply()");
491 if (!internal::check_nonzero_size(rstate))
492 throw exception::ZeroSize(
"qpp::apply()");
495 if (!internal::check_nonzero_size(target))
496 throw exception::ZeroSize(
"qpp::apply()");
499 if (!internal::check_square_mat(rA))
500 throw exception::MatrixNotSquare(
"qpp::apply()");
503 if (!internal::check_dims(dims))
504 throw exception::DimsInvalid(
"qpp::apply()");
507 if (!internal::check_subsys_match_dims(target, dims))
508 throw exception::SubsysMismatchDims(
"qpp::apply()");
511 if (internal::check_cvector(rstate)) {
512 if (!internal::check_dims_match_cvect(dims, state))
513 throw exception::DimsMismatchCvector(
"qpp::apply()");
514 }
else if (internal::check_square_mat(rstate)) {
515 if (!internal::check_dims_match_mat(dims, state))
516 throw exception::DimsMismatchMatrix(
"qpp::apply()");
518 throw exception::MatrixNotSquareNorCvector(
"qpp::apply()");
521 std::vector<idx> subsys_dims(target.size());
522 for (idx i = 0; i < target.size(); ++i)
523 subsys_dims[i] = dims[target[i]];
524 if (!internal::check_dims_match_mat(subsys_dims, rA))
525 throw exception::MatrixMismatchSubsys(
"qpp::apply()");
529 if (internal::check_cvector(rstate))
530 return applyCTRL(rstate, rA, {}, target, dims);
533 return applyCTRL(rstate, rA, {}, target, dims);
548 template <
typename Derived1,
typename Derived2>
549 dyn_mat<typename Derived1::Scalar>
550 apply(
const Eigen::MatrixBase<Derived1>& state,
551 const Eigen::MatrixBase<Derived2>& A,
const std::vector<idx>& target,
553 const typename Eigen::MatrixBase<Derived1>::EvalReturnType& rstate =
555 const dyn_mat<typename Derived1::Scalar>& rA = A.derived();
560 if (!internal::check_nonzero_size(rstate))
561 throw exception::ZeroSize(
"qpp::apply()");
565 throw exception::DimsInvalid(
"qpp::apply()");
568 idx n = internal::get_num_subsys(static_cast<idx>(rstate.rows()), d);
569 std::vector<idx> dims(n, d);
571 return apply(rstate, rA, target, dims);
582 template <
typename Derived>
583 cmat apply(
const Eigen::MatrixBase<Derived>& A,
const std::vector<cmat>& Ks) {
584 const cmat& rA = A.derived();
588 if (!internal::check_nonzero_size(rA))
589 throw exception::ZeroSize(
"qpp::apply()");
590 if (!internal::check_square_mat(rA))
591 throw exception::MatrixNotSquare(
"qpp::apply()");
593 throw exception::ZeroSize(
"qpp::apply()");
594 if (!internal::check_square_mat(Ks[0]))
595 throw exception::MatrixNotSquare(
"qpp::apply()");
596 if (Ks[0].rows() != rA.rows())
597 throw exception::DimsMismatchMatrix(
"qpp::apply()");
598 for (
auto&& elem : Ks)
599 if (elem.rows() != Ks[0].rows() || elem.cols() != Ks[0].rows())
600 throw exception::DimsNotEqual(
"qpp::apply()");
603 cmat result = cmat::Zero(rA.rows(), rA.rows());
606 #pragma omp parallel for 607 #endif // WITH_OPENMP_ 608 for (idx i = 0; i < Ks.size(); ++i) {
611 #endif // WITH_OPENMP_ 612 { result += Ks[i] * rA * adjoint(Ks[i]); }
628 template <
typename Derived>
629 cmat apply(
const Eigen::MatrixBase<Derived>& A,
const std::vector<cmat>& Ks,
630 const std::vector<idx>& target,
const std::vector<idx>& dims) {
631 const cmat& rA = A.derived();
636 if (!internal::check_nonzero_size(rA))
637 throw exception::ZeroSize(
"qpp::apply()");
640 if (!internal::check_nonzero_size(target))
641 throw exception::ZeroSize(
"qpp::apply()");
644 if (!internal::check_square_mat(rA))
645 throw exception::MatrixNotSquare(
"qpp::apply()");
648 if (!internal::check_dims(dims))
649 throw exception::DimsInvalid(
"qpp::apply()");
652 if (!internal::check_subsys_match_dims(target, dims))
653 throw exception::SubsysMismatchDims(
"qpp::apply()");
656 if (internal::check_cvector(rA)) {
657 if (!internal::check_dims_match_cvect(dims, rA))
658 throw exception::DimsMismatchCvector(
"qpp::apply()");
659 }
else if (internal::check_square_mat(rA)) {
660 if (!internal::check_dims_match_mat(dims, rA))
661 throw exception::DimsMismatchMatrix(
"qpp::apply()");
663 throw exception::MatrixNotSquareNorCvector(
"qpp::apply()");
665 std::vector<idx> subsys_dims(target.size());
666 for (idx i = 0; i < target.size(); ++i)
667 subsys_dims[i] = dims[target[i]];
671 throw exception::ZeroSize(
"qpp::apply()");
672 if (!internal::check_square_mat(Ks[0]))
673 throw exception::MatrixNotSquare(
"qpp::apply()");
674 if (!internal::check_dims_match_mat(subsys_dims, Ks[0]))
675 throw exception::MatrixMismatchSubsys(
"qpp::apply()");
676 for (
auto&& elem : Ks)
677 if (elem.rows() != Ks[0].rows() || elem.cols() != Ks[0].rows())
678 throw exception::DimsNotEqual(
"qpp::apply()");
681 cmat result = cmat::Zero(rA.rows(), rA.rows());
683 for (idx i = 0; i < Ks.size(); ++i)
684 result += apply(rA, Ks[i], target, dims);
699 template <
typename Derived>
700 cmat apply(
const Eigen::MatrixBase<Derived>& A,
const std::vector<cmat>& Ks,
701 const std::vector<idx>& target, idx d = 2) {
702 const cmat& rA = A.derived();
707 if (!internal::check_nonzero_size(rA))
708 throw exception::ZeroSize(
"qpp::apply()");
712 throw exception::DimsInvalid(
"qpp::apply()");
715 idx n = internal::get_num_subsys(static_cast<idx>(rA.rows()), d);
716 std::vector<idx> dims(n, d);
718 return apply(rA, Ks, target, dims);
732 inline cmat kraus2super(
const std::vector<cmat>& Ks) {
736 throw exception::ZeroSize(
"qpp::kraus2super()");
737 if (!internal::check_nonzero_size(Ks[0]))
738 throw exception::ZeroSize(
"qpp::kraus2super()");
739 if (!internal::check_square_mat(Ks[0]))
740 throw exception::MatrixNotSquare(
"qpp::kraus2super()");
741 for (
auto&& elem : Ks)
742 if (elem.rows() != Ks[0].rows() || elem.cols() != Ks[0].rows())
743 throw exception::DimsNotEqual(
"qpp::kraus2super()");
746 idx D =
static_cast<idx
>(Ks[0].rows());
748 cmat result(D * D, D * D);
749 cmat MN = cmat::Zero(D, D);
750 bra A = bra::Zero(D);
751 ket B = ket::Zero(D);
752 cmat EMN = cmat::Zero(D, D);
755 #pragma omp parallel for collapse(2) 756 #endif // WITH_OPENMP_ 757 for (idx m = 0; m < D; ++m) {
758 for (idx n = 0; n < D; ++n) {
761 #endif // WITH_OPENMP_ 765 for (idx i = 0; i < Ks.size(); ++i)
766 EMN += Ks[i] * MN * adjoint(Ks[i]);
769 for (idx a = 0; a < D; ++a) {
771 for (idx b = 0; b < D; ++b) {
774 result(a * D + b, m * D + n) =
775 static_cast<cmat
>(A * EMN * B).value();
780 EMN = cmat::Zero(D, D);
803 inline cmat kraus2choi(
const std::vector<cmat>& Ks) {
807 throw exception::ZeroSize(
"qpp::kraus2choi()");
808 if (!internal::check_nonzero_size(Ks[0]))
809 throw exception::ZeroSize(
"qpp::kraus2choi()");
810 if (!internal::check_square_mat(Ks[0]))
811 throw exception::MatrixNotSquare(
"qpp::kraus2choi()");
812 for (
auto&& elem : Ks)
813 if (elem.rows() != Ks[0].rows() || elem.cols() != Ks[0].rows())
814 throw exception::DimsNotEqual(
"qpp::kraus2choi()");
817 idx D =
static_cast<idx
>(Ks[0].rows());
821 cmat MES = cmat::Zero(D * D, 1);
822 for (idx a = 0; a < D; ++a)
825 cmat Omega = MES * adjoint(MES);
827 cmat result = cmat::Zero(D * D, D * D);
830 #pragma omp parallel for 831 #endif // WITH_OPENMP_ 832 for (idx i = 0; i < Ks.size(); ++i) {
835 #endif // WITH_OPENMP_ 837 result += kron(cmat::Identity(D, D), Ks[i]) * Omega *
838 adjoint(kron(cmat::Identity(D, D), Ks[i]));
858 inline std::vector<cmat> choi2kraus(
const cmat& A) {
861 if (!internal::check_nonzero_size(A))
862 throw exception::ZeroSize(
"qpp::choi2kraus()");
863 if (!internal::check_square_mat(A))
864 throw exception::MatrixNotSquare(
"qpp::choi2kraus()");
865 idx D = internal::get_dim_subsys(A.rows(), 2);
867 if (D * D != static_cast<idx>(A.rows()))
868 throw exception::DimsInvalid(
"qpp::choi2kraus()");
872 cmat evec = hevects(A);
873 std::vector<cmat> result;
875 for (idx i = 0; i < D * D; ++i) {
876 if (std::abs(ev(i)) > 0)
877 result.emplace_back(std::sqrt(std::abs(ev(i))) *
878 reshape(evec.col(i), D, D));
891 inline cmat choi2super(
const cmat& A) {
894 if (!internal::check_nonzero_size(A))
895 throw exception::ZeroSize(
"qpp::choi2super()");
896 if (!internal::check_square_mat(A))
897 throw exception::MatrixNotSquare(
"qpp::choi2super()");
898 idx D = internal::get_dim_subsys(static_cast<idx>(A.rows()), 2);
900 if (D * D != static_cast<idx>(A.rows()))
901 throw exception::DimsInvalid(
"qpp::choi2super()");
904 cmat result(D * D, D * D);
907 #pragma omp parallel for collapse(4) 908 #endif // WITH_OPENMP_ 909 for (idx a = 0; a < D; ++a)
910 for (idx b = 0; b < D; ++b)
911 for (idx m = 0; m < D; ++m)
912 for (idx n = 0; n < D; ++n)
913 result(a * D + b, m * D + n) = A(m * D + a, n * D + b);
925 inline cmat super2choi(
const cmat& A) {
928 if (!internal::check_nonzero_size(A))
929 throw exception::ZeroSize(
"qpp::super2choi()");
930 if (!internal::check_square_mat(A))
931 throw exception::MatrixNotSquare(
"qpp::super2choi()");
932 idx D = internal::get_dim_subsys(static_cast<idx>(A.rows()), 2);
934 if (D * D != static_cast<idx>(A.rows()))
935 throw exception::DimsInvalid(
"qpp::super2choi()");
938 cmat result(D * D, D * D);
941 #pragma omp parallel for collapse(4) 942 #endif // WITH_OPENMP_ 943 for (idx a = 0; a < D; ++a)
944 for (idx b = 0; b < D; ++b)
945 for (idx m = 0; m < D; ++m)
946 for (idx n = 0; n < D; ++n)
947 result(m * D + a, n * D + b) = A(a * D + b, m * D + n);
965 template <
typename Derived>
966 dyn_mat<typename Derived::Scalar> ptrace1(
const Eigen::MatrixBase<Derived>& A,
967 const std::vector<idx>& dims) {
968 const typename Eigen::MatrixBase<Derived>::EvalReturnType& rA = A.derived();
973 if (!internal::check_nonzero_size(rA))
974 throw exception::ZeroSize(
"qpp::ptrace1()");
977 if (!internal::check_dims(dims))
978 throw exception::DimsInvalid(
"qpp::ptrace1()");
981 if (dims.size() != 2)
982 throw exception::NotBipartite(
"qpp::ptrace1()");
988 dyn_mat<typename Derived::Scalar> result =
989 dyn_mat<typename Derived::Scalar>::Zero(DB, DB);
992 if (internal::check_cvector(rA))
995 if (!internal::check_dims_match_cvect(dims, rA))
996 throw exception::DimsMismatchCvector(
"qpp::ptrace1()");
998 auto worker = [&](idx i, idx j) noexcept->typename Derived::Scalar {
999 typename Derived::Scalar sum = 0;
1000 for (idx m = 0; m < DA; ++m)
1001 sum += rA(m * DB + i) * std::conj(rA(m * DB + j));
1007 #pragma omp parallel for collapse(2) 1008 #endif // WITH_OPENMP_ 1010 for (idx j = 0; j < DB; ++j)
1011 for (idx i = 0; i < DB; ++i)
1012 result(i, j) = worker(i, j);
1015 else if (internal::check_square_mat(rA))
1018 if (!internal::check_dims_match_mat(dims, rA))
1019 throw exception::DimsMismatchMatrix(
"qpp::ptrace1()");
1021 auto worker = [&](idx i, idx j) noexcept->typename Derived::Scalar {
1022 typename Derived::Scalar sum = 0;
1023 for (idx m = 0; m < DA; ++m)
1024 sum += rA(m * DB + i, m * DB + j);
1030 #pragma omp parallel for collapse(2) 1031 #endif // WITH_OPENMP_ 1033 for (idx j = 0; j < DB; ++j)
1034 for (idx i = 0; i < DB; ++i)
1035 result(i, j) = worker(i, j);
1039 throw exception::MatrixNotSquareNorCvector(
"qpp::ptrace1()");
1057 template <
typename Derived>
1058 dyn_mat<typename Derived::Scalar> ptrace1(
const Eigen::MatrixBase<Derived>& A,
1060 const dyn_mat<typename Derived::Scalar>& rA = A.derived();
1065 if (!internal::check_nonzero_size(rA))
1066 throw exception::ZeroSize(
"qpp::ptrace1()");
1070 throw exception::DimsInvalid(
"qpp::ptrace1()");
1073 std::vector<idx> dims(2, d);
1075 return ptrace1(rA, dims);
1091 template <
typename Derived>
1092 dyn_mat<typename Derived::Scalar> ptrace2(
const Eigen::MatrixBase<Derived>& A,
1093 const std::vector<idx>& dims) {
1094 const typename Eigen::MatrixBase<Derived>::EvalReturnType& rA = A.derived();
1099 if (!internal::check_nonzero_size(rA))
1100 throw exception::ZeroSize(
"qpp::ptrace2()");
1103 if (!internal::check_dims(dims))
1104 throw exception::DimsInvalid(
"qpp::ptrace2()");
1107 if (dims.size() != 2)
1108 throw exception::NotBipartite(
"qpp::ptrace2()");
1114 dyn_mat<typename Derived::Scalar> result =
1115 dyn_mat<typename Derived::Scalar>::Zero(DA, DA);
1118 if (internal::check_cvector(rA))
1121 if (!internal::check_dims_match_cvect(dims, rA))
1122 throw exception::DimsMismatchCvector(
"qpp::ptrace2()");
1124 auto worker = [&](idx i, idx j) noexcept->typename Derived::Scalar {
1125 typename Derived::Scalar sum = 0;
1126 for (idx m = 0; m < DB; ++m)
1127 sum += rA(i * DB + m) * std::conj(rA(j * DB + m));
1133 #pragma omp parallel for collapse(2) 1134 #endif // WITH_OPENMP_ 1136 for (idx j = 0; j < DA; ++j)
1137 for (idx i = 0; i < DA; ++i)
1138 result(i, j) = worker(i, j);
1141 else if (internal::check_square_mat(rA))
1144 if (!internal::check_dims_match_mat(dims, rA))
1145 throw exception::DimsMismatchMatrix(
"qpp::ptrace2()");
1148 #pragma omp parallel for collapse(2) 1149 #endif // WITH_OPENMP_ 1151 for (idx j = 0; j < DA; ++j)
1152 for (idx i = 0; i < DA; ++i)
1153 result(i, j) = trace(rA.block(i * DB, j * DB, DB, DB));
1157 throw exception::MatrixNotSquareNorCvector(
"qpp::ptrace1()");
1175 template <
typename Derived>
1176 dyn_mat<typename Derived::Scalar> ptrace2(
const Eigen::MatrixBase<Derived>& A,
1178 const dyn_mat<typename Derived::Scalar>& rA = A.derived();
1183 if (!internal::check_nonzero_size(rA))
1184 throw exception::ZeroSize(
"qpp::ptrace2()");
1188 throw exception::DimsInvalid(
"qpp::ptrace2()");
1191 std::vector<idx> dims(2, d);
1193 return ptrace2(rA, dims);
1210 template <
typename Derived>
1211 dyn_mat<typename Derived::Scalar> ptrace(
const Eigen::MatrixBase<Derived>& A,
1212 const std::vector<idx>& target,
1213 const std::vector<idx>& dims) {
1214 const typename Eigen::MatrixBase<Derived>::EvalReturnType& rA = A.derived();
1219 if (!internal::check_nonzero_size(rA))
1220 throw exception::ZeroSize(
"qpp::ptrace()");
1223 if (!internal::check_dims(dims))
1224 throw exception::DimsInvalid(
"qpp::ptrace()");
1227 if (!internal::check_subsys_match_dims(target, dims))
1228 throw exception::SubsysMismatchDims(
"qpp::ptrace()");
1231 if (internal::check_cvector(rA)) {
1232 if (!internal::check_dims_match_cvect(dims, rA))
1233 throw exception::DimsMismatchCvector(
"qpp::ptrace()");
1234 }
else if (internal::check_square_mat(rA)) {
1235 if (!internal::check_dims_match_mat(dims, rA))
1236 throw exception::DimsMismatchMatrix(
"qpp::ptrace()");
1238 throw exception::MatrixNotSquareNorCvector(
"qpp::ptrace()");
1241 idx D =
static_cast<idx
>(rA.rows());
1242 idx n = dims.size();
1243 idx n_subsys = target.size();
1244 idx n_subsys_bar = n - n_subsys;
1246 for (idx i = 0; i < n_subsys; ++i)
1247 Dsubsys *= dims[target[i]];
1248 idx Dsubsys_bar = D / Dsubsys;
1252 idx Cdimssubsys[maxn];
1253 idx Csubsys_bar[maxn];
1254 idx Cdimssubsys_bar[maxn];
1256 idx Cmidxcolsubsys_bar[maxn];
1258 std::vector<idx> subsys_bar = complement(target, n);
1259 std::copy(std::begin(subsys_bar), std::end(subsys_bar),
1260 std::begin(Csubsys_bar));
1262 for (idx i = 0; i < n; ++i) {
1265 for (idx i = 0; i < n_subsys; ++i) {
1266 Csubsys[i] = target[i];
1267 Cdimssubsys[i] = dims[target[i]];
1269 for (idx i = 0; i < n_subsys_bar; ++i) {
1270 Cdimssubsys_bar[i] = dims[subsys_bar[i]];
1273 dyn_mat<typename Derived::Scalar> result =
1274 dyn_mat<typename Derived::Scalar>(Dsubsys_bar, Dsubsys_bar);
1277 if (internal::check_cvector(rA))
1279 if (target.size() == dims.size()) {
1280 result(0, 0) = (adjoint(rA) * rA).value();
1285 return rA * adjoint(rA);
1287 auto worker = [&](idx i) noexcept->typename Derived::Scalar {
1292 idx Cmidxrowsubsys_bar[maxn];
1293 idx Cmidxsubsys[maxn];
1296 internal::n2multiidx(i, n_subsys_bar, Cdimssubsys_bar,
1297 Cmidxrowsubsys_bar);
1299 for (idx k = 0; k < n_subsys_bar; ++k) {
1300 Cmidxrow[Csubsys_bar[k]] = Cmidxrowsubsys_bar[k];
1301 Cmidxcol[Csubsys_bar[k]] = Cmidxcolsubsys_bar[k];
1303 typename Derived::Scalar sm = 0;
1304 for (idx a = 0; a < Dsubsys; ++a) {
1306 internal::n2multiidx(a, n_subsys, Cdimssubsys, Cmidxsubsys);
1308 for (idx k = 0; k < n_subsys; ++k)
1309 Cmidxrow[Csubsys[k]] = Cmidxcol[Csubsys[k]] =
1313 sm += rA(internal::multiidx2n(Cmidxrow, n, Cdims)) *
1314 std::conj(rA(internal::multiidx2n(Cmidxcol, n, Cdims)));
1320 for (idx j = 0; j < Dsubsys_bar; ++j)
1323 internal::n2multiidx(j, n_subsys_bar, Cdimssubsys_bar,
1324 Cmidxcolsubsys_bar);
1326 #pragma omp parallel for 1327 #endif // WITH_OPENMP_ 1328 for (idx i = 0; i < Dsubsys_bar; ++i) {
1329 result(i, j) = worker(i);
1336 if (target.size() == dims.size()) {
1337 result(0, 0) = rA.trace();
1344 auto worker = [&](idx i) noexcept->typename Derived::Scalar {
1349 idx Cmidxrowsubsys_bar[maxn];
1350 idx Cmidxsubsys[maxn];
1353 internal::n2multiidx(i, n_subsys_bar, Cdimssubsys_bar,
1354 Cmidxrowsubsys_bar);
1356 for (idx k = 0; k < n_subsys_bar; ++k) {
1357 Cmidxrow[Csubsys_bar[k]] = Cmidxrowsubsys_bar[k];
1358 Cmidxcol[Csubsys_bar[k]] = Cmidxcolsubsys_bar[k];
1360 typename Derived::Scalar sm = 0;
1361 for (idx a = 0; a < Dsubsys; ++a) {
1363 internal::n2multiidx(a, n_subsys, Cdimssubsys, Cmidxsubsys);
1365 for (idx k = 0; k < n_subsys; ++k)
1366 Cmidxrow[Csubsys[k]] = Cmidxcol[Csubsys[k]] =
1370 sm += rA(internal::multiidx2n(Cmidxrow, n, Cdims),
1371 internal::multiidx2n(Cmidxcol, n, Cdims));
1377 for (idx j = 0; j < Dsubsys_bar; ++j)
1380 internal::n2multiidx(j, n_subsys_bar, Cdimssubsys_bar,
1381 Cmidxcolsubsys_bar);
1383 #pragma omp parallel for 1384 #endif // WITH_OPENMP_ 1385 for (idx i = 0; i < Dsubsys_bar; ++i) {
1386 result(i, j) = worker(i);
1408 template <
typename Derived>
1409 dyn_mat<typename Derived::Scalar> ptrace(
const Eigen::MatrixBase<Derived>& A,
1410 const std::vector<idx>& target,
1412 const typename Eigen::MatrixBase<Derived>::EvalReturnType& rA = A.derived();
1417 if (!internal::check_nonzero_size(rA))
1418 throw exception::ZeroSize(
"qpp::ptrace()");
1422 throw exception::DimsInvalid(
"qpp::ptrace()");
1425 idx n = internal::get_num_subsys(static_cast<idx>(rA.rows()), d);
1426 std::vector<idx> dims(n, d);
1428 return ptrace(rA, target, dims);
1444 template <
typename Derived>
1445 dyn_mat<typename Derived::Scalar>
1446 ptranspose(
const Eigen::MatrixBase<Derived>& A,
const std::vector<idx>& target,
1447 const std::vector<idx>& dims) {
1448 const typename Eigen::MatrixBase<Derived>::EvalReturnType& rA = A.derived();
1453 if (!internal::check_nonzero_size(rA))
1454 throw exception::ZeroSize(
"qpp::ptranspose()");
1457 if (!internal::check_dims(dims))
1458 throw exception::DimsInvalid(
"qpp::ptranspose()");
1461 if (!internal::check_subsys_match_dims(target, dims))
1462 throw exception::SubsysMismatchDims(
"qpp::ptranspose()");
1465 if (internal::check_cvector(rA)) {
1466 if (!internal::check_dims_match_cvect(dims, rA))
1467 throw exception::DimsMismatchCvector(
"qpp::ptranspose()");
1468 }
else if (internal::check_square_mat(rA)) {
1469 if (!internal::check_dims_match_mat(dims, rA))
1470 throw exception::DimsMismatchMatrix(
"qpp::ptranspose()");
1472 throw exception::MatrixNotSquareNorCvector(
"qpp::ptranspose()");
1475 idx D =
static_cast<idx
>(rA.rows());
1476 idx n = dims.size();
1477 idx n_subsys = target.size();
1483 for (idx i = 0; i < n; ++i)
1485 for (idx i = 0; i < n_subsys; ++i)
1486 Csubsys[i] = target[i];
1488 dyn_mat<typename Derived::Scalar> result(D, D);
1491 if (internal::check_cvector(rA))
1493 if (target.size() == dims.size())
1494 return (rA * adjoint(rA)).transpose();
1497 return rA * adjoint(rA);
1499 auto worker = [&](idx i) noexcept->typename Derived::Scalar {
1501 idx midxcoltmp[maxn];
1504 for (idx k = 0; k < n; ++k)
1505 midxcoltmp[k] = Cmidxcol[k];
1508 internal::n2multiidx(i, n, Cdims, midxrow);
1510 for (idx k = 0; k < n_subsys; ++k)
1511 std::swap(midxcoltmp[Csubsys[k]], midxrow[Csubsys[k]]);
1514 return rA(internal::multiidx2n(midxrow, n, Cdims)) *
1515 std::conj(rA(internal::multiidx2n(midxcoltmp, n, Cdims)));
1518 for (idx j = 0; j < D; ++j) {
1520 internal::n2multiidx(j, n, Cdims, Cmidxcol);
1523 #pragma omp parallel for 1524 #endif // WITH_OPENMP_ 1525 for (idx i = 0; i < D; ++i)
1526 result(i, j) = worker(i);
1532 if (target.size() == dims.size())
1533 return rA.transpose();
1538 auto worker = [&](idx i) noexcept->typename Derived::Scalar {
1540 idx midxcoltmp[maxn];
1543 for (idx k = 0; k < n; ++k)
1544 midxcoltmp[k] = Cmidxcol[k];
1547 internal::n2multiidx(i, n, Cdims, midxrow);
1549 for (idx k = 0; k < n_subsys; ++k)
1550 std::swap(midxcoltmp[Csubsys[k]], midxrow[Csubsys[k]]);
1553 return rA(internal::multiidx2n(midxrow, n, Cdims),
1554 internal::multiidx2n(midxcoltmp, n, Cdims));
1557 for (idx j = 0; j < D; ++j) {
1559 internal::n2multiidx(j, n, Cdims, Cmidxcol);
1562 #pragma omp parallel for 1563 #endif // WITH_OPENMP_ 1564 for (idx i = 0; i < D; ++i)
1565 result(i, j) = worker(i);
1585 template <
typename Derived>
1586 dyn_mat<typename Derived::Scalar>
1587 ptranspose(
const Eigen::MatrixBase<Derived>& A,
const std::vector<idx>& target,
1589 const typename Eigen::MatrixBase<Derived>::EvalReturnType& rA = A.derived();
1594 if (!internal::check_nonzero_size(rA))
1595 throw exception::ZeroSize(
"qpp::ptranspose()");
1599 throw exception::DimsInvalid(
"qpp::ptranspose()");
1602 idx n = internal::get_num_subsys(static_cast<idx>(rA.rows()), d);
1603 std::vector<idx> dims(n, d);
1605 return ptranspose(rA, target, dims);
1620 template <
typename Derived>
1621 dyn_mat<typename Derived::Scalar>
1622 syspermute(
const Eigen::MatrixBase<Derived>& A,
const std::vector<idx>& perm,
1623 const std::vector<idx>& dims) {
1624 const typename Eigen::MatrixBase<Derived>::EvalReturnType& rA = A.derived();
1629 if (!internal::check_nonzero_size(rA))
1630 throw exception::ZeroSize(
"qpp::syspermute()");
1633 if (!internal::check_dims(dims))
1634 throw exception::DimsInvalid(
"qpp::syspermute()");
1637 if (!internal::check_perm(perm))
1638 throw exception::PermInvalid(
"qpp::syspermute()");
1641 if (perm.size() != dims.size())
1642 throw exception::PermMismatchDims(
"qpp::syspermute()");
1645 if (internal::check_cvector(rA)) {
1646 if (!internal::check_dims_match_cvect(dims, rA))
1647 throw exception::DimsMismatchCvector(
"qpp::syspermute()");
1648 }
else if (internal::check_square_mat(rA)) {
1649 if (!internal::check_dims_match_mat(dims, rA))
1650 throw exception::DimsMismatchMatrix(
"qpp::syspermute()");
1652 throw exception::MatrixNotSquareNorCvector(
"qpp::syspermute()");
1655 idx D =
static_cast<idx
>(rA.rows());
1656 idx n = dims.size();
1658 dyn_mat<typename Derived::Scalar> result;
1661 if (internal::check_cvector(rA))
1667 for (idx i = 0; i < n; ++i) {
1671 result.resize(D, 1);
1673 auto worker = [&Cdims, &Cperm, n ](idx i) noexcept->idx {
1681 internal::n2multiidx(i, n, Cdims, midx);
1683 for (idx k = 0; k < n; ++k) {
1684 permdims[k] = Cdims[Cperm[k]];
1685 midxtmp[k] = midx[Cperm[k]];
1688 return internal::multiidx2n(midxtmp, n, permdims);
1692 #pragma omp parallel for 1693 #endif // WITH_OPENMP_ 1694 for (idx i = 0; i < D; ++i)
1695 result(worker(i)) = rA(i);
1700 idx Cdims[2 * maxn];
1701 idx Cperm[2 * maxn];
1704 for (idx i = 0; i < n; ++i) {
1706 Cdims[i + n] = dims[i];
1708 Cperm[i + n] = perm[i] + n;
1710 result.resize(D * D, 1);
1712 dyn_mat<typename Derived::Scalar> vectA =
1713 Eigen::Map<dyn_mat<typename Derived::Scalar>>(
1714 const_cast<typename Derived::Scalar*
>(rA.data()), D * D, 1);
1716 auto worker = [&Cdims, &Cperm, n ](idx i) noexcept->idx {
1720 idx midxtmp[2 * maxn];
1721 idx permdims[2 * maxn];
1724 internal::n2multiidx(i, 2 * n, Cdims, midx);
1726 for (idx k = 0; k < 2 * n; ++k) {
1727 permdims[k] = Cdims[Cperm[k]];
1728 midxtmp[k] = midx[Cperm[k]];
1731 return internal::multiidx2n(midxtmp, 2 * n, permdims);
1735 #pragma omp parallel for 1736 #endif // WITH_OPENMP_ 1737 for (idx i = 0; i < D * D; ++i)
1738 result(worker(i)) = rA(i);
1740 result = reshape(result, D, D);
1758 template <
typename Derived>
1759 dyn_mat<typename Derived::Scalar>
1760 syspermute(
const Eigen::MatrixBase<Derived>& A,
const std::vector<idx>& perm,
1762 const typename Eigen::MatrixBase<Derived>::EvalReturnType& rA = A.derived();
1767 if (!internal::check_nonzero_size(rA))
1768 throw exception::ZeroSize(
"qpp::syspermute()");
1772 throw exception::DimsInvalid(
"qpp::syspermute()");
1775 idx n = internal::get_num_subsys(static_cast<idx>(rA.rows()), d);
1776 std::vector<idx> dims(n, d);
1778 return syspermute(rA, perm, dims);
1792 template <
typename Derived>
1793 dyn_mat<typename Derived::Scalar> applyQFT(
const Eigen::MatrixBase<Derived>& A,
1794 const std::vector<idx>& target,
1795 idx d = 2,
bool swap =
true) {
1796 const dyn_mat<typename Derived::Scalar>& rA = A.derived();
1801 if (!internal::check_nonzero_size(rA))
1802 throw exception::ZeroSize(
"qpp::applyQFT()");
1806 throw exception::DimsInvalid(
"qpp::applyQFT()");
1809 idx n = internal::get_num_subsys(static_cast<idx>(rA.rows()), d);
1811 std::vector<idx> dims(n, d);
1814 if (!internal::check_subsys_match_dims(target, dims))
1815 throw exception::SubsysMismatchDims(
"qpp::applyQFT()");
1818 if (internal::check_cvector(rA)) {
1819 if (!internal::check_dims_match_cvect(dims, rA))
1820 throw exception::DimsMismatchCvector(
"qpp::applyQFT()");
1821 }
else if (internal::check_square_mat(rA)) {
1822 if (!internal::check_dims_match_mat(dims, rA))
1823 throw exception::DimsMismatchMatrix(
"qpp::applyQFT()");
1825 throw exception::MatrixNotSquareNorCvector(
"qpp::applyQFT()");
1828 dyn_mat<typename Derived::Scalar> result = rA;
1830 idx n_subsys = target.size();
1834 for (idx i = 0; i < n_subsys; ++i) {
1836 result = apply(result, Gates::get_instance().H, {target[i]});
1838 for (idx j = 2; j <= n_subsys - i; ++j) {
1841 Rj << 1, 0, 0, exp(2.0 * pi * 1_i / std::pow(2, j));
1843 applyCTRL(result, Rj, {target[i + j - 1]}, {target[i]});
1848 for (idx i = 0; i < n_subsys / 2; ++i) {
1849 result = apply(result, Gates::get_instance().SWAP,
1850 {target[i], target[n_subsys - i - 1]});
1855 for (idx i = 0; i < n_subsys; ++i) {
1857 result = apply(result, Gates::get_instance().Fd(d), {target[i]}, d);
1859 for (idx j = 2; j <= n_subsys - i; ++j) {
1861 cmat Rj = cmat::Zero(d, d);
1862 for (idx m = 0; m < d; ++m) {
1863 Rj(m, m) = exp(2.0 * pi * m * 1_i / std::pow(d, j));
1866 applyCTRL(result, Rj, {target[i + j - 1]}, {target[i]}, d);
1871 for (idx i = 0; i < n_subsys / 2; ++i) {
1872 result = apply(result, Gates::get_instance().SWAPd(d),
1873 {target[i], target[n_subsys - i - 1]}, d);
1893 template <
typename Derived>
1894 dyn_mat<typename Derived::Scalar> applyTFQ(
const Eigen::MatrixBase<Derived>& A,
1895 const std::vector<idx>& target,
1896 idx d = 2,
bool swap =
true) {
1897 const dyn_mat<typename Derived::Scalar>& rA = A.derived();
1902 if (!internal::check_nonzero_size(rA))
1903 throw exception::ZeroSize(
"qpp::applyTFQ()");
1907 throw exception::DimsInvalid(
"qpp::applyTFQ()");
1910 idx n = internal::get_num_subsys(static_cast<idx>(rA.rows()), d);
1912 std::vector<idx> dims(n, d);
1915 if (!internal::check_subsys_match_dims(target, dims))
1916 throw exception::SubsysMismatchDims(
"qpp::applyTFQ()");
1919 if (internal::check_cvector(rA)) {
1920 if (!internal::check_dims_match_cvect(dims, rA))
1921 throw exception::DimsMismatchCvector(
"qpp::applyTFQ()");
1922 }
else if (internal::check_square_mat(rA)) {
1923 if (!internal::check_dims_match_mat(dims, rA))
1924 throw exception::DimsMismatchMatrix(
"qpp::applyTFQ()");
1926 throw exception::MatrixNotSquareNorCvector(
"qpp::applyTFQ()");
1929 dyn_mat<typename Derived::Scalar> result = rA;
1931 idx n_subsys = target.size();
1937 for (idx i = n_subsys / 2; i-- > 0;) {
1938 result = apply(result, Gates::get_instance().SWAP,
1939 {target[i], target[n_subsys - i - 1]});
1942 for (idx i = n_subsys; i-- > 0;) {
1944 for (idx j = n_subsys - i + 1; j-- > 2;) {
1947 Rj << 1, 0, 0, exp(-2.0 * pi * 1_i / std::pow(2, j));
1949 applyCTRL(result, Rj, {target[i + j - 1]}, {target[i]});
1952 result = apply(result, Gates::get_instance().H, {target[i]});
1957 for (idx i = n_subsys / 2; i-- > 0;) {
1958 result = apply(result, Gates::get_instance().SWAPd(d),
1959 {target[i], target[n_subsys - i - 1]}, d);
1962 for (idx i = n_subsys; i-- > 0;) {
1964 for (idx j = n_subsys - i + 1; j-- > 2;) {
1966 cmat Rj = cmat::Zero(d, d);
1967 for (idx m = 0; m < d; ++m) {
1968 Rj(m, m) = exp(-2.0 * pi * m * 1_i / std::pow(d, j));
1971 applyCTRL(result, Rj, {target[i + j - 1]}, {target[i]}, d);
1974 result = apply(result, adjoint(Gates::get_instance().Fd(d)),
1991 template <
typename Derived>
1992 dyn_col_vect<typename Derived::Scalar> QFT(
const Eigen::MatrixBase<Derived>& A,
1993 idx d = 2,
bool swap =
true) {
1994 const dyn_mat<typename Derived::Scalar>& rA = A.derived();
1999 if (!internal::check_nonzero_size(rA))
2000 throw exception::ZeroSize(
"qpp::QFT()");
2004 throw exception::DimsInvalid(
"qpp::QFT()");
2007 idx n = internal::get_num_subsys(static_cast<idx>(rA.rows()), d);
2009 std::vector<idx> dims(n, d);
2012 if (internal::check_cvector(rA)) {
2013 if (!internal::check_dims_match_cvect(dims, rA))
2014 throw exception::DimsMismatchCvector(
"qpp::QFT()");
2015 }
else if (internal::check_square_mat(rA)) {
2016 if (!internal::check_dims_match_mat(dims, rA))
2017 throw exception::DimsMismatchMatrix(
"qpp::QFT()");
2019 throw exception::MatrixNotSquareNorCvector(
"qpp::QFT()");
2022 std::vector<idx> subsys(n);
2023 std::iota(std::begin(subsys), std::end(subsys), 0);
2024 ket result = applyQFT(rA, subsys, d, swap);
2038 template <
typename Derived>
2039 dyn_col_vect<typename Derived::Scalar> TFQ(
const Eigen::MatrixBase<Derived>& A,
2040 idx d = 2,
bool swap =
true) {
2041 const dyn_mat<typename Derived::Scalar>& rA = A.derived();
2046 if (!internal::check_nonzero_size(rA))
2047 throw exception::ZeroSize(
"qpp::TFQ()");
2051 throw exception::DimsInvalid(
"qpp::TFQ()");
2054 idx n = internal::get_num_subsys(static_cast<idx>(rA.rows()), d);
2056 std::vector<idx> dims(n, d);
2059 if (internal::check_cvector(rA)) {
2060 if (!internal::check_dims_match_cvect(dims, rA))
2061 throw exception::DimsMismatchCvector(
"qpp::QFT()");
2062 }
else if (internal::check_square_mat(rA)) {
2063 if (!internal::check_dims_match_mat(dims, rA))
2064 throw exception::DimsMismatchMatrix(
"qpp::QFT()");
2066 throw exception::MatrixNotSquareNorCvector(
"qpp::QFT()");
2069 std::vector<idx> subsys(n);
2070 std::iota(std::begin(subsys), std::end(subsys), 0);
2071 ket result = applyTFQ(rA, subsys, d, swap);
Quantum++ main namespace.
Definition: circuits.h:35