예제 #1
0
inline TR sysperm(const T1& rho1, const arma::uvec& sys,
                   const arma::uvec& dim) {
  const auto& p = as_Mat(rho1);
  const arma::uword n = dim.n_elem;

  bool checkV = true;
  if (p.n_cols == 1)
    checkV = false;

#ifndef QICLIB_NO_DEBUG
  if (p.n_elem == 0)
    throw Exception("qic::sysperm", Exception::type::ZERO_SIZE);

  if (checkV)
    if (p.n_rows != p.n_cols)
      throw Exception("qic::sysperm",
                      Exception::type::MATRIX_NOT_SQUARE_OR_CVECTOR);

  if (dim.n_elem == 0 || arma::any(dim == 0))
    throw Exception("qic::sysperm", Exception::type::INVALID_DIMS);

  if (arma::prod(dim) != p.n_rows)
    throw Exception("qic::sysperm", Exception::type::DIMS_MISMATCH_MATRIX);

  if (n != sys.n_elem || arma::any(sys == 0) || arma::any(sys > n) ||
      sys.n_elem != arma::unique(sys).eval().n_elem)
    throw Exception("qic::sysperm", Exception::type::PERM_INVALID);
#endif

  arma::uword product[_internal::MAXQDIT];
  product[n-1] = 1;
  for (arma::sword i = n - 2; i >= 0; --i)
    product[i] = product[i + 1] * dim.at(i + 1);

  arma::uword productr[_internal::MAXQDIT];
  productr[n-1] = 1;
  for (arma::sword i = n - 2; i >= 0; --i)
    productr[i] = productr[i + 1] * dim.at(sys.at(i + 1) - 1);

  if (checkV) {
    arma::Mat<trait::eT<T1> > p_r(p.n_rows, p.n_cols, arma::fill::zeros);

    const arma::uword loop_no = 2 * n;
    constexpr auto loop_no_buffer = 2 * _internal::MAXQDIT + 1;
    arma::uword loop_counter[loop_no_buffer] = {0};
    arma::uword MAX[loop_no_buffer];

    for (arma::uword i = 0; i < n; ++i) {
      MAX[i] = dim.at(i);
      MAX[i + n] = dim.at(i);
    }
    MAX[loop_no] = 2;

    arma::uword p1 = 0;

    while (loop_counter[loop_no] == 0) {
      arma::uword I(0), J(0), K(0), L(0);
      for (arma::uword i = 0; i < n; ++i) {
        I += product[i] * loop_counter[i];
        J += product[i] * loop_counter[i + n];
        K += productr[i] * loop_counter[sys.at(i) - 1];
        L += productr[i] * loop_counter[sys.at(i) + n - 1];
      }

      p_r.at(K, L) = p.at(I, J);

      ++loop_counter[0];
      while (loop_counter[p1] == MAX[p1]) {
        loop_counter[p1] = 0;
        loop_counter[++p1]++;
        if (loop_counter[p1] != MAX[p1])
          p1 = 0;
      }
    }
    return p_r;

  } else {
    arma::Col<trait::eT<T1> > p_r(p.n_rows, arma::fill::zeros);

    const arma::uword loop_no = n;
    constexpr auto loop_no_buffer = _internal::MAXQDIT + 1;
    arma::uword loop_counter[loop_no_buffer] = {0};
    arma::uword MAX[loop_no_buffer];

    for (arma::uword i = 0; i < n; ++i) MAX[i] = dim.at(i);
    MAX[loop_no] = 2;

    for (arma::uword i = 0; i < loop_no + 1; ++i) loop_counter[i] = 0;

    arma::uword p1 = 0;

    while (loop_counter[loop_no] == 0) {
      arma::uword I(0), K(0);
      for (arma::uword i = 0; i < n; ++i) {
        I += product[i] * loop_counter[i];
        K += productr[i] * loop_counter[sys.at(i) - 1];
      }

      p_r.at(K) = p.at(I);

      ++loop_counter[0];
      while (loop_counter[p1] == MAX[p1]) {
        loop_counter[p1] = 0;
        loop_counter[++p1]++;
        if (loop_counter[p1] != MAX[p1])
          p1 = 0;
      }
    }

    return p_r;
  }
}
예제 #2
0
inline TR TrX(const T1& rho1, arma::uvec sys, arma::uvec dim) {
  const auto& p = as_Mat(rho1);

  bool checkV = true;
  if (p.n_cols == 1)
    checkV = false;

#ifndef QICLIB_NO_DEBUG
  if (p.n_elem == 0)
    throw Exception("qic::TrX", Exception::type::ZERO_SIZE);

  if (checkV)
    if (p.n_rows != p.n_cols)
      throw Exception("qic::TrX",
                      Exception::type::MATRIX_NOT_SQUARE_OR_CVECTOR);

  if (dim.n_elem == 0 || arma::any(dim == 0))
    throw Exception("qic::TrX", Exception::type::INVALID_DIMS);

  if (arma::prod(dim) != p.n_rows)
    throw Exception("qic::TrX", Exception::type::DIMS_MISMATCH_MATRIX);

  if (dim.n_elem < sys.n_elem || arma::any(sys == 0) ||
      arma::any(sys > dim.n_elem) ||
      sys.n_elem != arma::find_unique(sys, false).eval().n_elem)
    throw Exception("qic::TrX", Exception::type::INVALID_SUBSYS);
#endif

  if (sys.n_elem == dim.n_elem)
    return {arma::trace(p)};
  
  _internal::dim_collapse_sys(dim, sys);
  const arma::uword n = dim.n_elem;
  const arma::uword m = sys.n_elem;

  arma::uvec keep(n - m);
  arma::uword keep_count(0);
  for (arma::uword run = 0; run < n; ++run) {
    if (!arma::any(sys == run + 1)) {
      keep.at(keep_count) = run + 1;
      ++keep_count;
    }
  }

  arma::uword dimtrace = arma::prod(dim(sys - 1));
  arma::uword dimkeep = p.n_rows / dimtrace;

  arma::uvec product(n, arma::fill::ones);
  for (arma::sword i = n - 2; i > -1; --i)
    product.at(i) = product.at(i + 1) * dim.at(i + 1);

  arma::uvec productr(n - m, arma::fill::ones);
  for (arma::sword i = n - m - 2; i > -1; --i)
    productr.at(i) = productr.at(i + 1) * dim.at(keep.at(i + 1) - 1);

  arma::Mat<trait::eT<T1> > tr_p(dimkeep, dimkeep, arma::fill::zeros);

  const arma::uword loop_no = 2 * n;
  arma::uword* loop_counter = new arma::uword[loop_no + 1];
  arma::uword* MAX = new arma::uword[loop_no + 1];

  for (arma::uword i = 0; i < n; ++i) {
    MAX[i] = dim.at(i);
    if (arma::any(sys == (i + 1)))
      MAX[i + n] = 1;
    else
      MAX[i + n] = dim.at(i);
  }
  MAX[loop_no] = 2;

  for (arma::uword i = 0; i < loop_no + 1; ++i) loop_counter[i] = 0;

  arma::uword p1 = 0;

  while (loop_counter[loop_no] == 0) {
    arma::uword I(0), J(0), K(0), L(0), n_to_k(0);

    for (arma::uword i = 0; i < n; ++i) {
      if (arma::any(sys == i + 1)) {
        I += product.at(i) * loop_counter[i];
        J += product.at(i) * loop_counter[i];

      } else {
        I += product.at(i) * loop_counter[i];
        J += product.at(i) * loop_counter[i + n];
      }

      if (arma::any(keep == i + 1)) {
        K += productr.at(n_to_k) * loop_counter[i];
        L += productr.at(n_to_k) * loop_counter[i + n];
        ++n_to_k;
      }
    }

    tr_p.at(K, L) += checkV ? p.at(I, J) : p.at(I) * std::conj(p.at(J));

    ++loop_counter[0];
    while (loop_counter[p1] == MAX[p1]) {
      loop_counter[p1] = 0;
      loop_counter[++p1]++;
      if (loop_counter[p1] != MAX[p1])
        p1 = 0;
    }
  }
  delete[] loop_counter;
  delete[] MAX;
  return tr_p;
}
예제 #3
0
TR discord3_reg(const T1& rho1, arma::uword nodal, arma::uvec dim) {
  const auto& rho = as_Mat(rho1);
  arma::uword party_no = dim.n_elem;
  arma::uword dim1 = arma::prod(dim);

#ifndef QICLIB_NO_DEBUG
  if (rho.n_elem == 0)
    throw Exception("qic::discord3_reg", Exception::type::ZERO_SIZE);

  if (rho.n_rows != rho.n_cols)
    throw Exception("qic::discord3_reg", Exception::type::MATRIX_NOT_SQUARE);

  if (any(dim == 0))
    throw Exception("qic::discord3_reg", Exception::type::INVALID_DIMS);

  if (dim1 != rho.n_rows)
    throw Exception("qic::discord3_reg", Exception::type::DIMS_MISMATCH_MATRIX);

  if (nodal <= 0 || nodal > party_no)
    throw Exception("qic::discord3_reg", "Invalid measured party index");

  if (dim(nodal - 1) != 3)
    throw Exception("qic::discord3_reg", "Measured party is not qutrit");
#endif

  arma::uvec party = arma::zeros<arma::uvec>(party_no);
  for (arma::uword i = 0; i < party_no; ++i) party.at(i) = i + 1;

  arma::uvec rest = party;
  rest.shed_row(nodal - 1);

  auto rho_A = TrX(rho, rest, dim);
  auto rho_B = TrX(rho, {nodal}, dim);

  auto S_A = entropy(rho_A);
  auto S_B = entropy(rho_B);
  auto S_A_B = entropy(rho);
  auto I1 = S_A + S_B - S_A_B;

  dim1 /= 3;
  arma::uword dim2(1);
  for (arma::uword i = 0; i < nodal - 1; ++i) dim2 *= dim.at(i);
  arma::uword dim3(1);
  for (arma::uword i = nodal; i < party_no; ++i) dim3 *= dim.at(i);

  arma::Mat<trait::pT<T1> > eye2 =
    arma::eye<arma::Mat<trait::pT<T1> > >(dim1, dim1);
  arma::Mat<trait::pT<T1> > eye3 =
    arma::eye<arma::Mat<trait::pT<T1> > >(dim2, dim2);
  arma::Mat<trait::pT<T1> > eye4 =
    arma::eye<arma::Mat<trait::pT<T1> > >(dim3, dim3);

  typename arma::Col<trait::pT<T1> >::template fixed<3> disc;

  for (arma::uword i = 0; i < 3; ++i) {
    arma::Mat<std::complex<trait::pT<T1> > > proj1 =
      SPM<trait::pT<T1> >::get_instance().proj3.at(0, i + 1);

    arma::Mat<std::complex<trait::pT<T1> > > proj2 =
      SPM<trait::pT<T1> >::get_instance().proj3.at(1, i + 1);

    arma::Mat<std::complex<trait::pT<T1> > > proj3 =
      SPM<trait::pT<T1> >::get_instance().proj3.at(2, i + 1);

    if (nodal == 1) {
      proj1 = kron(proj1, eye2);
      proj2 = kron(proj2, eye2);
      proj3 = kron(proj3, eye2);
    } else if (party_no == nodal) {
      proj1 = kron(eye2, proj1);
      proj2 = kron(eye2, proj2);
      proj3 = kron(eye2, proj3);
    } else {
      proj1 = kron(kron(eye3, proj1), eye4);
      proj2 = kron(kron(eye3, proj2), eye4);
      proj3 = kron(kron(eye3, proj3), eye4);
    }

    arma::Mat<std::complex<trait::pT<T1> > > rho_1 = (proj1 * rho * proj1);
    arma::Mat<std::complex<trait::pT<T1> > > rho_2 = (proj2 * rho * proj2);
    arma::Mat<std::complex<trait::pT<T1> > > rho_3 = (proj3 * rho * proj3);

    trait::pT<T1> p1 = std::real(arma::trace(rho_1));
    trait::pT<T1> p2 = std::real(arma::trace(rho_2));
    trait::pT<T1> p3 = std::real(arma::trace(rho_3));

    trait::pT<T1> S_max = 0.0;
    if (p1 > _precision::eps<trait::pT<T1> >::value) {
      rho_1 /= p1;
      S_max += p1 * entropy(rho_1);
    }
    if (p2 > _precision::eps<trait::pT<T1> >::value) {
      rho_2 /= p2;
      S_max += p2 * entropy(rho_2);
    }
    if (p3 > _precision::eps<trait::pT<T1> >::value) {
      rho_3 /= p3;
      S_max += p3 * entropy(rho_3);
    }
    disc.at(i) = I1 - (S_B - S_max);
  }

  return disc;
}