QkObs
typedef struct QkObs QkObsAn observable over Pauli bases that stores its data in a qubit-sparse format.
Mathematics
This observable represents a sum over strings of the Pauli operators and Pauli-eigenstate projectors, with each term weighted by some complex number. That is, the full observable is
for complex numbers and single-qubit operators acting on qubit from a restricted alphabet . The sum over is the sum of the individual terms, and the tensor product produces the operator strings. The alphabet of allowed single-qubit operators that the are drawn from is the Pauli operators and the Pauli-eigenstate projection operators. Explicitly, these are:
| Operator | QkBitTerm | Numeric value | 
|---|---|---|
| (identity) | Not stored. | Not stored. | 
| (Pauli X) | QkBitTerm_X | 0b0010(2) | 
| (Pauli Y) | QkBitTerm_Y | 0b0011(3) | 
| (Pauli Z) | QkBitTerm_Z | 0b0001(1) | 
| (projector to positive eigenstate of X) | QkBitTerm_Plus | 0b1010(10) | 
| (projector to negative eigenstate of X) | QkBitTerm_Minus | 0b0110(6) | 
| (projector to positive eigenstate of Y) | QkBitTerm_Right | 0b1011(11) | 
| (projector to negative eigenstate of Y) | QkBitTerm_Left | 0b0111(7) | 
| (projector to positive eigenstate of Z) | QkBitTerm_Zero | 0b1001(9) | 
| (projector to negative eigenstate of Z) | QkBitTerm_One | 0b0101(5) | 
Due to allowing both the Paulis and their projectors, the allowed alphabet forms an overcomplete basis of the operator space. This means that there is not a unique summation to represent a given observable. As a consequence, comparison requires additional care and using qk_obs_canonicalize on two mathematically equivalent observables might not result in the same representation.
QkObs uses its particular overcomplete basis with the aim of making “efficiency of measurement” equivalent to “efficiency of representation”. For example, the observable  can be efficiently measured on hardware with simple  measurements, but can only be represented in terms of Paulis as , which requires  stored terms. QkObs requires only a single term to store this. The downside to this is that it is impractical to take an arbitrary matrix and find the best QkObs representation. You typically will want to construct a QkObs directly, rather than trying to decompose into one.
Representation
The internal representation of a QkObs stores only the non-identity qubit operators. This makes it significantly more efficient to represent observables such as ; QkObs requires an amount of memory linear in the total number of qubits. The terms are stored compressed, similar in spirit to the compressed sparse row format of sparse matrices. In this analogy, the terms of the sum are the “rows”, and the qubit terms are the “columns”, where an absent entry represents the identity rather than a zero. More explicitly, the representation is made up of four contiguous arrays:
| Attribute accessible by | Length | Description | 
|---|---|---|
| qk_obs_coeffs | The complex scalar multiplier for each term. | |
| qk_obs_bit_terms | Each of the non-identity single-qubit terms for all of the operators, in order. These correspond to the non-identity in the sum description, where the entries are stored in order of increasing first, and in order of increasing within each term. | |
| qk_obs_indices | The corresponding qubit () for each of the bit terms. QkObsrequires that this list is term-wise sorted, and algorithms can rely on this invariant being upheld. | |
| qk_obs_boundaries | The indices that partition the bit terms and indices into complete terms. For term number , its complex coefficient is stored at index i, and its non-identity single-qubit operators and their corresponding qubits are in the range[boundaries[i], boundaries[i+1])in the bit terms and indices, respectively. The boundaries always have an explicit 0 as their first element. | 
The length parameter  is the number of terms in the sum and can be queried using qk_obs_num_terms. The parameter  is the total number of non-identity single-qubit terms and can be queried using qk_obs_len.
As illustrative examples:
- in the case of a zero operator, the boundaries are length 1 (a single 0) and all other vectors are empty.
- in the case of a fully simplified identity operator, the boundaries are {0, 0}, the coefficients have a single entry, and both the bit terms and indices are empty.
- for the operator , the boundaries are {0, 2, 4}, the coeffs are{1.0, -1.0}, the bit terms are{QkBitTerm_Z, QkBitTerm_Z, QkBitTerm_Y, QkBitTerm_X}and the indices are{0, 2, 1, 3}. The operator might act on more than four qubits, depending on the the number of qubits (seeqk_obs_num_qubits). Note that the single-bit terms and indices are sorted into termwise sorted order.
These cases are not special, they’re fully consistent with the rules and should not need special handling.
Canonical ordering
For any given mathematical observable, there are several ways of representing it with QkObs. For example, the same set of single-bit terms and their corresponding indices might appear multiple times in the observable. Mathematically, this is equivalent to having only a single term with all the coefficients summed. Similarly, the terms of the sum in a QkObs can be in any order while representing the same observable, since addition is commutative (although while floating-point addition is not associative, QkObs makes no guarantees about the summation order).
These two categories of representation degeneracy can cause the operator equality, qk_obs_equal, to claim that two observables are not equal, despite representing the same object. In these cases, it can be convenient to define some canonical form, which allows observables to be compared structurally. You can put a QkObs in canonical form by using the qk_obs_canonicalize function. The precise ordering of terms in canonical ordering is not specified, and may change between versions of Qiskit. Within the same version of Qiskit, however, you can compare two observables structurally by comparing their simplified forms.
If you wish to account for floating-point tolerance in the comparison, it is safest to use a recipe such as:
bool equivalent(QkObs *left, QkObs *right, double tol) {
  // compare a canonicalized version of left - right to the zero observable
  QkObs *neg_right = qk_obs_multiply(right, &(QkComplex64){-1, 0});
  QkObs *diff = qk_obs_add(left, neg_right);
  QkObs *canonical = qk_obs_canonicalize(diff, tol);
 
  QkObs *zero = qk_obs_zero(qk_obs_num_qubits(left));
  bool equiv = qk_obs_equal(diff, zero);
  // free all temporary variables
  qk_obs_free(neg_right);
  qk_obs_free(diff);
  qk_obs_free(canonical);
  qk_obs_free(zero);
  return equiv;
}The canonical form produced by qk_obs_canonicalize alone will not universally detect all observables that are equivalent due to the over-complete basis alphabet.
Indexing
Individual observable sum terms in QkObs can be accessed via qk_obs_term and return objects of type QkObsTerm. These terms then contain fields with the coefficient of the term, its bit terms, indices and the number of qubits it is defined on. Together with the information of the number of terms, you can iterate over all observable terms as
size_t num_terms = qk_obs_num_terms(obs);  // obs is QkObs*
for (size_t i = 0; i < num_terms; i++) {
    QkObsTerm term;  // allocate term on stack
    int exit = qk_obs_term(obs, i, &term);  // get the term (exit > 0 upon index errors)
    // do something with the term...
}Populating a QkObsTerm via qk_obs_term will reference data of the original QkObs. Modifying the bit terms or indices will change the observable and can leave it in an incoherent state.
Construction
QkObs can be constructed by initializing an empty observable (with qk_obs_zero) and iteratively adding terms (with qk_obs_add_term). Alternatively, an observable can be constructed from “raw” data (with qk_obs_new) if all internal data is specified. This requires care to ensure the data is coherent and results in a valid observable.
| Function | Summary | 
|---|---|
| qk_obs_zero | Construct an empty observable on a given number of qubits. | 
| qk_obs_identity | Construct the identity observable on a given number of qubits. | 
| qk_obs_new | Construct an observable from the raw data arrays. | 
Mathematical manipulation
QkObs supports fundamental arithmetic operations in between observables or with scalars. You can:
- add two observables using qk_obs_add
- multiply by a complex number with qk_obs_multiply
- compose (multiply) two observables via qk_obs_composeandqk_obs_compose_map
Functions
qk_obs_zero
QkObs *qk_obs_zero(uint32_t num_qubits)
Construct the zero observable (without any terms).
Example
QkObs *zero = qk_obs_zero(100);Parameters
num_qubits – The number of qubits the observable is defined on.
Returns
A pointer to the created observable.
qk_obs_identity
QkObs *qk_obs_identity(uint32_t num_qubits)
Construct the identity observable.
Example
QkObs *identity = qk_obs_identity(100);Parameters
num_qubits – The number of qubits the observable is defined on.
Returns
A pointer to the created observable.
qk_obs_new
QkObs *qk_obs_new(uint32_t num_qubits, uint64_t num_terms, uint64_t num_bits, QkComplex64 *coeffs, QkBitTerm *bit_terms, uint32_t *indices, size_t *boundaries)
Construct a new observable from raw data.
Example
// define the raw data for the 100-qubit observable |01><01|_{0, 1} - |+-><+-|_{98, 99}
uint32_t num_qubits = 100;
uint64_t num_terms = 2;  // we have 2 terms: |01><01|, -1 * |+-><+-|
uint64_t num_bits = 4; // we have 4 non-identity bits: 0, 1, +, -
QkComplex64 coeffs = {1, -1};
QkBitTerm bits[4] = {QkBitTerm_Zero, QkBitTerm_One, QkBitTerm_Plus, QkBitTerm_Minus};
 
uint32_t indices[4] = {0, 1, 98, 99};  // <-- e.g. {1, 0, 99, 98} would be invalid
size_t boundaries[3] = {0, 2, 4};
QkObs *obs = qk_obs_new(
    num_qubits, num_terms, num_bits, &coeffs, bits, indices, boundaries
);Safety
Behavior is undefined if any of the following conditions are violated:
- coeffsis a pointer to a- QkComplex64array of length- num_terms
- bit_termsis a pointer to an array of valid- QkBitTermelements of length- num_bits
- indicesis a pointer to a- uint32_tarray of length- num_bits, which is term-wise sorted in strict ascending order, and every element is smaller than- num_qubits
- boundariesis a pointer to a- size_tarray of length- num_terms + 1, which is sorted in ascending order, the first element is 0 and the last element is smaller than- num_terms
Parameters
- num_qubits – The number of qubits the observable is defined on.
- num_terms – The number of terms.
- num_bits – The total number of non-identity bit terms.
- coeffs – A pointer to the first element of the coefficients array, which has length num_terms.
- bit_terms – A pointer to the first element of the bit terms array, which has length num_bits.
- indices – A pointer to the first element of the indices array, which has length num_bits. Note that, per term, these must be sorted incrementally.
- boundaries – A pointer to the first element of the boundaries array, which has length num_terms + 1.
Returns
If the input data was coherent and the construction successful, the result is a pointer to the observable. Otherwise a null pointer is returned.
qk_obs_free
void qk_obs_free(QkObs *obs)
Free the observable.
Example
QkObs *obs = qk_obs_zero(100);
qk_obs_free(obs);Safety
Behavior is undefined if obs is not either null or a valid pointer to a QkObs.
Parameters
obs – A pointer to the observable to free.
qk_obs_add_term
QkExitCode qk_obs_add_term(QkObs *obs, const QkObsTerm *cterm)
Add a term to the observable.
Example
uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);
 
QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits};
 
int exit_code = qk_obs_add_term(obs, &term);Safety
Behavior is undefined if any of the following is violated:
- obsis a valid, non-null pointer to a- QkObs
- ctermis a valid, non-null pointer to a- QkObsTerm
Parameters
- obs – A pointer to the observable.
- cterm – A pointer to the term to add.
Returns
An exit code. This is >0 if the term is incoherent or adding the term fails.
qk_obs_term
QkExitCode qk_obs_term(QkObs *obs, uint64_t index, QkObsTerm *out)
Get an observable term by reference.
A QkObsTerm contains pointers to the indices and bit terms in the term, which can be used to modify the internal data of the observable. This can leave the observable in an incoherent state and should be avoided, unless great care is taken. It is generally safer to construct a new observable instead of attempting in-place modifications.
Example
QkObs *obs = qk_obs_identity(100);
QkObsTerm term;
int exit_code = qk_obs_term(obs, 0, &term);
// out-of-bounds indices return an error code
// int error = qk_obs_term(obs, 12, &term);Safety
Behavior is undefined if any of the following is violated
- obsis a valid, non-null pointer to a- QkObs
- outis a valid, non-null pointer to a- QkObsTerm
Parameters
- obs – A pointer to the observable.
- index – The index of the term to get.
- out – A pointer to a QkObsTermused to return the observable term.
Returns
An exit code.
qk_obs_num_terms
size_t qk_obs_num_terms(const QkObs *obs)
Get the number of terms in the observable.
Example
QkObs *obs = qk_obs_identity(100);
size_t num_terms = qk_obs_num_terms(obs);  // num_terms==1Safety
Behavior is undefined obs is not a valid, non-null pointer to a QkObs.
Parameters
obs – A pointer to the observable.
Returns
The number of terms in the observable.
qk_obs_num_qubits
uint32_t qk_obs_num_qubits(const QkObs *obs)
Get the number of qubits the observable is defined on.
Example
QkObs *obs = qk_obs_identity(100);
uint32_t num_qubits = qk_obs_num_qubits(obs);  // num_qubits==100Safety
Behavior is undefined obs is not a valid, non-null pointer to a QkObs.
Parameters
obs – A pointer to the observable.
Returns
The number of qubits the observable is defined on.
qk_obs_len
size_t qk_obs_len(const QkObs *obs)
Get the number of bit terms/indices in the observable.
Example
QkObs *obs = qk_obs_identity(100);
size_t len = qk_obs_len(obs);  // len==0, as there are no non-trivial bit termsSafety
Behavior is undefined obs is not a valid, non-null pointer to a QkObs.
Parameters
obs – A pointer to the observable.
Returns
The number of terms in the observable.
qk_obs_coeffs
QkComplex64 *qk_obs_coeffs(QkObs *obs)
Get a pointer to the coefficients.
This can be used to read and modify the observable’s coefficients. The resulting pointer is valid to read for qk_obs_num_terms(obs) elements of QkComplex64.
Example
QkObs *obs = qk_obs_identity(100);
size_t num_terms = qk_obs_num_terms(obs);
QkComplex64 *coeffs = qk_obs_coeffs(obs);
 
for (size_t i = 0; i < num_terms; i++) {
    printf("%f + i%f\n", coeffs[i].re, coeffs[i].im);
}Safety
Behavior is undefined obs is not a valid, non-null pointer to a QkObs.
Parameters
obs – A pointer to the observable.
Returns
A pointer to the coefficients.
qk_obs_indices
uint32_t *qk_obs_indices(QkObs *obs)
Get a pointer to the indices.
This can be used to read and modify the observable’s indices. The resulting pointer is valid to read for qk_obs_len(obs) elements of size uint32_t.
Example
uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);
 
QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t term_indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, term_indices, num_qubits};
qk_obs_add_term(obs, &term);
 
size_t len = qk_obs_len(obs);
uint32_t *indices = qk_obs_indices(obs);
 
for (size_t i = 0; i < len; i++) {
    printf("index %i: %i\n", i, indices[i]);
}qk_obs_free(obs);Safety
Behavior is undefined obs is not a valid, non-null pointer to a QkObs.
Parameters
obs – A pointer to the observable.
Returns
A pointer to the indices.
qk_obs_boundaries
size_t *qk_obs_boundaries(QkObs *obs)
Get a pointer to the term boundaries.
This can be used to read and modify the observable’s term boundaries. The resulting pointer is valid to read for qk_obs_num_terms(obs) + 1 elements of size size_t.
Example
uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);
 
QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits};
qk_obs_add_term(obs, &term);
 
size_t num_terms = qk_obs_num_terms(obs);
size_t *boundaries = qk_obs_boundaries(obs);
 
for (size_t i = 0; i < num_terms + 1; i++) {
    printf("boundary %i: %i\n", i, boundaries[i]);
}Safety
Behavior is undefined obs is not a valid, non-null pointer to a QkObs.
Parameters
obs – A pointer to the observable.
Returns
A pointer to the boundaries.
qk_obs_bit_terms
QkBitTerm *qk_obs_bit_terms(QkObs *obs)
Get a pointer to the bit terms.
This can be used to read and modify the observable’s bit terms. The resulting pointer is valid to read for qk_obs_len(obs) elements of size uint8_t.
Example
uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);
 
QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits};
qk_obs_add_term(obs, &term);
 
size_t len = qk_obs_len(obs);
QkBitTerm *bits = qk_obs_bit_terms(obs);
 
for (size_t i = 0; i < len; i++) {
    printf("bit term %i: %i\n", i, bits[i]);
}
 
qk_obs_free(obs);Safety
Behavior is undefined obs is not a valid, non-null pointer to a QkObs, or if invalid valus are written into the resulting QkBitTerm pointer.
Parameters
obs – A pointer to the observable.
Returns
A pointer to the bit terms.
qk_obs_multiply
QkObs *qk_obs_multiply(const QkObs *obs, const QkComplex64 *coeff)
Multiply the observable by a complex coefficient.
Example
QkObs *obs = qk_obs_identity(100);
QkComplex64 coeff = {2, 0};
QkObs *result = qk_obs_multiply(obs, &coeff);Safety
Behavior is undefined if any of the following is violated
- obsis a valid, non-null pointer to a- QkObs
- coeffis a valid, non-null pointer to a- QkComplex64
Parameters
- obs – A pointer to the observable.
- coeff – The coefficient to multiply the observable with.
qk_obs_add
QkObs *qk_obs_add(const QkObs *left, const QkObs *right)
Add two observables.
Example
QkObs *left = qk_obs_identity(100);
QkObs *right = qk_obs_zero(100);
QkObs *result = qk_obs_add(left, right);Safety
Behavior is undefined if left or right are not valid, non-null pointers to QkObs\ s.
Parameters
- left – A pointer to the left observable.
- right – A pointer to the right observable.
Returns
A pointer to the result left + right.
qk_obs_compose
QkObs *qk_obs_compose(const QkObs *first, const QkObs *second)
Compose (multiply) two observables.
Example
QkObs *first = qk_obs_zero(100);
QkObs *second = qk_obs_identity(100);
QkObs *result = qk_obs_compose(first, second);Safety
Behavior is undefined if first or second are not valid, non-null pointers to QkObs\ s.
Parameters
- first – One observable.
- second – The other observable.
Returns
first.compose(second) which equals the observable result = second @ first, in terms of the matrix multiplication @.
qk_obs_compose_map
QkObs *qk_obs_compose_map(const QkObs *first, const QkObs *second, const uint32_t *qargs)
Compose (multiply) two observables according to a custom qubit order.
Notably, this allows composing two observables of different size.
Example
QkObs *first = qk_obs_zero(100);
QkObs *second = qk_obs_identity(100);
QkObs *result = qk_obs_compose(first, second);Safety
To call this function safely
- firstand- secondmust be valid, non-null pointers to- QkObs\ s
- qargsmust point to an array of- uint32_t, readable for- qk_obs_num_qubits(second)elements (meaning the number of qubits in- second)
Parameters
- first – One observable.
- second – The other observable. The number of qubits must match the length of qargs.
- qargs – The qubit arguments specified which indices in firstto associate with the ones insecond.
Returns
first.compose(second) which equals the observable result = second @ first, in terms of the matrix multiplication @.
qk_obs_apply_layout
QkExitCode qk_obs_apply_layout(QkObs *obs, const uint32_t *layout, uint32_t num_qubits)
Apply a new qubit layout to the observable.
The layout is set by an array layout of new indices, specifying that qubit at current index i is relabelled to index layout[i]. The number of qubits the observable acts on can be extended by setting a larger num_qubits than the current observable has.
Example
This interface allows to relabel and extend the qubit indices:
QkObs *obs = qk_obs_zero(4);
 
// add a term to the observable
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t qubits[3] = {1, 2, 3};
complex double coeff = 1;
QkObsTerm term = {coeff, 3, bit_terms, qubits, 4};
qk_obs_add_term(obs, &term);
 
uint32_t layout[3] = {0, 10, 9};  // qubit mapping is: 0->0, 1->10, 2->9
uint32_t num_output_qubits = 11;
int exit = qk_obs_apply_layout(obs, layout, num_output_qubits);In a compiler workflow, this function can conveniently be used to apply a QkTranspileLayout* obtained from a transpiler pass, called transpile_layout in the following example:
// get the number of output qubits
uint32_t num_output_qubits = qk_transpile_layout_num_output_qubits(transpile_layout);
 
// get the layout including the ancillas (hence the ``false`` in the function call)
uint32_t *layout = malloc(sizeof(uint32_t) * num_output_qubits);
qk_transpile_layout_final_layout(transpile_layout, false, layout);
 
// apply the layout
int exit = qk_obs_apply_layout(obs, layout, num_output_qubits);
 
// free the layout array
free(layout);Safety
Behavior is undefined if obs is not a valid, non-null pointer to QkObs or if layout is not a valid, non-null pointer to a sequence of qk_obs_num_qubits(obs) consecutive elements of uint32_t.
Parameters
- obs – A pointer to the observable, this observable will be modified in place upon success. Check the exit code to ensure the layout was correctly applied.
- layout – A pointer to the layout. The pointer must point to an array to qk_obs_num_qubits(obs)elements of typeuint32_t. Each element must have values in[0, num_qubits).
- num_qubits – The number of output qubits.
Returns
An exit code.
- QkExitCode_Successupon success
- QkExitCode_DuplicteIndexErrorif duplicate qubit indices were found
- QkExitCode_MismatchedQubitsif- num_qubitsis smaller than the number of qubits in the observable
- QkExitCode_IndexErrorfor any other index errors, such as invalid values in- layout.
qk_obs_canonicalize
QkObs *qk_obs_canonicalize(const QkObs *obs, double tol)
Calculate the canonical representation of the observable.
Example
QkObs *iden = qk_obs_identity(100);
QkObs *two = qk_obs_add(iden, iden);
 
double tol = 1e-6;
QkObs *canonical = qk_obs_canonicalize(two, tol);Safety
Behavior is undefined obs is not a valid, non-null pointer to a QkObs.
Parameters
- obs – A pointer to the observable.
- tol – The tolerance below which coefficients are considered to be zero.
Returns
The canonical representation of the observable.
qk_obs_copy
QkObs *qk_obs_copy(const QkObs *obs)
Copy the observable.
Example
QkObs *original = qk_obs_identity(100);
QkObs *copied = qk_obs_copy(original);Safety
Behavior is undefined obs is not a valid, non-null pointer to a QkObs.
Parameters
obs – A pointer to the observable.
Returns
A pointer to a copy of the observable.
qk_obs_equal
bool qk_obs_equal(const QkObs *obs, const QkObs *other)
Compare two observables for equality.
Note that this does not compare mathematical equality, but data equality. This means that two observables might represent the same observable but not compare as equal.
Example
QkObs *observable = qk_obs_identity(100);
QkObs *other = qk_obs_identity(100);
bool are_equal = qk_obs_equal(observable, other);Safety
Behavior is undefined if obs or other are not valid, non-null pointers to QkObs\ s.
Parameters
- obs – A pointer to one observable.
- other – A pointer to another observable.
Returns
true if the observables are equal, false otherwise.
qk_obs_str
char *qk_obs_str(const QkObs *obs)
Return a string representation of a QkObs.
Example
QkObs *obs = qk_obs_identity(100);
char *string = qk_obs_str(obs);
qk_str_free(string);Safety
Behavior is undefined obs is not a valid, non-null pointer to a QkObs.
The string must not be freed with the normal C free, you must use qk_str_free to free the memory consumed by the String. Not calling qk_str_free will lead to a memory leak.
Do not change the length of the string after it’s returned (by writing a nul byte somewhere inside the string or removing the final one), although values can be mutated.
Parameters
obs – A pointer to the QkObs to get the string for.
Returns
A pointer to a nul-terminated char array of the string representation for obs
qk_str_free
void qk_str_free(char *string)
Free a string representation.
Safety
Behavior is undefined if str is not a pointer returned by qk_obs_str or qk_obsterm_str.
Parameters
string – A pointer to the returned string representation from qk_obs_str or qk_obsterm_str.
qk_obs_to_python
PyObject *qk_obs_to_python(const QkObs *obs)
Convert to a Python-space SparseObservable.
Safety
Behavior is undefined if obs is not a valid, non-null pointer to a QkObs.
It is assumed that the thread currently executing this function holds the Python GIL this is required to create the Python object returned by this function.
Parameters
obs – The C-space QkObs pointer.
Returns
A Python object representing the SparseObservable.