Quantum++  v0.8.8
C++11 quantum computing library
entanglement.h
Go to the documentation of this file.
1 /*
2  * Quantum++
3  *
4  * Copyright (c) 2013 - 2016 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 {
49  const dyn_mat<typename Derived::Scalar>& rA = A.derived();
50 
51  // EXCEPTION CHECKS
52 
53  // check zero-size
55  throw Exception("qpp::schmidtcoeffs()", Exception::Type::ZERO_SIZE);
56  // check bi-partite
57  if ( dims.size() != 2 )
58  throw Exception("qpp::schmidtcoeffs()", Exception::Type::NOT_BIPARTITE);
59  // check column vector
60  if ( !internal::_check_cvector(rA))
61  throw Exception("qpp::schmidtcoeffs()",
63  // check matching dimensions
64  if ( !internal::_check_dims_match_mat(dims, rA))
65  throw Exception("qpp::schmidtcoeffs()",
67  // END EXCEPTION CHECKS
68 
69  return svals(transpose(reshape(rA, dims[1], dims[0])));
70 }
71 
80 template<typename Derived>
81 cmat schmidtA(const Eigen::MatrixBase<Derived>& A,
82  const std::vector<idx>& dims)
83 {
84  const dyn_mat<typename Derived::Scalar>& rA = A.derived();
85 
86  // EXCEPTION CHECKS
87 
88  // check zero-size
90  throw Exception("qpp::schmidtU()", Exception::Type::ZERO_SIZE);
91  // check bi-partite
92  if ( dims.size() != 2 )
93  throw Exception("qpp::schmidtU()", Exception::Type::NOT_BIPARTITE);
94  // check column vector
95  if ( !internal::_check_cvector(rA))
96  throw Exception("qpp::schmidtU()",
98  // check matching dimensions
99  if ( !internal::_check_dims_match_mat(dims, rA))
100  throw Exception("qpp::schmidtU()",
102  // END EXCEPTION CHECKS
103 
104  return svdU(transpose(reshape(rA, dims[1], dims[0])));
105 }
106 
115 template<typename Derived>
116 cmat schmidtB(const Eigen::MatrixBase<Derived>& A,
117  const std::vector<idx>& dims)
118 {
119  const dyn_mat<typename Derived::Scalar>& rA = A.derived();
120 
121  // EXCEPTION CHECKS
122 
123  // check zero-size
125  throw Exception("qpp::schmidtV()", Exception::Type::ZERO_SIZE);
126  // check bi-partite
127  if ( dims.size() != 2 )
128  throw Exception("qpp::schmidtV()", Exception::Type::NOT_BIPARTITE);
129  // check column vector
130  if ( !internal::_check_cvector(rA))
131  throw Exception("qpp::schmidtV()",
133  // check matching dimensions
134  if ( !internal::_check_dims_match_mat(dims, rA))
135  throw Exception("qpp::schmidtV()",
137  // END EXCEPTION CHECKS
138 
139  // by default returns V^*, we need V, i.e. the complex conjugate,
140  // i.e. adjoint(transpose(V))
141  return svdV(transpose(reshape(conjugate(rA), dims[1], dims[0])));
142 }
143 
155 template<typename Derived>
156 std::vector<double> schmidtprobs(const Eigen::MatrixBase<Derived>& A,
157  const std::vector<idx>& dims)
158 {
159  const dyn_mat<typename Derived::Scalar>& rA = A.derived();
160 
161  // EXCEPTION CHECKS
162 
163  // check zero-size
165  throw Exception("qpp::schmidtprobs()", Exception::Type::ZERO_SIZE);
166  // check bi-partite
167  if ( dims.size() != 2 )
168  throw Exception("qpp::schmidtprobs()", Exception::Type::NOT_BIPARTITE);
169  // check column vector
170  if ( !internal::_check_cvector(rA))
171  throw Exception("qpp::schmidtprobs()",
173  // check matching dimensions
174  if ( !internal::_check_dims_match_mat(dims, rA))
175  throw Exception("qpp::schmidtprobs()",
177  // END EXCEPTION CHECKS
178 
179  std::vector<double> result;
180  dyn_col_vect<double> scf = schmidtcoeffs(rA, dims);
181  for ( idx i = 0; i < static_cast<idx>(scf.rows()); ++i )
182  result.push_back(std::pow(scf(i), 2));
183 
184  return result;
185 }
186 
198 template<typename Derived>
199 double entanglement(const Eigen::MatrixBase<Derived>& A,
200  const std::vector<idx>& dims)
201 {
202  const dyn_mat<typename Derived::Scalar>& rA = A.derived();
203 
204  // EXCEPTION CHECKS
205 
206  // check zero-size
208  throw Exception("qpp::entanglement()", Exception::Type::ZERO_SIZE);
209  // check bi-partite
210  if ( dims.size() != 2 )
211  throw Exception("qpp::entanglement()", Exception::Type::NOT_BIPARTITE);
212  // check column vector
213  if ( !internal::_check_cvector(rA))
214  throw Exception("qpp::entanglement()",
216  // check matching dimensions
217  if ( !internal::_check_dims_match_mat(dims, rA))
218  throw Exception("qpp::entanglement()",
220  // END EXCEPTION CHECKS
221 
222  return entropy(schmidtprobs(rA, dims));
223 }
224 
236 template<typename Derived>
237 // the G-concurrence
238 double gconcurrence(const Eigen::MatrixBase<Derived>& A)
239 {
240  const dyn_mat<typename Derived::Scalar>& rA = A.derived();
241 
242  // EXCEPTION CHECKS
243 
244  // check zero-size
246  throw Exception("qpp::gconcurrence()", Exception::Type::ZERO_SIZE);
247  // check column vector
248  if ( !internal::_check_cvector(rA))
249  throw Exception("qpp::gconcurrence()",
251 
252  // check equal local dimensions
253  idx D = static_cast<idx>(std::llround(
254  std::sqrt(static_cast<double>(rA.rows()))));
255  if ( D * D != static_cast<idx>(rA.rows()))
256  throw Exception("qpp::gconcurrence()",
258  // END EXCEPTION CHECKS
259 
260  // we compute exp(logdet()) to avoid underflow
261  return D * std::abs(std::exp(2. / D * logdet(reshape(rA, D, D))));
262 }
263 
271 template<typename Derived>
272 double negativity(const Eigen::MatrixBase<Derived>& A,
273  const std::vector<idx>& dims)
274 {
275  const dyn_mat<typename Derived::Scalar>& rA = A.derived();
276 
277  // EXCEPTION CHECKS
278 
279  // check zero-size
281  throw Exception("qpp::negativity()", Exception::Type::ZERO_SIZE);
282  // check bi-partite
283  if ( dims.size() != 2 )
284  throw Exception("qpp::negativity()", Exception::Type::NOT_BIPARTITE);
285  // check square matrix vector
286  if ( !internal::_check_square_mat(rA))
287  throw Exception("qpp::negativity()",
289  // check matching dimensions
290  if ( !internal::_check_dims_match_mat(dims, rA))
291  throw Exception("qpp::negativity()",
293  // END EXCEPTION CHECKS
294 
295  return (schatten(ptranspose(rA, {0}, dims), 1) - 1.) / 2.;
296 }
297 
305 template<typename Derived>
306 double lognegativity(const Eigen::MatrixBase<Derived>& A,
307  const std::vector<idx>& dims)
308 {
309  const dyn_mat<typename Derived::Scalar>& rA = A.derived();
310 
311  // EXCEPTION CHECKS
312 
313  // check zero-size
315  throw Exception("qpp::lognegativity()", Exception::Type::ZERO_SIZE);
316  // check bi-partite
317  if ( dims.size() != 2 )
318  throw Exception("qpp::lognegativity()",
320  // check square matrix vector
321  if ( !internal::_check_square_mat(rA))
322  throw Exception("qpp::lognegativity()",
324  // check matching dimensions
325  if ( !internal::_check_dims_match_mat(dims, rA))
326  throw Exception("qpp::lognegativity()",
328  // END EXCEPTION CHECKS
329 
330  return std::log2(2 * negativity(rA, dims) + 1);
331 }
332 
339 template<typename Derived>
340 double concurrence(const Eigen::MatrixBase<Derived>& A)
341 {
342  const dyn_mat<typename Derived::Scalar>& rA = A.derived();
343 
344  // EXCEPTION CHECKS
345 
346  // check zero-size
348  throw Exception("qpp::concurrence()", Exception::Type::ZERO_SIZE);
349  // check square matrix vector
350  if ( !internal::_check_square_mat(rA))
351  throw Exception("qpp::concurrence()",
353  // check that the state is a 2-qubit state
354  if ( rA.rows() != 4 )
355  throw Exception("qpp::concurrence()",
357  // END EXCEPTION CHECKS
358 
359  cmat sigmaY = Gates::get_instance().Y;
360  dyn_col_vect<double> lambdas =
361  evals(rA * kron(sigmaY, sigmaY) * conjugate(rA)
362  * kron(sigmaY, sigmaY)).real();
363 
364  std::vector<double> lambdas_sorted(lambdas.data(),
365  lambdas.data() + lambdas.size());
366 
367  std::sort(std::begin(lambdas_sorted), std::end(lambdas_sorted),
368  std::greater<double>());
369  std::transform(std::begin(lambdas_sorted), std::end(lambdas_sorted),
370  std::begin(lambdas_sorted), [](double elem)
371  {
372  return std::sqrt(std::abs(elem));
373  }); // chop tiny negatives
374 
375  return std::max(0.,
376  lambdas_sorted[0] - lambdas_sorted[1] - lambdas_sorted[2]
377  - lambdas_sorted[3]);
378 }
379 
380 } /* namespace qpp */
381 
382 #endif /* ENTANGLEMENT_H_ */
bool _check_cvector(const Eigen::MatrixBase< Derived > &A)
Definition: util.h:105
Derived::Scalar logdet(const Eigen::MatrixBase< Derived > &A)
Logarithm of the determinant.
Definition: functions.h:173
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:156
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:238
double lognegativity(const Eigen::MatrixBase< Derived > &A, const std::vector< idx > &dims)
Logarithmic negativity of the bi-partite mixed state A.
Definition: entanglement.h:306
Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic > dyn_mat
Dynamic Eigen matrix over the field specified by Scalar.
Definition: types.h:83
Quantum++ main namespace.
Definition: codes.h:30
bool _check_square_mat(const Eigen::MatrixBase< Derived > &A)
Definition: util.h:84
double schatten(const Eigen::MatrixBase< Derived > &A, double p)
Schatten matrix norm.
Definition: functions.h:831
cmat svdU(const Eigen::MatrixBase< Derived > &A)
Left singular vectors.
Definition: functions.h:499
cmat schmidtA(const Eigen::MatrixBase< Derived > &A, const std::vector< idx > &dims)
Schmidt basis on Alice side.
Definition: entanglement.h:81
dyn_col_vect< double > svals(const Eigen::MatrixBase< Derived > &A)
Singular values.
Definition: functions.h:475
dyn_mat< typename T::Scalar > kron(const T &head)
Kronecker product.
Definition: functions.h:900
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:306
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:112
cmat schmidtB(const Eigen::MatrixBase< Derived > &A, const std::vector< idx > &dims)
Schmidt basis on Bob side.
Definition: entanglement.h:116
cmat svdV(const Eigen::MatrixBase< Derived > &A)
Right singular vectors.
Definition: functions.h:524
double entanglement(const Eigen::MatrixBase< Derived > &A, const std::vector< idx > &dims)
Entanglement of the bi-partite pure state A.
Definition: entanglement.h:199
Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > dyn_col_vect
Dynamic Eigen column vector over the field specified by Scalar.
Definition: types.h:95
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:1479
Eigen::MatrixXcd cmat
Complex (double precision) dynamic Eigen matrix.
Definition: types.h:66
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:340
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:1140
double negativity(const Eigen::MatrixBase< Derived > &A, const std::vector< idx > &dims)
Negativity of the bi-partite mixed state A.
Definition: entanglement.h:272