| 2296 | // T can be CompMatr, DiagMatr, FullStateDiagMatr |
| 2297 | template <class T> |
| 2298 | void assertAdditionalHeapMatrixFieldsAreValid(T matr, const char* caller) { |
| 2299 | |
| 2300 | // assert heap pointers are not NULL |
| 2301 | assertThat(mem_isAllocated(matr.isApproxUnitary), report::INVALID_HEAP_FLAG_PTR, caller); |
| 2302 | assertThat(mem_isAllocated(matr.isApproxHermitian), report::INVALID_HEAP_FLAG_PTR, caller); |
| 2303 | assertThat(mem_isAllocated(matr.wasGpuSynced), report::INVALID_HEAP_FLAG_PTR, caller); |
| 2304 | |
| 2305 | // only diagonal matrices (which can be exponentiated) have these additional flags |
| 2306 | if constexpr (!util_isDenseMatrixType<T>()) { |
| 2307 | assertThat(mem_isAllocated(matr.isApproxNonZero), report::INVALID_HEAP_FLAG_PTR, caller); |
| 2308 | assertThat(mem_isAllocated(matr.isStrictlyNonNegative), report::INVALID_HEAP_FLAG_PTR, caller); |
| 2309 | } |
| 2310 | |
| 2311 | tokenSubs vars = {{"${BAD_FLAG}", 0}, {"${UNKNOWN_FLAG}", validate_STRUCT_PROPERTY_UNKNOWN_FLAG}}; |
| 2312 | |
| 2313 | // assert isApproxUnitary has valid value |
| 2314 | int flag = *matr.isApproxUnitary; |
| 2315 | vars["${BAD_FLAG}"] = flag; |
| 2316 | assertThat(flag == 0 || flag == 1 || flag == validate_STRUCT_PROPERTY_UNKNOWN_FLAG, report::INVALID_HEAP_FLAG_VALUE, vars, caller); |
| 2317 | |
| 2318 | // assert isApproxHermitian has valid value |
| 2319 | flag = *matr.isApproxHermitian; |
| 2320 | vars["${BAD_FLAG}"] = flag; |
| 2321 | assertThat(flag == 0 || flag == 1 || flag == validate_STRUCT_PROPERTY_UNKNOWN_FLAG, report::INVALID_HEAP_FLAG_VALUE, vars, caller); |
| 2322 | |
| 2323 | // assert wasGpuSynced has a valid value |
| 2324 | flag = *matr.wasGpuSynced; |
| 2325 | vars["${BAD_FLAG}"] = flag; |
| 2326 | assertThat(flag == 0 || flag == 1, report::INVALID_HEAP_FLAG_VALUE, vars, caller); |
| 2327 | |
| 2328 | // assert isApproxNonZero and isStrictlyNonNegative have valid values (only bound to diagonal matrices) |
| 2329 | if constexpr (!util_isDenseMatrixType<T>()) { |
| 2330 | flag = *matr.isApproxNonZero; |
| 2331 | vars["${BAD_FLAG}"] = flag; |
| 2332 | assertThat(flag == 0 || flag == 1 || flag == validate_STRUCT_PROPERTY_UNKNOWN_FLAG, report::INVALID_HEAP_FLAG_VALUE, vars, caller); |
| 2333 | |
| 2334 | flag = *matr.isStrictlyNonNegative; |
| 2335 | vars["${BAD_FLAG}"] = flag; |
| 2336 | assertThat(flag == 0 || flag == 1 || flag == validate_STRUCT_PROPERTY_UNKNOWN_FLAG, report::INVALID_HEAP_FLAG_VALUE, vars, caller); |
| 2337 | } |
| 2338 | |
| 2339 | // checks whether users have, after destroying their struct, manually set the outer |
| 2340 | // heap-memory pointers to NULL. We do not check inner pointers of 2D structures (which may |
| 2341 | // be too expensive to enumerate), and we cannot determine whether the struct was not validly |
| 2342 | // created because un-initialised structs will have random non-NULL pointers. |
| 2343 | assertThat(mem_isOuterAllocated(matr.cpuElems), report::INVALID_MATRIX_CPU_ELEMS_PTR, caller); |
| 2344 | |
| 2345 | // check whether GPU status/memory pointers are consistent with env |
| 2346 | validate_envIsInit(caller); |
| 2347 | bool envIsGpuAccel = getQuESTEnv().isGpuAccelerated; |
| 2348 | bool matrHasGpuAlloc = mem_isOuterAllocated(util_getGpuMemPtr(matr)); |
| 2349 | |
| 2350 | // FullStateDiagMatr can disable GPU-accel even in GPU-accelerated environments |
| 2351 | if constexpr (util_isFullStateDiagMatr<T>()) { |
| 2352 | if (matr.isGpuAccelerated) { |
| 2353 | assertThat(envIsGpuAccel, report::FULL_STATE_DIAG_MATR_GPU_ACCEL_IN_NON_GPU_ENV, caller); |
| 2354 | assertThat(matrHasGpuAlloc, report::MATRIX_GPU_ELEMS_PTR_UNEXPECTEDLY_NULL, caller); |
| 2355 | } else |
no test coverage detected