| 538 | |
| 539 | |
| 540 | void localiser_densmatr_getAmps(qcomp** outAmps, Qureg qureg, qindex startRow, qindex startCol, qindex numRows, qindex numCols) { |
| 541 | assert_localiserGivenDensMatr(qureg); |
| 542 | |
| 543 | /// @todo improve the performance! |
| 544 | /// this function simply serially invokes localiser_statevec_getAmps() upon |
| 545 | /// every indicated column, for simplicity, and since we believe this function |
| 546 | /// will only ever be called upon tractably small sub-matrices. After all, the |
| 547 | /// user is likely to serially process outAmps themselves. Our method incurs the |
| 548 | /// below insignificant performance penalties: |
| 549 | /// - we must allocate temporary memory that is the same size as outAmps, |
| 550 | /// but transposed, because we cannot make a pointer to a column of outAmps |
| 551 | /// in order to invoke localiser_statevec_getAmps() thereupon. Thereafter, we |
| 552 | /// serially populate outAmps with the transposed temp memory. |
| 553 | /// - every invocation of localiser_statevec_getAmps() invokes synchronous |
| 554 | /// GPU-CPU copying (a total of #numCols), whereas a bespoke implementation |
| 555 | /// could perform each non-contiguous copy asynchronously then wait |
| 556 | /// - every invocation invokes synchronous MPI broadcasting, whereas a bespoke |
| 557 | /// method could asynch all per-col broadcasts before a final wait |
| 558 | /// A custom function to remedy these issues is complicated; it would involve |
| 559 | /// e.g. exposing MPI_Request outside of comm_routines.cpp (unacceptable for |
| 560 | /// compiler compatibility), or having comm_routines cache un-fulfilled asynch |
| 561 | /// requests, etc. |
| 562 | |
| 563 | vector<vector<qcomp>> tempOut; |
| 564 | util_tryAllocMatrix(tempOut, numCols, numRows, error_localiserFailedToAllocTempMemory); // transposed dim of outAmps |
| 565 | |
| 566 | for (qindex c=0; c<numCols; c++) { |
| 567 | qindex flatInd = util_getGlobalFlatIndex(qureg, startRow, startCol + c); |
| 568 | localiser_statevec_getAmps(tempOut[c].data(), qureg, flatInd, numRows); |
| 569 | } |
| 570 | |
| 571 | // serially overwrite outAmps = transpose(tempOut) |
| 572 | for (qindex r=0; r<numRows; r++) |
| 573 | for (qindex c=0; c<numCols; c++) |
| 574 | outAmps[r][c] = tempOut[c][r]; // writes contiguous, reads strided |
| 575 | } |
| 576 | |
| 577 | |
| 578 | void localiser_fullstatediagmatr_getElems(qcomp* outElems, FullStateDiagMatr matr, qindex globalStartInd, qindex globalNumElems) { |
no test coverage detected