XACC
random.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 RANDOM_H_
33 #define RANDOM_H_
34 
35 namespace qpp {
45 inline double rand(double a, double b) {
46  // EXCEPTION CHECKS
47 
48  if (a >= b)
49  throw exception::OutOfRange("qpp::rand()");
50  // END EXCEPTION CHECKS
51 
52  std::uniform_real_distribution<> ud(a, b);
53  auto& gen =
54 #ifdef NO_THREAD_LOCAL_
55  RandomDevices::get_instance().get_prng();
56 #else
57  RandomDevices::get_thread_local_instance().get_prng();
58 #endif
59 
60  return ud(gen);
61 }
62 
74 inline bigint rand(bigint a, bigint b) {
75  // EXCEPTION CHECKS
76 
77  if (a > b)
78  throw exception::OutOfRange("qpp::rand()");
79  // END EXCEPTION CHECKS
80 
81  std::uniform_int_distribution<bigint> uid(a, b);
82 
83  auto& gen =
84 #ifdef NO_THREAD_LOCAL_
85  RandomDevices::get_instance().get_prng();
86 #else
87  RandomDevices::get_thread_local_instance().get_prng();
88 #endif
89 
90  return uid(gen);
91 }
92 
101 inline idx randidx(idx a = std::numeric_limits<idx>::min(),
102  idx b = std::numeric_limits<idx>::max()) {
103  // EXCEPTION CHECKS
104 
105  if (a > b)
106  throw exception::OutOfRange("qpp::randidx()");
107  // END EXCEPTION CHECKS
108 
109  std::uniform_int_distribution<idx> uid(a, b);
110  auto& gen =
111 #ifdef NO_THREAD_LOCAL_
112  RandomDevices::get_instance().get_prng();
113 #else
114  RandomDevices::get_thread_local_instance().get_prng();
115 #endif
116 
117  return uid(gen);
118 }
119 
131 template <typename Derived>
132 Derived rand(idx rows QPP_UNUSED_, idx cols QPP_UNUSED_,
133  double a QPP_UNUSED_ = 0, double b QPP_UNUSED_ = 1) {
134  throw exception::UndefinedType("qpp::rand()");
135 }
136 
157 template <>
158 inline dmat rand(idx rows, idx cols, double a, double b) {
159  // EXCEPTION CHECKS
160 
161  if (rows == 0 || cols == 0)
162  throw exception::ZeroSize("qpp::rand()");
163  if (a >= b)
164  throw exception::OutOfRange("qpp::rand()");
165  // END EXCEPTION CHECKS
166 
167  return dmat::Zero(rows, cols).unaryExpr([a, b](double) {
168  return rand(a, b);
169  });
170 }
171 
193 template <>
194 inline cmat rand(idx rows, idx cols, double a, double b) {
195  // EXCEPTION CHECKS
196 
197  if (rows == 0 || cols == 0)
198  throw exception::ZeroSize("qpp::rand()");
199  if (a >= b)
200  throw exception::OutOfRange("qpp::rand()");
201  // END EXCEPTION CHECKS
202 
203  return rand<dmat>(rows, cols, a, b).cast<cplx>() +
204  1_i * rand<dmat>(rows, cols, a, b).cast<cplx>();
205 }
206 
218 template <typename Derived>
219 Derived randn(idx rows QPP_UNUSED_, idx cols QPP_UNUSED_,
220  double mean QPP_UNUSED_ = 0, double sigma QPP_UNUSED_ = 1) {
221  throw exception::UndefinedType("qpp::randn()");
222 }
223 
244 template <>
245 inline dmat randn(idx rows, idx cols, double mean, double sigma) {
246  // EXCEPTION CHECKS
247 
248  if (rows == 0 || cols == 0)
249  throw exception::ZeroSize("qpp::randn()");
250  // END EXCEPTION CHECKS
251 
252  std::normal_distribution<> nd(mean, sigma);
253  auto& gen =
254 #ifdef NO_THREAD_LOCAL_
255  RandomDevices::get_instance().get_prng();
256 #else
257  RandomDevices::get_thread_local_instance().get_prng();
258 #endif
259 
260  return dmat::Zero(rows, cols).unaryExpr([&nd, &gen](double) {
261  return nd(gen);
262  });
263 }
264 
286 template <>
287 inline cmat randn(idx rows, idx cols, double mean, double sigma) {
288  // EXCEPTION CHECKS
289 
290  if (rows == 0 || cols == 0)
291  throw exception::ZeroSize("qpp::randn()");
292  // END EXCEPTION CHECKS
293 
294  return randn<dmat>(rows, cols, mean, sigma).cast<cplx>() +
295  1_i * randn<dmat>(rows, cols, mean, sigma).cast<cplx>();
296 }
297 
306 inline double randn(double mean = 0, double sigma = 1) {
307  std::normal_distribution<> nd(mean, sigma);
308  auto& gen =
309 #ifdef NO_THREAD_LOCAL_
310  RandomDevices::get_instance().get_prng();
311 #else
312  RandomDevices::get_thread_local_instance().get_prng();
313 #endif
314 
315  return nd(gen);
316 }
317 
324 inline cmat randU(idx D = 2)
325 // ~3 times slower than Toby Cubitt's MATLAB corresponding routine,
326 // because Eigen 3 QR algorithm is not parallelized
327 {
328  // EXCEPTION CHECKS
329 
330  if (D == 0)
331  throw exception::DimsInvalid("qpp::randU()");
332  // END EXCEPTION CHECKS
333 
334  cmat X = 1 / std::sqrt(2.) * randn<cmat>(D, D);
335  Eigen::HouseholderQR<cmat> qr(X);
336 
337  cmat Q = qr.householderQ();
338  // phase correction so that the resultant matrix is
339  // uniformly distributed according to the Haar measure
340 
341  Eigen::VectorXcd phases = (rand<dmat>(D, 1)).cast<cplx>();
342  for (idx i = 0; i < static_cast<idx>(phases.rows()); ++i)
343  phases(i) = std::exp(2 * pi * 1_i * phases(i));
344 
345  Q = Q * phases.asDiagonal();
346 
347  return Q;
348 }
349 
357 inline cmat randV(idx Din, idx Dout) {
358  // EXCEPTION CHECKS
359 
360  if (Din == 0 || Dout == 0 || Din > Dout)
361  throw exception::DimsInvalid("qpp::randV()");
362  // END EXCEPTION CHECKS
363 
364  return randU(Dout).block(0, 0, Dout, Din);
365 }
366 
377 inline std::vector<cmat> randkraus(idx N, idx D = 2) {
378  // EXCEPTION CHECKS
379 
380  if (N == 0)
381  throw exception::OutOfRange("qpp::randkraus()");
382  if (D == 0)
383  throw exception::DimsInvalid("qpp::randkraus()");
384  // END EXCEPTION CHECKS
385 
386  std::vector<cmat> result(N);
387  for (idx i = 0; i < N; ++i)
388  result[i] = cmat::Zero(D, D);
389 
390  cmat Fk(D, D);
391  cmat U = randU(N * D);
392 
393 #ifdef WITH_OPENMP_
394 #pragma omp parallel for collapse(3)
395 #endif // WITH_OPENMP_
396  for (idx k = 0; k < N; ++k)
397  for (idx a = 0; a < D; ++a)
398  for (idx b = 0; b < D; ++b)
399  result[k](a, b) = U(a * N + k, b * N);
400 
401  return result;
402 }
403 
410 inline cmat randH(idx D = 2) {
411  // EXCEPTION CHECKS
412 
413  if (D == 0)
414  throw exception::DimsInvalid("qpp::randH()");
415  // END EXCEPTION CHECKS
416 
417  cmat H = 2 * rand<cmat>(D, D) - (1. + 1_i) * cmat::Ones(D, D);
418 
419  return H + H.adjoint();
420 }
421 
428 inline ket randket(idx D = 2) {
429  // EXCEPTION CHECKS
430 
431  if (D == 0)
432  throw exception::DimsInvalid("qpp::randket()");
433  // END EXCEPTION CHECKS
434 
435  /* slow
436  ket kt = ket::Ones(D);
437  ket result = static_cast<ket>(randU(D) * kt);
438 
439  return result;
440  */
441 
442  ket kt = randn<cmat>(D, 1);
443 
444  return kt / kt.norm();
445 }
446 
453 inline cmat randrho(idx D = 2) {
454  // EXCEPTION CHECKS
455 
456  if (D == 0)
457  throw exception::DimsInvalid("qpp::randrho()");
458  // END EXCEPTION CHECKS
459 
460  cmat result = 10 * randH(D);
461  result = result * result.adjoint();
462 
463  return result / result.trace();
464 }
465 
475 inline std::vector<idx> randperm(idx N) {
476  // EXCEPTION CHECKS
477 
478  if (N == 0)
479  throw exception::PermInvalid("qpp::randperm()");
480  // END EXCEPTION CHECKS
481 
482  std::vector<idx> result(N);
483 
484  // fill in increasing order
485  std::iota(std::begin(result), std::end(result), 0);
486 
487  // shuffle
488  auto& gen =
489 #ifdef NO_THREAD_LOCAL_
490  RandomDevices::get_instance().get_prng();
491 #else
492  RandomDevices::get_thread_local_instance().get_prng();
493 #endif
494  std::shuffle(std::begin(result), std::end(result), gen);
495 
496  return result;
497 }
498 
506 inline std::vector<double> randprob(idx N) {
507  // EXCEPTION CHECKS
508 
509  if (N == 0)
510  throw exception::OutOfRange("qpp::randprob()");
511  // END EXCEPTION CHECKS
512 
513  std::vector<double> result(N);
514 
515  // generate
516  std::exponential_distribution<> ed(1);
517  auto& gen =
518 #ifdef NO_THREAD_LOCAL_
519  RandomDevices::get_instance().get_prng();
520 #else
521  RandomDevices::get_thread_local_instance().get_prng();
522 #endif
523  for (idx i = 0; i < N; ++i)
524  result[i] = ed(gen);
525 
526  // normalize
527  double sumprob = std::accumulate(std::begin(result), std::end(result), 0.0);
528  for (idx i = 0; i < N; ++i)
529  result[i] /= sumprob;
530 
531  return result;
532 }
533 
534 } /* namespace qpp */
535 
536 #endif /* RANDOM_H_ */
Quantum++ main namespace.
Definition: circuits.h:35