XACC
entropies.h
Go to the documentation of this file.
1 /*
2  * This file is part of Quantum++.
3  *
4  * MIT License
5  *
6  * Copyright (c) 2013 - 2020 Vlad Gheorghiu.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  */
26 
32 #ifndef ENTROPY_H_
33 #define ENTROPY_H_
34 
35 namespace qpp {
42 template <typename Derived>
43 double entropy(const Eigen::MatrixBase<Derived>& A) {
44  const dyn_mat<typename Derived::Scalar>& rA = A.derived();
45 
46  // EXCEPTION CHECKS
47 
48  // check zero-size
49  if (!internal::check_nonzero_size(rA))
50  throw exception::ZeroSize("qpp::entropy()");
51 
52  // check square matrix
53  if (!internal::check_square_mat(rA))
54  throw exception::MatrixNotSquare("qpp::entropy()");
55  // END EXCEPTION CHECKS
56 
57  dmat ev = svals(rA); // get the singular values
58  double result = 0;
59  for (idx i = 0; i < static_cast<idx>(ev.rows()); ++i)
60  if (ev(i) != 0) // not identically zero
61  result -= ev(i) * std::log2(ev(i));
62 
63  return result;
64 }
65 
72 inline double entropy(const std::vector<double>& prob) {
73  // EXCEPTION CHECKS
74 
75  // check zero-size
76  if (!internal::check_nonzero_size(prob))
77  throw exception::ZeroSize("qpp::entropy()");
78  // END EXCEPTION CHECKS
79 
80  double result = 0;
81  for (idx i = 0; i < prob.size(); ++i)
82  if (std::abs(prob[i]) != 0) // not identically zero
83  result -= std::abs(prob[i]) * std::log2(std::abs(prob[i]));
84 
85  return result;
86 }
87 
100 template <typename Derived>
101 double renyi(const Eigen::MatrixBase<Derived>& A, double alpha) {
102  const dyn_mat<typename Derived::Scalar>& rA = A.derived();
103 
104  // EXCEPTION CHECKS
105 
106  // check zero-size
107  if (!internal::check_nonzero_size(rA))
108  throw exception::ZeroSize("qpp::renyi()");
109 
110  // check square matrix
111  if (!internal::check_square_mat(rA))
112  throw exception::MatrixNotSquare("qpp::renyi()");
113 
114  if (alpha < 0)
115  throw exception::OutOfRange("qpp::renyi()");
116  // END EXCEPTION CHECKS
117 
118  if (alpha == 0) // H max
119  return std::log2(rA.rows());
120 
121  if (alpha == 1) // Shannon/von-Neumann
122  return entropy(rA);
123 
124  if (alpha == infty) // H min
125  return -std::log2(svals(rA)[0]);
126 
127  dmat sv = svals(rA); // get the singular values
128  double result = 0;
129  for (idx i = 0; i < static_cast<idx>(sv.rows()); ++i)
130  if (sv(i) != 0) // not identically zero
131  result += std::pow(sv(i), alpha);
132 
133  return std::log2(result) / (1 - alpha);
134 }
135 
148 inline double renyi(const std::vector<double>& prob, double alpha) {
149  // EXCEPTION CHECKS
150 
151  // check zero-size
152  if (!internal::check_nonzero_size(prob))
153  throw exception::ZeroSize("qpp::renyi()");
154 
155  if (alpha < 0)
156  throw exception::OutOfRange("qpp::renyi()");
157 
158  if (alpha == 0) // H max
159  return std::log2(prob.size());
160 
161  if (alpha == 1) // Shannon/von-Neumann
162  return entropy(prob);
163  // END EXCEPTION CHECKS
164 
165  if (alpha == infty) // H min
166  {
167  double max = 0;
168  for (idx i = 0; i < prob.size(); ++i)
169  if (std::abs(prob[i]) > max)
170  max = std::abs(prob[i]);
171 
172  return -std::log2(max);
173  }
174 
175  double result = 0;
176  for (idx i = 0; i < prob.size(); ++i)
177  if (std::abs(prob[i]) != 0) // not identically zero
178  result += std::pow(std::abs(prob[i]), alpha);
179 
180  return std::log2(result) / (1 - alpha);
181 }
182 
193 template <typename Derived>
194 double tsallis(const Eigen::MatrixBase<Derived>& A, double q) {
195  const dyn_mat<typename Derived::Scalar>& rA = A.derived();
196 
197  // EXCEPTION CHECKS
198 
199  // check zero-size
200  if (!internal::check_nonzero_size(rA))
201  throw exception::ZeroSize("qpp::tsallis()");
202 
203  // check square matrix
204  if (!internal::check_square_mat(rA))
205  throw exception::MatrixNotSquare("qpp::tsallis()");
206 
207  if (q < 0)
208  throw exception::OutOfRange("qpp::tsallis()");
209  // END EXCEPTION CHECKS
210 
211  if (q == 1) // Shannon/von-Neumann with base e logarithm
212  return entropy(rA) * std::log(2);
213 
214  dmat ev = svals(rA); // get the singular values
215  double result = 0;
216  for (idx i = 0; i < static_cast<idx>(ev.rows()); ++i)
217  if (ev(i) != 0) // not identically zero
218  result += std::pow(ev(i), q);
219 
220  return (result - 1) / (1 - q);
221 }
222 
234 inline double tsallis(const std::vector<double>& prob, double q) {
235  // EXCEPTION CHECKS
236 
237  // check zero-size
238  if (!internal::check_nonzero_size(prob))
239  throw exception::ZeroSize("qpp::tsallis()");
240 
241  if (q < 0)
242  throw exception::OutOfRange("qpp::tsallis()");
243  // END EXCEPTION CHECKS
244 
245  if (q == 1) // Shannon/von-Neumann with base e logarithm
246  return entropy(prob) * std::log(2);
247 
248  double result = 0;
249  for (idx i = 0; i < prob.size(); ++i)
250  if (std::abs(prob[i]) != 0) // not identically zero
251  result += std::pow(std::abs(prob[i]), q);
252 
253  return (result - 1) / (1 - q);
254 }
255 
265 template <typename Derived>
266 double qmutualinfo(const Eigen::MatrixBase<Derived>& A,
267  const std::vector<idx>& subsysA,
268  const std::vector<idx>& subsysB,
269  const std::vector<idx>& dims) {
270  const dyn_mat<typename Derived::Scalar>& rA = A.derived();
271 
272  // EXCEPTION CHECKS
273 
274  // check zero-size
275  if (!internal::check_nonzero_size(rA))
276  throw exception::ZeroSize("qpp::qmutualinfo()");
277 
278  // check that dims is a valid dimension vector
279  if (!internal::check_dims(dims))
280  throw exception::DimsInvalid("qpp::qmutualinfo()");
281 
282  // check square matrix
283  if (!internal::check_square_mat(rA))
284  throw exception::MatrixNotSquare("qpp::qmutualinfo()");
285 
286  // check that dims match the dimension of A
287  if (!internal::check_dims_match_mat(dims, rA))
288  throw exception::DimsMismatchMatrix("qpp::qmutualinfo()");
289 
290  // check that subsys are valid
291  if (!internal::check_subsys_match_dims(subsysA, dims) ||
292  !internal::check_subsys_match_dims(subsysB, dims))
293  throw exception::SubsysMismatchDims("qpp::qmutualinfo()");
294  // END EXCEPTION CHECKS
295 
296  // The full system indexes {0,1,...,n-1}
297  std::vector<idx> full_system(dims.size());
298  std::iota(std::begin(full_system), std::end(full_system), 0);
299 
300  // Sorted input subsystems
301  std::vector<idx> subsysAsorted{subsysA};
302  std::vector<idx> subsysBsorted{subsysB};
303 
304  // sort the input subsystems (as needed by std::set_union)
305  std::sort(std::begin(subsysAsorted), std::end(subsysAsorted));
306  std::sort(std::begin(subsysBsorted), std::end(subsysBsorted));
307 
308  // construct the union of A and B
309  std::vector<idx> subsysAB;
310  std::set_union(std::begin(subsysAsorted), std::end(subsysAsorted),
311  std::begin(subsysBsorted), std::end(subsysBsorted),
312  std::back_inserter(subsysAB));
313 
314  // construct the complements
315  std::vector<idx> subsysA_bar = complement(subsysA, dims.size());
316  std::vector<idx> subsysB_bar = complement(subsysB, dims.size());
317  std::vector<idx> subsysAB_bar = complement(subsysAB, dims.size());
318 
319  cmat rhoA = ptrace(rA, subsysA_bar, dims);
320  cmat rhoB = ptrace(rA, subsysB_bar, dims);
321  cmat rhoAB = ptrace(rA, subsysAB_bar, dims);
322 
323  return entropy(rhoA) + entropy(rhoB) - entropy(rhoAB);
324 }
325 
335 template <typename Derived>
336 double qmutualinfo(const Eigen::MatrixBase<Derived>& A,
337  const std::vector<idx>& subsysA,
338  const std::vector<idx>& subsysB, idx d = 2) {
339  const dyn_mat<typename Derived::Scalar>& rA = A.derived();
340 
341  // EXCEPTION CHECKS
342 
343  // check zero-size
344  if (!internal::check_nonzero_size(rA))
345  throw exception::ZeroSize("qpp::qmutualinfo()");
346 
347  // check valid dims
348  if (d < 2)
349  throw exception::DimsInvalid("qpp::qmutualinfo()");
350  // END EXCEPTION CHECKS
351 
352  idx n = internal::get_num_subsys(static_cast<idx>(rA.rows()), d);
353  std::vector<idx> dims(n, d); // local dimensions vector
354 
355  return qmutualinfo(rA, subsysA, subsysB, dims);
356 }
357 
358 } /* namespace qpp */
359 
360 #endif /* ENTROPY_H_ */
Quantum++ main namespace.
Definition: circuits.h:35