Quantum++  v1.2
A modern C++11 quantum computing library
noise.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 - 2019 Vlad Gheorghiu (vgheorgh@gmail.com)
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 CLASSES_NOISE_H_
33 #define CLASSES_NOISE_H_
34 
35 namespace qpp {
40 struct NoiseType {
46 
51  struct StateIndependent;
52 };
57 template <class T>
58 class NoiseBase {
59  public:
60  using noise_type = T;
61  static_assert(
62  std::is_same<NoiseType::StateDependent, noise_type>::value ||
63  std::is_same<NoiseType::StateIndependent, noise_type>::value,
64  "");
65 
66  protected:
67  const std::vector<cmat> Ks_;
68  mutable std::vector<double> probs_;
69  mutable idx d_{};
70 
71  mutable idx i_{};
72  mutable bool generated_{false};
73 
82  void compute_probs_(const cmat& state,
83  const std::vector<idx>& target) const {
84  if (!std::is_same<NoiseType::StateDependent, noise_type>::value)
85  return; // no-op
86 
87  // minimal EXCEPTION CHECKS
88 
89  if (!internal::check_nonzero_size(state))
90  throw exception::ZeroSize("qpp::NoiseBase::compute_probs_()");
91  // END EXCEPTION CHECKS
92 
93  cmat rho_i;
94  idx n = internal::get_num_subsys(state.rows(), d_);
95 
96  for (idx i = 0; i < Ks_.size(); ++i) {
97  rho_i = ptrace(state, complement(target, n), d_);
98  probs_[i] = trace(Ks_[i] * rho_i * adjoint(Ks_[i])).real();
99  }
100  } /* compute_probs_() */
101 
109  cmat compute_state_(const cmat& state,
110  const std::vector<idx>& target) const {
111  cmat result;
112  idx D = static_cast<idx>(state.rows());
113 
114  //************ ket ************//
115  if (internal::check_cvector(state)) {
116  result.resize(D, 1);
117  }
118  //************ density matrix ************//
119  else if (internal::check_square_mat(state)) {
120  result.resize(D, D);
121  }
122  //************ Exception: not ket nor density matrix ************//
123  else
125  "qpp::NoiseBase::compute_state_()");
126 
127  // now do the actual noise generation
128  std::discrete_distribution<idx> dd{std::begin(probs_),
129  std::end(probs_)};
130  auto& gen =
131 #ifdef NO_THREAD_LOCAL_
133 #else
135 #endif
136  i_ = dd(gen);
137  result = apply(state, Ks_[i_], target, d_);
138  generated_ = true;
139 
140  return normalize(result);
141  } /* compute_state_() */
142 
143  public:
153  template <typename U = noise_type>
154  explicit NoiseBase(
155  const std::vector<cmat>& Ks,
156  typename std::enable_if<
157  std::is_same<NoiseType::StateDependent, U>::value>::type* = nullptr)
158  : Ks_{Ks}, probs_(Ks.size()) {
159  // EXCEPTION CHECKS
160 
161  if (Ks.size() == 0)
162  throw exception::ZeroSize("qpp::NoiseBase::NoiseBase()");
163  if (!internal::check_nonzero_size(Ks[0]))
164  throw exception::ZeroSize("qpp::NoiseBase::NoiseBase()");
165  if (!internal::check_square_mat(Ks[0]))
166  throw exception::MatrixNotSquare("qpp::NoiseBase::NoiseBase()");
167  for (auto&& elem : Ks)
168  if (elem.rows() != Ks[0].rows() || elem.cols() != Ks[0].rows())
169  throw exception::DimsNotEqual("qpp::NoiseBase::NoiseBase()");
170  // END EXCEPTION CHECKS
171 
172  d_ = Ks[0].rows(); // set the local dimension
173  }
174 
184  template <typename U = noise_type>
185  explicit NoiseBase(
186  const std::vector<cmat>& Ks, const std::vector<double>& probs,
187  typename std::enable_if<std::is_same<NoiseType::StateIndependent,
188  U>::value>::type* = nullptr)
189  : Ks_{Ks}, probs_(probs) {
190  // EXCEPTION CHECKS
191 
192  if (Ks.size() == 0)
193  throw exception::ZeroSize("qpp::NoiseBase::NoiseBase()");
194  if (Ks.size() != probs.size())
195  throw exception::SizeMismatch("qpp::NoiseBase::NoiseBase");
196  if (!internal::check_nonzero_size(Ks[0]))
197  throw exception::ZeroSize("qpp::NoiseBase::NoiseBase()");
198  if (!internal::check_square_mat(Ks[0]))
199  throw exception::MatrixNotSquare("qpp::NoiseBase::NoiseBase()");
200  for (auto&& elem : Ks)
201  if (elem.rows() != Ks[0].rows() || elem.cols() != Ks[0].rows())
202  throw exception::DimsNotEqual("qpp::NoiseBase::NoiseBase()");
203  for (auto&& elem : probs)
204  if (elem < 0 || elem > 1)
205  throw exception::OutOfRange("qpp::NoiseBase::NoiseBase");
206  // END EXCEPTION CHECKS
207 
208  d_ = Ks[0].rows(); // set the local dimension
209  probs_ = probs;
210  }
211 
215  virtual ~NoiseBase() = default;
216 
217  // getters
223  idx get_d() const noexcept { return d_; };
224 
230  std::vector<cmat> get_Ks() const { return Ks_; }
231 
237  std::vector<double> get_probs() const {
238  if (generated_ ||
239  std::is_same<NoiseType::StateIndependent, noise_type>::value) {
240  return probs_;
241  } else
243  "qpp::NoiseBase::get_probs()",
244  "NoiseBase::operator() was not yet invoked");
245  }
246 
252  idx get_last_idx() const {
253  if (generated_) {
254  return i_;
255  } else
257  "qpp::NoiseBase::get_last_idx()",
258  "NoiseBase::operator() was not yet invoked");
259  }
260 
266  double get_last_p() const {
267  if (generated_) {
268  return probs_[i_];
269  } else
271  "qpp::NoiseBase::get_last_p()",
272  "NoiseBase::operator() was not yet invoked");
273  }
274 
280  cmat get_last_K() const {
281  if (generated_) {
282  return Ks_[i_];
283  } else
285  "qpp::NoiseBase::get_last_K()",
286  "NoiseBase::operator() was not yet invoked");
287  }
288  // end getters
289 
297  virtual cmat operator()(const cmat& state) const {
298  cmat result;
299  try {
300 
301  compute_probs_(state, std::vector<idx>{0});
302  result = compute_state_(state, std::vector<idx>{0});
303  } catch (exception::Exception&) {
304  std::cerr << "In qpp::NoiseBase::operator()\n";
305  throw;
306  }
307 
308  return result;
309  }
310 
320  virtual cmat operator()(const cmat& state, idx target) const {
321  cmat result;
322  try {
323  compute_probs_(state, std::vector<idx>{target});
324  result = compute_state_(state, std::vector<idx>{target});
325  } catch (exception::Exception&) {
326  std::cerr << "In qpp::NoiseBase::operator()\n";
327  throw;
328  }
329 
330  return result;
331  }
332 
342  virtual cmat operator()(const cmat& state,
343  const std::vector<idx>& target) const {
344  cmat result;
345  try {
346  compute_probs_(state, target);
347  result = compute_state_(state, target);
348  } catch (exception::Exception&) {
349  std::cerr << "In qpp::NoiseBase::operator()\n";
350  throw;
351  }
352 
353  return result;
354  }
355 }; /* class NoiseBase */
356 
357 // qubit noise models
358 
363 class QubitDepolarizingNoise : public NoiseBase<NoiseType::StateIndependent> {
364  public:
370  explicit QubitDepolarizingNoise(double p)
373  {1 - p, p / 3, p / 3, p / 3}) {
374  // EXCEPTION CHECKS
375 
376  if (p < 0 || p > 1)
377  throw exception::OutOfRange(
378  "qpp::QubitDepolarizingNoise::QubitDepolarizingNoise()");
379  // END EXCEPTION CHECKS
380  }
381 }; /* class QubitDepolarizingNoise */
382 
387 class QubitPhaseFlipNoise : public NoiseBase<NoiseType::StateIndependent> {
388  public:
394  explicit QubitPhaseFlipNoise(double p)
396  {1 - p, p}) {
397  // EXCEPTION CHECKS
398 
399  if (p < 0 || p > 1)
400  throw exception::OutOfRange(
401  "qpp::QubitPhaseFlipNoise::QubitPhaseFlipNoise()");
402  // END EXCEPTION CHECKS
403  }
404 }; /* class QubitPhaseFlipNoise */
405 
410 class QubitBitFlipNoise : public NoiseBase<NoiseType::StateIndependent> {
411  public:
417  explicit QubitBitFlipNoise(double p)
419  {1 - p, p}) {
420  // EXCEPTION CHECKS
421 
422  if (p < 0 || p > 1)
423  throw exception::OutOfRange(
424  "qpp::QubitBitFlipNoise::QubitBitFlipNoise()");
425  // END EXCEPTION CHECKS
426  }
427 }; /* class QubitBitFlipNoise */
428 
433 class QubitBitPhaseFlipNoise : public NoiseBase<NoiseType::StateIndependent> {
434  public:
440  explicit QubitBitPhaseFlipNoise(double p)
442  {1 - p, p}) {
443  // EXCEPTION CHECKS
444 
445  if (p < 0 || p > 1)
446  throw exception::OutOfRange(
447  "qpp::QubitBitPhaseFlipNoise::QubitBitPhaseFlipNoise()");
448  // END EXCEPTION CHECKS
449  }
450 }; /* class QubitBitPhaseFlipNoise */
451 
456 class QubitAmplitudeDampingNoise : public NoiseBase<NoiseType::StateDependent> {
457  public:
463  explicit QubitAmplitudeDampingNoise(double gamma)
464  : NoiseBase(std::vector<cmat>{
465  ((cmat(2, 2)) << 1, 0, 0, std::sqrt(gamma)).finished(),
466  ((cmat(2, 2)) << 0, std::sqrt(1 - gamma), 0, 0).finished()}) {
467  // EXCEPTION CHECKS
468 
469  if (gamma < 0 || gamma > 1)
470  throw exception::OutOfRange("qpp::QubitAmplitudeDampingNoise::"
471  "QubitAmplitudeDampingNoise()");
472  // END EXCEPTION CHECKS
473  }
474 }; /* class QubitAmplitudeDampingNoise */
475 
480 class QubitPhaseDampingNoise : public NoiseBase<NoiseType::StateDependent> {
481  public:
487  explicit QubitPhaseDampingNoise(double lambda)
488  : NoiseBase(std::vector<cmat>{
489  ((cmat(2, 2)) << 1, 0, 0, std::sqrt(1 - lambda)).finished(),
490  ((cmat(2, 2)) << 0, 0, 0, std::sqrt(lambda)).finished()}) {
491  // EXCEPTION CHECKS
492 
493  if (lambda < 0 || lambda > 1)
494  throw exception::OutOfRange("qpp::QubitPhaseDampingNoise::"
495  "QubitPhaseDampingNoise()");
496  // END EXCEPTION CHECKS
497  }
498 }; /* class QubitPhaseDampingNoise */
499 
500 // qudit noise models
501 
506 class QuditDepolarizingNoise : public NoiseBase<NoiseType::StateIndependent> {
513  std::vector<cmat> fill_Ks_(idx d) const {
514  std::vector<cmat> Ks(d * d);
515  idx cnt = 0;
516  for (idx i = 0; i < d; ++i)
517  for (idx j = 0; j < d; ++j)
518  Ks[cnt++] = powm(Gates::get_instance().Xd(d), i) *
519  powm(Gates::get_instance().Zd(d), j);
520 
521  return Ks;
522  }
523 
531  std::vector<double> fill_probs_(double p, idx d) const {
532  std::vector<double> probs(d * d);
533  probs[0] = 1 - p;
534  for (idx i = 1; i < d * d; ++i)
535  probs[i] = p / (d - 1) * (d - 1);
536 
537  return probs;
538  }
539 
540  public:
547  explicit QuditDepolarizingNoise(double p, idx d)
548  : NoiseBase(fill_Ks_(d), fill_probs_(p, d)) {
549  // EXCEPTION CHECKS
550 
551  if (d < 2 || p < 0 || p > 1)
552  throw exception::OutOfRange(
553  "qpp::QuditDepolarizingNoise::QuditDepolarizingNoise()");
554  // END EXCEPTION CHECKS
555  }
556 }; /* class QuditDepolarizingNoise */
557 
558 } /* namespace qpp */
559 
560 #endif /* CLASSES_NOISE_H_ */
bool check_nonzero_size(const T &x) noexcept
Definition: util.h:123
Dimensions not equal exception.
Definition: exception.h:284
Qudit depolarizing noise.
Definition: noise.h:506
bool check_cvector(const Eigen::MatrixBase< Derived > &A)
Definition: util.h:117
double get_last_p() const
Probability of the last occurring noise element.
Definition: noise.h:266
QubitDepolarizingNoise(double p)
Qubit depolarizing noise constructor.
Definition: noise.h:370
Custom exception.
Definition: exception.h:600
QubitBitFlipNoise(double p)
Qubit bit flip noise constructor.
Definition: noise.h:417
std::mt19937 & get_prng()
Returns a reference to the internal PRNG object.
Definition: random_devices.h:61
std::vector< double > fill_probs_(double p, idx d) const
Fills the probability vector.
Definition: noise.h:531
QubitBitPhaseFlipNoise(double p)
Qubit bit-phase flip noise constructor.
Definition: noise.h:440
std::vector< cmat > fill_Ks_(idx d) const
Fills the Kraus operator vector.
Definition: noise.h:513
Quantum++ main namespace.
Definition: circuits.h:35
STL namespace.
Qubit bit flip noise.
Definition: noise.h:410
Matrix is not square nor column vector exception.
Definition: exception.h:209
idx get_d() const noexcept
Qudit dimension.
Definition: noise.h:223
idx get_num_subsys(idx D, idx d)
Definition: util.h:370
virtual cmat operator()(const cmat &state) const
Function invocation operator, applies the underlying noise model on the state vector or density matri...
Definition: noise.h:297
Qubit depolarizing noise.
Definition: noise.h:363
NoiseBase(const std::vector< cmat > &Ks, typename std::enable_if< std::is_same< NoiseType::StateDependent, U >::value >::type *=nullptr)
Constructs a noise instance for StateDependent noise type.
Definition: noise.h:154
dyn_mat< typename Derived::Scalar > ptrace(const Eigen::MatrixBase< Derived > &A, const std::vector< idx > &target, const std::vector< idx > &dims)
Partial trace.
Definition: operations.h:1187
dyn_mat< typename Derived1::Scalar > apply(const Eigen::MatrixBase< Derived1 > &state, const Eigen::MatrixBase< Derived2 > &A, const std::vector< idx > &target, const std::vector< idx > &dims)
Applies the gate A to the part target of the multi-partite state vector or density matrix state...
Definition: operations.h:444
bool generated_
invoked, or if the noise is state-independent
Definition: noise.h:72
virtual ~NoiseBase()=default
Default virtual destructor.
dyn_mat< typename Derived::Scalar > adjoint(const Eigen::MatrixBase< Derived > &A)
Adjoint.
Definition: functions.h:89
QuditDepolarizingNoise(double p, idx d)
Qudit depolarizing noise constructor.
Definition: noise.h:547
static RandomDevices & get_thread_local_instance() noexcept(std::is_nothrow_constructible< RandomDevices >::value)
Definition: singleton.h:103
std::vector< double > probs_
probabilities
Definition: noise.h:68
cmat Id2
Identity gate.
Definition: gates.h:46
cmat get_last_K() const
Last occurring noise element.
Definition: noise.h:280
Qubit bit-phase flip (dephasing) noise.
Definition: noise.h:433
std::vector< double > get_probs() const
Vector of probabilities corresponding to each noise operator.
Definition: noise.h:237
std::vector< cmat > get_Ks() const
Vector of noise operators.
Definition: noise.h:230
cmat X
Pauli Sigma-X gate.
Definition: gates.h:48
virtual cmat operator()(const cmat &state, const std::vector< idx > &target) const
Function invocation operator, applies the underlying correlated noise model on qudits specified by ta...
Definition: noise.h:342
Template tag, used whenever the noise is state-independent.
Definition: noise.h:45
Contains template tags used to specify the noise type.
Definition: noise.h:40
virtual cmat operator()(const cmat &state, idx target) const
Function invocation operator, applies the underlying noise model on qudit target of the multi-partite...
Definition: noise.h:320
Qubit phase flip (dephasing) noise.
Definition: noise.h:387
dyn_mat< typename Derived::Scalar > powm(const Eigen::MatrixBase< Derived > &A, idx n)
Fast matrix power based on the SQUARE-AND-MULTIPLY algorithm.
Definition: functions.h:800
Template tag, used whenever the noise is state-dependent.
bool check_square_mat(const Eigen::MatrixBase< Derived > &A)
Definition: util.h:99
Derived::Scalar trace(const Eigen::MatrixBase< Derived > &A)
Trace.
Definition: functions.h:130
idx d_
qudit dimension
Definition: noise.h:69
Base class for all noise models, derive your particular noise model.
Definition: noise.h:58
void compute_probs_(const cmat &state, const std::vector< idx > &target) const
Compute probability outcomes for StateDependent noise type, otherwise returns without performing any ...
Definition: noise.h:82
Argument out of range exception.
Definition: exception.h:515
QubitPhaseDampingNoise(double lambda)
Qubit phase damping noise constructor.
Definition: noise.h:487
idx get_last_idx() const
Index of the last occurring noise element.
Definition: noise.h:252
static RandomDevices & get_instance() noexcept(std::is_nothrow_constructible< RandomDevices >::value)
Definition: singleton.h:92
Eigen::MatrixXcd cmat
Complex (double precision) dynamic Eigen matrix.
Definition: types.h:64
Qubit phase damping noise, as described in Nielsen and Chuang.
Definition: noise.h:480
Qubit amplitude damping noise, as described in Nielsen and Chuang.
Definition: noise.h:456
cmat compute_state_(const cmat &state, const std::vector< idx > &target) const
Compute the resulting state after the noise was applied.
Definition: noise.h:109
QubitAmplitudeDampingNoise(double gamma)
Qubit amplitude damping noise constructor.
Definition: noise.h:463
Size mismatch exception.
Definition: exception.h:543
std::size_t idx
Non-negative integer index, make sure you use an unsigned type.
Definition: types.h:39
cmat Z
Pauli Sigma-Z gate.
Definition: gates.h:50
Matrix is not square exception.
Definition: exception.h:149
std::vector< idx > complement(std::vector< idx > subsys, idx n)
Constructs the complement of a subsystem vector.
Definition: functions.h:1780
cmat Y
Pauli Sigma-Y gate.
Definition: gates.h:49
QubitPhaseFlipNoise(double p)
Qubit phase flip (dephasing) noise constructor.
Definition: noise.h:394
dyn_mat< typename Derived::Scalar > normalize(const Eigen::MatrixBase< Derived > &A)
Normalizes state vector (column or row vector) or density matrix.
Definition: functions.h:270
NoiseBase(const std::vector< cmat > &Ks, const std::vector< double > &probs, typename std::enable_if< std::is_same< NoiseType::StateIndependent, U >::value >::type *=nullptr)
Constructs a noise instance for StateIndependent noise type.
Definition: noise.h:185
idx i_
index of the last occurring noise element
Definition: noise.h:71
const std::vector< cmat > Ks_
Kraus operators.
Definition: noise.h:64
Base class for generating Quantum++ custom exceptions.
Definition: exception.h:71
Object has zero size exception.
Definition: exception.h:134