Quantum++  v0.6
C++11 quantum computing library
entanglement.h
Go to the documentation of this file.
1 /*
2  * Quantum++
3  *
4  * Copyright (c) 2013 - 2015 Vlad Gheorghiu (vgheorgh@gmail.com)
5  *
6  * This file is part of Quantum++.
7  *
8  * Quantum++ is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * Quantum++ is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Quantum++. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
27 #ifndef ENTANGLEMENT_H_
28 #define ENTANGLEMENT_H_
29 
30 // entanglement
31 
32 namespace qpp
33 {
34 
45 template<typename Derived>
46 dyn_col_vect<double> schmidtcoeffs(const Eigen::MatrixBase<Derived>& A,
47  const std::vector<idx>& dims)
48 {
50  // check zero-size
52  throw Exception("qpp::schmidtcoeffs()", Exception::Type::ZERO_SIZE);
53  // check bi-partite
54  if (dims.size() != 2)
55  throw Exception("qpp::schmidtcoeffs()", Exception::Type::NOT_BIPARTITE);
56  // check column vector
57  if (!internal::_check_cvector(rA))
58  throw Exception("qpp::schmidtcoeffs()",
60  // check matching dimensions
61  if (!internal::_check_dims_match_mat(dims, rA))
62  throw Exception("qpp::schmidtcoeffs()",
64 
65  return svals(transpose(reshape(rA, dims[1], dims[0])));
66 }
67 
76 template<typename Derived>
77 cmat schmidtA(const Eigen::MatrixBase<Derived>& A,
78  const std::vector<idx>& dims)
79 {
81  // check zero-size
83  throw Exception("qpp::schmidtU()", Exception::Type::ZERO_SIZE);
84  // check bi-partite
85  if (dims.size() != 2)
86  throw Exception("qpp::schmidtU()", Exception::Type::NOT_BIPARTITE);
87  // check column vector
88  if (!internal::_check_cvector(rA))
89  throw Exception("qpp::schmidtU()",
91  // check matching dimensions
92  if (!internal::_check_dims_match_mat(dims, rA))
93  throw Exception("qpp::schmidtU()",
95 
96  return svdU(transpose(reshape(rA, dims[1], dims[0])));
97 }
98 
107 template<typename Derived>
108 cmat schmidtB(const Eigen::MatrixBase<Derived>& A,
109  const std::vector<idx>& dims)
110 {
111  const dyn_mat<typename Derived::Scalar>& rA = A;
112  // check zero-size
114  throw Exception("qpp::schmidtV()", Exception::Type::ZERO_SIZE);
115  // check bi-partite
116  if (dims.size() != 2)
117  throw Exception("qpp::schmidtV()", Exception::Type::NOT_BIPARTITE);
118  // check column vector
119  if (!internal::_check_cvector(rA))
120  throw Exception("qpp::schmidtV()",
122  // check matching dimensions
123  if (!internal::_check_dims_match_mat(dims, rA))
124  throw Exception("qpp::schmidtV()",
126 
127  // by default returns V^*, we need V, i.e. the complex conjugate,
128  // i.e. adjoint(transpose(V))
129  return svdV(transpose(reshape(conjugate(rA), dims[1], dims[0])));
130 }
131 
143 template<typename Derived>
144 std::vector<double> schmidtprobs(const Eigen::MatrixBase<Derived>& A,
145  const std::vector<idx>& dims)
146 {
147  const dyn_mat<typename Derived::Scalar>& rA = A;
148  // check zero-size
150  throw Exception("qpp::schmidtprobs()", Exception::Type::ZERO_SIZE);
151  // check bi-partite
152  if (dims.size() != 2)
153  throw Exception("qpp::schmidtprobs()", Exception::Type::NOT_BIPARTITE);
154  // check column vector
155  if (!internal::_check_cvector(rA))
156  throw Exception("qpp::schmidtprobs()",
158  // check matching dimensions
159  if (!internal::_check_dims_match_mat(dims, rA))
160  throw Exception("qpp::schmidtprobs()",
162 
163  std::vector<double> result;
164  dyn_col_vect<double> scf = schmidtcoeffs(rA, dims);
165  for (idx i = 0; i < static_cast<idx>(scf.rows()); ++i)
166  result.push_back(std::pow(scf(i), 2));
167 
168  return result;
169 }
170 
182 template<typename Derived>
183 double entanglement(const Eigen::MatrixBase<Derived>& A,
184  const std::vector<idx>& dims)
185 {
186  const dyn_mat<typename Derived::Scalar>& rA = A;
187  // check zero-size
189  throw Exception("qpp::entanglement()", Exception::Type::ZERO_SIZE);
190  // check bi-partite
191  if (dims.size() != 2)
192  throw Exception("qpp::entanglement()", Exception::Type::NOT_BIPARTITE);
193  // check column vector
194  if (!internal::_check_cvector(rA))
195  throw Exception("qpp::entanglement()",
197  // check matching dimensions
198  if (!internal::_check_dims_match_mat(dims, rA))
199  throw Exception("qpp::entanglement()",
201 
202  return entropy(schmidtprobs(rA, dims));
203 }
204 
216 template<typename Derived>
217 // the G-concurrence
218 double gconcurrence(const Eigen::MatrixBase<Derived>& A)
219 {
220  const dyn_mat<typename Derived::Scalar>& rA = A;
221 
222  // check zero-size
224  throw Exception("qpp::gconcurrence()", Exception::Type::ZERO_SIZE);
225  // check column vector
226  if (!internal::_check_cvector(rA))
227  throw Exception("qpp::gconcurrence()",
229 
230  // check equal local dimensions
231  idx D = static_cast<idx>(std::llround(
232  std::sqrt(static_cast<double>(rA.rows()))));
233  if (D * D != static_cast<idx>(rA.rows()))
234  throw Exception("qpp::gconcurrence()",
236 
237  // we compute exp(logdet()) to avoid underflow
238  return D * std::abs(std::exp(2. / D * logdet(reshape(rA, D, D))));
239 }
240 
248 template<typename Derived>
249 double negativity(const Eigen::MatrixBase<Derived>& A,
250  const std::vector<idx>& dims)
251 {
252  const dyn_mat<typename Derived::Scalar>& rA = A;
253  // check zero-size
255  throw Exception("qpp::negativity()", Exception::Type::ZERO_SIZE);
256  // check bi-partite
257  if (dims.size() != 2)
258  throw Exception("qpp::negativity()", Exception::Type::NOT_BIPARTITE);
259  // check square matrix vector
261  throw Exception("qpp::negativity()",
263  // check matching dimensions
264  if (!internal::_check_dims_match_mat(dims, rA))
265  throw Exception("qpp::negativity()",
267 
268  return (schatten(ptranspose(rA, {0}, dims), 1) - 1.) / 2.;
269 }
270 
278 template<typename Derived>
279 double lognegativity(const Eigen::MatrixBase<Derived>& A,
280  const std::vector<idx>& dims)
281 {
282  const dyn_mat<typename Derived::Scalar>& rA = A;
283  // check zero-size
285  throw Exception("qpp::lognegativity()", Exception::Type::ZERO_SIZE);
286  // check bi-partite
287  if (dims.size() != 2)
288  throw Exception("qpp::lognegativity()",
290  // check square matrix vector
292  throw Exception("qpp::lognegativity()",
294  // check matching dimensions
295  if (!internal::_check_dims_match_mat(dims, rA))
296  throw Exception("qpp::lognegativity()",
298 
299  return std::log2(2 * negativity(rA, dims) + 1);
300 }
301 
308 template<typename Derived>
309 double concurrence(const Eigen::MatrixBase<Derived>& A)
310 {
311  const dyn_mat<typename Derived::Scalar>& rA = A;
312  // check zero-size
314  throw Exception("qpp::concurrence()", Exception::Type::ZERO_SIZE);
315  // check square matrix vector
317  throw Exception("qpp::concurrence()",
319  // check that the state is a 2-qubit state
320  if (rA.rows() != 4)
321  throw Exception("qpp::concurrence()",
323 
324  cmat sigmaY = Gates::get_instance().Y;
325  dyn_col_vect<double> lambdas =
326  evals(
327  rA * kron(sigmaY, sigmaY) * conjugate(rA)
328  * kron(sigmaY, sigmaY)).real();
329 
330  std::vector<double> lambdas_sorted(lambdas.data(),
331  lambdas.data() + lambdas.size());
332 
333  std::sort(std::begin(lambdas_sorted), std::end(lambdas_sorted),
334  std::greater<double>());
335  std::transform(std::begin(lambdas_sorted), std::end(lambdas_sorted),
336  std::begin(lambdas_sorted), [](double elem)
337  {
338  return std::sqrt(std::abs(elem));
339  }); // chop tiny negatives
340 
341  return std::max(0.,
342  lambdas_sorted[0] - lambdas_sorted[1] - lambdas_sorted[2]
343  - lambdas_sorted[3]);
344 }
345 
346 } /* namespace qpp */
347 
348 #endif /* ENTANGLEMENT_H_ */
bool _check_cvector(const Eigen::MatrixBase< Derived > &A)
Definition: util.h:110
Derived::Scalar logdet(const Eigen::MatrixBase< Derived > &A)
Logarithm of the determinant.
Definition: functions.h:161
std::vector< double > schmidtprobs(const Eigen::MatrixBase< Derived > &A, const std::vector< idx > &dims)
Schmidt probabilities of the bi-partite pure state A.
Definition: entanglement.h:144
bool _check_dims_match_mat(const std::vector< idx > &dims, const Eigen::MatrixBase< Derived > &A)
Definition: util.h:141
double gconcurrence(const Eigen::MatrixBase< Derived > &A)
G-concurrence of the bi-partite pure state A.
Definition: entanglement.h:218
double lognegativity(const Eigen::MatrixBase< Derived > &A, const std::vector< idx > &dims)
Logarithmic negativity of the bi-partite mixed state A.
Definition: entanglement.h:279
Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic > dyn_mat
Dynamic Eigen matrix over the field specified by Scalar.
Definition: types.h:73
Quantum++ main namespace.
Definition: codes.h:30
bool _check_square_mat(const Eigen::MatrixBase< Derived > &A)
Definition: util.h:83
double schatten(const Eigen::MatrixBase< Derived > &A, double p)
Schatten matrix norm.
Definition: functions.h:738
cmat svdU(const Eigen::MatrixBase< Derived > &A)
Left singular vectors.
Definition: functions.h:447
cmat schmidtA(const Eigen::MatrixBase< Derived > &A, const std::vector< idx > &dims)
Schmidt basis on Alice side.
Definition: entanglement.h:77
dyn_col_vect< double > svals(const Eigen::MatrixBase< Derived > &A)
Singular values.
Definition: functions.h:426
dyn_mat< typename T::Scalar > kron(const T &head)
Kronecker product.
Definition: functions.h:798
double entropy(const Eigen::MatrixBase< Derived > &A)
von-Neumann entropy of the density matrix A
Definition: entropies.h:43
Generates custom exceptions, used when validating function parameters.
Definition: exception.h:39
dyn_mat< typename Derived::Scalar > transpose(const Eigen::MatrixBase< Derived > &A)
Transpose.
Definition: functions.h:44
dyn_col_vect< cplx > evals(const Eigen::MatrixBase< Derived > &A)
Eigenvalues.
Definition: functions.h:277
dyn_mat< typename Derived::Scalar > conjugate(const Eigen::MatrixBase< Derived > &A)
Complex conjugate.
Definition: functions.h:64
bool _check_nonzero_size(const T &x) noexcept
Definition: util.h:119
cmat schmidtB(const Eigen::MatrixBase< Derived > &A, const std::vector< idx > &dims)
Schmidt basis on Bob side.
Definition: entanglement.h:108
cmat svdV(const Eigen::MatrixBase< Derived > &A)
Right singular vectors.
Definition: functions.h:469
double entanglement(const Eigen::MatrixBase< Derived > &A, const std::vector< idx > &dims)
Entanglement of the bi-partite pure state A.
Definition: entanglement.h:183
Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > dyn_col_vect
Dynamic Eigen column vector over the field specified by Scalar.
Definition: types.h:85
static const Gates & get_instance() noexcept(std::is_nothrow_constructible< const Gates >::value)
Definition: singleton.h:90
dyn_mat< typename Derived::Scalar > ptranspose(const Eigen::MatrixBase< Derived > &A, const std::vector< idx > &subsys, const std::vector< idx > &dims)
Partial transpose.
Definition: operations.h:1328
Eigen::MatrixXcd cmat
Complex (double precision) dynamic Eigen matrix.
Definition: types.h:56
std::size_t idx
Non-negative integer index.
Definition: types.h:36
double concurrence(const Eigen::MatrixBase< Derived > &A)
Wootters concurrence of the bi-partite qubit mixed state A.
Definition: entanglement.h:309
cmat Y
Pauli Sigma-Y gate.
Definition: gates.h:46
dyn_col_vect< double > schmidtcoeffs(const Eigen::MatrixBase< Derived > &A, const std::vector< idx > &dims)
Schmidt coefficients of the bi-partite pure state A.
Definition: entanglement.h:46
dyn_mat< typename Derived::Scalar > reshape(const Eigen::MatrixBase< Derived > &A, idx rows, idx cols)
Reshape.
Definition: functions.h:1026
double negativity(const Eigen::MatrixBase< Derived > &A, const std::vector< idx > &dims)
Negativity of the bi-partite mixed state A.
Definition: entanglement.h:249