| 2511 | // type T can be DiagMatr, FullStateDiagMatr |
| 2512 | template <class T> |
| 2513 | void assertMatrExpIsHermitian(T matr, qreal exponent, const char* caller) { |
| 2514 | |
| 2515 | // below validation can invoke communication and expensive data processing, |
| 2516 | // even when numerical-epsilon is zero, which we avoid when all validation is off. |
| 2517 | // we always proceed however if merely numerical-validation is disabled (via zero |
| 2518 | // epsilon) because some checks below are epsilon independent |
| 2519 | if (!global_isValidationEnabled) |
| 2520 | return; |
| 2521 | |
| 2522 | // the calling function will use the std::pow(qreal,qreal) overload, rather than |
| 2523 | // std::pow(qcomp,qcomp), passing in the real components of matr and the given |
| 2524 | // exponent. As such, the result must never be complex which instead becomes NaN. |
| 2525 | // The validation below ergo ensures that pow(a,b) is always real and stable. |
| 2526 | // All validations upon 'matr' consult existing properties (like .isHermitian), |
| 2527 | // computing them fresh and recording them if not already known |
| 2528 | |
| 2529 | // the matrix itself must be approximately real, since we consult only its reals. |
| 2530 | // this also validates the matrix fields, and whether GPU-matrices are synced |
| 2531 | validate_matrixIsHermitian(matr, caller); |
| 2532 | |
| 2533 | // when the exponent is not STRICTLY an integer, it is required that every matrix |
| 2534 | // elem's real component is STRICTLY positive, so that real-pow doesn't create NaNs. |
| 2535 | // this can overwrite matr.isStrictlyNonNegative even when validation epsilon=0 |
| 2536 | if (!util_isStrictlyInteger(exponent)) |
| 2537 | assertThat(util_isStrictlyNonNegative(matr), report::HERMITIAN_DIAG_MATR_NEGATIVE_WHILE_EXPONENT_NOT_INTEGER, caller); |
| 2538 | |
| 2539 | // divergences don't break Hermiticity per se, but do sabotage numerical accuracy. |
| 2540 | validate_matrixExpIsNonDiverging(matr, qcomp(exponent,0), caller); |
| 2541 | |
| 2542 | // the final plausible scenario we have not checked is when both the matrix elem |
| 2543 | // and exponent are strictly positive but very close to zero. In that case, the |
| 2544 | // result tends to 1 so does not vanish or blow up unexpectedly. All fine! |
| 2545 | } |
| 2546 | |
| 2547 | void validate_matrixExpIsHermitian(DiagMatr m, qreal p, const char* caller) { assertMatrExpIsHermitian(m, p, caller); } |
| 2548 | void validate_matrixExpIsHermitian(FullStateDiagMatr m, qreal p, const char* caller) { assertMatrExpIsHermitian(m, p, caller); } |
no test coverage detected