| 783 | */ |
| 784 | |
| 785 | bool util_isCPTP(KrausMap map, qreal eps) { |
| 786 | assert_utilsGivenNonZeroEpsilon(eps); |
| 787 | |
| 788 | // use pre-computed CPTP if it exists |
| 789 | if (*(map.isApproxCPTP) != validate_STRUCT_PROPERTY_UNKNOWN_FLAG) |
| 790 | return *(map.isApproxCPTP); |
| 791 | |
| 792 | /// @todo |
| 793 | /// if KrausMap is GPU-accelerated, we should maybe |
| 794 | /// instead perform this calculation using the GPU. |
| 795 | /// otherwise, if matrix is large, we should potentially |
| 796 | /// use a multithreaded routine |
| 797 | |
| 798 | *(map.isApproxCPTP) = 1; |
| 799 | |
| 800 | // check whether each element satisfies Identity = sum dagger(m)*m |
| 801 | for (qindex r=0; r<map.numRows; r++) { |
| 802 | for (qindex c=0; c<map.numRows; c++) { |
| 803 | |
| 804 | // calculate (r,c)-th element of sum dagger(m)*m |
| 805 | qcomp elem = 0; |
| 806 | for (int n=0; n<map.numMatrices; n++) |
| 807 | for (qindex k=0; k<map.numRows; k++) |
| 808 | elem += std::conj(map.matrices[n][k][r]) * map.matrices[n][k][c]; |
| 809 | |
| 810 | // fail if too distant from Identity element... |
| 811 | qreal distSquared = std::norm(elem - (r==c)); |
| 812 | if (distSquared > eps) { |
| 813 | |
| 814 | // by recording the result and returning immediately |
| 815 | *(map.isApproxCPTP) = 0; |
| 816 | return *(map.isApproxCPTP); |
| 817 | } |
| 818 | } |
| 819 | } |
| 820 | |
| 821 | // always true by this point |
| 822 | return *(map.isApproxCPTP); |
| 823 | } |
| 824 | |
| 825 | // T can be qcomp*** or vector<vector<vector<qcomp>>> |
| 826 | template <typename T> |
no test coverage detected