| 675 | } |
| 676 | |
| 677 | QMatrix getRandomUnitary(int numQb) { |
| 678 | DEMAND( numQb >= 1 ); |
| 679 | |
| 680 | // create Z ~ random complex matrix (distribution not too important) |
| 681 | size_t dim = 1 << numQb; |
| 682 | QMatrix matrZ = getRandomQMatrix(dim); |
| 683 | QMatrix matrZT = getTranspose(matrZ); |
| 684 | |
| 685 | // create Z = Q R (via QR decomposition) ... |
| 686 | QMatrix matrQT = getOrthonormalisedRows(matrZ); |
| 687 | QMatrix matrQ = getTranspose(matrQT); |
| 688 | QMatrix matrR = getZeroMatrix(dim); |
| 689 | |
| 690 | // ... where R_rc = (columm c of Z) . (column r of Q) = (row c of ZT) . (row r of QT) |
| 691 | for (size_t r=0; r<dim; r++) |
| 692 | for (size_t c=r; c<dim; c++) |
| 693 | matrR[r][c] = matrZT[c] * matrQT[r]; |
| 694 | |
| 695 | // create D = normalised diagonal of R |
| 696 | QMatrix matrD = getZeroMatrix(dim); |
| 697 | for (size_t i=0; i<dim; i++) |
| 698 | matrD[i][i] = matrR[i][i] / abs(matrR[i][i]); |
| 699 | |
| 700 | // create U = Q D |
| 701 | QMatrix matrU = matrQ * matrD; |
| 702 | |
| 703 | // in the rare scenario the result is not sufficiently precisely unitary, |
| 704 | // replace it with a trivially unitary diagonal matrix |
| 705 | QMatrix daggerProd = matrU * getConjugateTranspose(matrU); |
| 706 | QMatrix iden = getIdentityMatrix(dim); |
| 707 | if( ! areEqual(daggerProd, iden) ) |
| 708 | matrU = getRandomDiagonalUnitary(numQb); |
| 709 | |
| 710 | return matrU; |
| 711 | } |
| 712 | |
| 713 | vector<QMatrix> getRandomKrausMap(int numQb, int numOps) { |
| 714 | DEMAND( numOps >= 1 ); |
no test coverage detected