Skip to content

Commit 2cf512a

Browse files
tidied heap flags
- renamed KrausMap.isCPTP to KrausMap.isApproxCPTP to reflect its epsilon-dependence, for consistency with isApproxUnitarity, isApproxHermitian and isApproxNonZero - defined util_setFlagToUnknown() so that constant validate_STRUCT_PROPERTY_UNKNOWN_FLAG need not be exposed beyond validation.cpp and utilities.cpp - renamed util_setEpsilonSensitiveStructFieldsToUnknown() to util_setEpsilonSensitiveHeapFlagsToUnknown() to be consistent with related utility functions util_(de)allocEpsilonSensitiveHeapFlag() - made util_allocEpsilonSensitiveHeapFlag() update the ptr to validate_STRUCT_PROPERTY_UNKNOWN_FLAG by default, in case caller forgets to - removed redundant logic from validation.cpp which checked whether KrausMap.isCPTP and PauliStrSum.isApproxHermitian were pre-set - added tests to check that sync() functions (syncKrausMap, syncCompMatr, syncDiagMatr, syncFullStateDiagMatr) clear all property fields (isApproxUnitary, isApproxHermitian, isApproxNonZero, isStrictlyNonNegative) - added tests to check that validation-changes (setValidationEpsilon, setValidationEpsilonToDefault()) clear all epsilon-dependent struct fields - hid "struct not initialised" tests from address sanitizer (which erm disliked them)
1 parent a5e8e3e commit 2cf512a

File tree

13 files changed

+410
-121
lines changed

13 files changed

+410
-121
lines changed

quest/include/channels.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ typedef struct {
102102

103103
// CPTP-ness is determined at validation; 0 or 1, or -1 to indicate unknown. The flag is
104104
// stored in heap so even copies of structs are mutable, but pointer itself is immutable.
105-
int* isCPTP;
105+
int* isApproxCPTP;
106106

107107
} KrausMap;
108108

quest/src/api/channels.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ void freeKrausMap(KrausMap map) {
5454
cpu_deallocMatrixList(map.matrices, map.numRows, map.numMatrices);
5555

5656
// free teeny-tiny heap flag
57-
util_deallocEpsilonSensitiveHeapFlag(map.isCPTP);
57+
util_deallocEpsilonSensitiveHeapFlag(map.isApproxCPTP);
5858

5959
// free superoperator (which may include freeing GPU memory)
6060
freeSuperOp(map.superop);
@@ -88,7 +88,7 @@ bool didAnyLocalAllocsFail(SuperOp op) {
8888

8989
bool didAnyLocalAllocsFail(KrausMap map) {
9090

91-
if (!mem_isAllocated(map.isCPTP))
91+
if (!mem_isAllocated(map.isApproxCPTP))
9292
return true;
9393

9494
if (!mem_isAllocated(map.matrices, map.numRows, map.numMatrices))
@@ -184,15 +184,15 @@ extern "C" KrausMap createKrausMap(int numQubits, int numOperators) {
184184
.matrices = cpu_allocMatrixList(numRows, numOperators), // is or contains nullptr if failed
185185
.superop = allocSuperOp(numQubits), // heap fields are or contain nullptr if failed
186186

187-
.isCPTP = util_allocEpsilonSensitiveHeapFlag(), // nullptr if failed
187+
.isApproxCPTP = util_allocEpsilonSensitiveHeapFlag(), // nullptr if failed
188188
};
189189

190190
// free memory before throwing validation error to avoid memory leaks
191191
freeAllMemoryIfAnyAllocsFailed(out); // sets out.matrices=nullptr if failed
192192
validate_newKrausMapAllocs(out, __func__);
193193

194194
// mark CPTP as unknown; it will be lazily evaluated whene a function asserts CPTP-ness
195-
*(out.isCPTP) = validate_STRUCT_PROPERTY_UNKNOWN_FLAG;
195+
util_setFlagToUnknown(out.isApproxCPTP);
196196

197197
return out;
198198
}
@@ -240,7 +240,7 @@ extern "C" void syncKrausMap(KrausMap map) {
240240

241241
// indicate that we do not know whether the revised map is
242242
// is CPTP; we defer establishing that until a CPTP check
243-
*(map.isCPTP) = validate_STRUCT_PROPERTY_UNKNOWN_FLAG;
243+
util_setFlagToUnknown(map.isApproxCPTP);
244244
}
245245

246246

@@ -299,7 +299,7 @@ void setAndSyncKrausMapElems(KrausMap map, T matrices) {
299299
for (int n=0; n<map.numMatrices; n++)
300300
cpu_copyMatrix(map.matrices[n], matrices[n], map.numRows);
301301

302-
// update the superoperator, including its GPU memory, and its isCPTP flag
302+
// update the superoperator, including its GPU memory, and its isApproxCPTP flag
303303
syncKrausMap(map);
304304
}
305305

quest/src/api/debug.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,14 @@ void setValidationEpsilon(qreal eps) {
9090
validate_newEpsilonValue(eps, __func__);
9191

9292
validateconfig_setEpsilon(eps);
93-
util_setEpsilonSensitiveStructFieldsToUnknown();
93+
util_setEpsilonSensitiveHeapFlagsToUnknown();
9494
}
9595

9696
void setValidationEpsilonToDefault() {
9797
validate_envIsInit(__func__);
9898

9999
validateconfig_setEpsilonToDefault();
100-
util_setEpsilonSensitiveStructFieldsToUnknown();
100+
util_setEpsilonSensitiveHeapFlagsToUnknown();
101101
}
102102

103103
qreal getValidationEpsilon() {

quest/src/api/matrices.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -187,14 +187,14 @@ template <class T>
187187
void setInitialHeapFlags(T matr) {
188188

189189
// set initial propreties of the newly created matrix to unknown
190-
*(matr.isApproxUnitary) = validate_STRUCT_PROPERTY_UNKNOWN_FLAG;
191-
*(matr.isApproxHermitian) = validate_STRUCT_PROPERTY_UNKNOWN_FLAG;
190+
util_setFlagToUnknown(matr.isApproxUnitary);
191+
util_setFlagToUnknown(matr.isApproxHermitian);
192192

193193
// only diagonal matrices (which can be exponentiated)
194194
// have these additional fields
195195
if constexpr (!util_isDenseMatrixType<T>()) {
196-
*(matr.isApproxNonZero) = validate_STRUCT_PROPERTY_UNKNOWN_FLAG;
197-
*(matr.isStrictlyNonNegative) = validate_STRUCT_PROPERTY_UNKNOWN_FLAG;
196+
util_setFlagToUnknown(matr.isApproxNonZero);
197+
util_setFlagToUnknown(matr.isStrictlyNonNegative);
198198
}
199199

200200
// indicate that GPU memory has not yet been synchronised
@@ -228,8 +228,9 @@ extern "C" CompMatr createCompMatr(int numQubits) {
228228

229229
// allocate flags in the heap so that struct copies are mutable
230230
.isApproxUnitary = util_allocEpsilonSensitiveHeapFlag(), // nullptr if failed
231-
.isApproxHermitian = util_allocEpsilonSensitiveHeapFlag(), // nullptr if failed
232-
.wasGpuSynced = cpu_allocHeapFlag(), // nullptr if failed
231+
.isApproxHermitian = util_allocEpsilonSensitiveHeapFlag(),
232+
233+
.wasGpuSynced = cpu_allocHeapFlag(), // nullptr if failed
233234

234235
.cpuElems = cpu_allocAndInitMatrixWrapper(cpuMem, numRows), // nullptr if failed
235236
.cpuElemsFlat = cpuMem,
@@ -345,14 +346,14 @@ void markMatrixAsSynced(T matr) {
345346

346347
// indicate that we do not know the revised matrix properties;
347348
// we defer establishing that until validation needs to check them
348-
*(matr.isApproxUnitary) = validate_STRUCT_PROPERTY_UNKNOWN_FLAG;
349-
*(matr.isApproxHermitian) = validate_STRUCT_PROPERTY_UNKNOWN_FLAG;
349+
util_setFlagToUnknown(matr.isApproxUnitary);
350+
util_setFlagToUnknown(matr.isApproxHermitian);
350351

351352
// only diagonal matrices (which can be exponentiated)
352353
// have these additional fields
353354
if constexpr (!util_isDenseMatrixType<T>()) {
354-
*(matr.isApproxNonZero) = validate_STRUCT_PROPERTY_UNKNOWN_FLAG;
355-
*(matr.isStrictlyNonNegative) = validate_STRUCT_PROPERTY_UNKNOWN_FLAG;
355+
util_setFlagToUnknown(matr.isApproxNonZero);
356+
util_setFlagToUnknown(matr.isStrictlyNonNegative);
356357
}
357358
}
358359

quest/src/api/paulis.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ extern "C" PauliStrSum createPauliStrSum(PauliStr* strings, qcomp* coeffs, qinde
401401

402402
// otherwise copy given data into new heap structure, and set initial flags
403403
cpu_copyPauliStrSum(out, strings, coeffs);
404-
*(out.isApproxHermitian) = validate_STRUCT_PROPERTY_UNKNOWN_FLAG;
404+
util_setFlagToUnknown(out.isApproxHermitian);
405405

406406
return out;
407407
}

quest/src/core/utilities.cpp

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -729,16 +729,16 @@ bool util_isCPTP(KrausMap map, qreal eps) {
729729
assert_utilsGivenNonZeroEpsilon(eps);
730730

731731
// use pre-computed CPTP if it exists
732-
if (*(map.isCPTP) != validate_STRUCT_PROPERTY_UNKNOWN_FLAG)
733-
return *(map.isCPTP);
732+
if (*(map.isApproxCPTP) != validate_STRUCT_PROPERTY_UNKNOWN_FLAG)
733+
return *(map.isApproxCPTP);
734734

735735
/// @todo
736736
/// if KrausMap is GPU-accelerated, we should maybe
737737
/// instead perform this calculation using the GPU.
738738
/// otherwise, if matrix is large, we should potentially
739739
/// use a multithreaded routine
740740

741-
*(map.isCPTP) = true;
741+
*(map.isApproxCPTP) = 1;
742742

743743
// check whether each element satisfies Identity = sum dagger(m)*m
744744
for (qindex r=0; r<map.numRows; r++) {
@@ -755,14 +755,14 @@ bool util_isCPTP(KrausMap map, qreal eps) {
755755
if (distSquared > eps) {
756756

757757
// by recording the result and returning immediately
758-
*(map.isCPTP) = false;
759-
return *(map.isCPTP);
758+
*(map.isApproxCPTP) = 0;
759+
return *(map.isApproxCPTP);
760760
}
761761
}
762762
}
763763

764764
// always true by this point
765-
return *(map.isCPTP);
765+
return *(map.isApproxCPTP);
766766
}
767767

768768
// T can be qcomp*** or vector<vector<vector<qcomp>>>
@@ -813,16 +813,27 @@ void util_setSuperoperator(qcomp** superop, qcomp*** matrices, int numMatrices,
813813

814814
std::list<int*> globalStructFieldPtrs(0);
815815

816+
void util_setFlagToUnknown(int* ptr) {
817+
818+
*ptr = validate_STRUCT_PROPERTY_UNKNOWN_FLAG;
819+
}
820+
816821
int* util_allocEpsilonSensitiveHeapFlag() {
817822

818823
int* ptr = cpu_allocHeapFlag(); // may be nullptr
819824

820-
// if allocated successfully, record the ptr, so that
821-
// we can set it to -1 when user changes epsilon
822-
if (mem_isAllocated(ptr))
823-
globalStructFieldPtrs.push_back(ptr);
825+
// if failed to alloc, do not add to global list;
826+
// caller will handle validation/error messaging
827+
if (!mem_isAllocated(ptr))
828+
return ptr;
829+
830+
// caller should set ptr to the default "unknown"
831+
// value, but we do so here too just to be safe
832+
util_setFlagToUnknown(ptr);
824833

825-
// caller will handle nullptr
834+
// store the pointer so that we can reset the
835+
// value to "unknown" when epsilon is changed
836+
globalStructFieldPtrs.push_back(ptr);
826837
return ptr;
827838
}
828839

@@ -837,10 +848,10 @@ void util_deallocEpsilonSensitiveHeapFlag(int* ptr) {
837848
cpu_deallocHeapFlag(ptr);
838849
}
839850

840-
void util_setEpsilonSensitiveStructFieldsToUnknown() {
851+
void util_setEpsilonSensitiveHeapFlagsToUnknown() {
841852

842853
for (auto ptr : globalStructFieldPtrs)
843-
*ptr = validate_STRUCT_PROPERTY_UNKNOWN_FLAG;
854+
util_setFlagToUnknown(ptr);
844855
}
845856

846857

quest/src/core/utilities.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,9 @@ int* util_allocEpsilonSensitiveHeapFlag();
315315

316316
void util_deallocEpsilonSensitiveHeapFlag(int* ptr);
317317

318-
void util_setEpsilonSensitiveStructFieldsToUnknown();
318+
void util_setEpsilonSensitiveHeapFlagsToUnknown();
319+
320+
void util_setFlagToUnknown(int* ptr);
319321

320322

321323

quest/src/core/validation.cpp

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -598,10 +598,10 @@ namespace report {
598598

599599

600600
string INVALID_KRAUS_MAP_IS_CPTP_PTR =
601-
"The 'isCPTP' field of the given KrausMap was a NULL pointer, instead of the expected pointer to persistent heap memory. This suggests the KrausMap was already destroyed and had its fields overwritten by the user.";
601+
"The 'isApproxCPTP' field of the given KrausMap was a NULL pointer, instead of the expected pointer to persistent heap memory. This suggests the KrausMap was already destroyed and had its fields overwritten by the user.";
602602

603603
string INVALID_KRAUS_MAP_IS_CPTP_FLAG =
604-
"The 'isCPTP' field of the given Kraus map had invalid value ${BAD_FLAG}, suggesting it was manually modified. Valid values are 0, 1 and ${UNKNOWN_FLAG} (to indicate that unitarity is not yet known, deferring evaluation) although this need never be modified by the user.";
604+
"The 'isApproxCPTP' field of the given Kraus map had invalid value ${BAD_FLAG}, suggesting it was manually modified. Valid values are 0, 1 and ${UNKNOWN_FLAG} (to indicate that unitarity is not yet known, deferring evaluation) although this need never be modified by the user.";
605605

606606

607607
string INVALID_KRAUS_MAPS_SUPER_OP_CPU_MEM_PTR =
@@ -1122,7 +1122,7 @@ qreal REDUCTION_EPSILON_FACTOR = 100;
11221122
* e.g. checking unitarity/hermiticity/CPTP-ness. This is only
11231123
* consulted when global_isValidationEnabled=true, and can be
11241124
* separately disabled by setting epsilon=0, in which case
1125-
* permanent properties of structs (like .isCPTP) will not be
1125+
* permanent properties of structs (like .isApproxCPTP) will not be
11261126
* overwritten (so will stay validate_STRUCT_PROPERTY_UNKNOWN_FLAG)
11271127
*/
11281128

@@ -2809,7 +2809,7 @@ void validate_newKrausMapAllocs(KrausMap map, const char* caller) {
28092809
{"${NUM_QUBITS}", map.numQubits}};
28102810

28112811
// assert the teeny-tiny heap flag was alloc'd
2812-
assertAllNodesAgreeThat(mem_isAllocated(map.isCPTP), report::NEW_HEAP_FLAG_ALLOC_FAILED, {{"${NUM_BYTES}", sizeof(*(map.isCPTP))}}, caller);
2812+
assertAllNodesAgreeThat(mem_isAllocated(map.isApproxCPTP), report::NEW_HEAP_FLAG_ALLOC_FAILED, {{"${NUM_BYTES}", sizeof(*(map.isApproxCPTP))}}, caller);
28132813

28142814
// assert that the superoperator itself was allocated (along with its own heap fields)
28152815
bool isInKrausMap = true;
@@ -2909,11 +2909,11 @@ void validate_krausMapFields(KrausMap map, const char* caller) {
29092909
// check only outer CPU matrix list is allocated, to avoid expensive enumerating of matrices/rows
29102910
assertThat(mem_isOuterAllocated(map.matrices), report::INVALID_KRAUS_MAP_MATRIX_LIST_MEM_PTR, caller);
29112911

2912-
// assert isCPTP heap flag allocated, and that is has a valid value
2913-
assertThat(mem_isAllocated(map.isCPTP), report::INVALID_HEAP_FLAG_PTR, caller);
2912+
// assert isApproxCPTP heap flag allocated, and that is has a valid value
2913+
assertThat(mem_isAllocated(map.isApproxCPTP), report::INVALID_HEAP_FLAG_PTR, caller);
29142914

29152915
// and that its value is a boolean
2916-
int flag = *map.isCPTP;
2916+
int flag = *map.isApproxCPTP;
29172917
bool valid = flag == 0 || flag == 1 || flag == validate_STRUCT_PROPERTY_UNKNOWN_FLAG;
29182918
tokenSubs moreVars = {{"${BAD_FLAG}", flag}, {"${UNKNOWN_FLAG}", validate_STRUCT_PROPERTY_UNKNOWN_FLAG}};
29192919
assertThat(valid, report::INVALID_HEAP_FLAG_VALUE, moreVars, caller);
@@ -2941,15 +2941,12 @@ void validate_krausMapIsCPTP(KrausMap map, const char* caller) {
29412941
validate_krausMapFields(map, caller);
29422942
validate_krausMapIsSynced(map, caller);
29432943

2944-
// avoid expensive CPTP check (and do not overwrite .isCPTP) if validation is anyway disabled
2944+
// avoid expensive CPTP check (and do not overwrite .isApproxCPTP) if validation is anyway disabled
29452945
if (isNumericalValidationDisabled())
29462946
return;
29472947

2948-
// evaluate CPTPness if it isn't already known
2949-
if (*(map.isCPTP) == validate_STRUCT_PROPERTY_UNKNOWN_FLAG)
2950-
*(map.isCPTP) = util_isCPTP(map, global_validationEpsilon);
2951-
2952-
assertThat(*(map.isCPTP), report::KRAUS_MAP_NOT_CPTP, caller);
2948+
// use existing CPTPness or calculate afresh
2949+
assertThat(util_isCPTP(map, global_validationEpsilon), report::KRAUS_MAP_NOT_CPTP, caller);
29532950
}
29542951

29552952
void validate_krausMapMatchesTargets(KrausMap map, int numTargets, const char* caller) {
@@ -3203,11 +3200,8 @@ void validate_pauliStrSumIsHermitian(PauliStrSum sum, const char* caller) {
32033200
if (isNumericalValidationDisabled())
32043201
return;
32053202

3206-
// ensure hermiticity is known (if not; compute it)
3207-
if (*(sum.isApproxHermitian) == validate_STRUCT_PROPERTY_UNKNOWN_FLAG)
3208-
*(sum.isApproxHermitian) = util_isHermitian(sum, global_validationEpsilon);
3209-
3210-
assertThat(*(sum.isApproxHermitian), report::PAULI_STR_SUM_NOT_HERMITIAN, caller);
3203+
// consult existing Hermiticity or compute it afresh
3204+
assertThat(util_isHermitian(sum, global_validationEpsilon), report::PAULI_STR_SUM_NOT_HERMITIAN, caller);
32113205
}
32123206

32133207
void validate_pauliStrSumTargets(PauliStrSum sum, Qureg qureg, const char* caller) {

0 commit comments

Comments
 (0)