QfTransferVertexOperator¶
-
struct QfTransferVertexOperator¶
A transfer-vertex operator.
Note
This is an opaque data structure to the C API whose internals are implemented entirely in Rust. The remainder of this page describes the design and related functions to work with this struct.
Definition¶
This operator is defined in terms of the transfer-vertex (\(T_{jk}\), \(V_j\)) operators:
where \(E_{jk}\) is an edge operator of the QfEdgeVertexOperator and these
individual terms fulfill the following mixed fermionic-bosonic commutation relations for
\(j \lt k \lt l \lt m\): [1]
Caution
Unlike the edge operators, where \(E_{kj} = -E_{jk}\) makes the two orientations two
representations of a single operator, \(T_{jk}\) and \(T_{kj}\) are different
operators. The order of the two index arrays is therefore significant, and there is no
orientation convention to normalize — which is why
qf_transfer_op_normal_ordered() takes no ascending parameter where
qf_edge_op_normal_ordered() does.
We can abuse the notation a little bit and define \(V_j = T_{jj}\) which reflects how the internal data structure of this operator works. This makes the definition of the entire operator the following:
where \(lr\) indexes the involved operator terms and \(c_i\) is the (complex) coefficient making up the linear combination of products. The indices \(l\) and \(r\) can take any value between 0 and the number of fermionic modes acted upon by the operator minus 1.
We will refer to \(T_{lr}\) as generalized transfer operators.
Implementation¶
This struct stores the terms and coefficients in multiple sparse vectors, akin to the compressed sparse row format commonly used for sparse matrices. More concretely, a single operator contains 4 arrays:
|
A vector of complex coefficients consisting of two 64-bit floating point numbers. |
|
A vector of 32-bit integers storing the left fermionic mode indices (\(l\)). |
|
A vector of 32-bit integers storing the right fermionic mode indices (\(r\)). |
|
A vector of integers indicating the boundaries between terms. |
Fermionic modes indexed by left_indices and right_indices are considered spinless. The two
index arrays always have the same length, since every generator is identified by exactly one
(left, right) pair; this is why the constructor takes a single num_indices length for both.
Note
You can access read-only borrows of these internal arrays via their respective functions:
The returned pointers stay valid only until the operator is modified or freed, and must not be freed by the caller.
This data structure allows for very efficient construction and manipulation of operators.
However, it implies that duplicate terms might be contained in an operator at any moment.
These must be resolved manually through the use of qf_transfer_op_simplify().
Construction¶
A new operator can be constructed directly by specifying the corresponding arrays outlined above.
Alternatively, an empty QfTransferVertexOperator can be initialized with
qf_transfer_op_zero() and terms can be added iteratively via
qf_transfer_op_add_term().
Constructs a new operator from the provided arrays. |
|
Constructs the additive identity operator. |
|
Constructs the multiplicative identity operator. |
|
Adds a term to an existing |
Note
A QfTransferVertexOperator can be freed with qf_transfer_op_free().
Arithmetics¶
The following functions provide arithmetic manipulation:
Adds two operators together. |
|
Multiplies an operator by a scalar. |
|
Composes two operators with each other. |
|
Returns the Hermitian conjugate operator. |
Manipulation¶
The following functions provide operator manipulation logic:
Removes terms with small coefficient magnitudes. |
|
Returns an equivalent but simplified operator. |
|
Returns an equivalent operator with normal ordered terms. |
|
Relabels the modes of an operator. |
Properties¶
The following functions exist to check certain properties of an operator.
Returns whether an operator is Hermitian. |
|
Returns the number of terms in this operator. |
Mapping¶
The following functions map this operator into another representation:
Maps to a |
|
Maps to a |
|
Maps to a |
Members¶
-
QfTransferVertexOperator *qf_transfer_op_new(uint64_t num_terms, uint64_t num_indices, const QkComplex64 *coeffs, const uint32_t *left_indices, const uint32_t *right_indices, const uint32_t *boundaries)¶
Constructs a new operator.
Any of the pointer arguments can be
NULLif and only if their corresponding length is zero.A generator with equal indices is a vertex operator, \(V_j\); one with differing indices is a transfer operator, \(T_{jk}\).
Caution
Unlike the edge operators, \(T_{jk}\) and \(T_{kj}\) are different operators, not two representations of one. The order of the two index arrays is therefore significant.
Example¶
1// this builds `1.0 + (-1.0) * V(0) T(0,1)` 2uint64_t num_terms = 2; 3uint64_t num_indices = 2; 4uint32_t left_indices[2] = {0, 0}; 5uint32_t right_indices[2] = {0, 1}; 6QkComplex64 coeffs[2] = {{1.0, 0.0}, {-1.0, 0.0}}; 7uint32_t boundaries[3] = {0, 0, 2}; 8QfTransferVertexOperator *op = qf_transfer_op_new(num_terms, num_indices, coeffs, 9 left_indices, right_indices, boundaries);
- Parameters:
num_terms – The number of terms in the operator.
num_indices – The number of generators summed over all terms. Both index arrays have this same length, since every generator is identified by exactly one
(left, right)pair.coeffs – A pointer to an array of term coefficients. The length of this array should be
num_terms.left_indices – A pointer to an array of left-hand mode indices over all terms. The length of this array should be
num_indices.right_indices – A pointer to an array of right-hand mode indices over all terms. The length of this array should be
num_indices.boundaries – A pointer to an array of the boundaries between terms. The length of this array should be
num_terms + 1.
- Returns:
A pointer to the created operator.
-
void qf_transfer_op_free(QfTransferVertexOperator *op)¶
Frees an existing operator.
Example¶
1QfTransferVertexOperator *op = qf_transfer_op_one(); 2qf_transfer_op_free(op);
- Parameters:
op – A pointer to the transfer-vertex operator to be freed.
-
void qf_transfer_op_get_coeffs(const QfTransferVertexOperator *op, QkComplex64 **coeffs_out, uint64_t *coeffs_len)¶
Provides read-only access to the operator’s coefficients.
See also
The explanation of the internal data structure, here.
Example¶
1uint64_t num_terms = 2; 2QkComplex64 coeffs[2] = {{1.0, 0.0}, {0.0, -1.0}}; 3uint32_t boundaries[3] = {0, 0, 0}; 4QfTransferVertexOperator *op = 5 qf_transfer_op_new(num_terms, 0, coeffs, NULL, NULL, boundaries); 6 7QkComplex64 *coeffs_out; 8uint64_t coeffs_len; 9 10qf_transfer_op_get_coeffs(op, &coeffs_out, &coeffs_len); 11 12assert(coeffs_len == 2);
Note
This function borrows the operator’s internal buffer rather than copying it. The returned pointer stays valid only until the operator is modified or freed; do not free it yourself.
- Parameters:
op – A pointer to the transfer-vertex operator whose coefficients to access.
coeffs_out – A pointer to the array of complex values into which to write the coefficients.
coeffs_len – A pointer to the integer into which to write the length of the output array.
-
void qf_transfer_op_get_left_indices(const QfTransferVertexOperator *op, uint32_t **left_indices_out, uint64_t *left_indices_len)¶
Provides read-only access to the operator’s left-hand mode indices.
See also
The explanation of the internal data structure, here.
Example¶
1uint64_t num_terms = 1; 2uint64_t num_indices = 2; 3uint32_t left_indices[2] = {0, 0}; 4uint32_t right_indices[2] = {0, 1}; 5QkComplex64 coeffs[1] = {{1.0, 0.0}}; 6uint32_t boundaries[2] = {0, 2}; 7QfTransferVertexOperator *op = qf_transfer_op_new(num_terms, num_indices, coeffs, 8 left_indices, right_indices, boundaries); 9 10uint32_t *left_out; 11uint64_t left_len; 12 13qf_transfer_op_get_left_indices(op, &left_out, &left_len); 14 15assert(left_len == 2);
Note
This function borrows the operator’s internal buffer rather than copying it. The returned pointer stays valid only until the operator is modified or freed; do not free it yourself.
- Parameters:
op – A pointer to the transfer-vertex operator whose left indices to access.
left_indices_out – A pointer to the array of integers into which to write the indices.
left_indices_len – A pointer to the integer into which to write the length of the output array.
-
void qf_transfer_op_get_right_indices(const QfTransferVertexOperator *op, uint32_t **right_indices_out, uint64_t *right_indices_len)¶
Provides read-only access to the operator’s right-hand mode indices.
See also
The explanation of the internal data structure, here.
Example¶
1uint64_t num_terms = 1; 2uint64_t num_indices = 2; 3uint32_t left_indices[2] = {0, 0}; 4uint32_t right_indices[2] = {0, 1}; 5QkComplex64 coeffs[1] = {{1.0, 0.0}}; 6uint32_t boundaries[2] = {0, 2}; 7QfTransferVertexOperator *op = qf_transfer_op_new(num_terms, num_indices, coeffs, 8 left_indices, right_indices, boundaries); 9 10uint32_t *right_out; 11uint64_t right_len; 12 13qf_transfer_op_get_right_indices(op, &right_out, &right_len); 14 15assert(right_len == 2);
Note
This function borrows the operator’s internal buffer rather than copying it. The returned pointer stays valid only until the operator is modified or freed; do not free it yourself.
- Parameters:
op – A pointer to the transfer-vertex operator whose right indices to access.
right_indices_out – A pointer to the array of integers into which to write the indices.
right_indices_len – A pointer to the integer into which to write the length of the output array.
-
void qf_transfer_op_get_boundaries(const QfTransferVertexOperator *op, size_t **boundaries_out, uint64_t *boundaries_len)¶
Provides read-only access to the indices indicating the boundaries between operator terms.
See also
The explanation of the internal data structure, here.
Example¶
1uint64_t num_terms = 1; 2uint64_t num_indices = 2; 3uint32_t left_indices[2] = {0, 0}; 4uint32_t right_indices[2] = {0, 1}; 5QkComplex64 coeffs[1] = {{1.0, 0.0}}; 6uint32_t boundaries[2] = {0, 2}; 7QfTransferVertexOperator *op = qf_transfer_op_new(num_terms, num_indices, coeffs, 8 left_indices, right_indices, boundaries); 9 10size_t *boundaries_out; 11uint64_t boundaries_len; 12 13qf_transfer_op_get_boundaries(op, &boundaries_out, &boundaries_len); 14 15assert(boundaries_len == 2);
Note
This function borrows the operator’s internal buffer rather than copying it. The returned pointer stays valid only until the operator is modified or freed; do not free it yourself.
- Parameters:
op – A pointer to the transfer-vertex operator whose boundaries to access.
boundaries_out – A pointer to the array of integers into which to write the boundaries.
boundaries_len – A pointer to the integer into which to write the length of the output array.
-
uint32_t qf_transfer_op_num_support(const QfTransferVertexOperator *op)¶
Gets the size of the support of an operator.
Use this to size the output buffer of
qf_transfer_op_get_support(), which does not report a length of its own.Example¶
1uint32_t left_indices[3] = {2, 0, 2}; 2uint32_t right_indices[3] = {2, 1, 2}; 3QkComplex64 coeffs[2] = {{1.0, 0.0}, {1.0, 0.0}}; 4uint32_t boundaries[3] = {0, 2, 3}; 5QfTransferVertexOperator *op = 6 qf_transfer_op_new(2, 3, coeffs, left_indices, right_indices, boundaries); 7 8uint32_t num_support = qf_transfer_op_num_support(op); 9 10assert(num_support == 3);
- Parameters:
op – A pointer to the transfer-vertex operator whose support size to get.
- Returns:
The number of distinct mode indices acted upon by the operator.
-
void qf_transfer_op_get_support(const QfTransferVertexOperator *op, uint32_t *support_out)¶
Gets the support of an operator, i.e. the mode indices acted upon by the operator.
The indices are written in ascending order, and every index appears exactly once no matter how many terms act upon it.
Example¶
1uint32_t left_indices[3] = {2, 0, 2}; 2uint32_t right_indices[3] = {2, 1, 2}; 3QkComplex64 coeffs[2] = {{1.0, 0.0}, {1.0, 0.0}}; 4uint32_t boundaries[3] = {0, 2, 3}; 5QfTransferVertexOperator *op = 6 qf_transfer_op_new(2, 3, coeffs, left_indices, right_indices, boundaries); 7 8uint32_t num_support = qf_transfer_op_num_support(op); 9uint32_t *support_out = malloc(num_support * sizeof(uint32_t)); 10 11qf_transfer_op_get_support(op, support_out); 12 13assert(support_out[0] == 0); 14assert(support_out[1] == 1); 15assert(support_out[2] == 2); 16 17free(support_out);
Note
Unlike the other getters, this does not hand out a pointer into the operator: the support is computed on demand rather than stored, so the caller provides the output buffer. Query its required length with
qf_transfer_op_num_support()first.Note
Both the left and the right indices of every generalized transfer operator contribute to the support.
- Parameters:
op – A pointer to the transfer-vertex operator whose support to get.
support_out – A pointer to the integer array into which to write the support. It must be sized to at least :c:func:
qf_transfer_op_num_supportelements.
-
QfTransferVertexOperator *qf_transfer_op_zero(void)¶
Constructs the additive identity operator.
Adding the operator that is constructed by this method to another one has no effect.
Example¶
1QfTransferVertexOperator *zero = qf_transfer_op_zero(); 2 3QfTransferVertexOperator *op_plus_zero = qf_transfer_op_add(op, zero); 4 5assert(qf_transfer_op_equal(op, op_plus_zero));
- Returns:
A pointer to the created operator.
-
QfTransferVertexOperator *qf_transfer_op_one(void)¶
Constructs the multiplicative identity operator.
Composing the operator that is constructed by this method with another one has no effect.
Example¶
1QfTransferVertexOperator *one = qf_transfer_op_one(); 2 3QfTransferVertexOperator *op_times_one = qf_transfer_op_compose(op, one); 4 5assert(qf_transfer_op_equal(op, op_times_one));
- Returns:
A pointer to the created operator.
-
bool qf_transfer_op_has_groups(const QfTransferVertexOperator *op)¶
Checks whether an operator has its
groupsattribute set.See also
The explanation on Group operator terms: use the operator structure.
Example¶
1QfTransferVertexOperator *op = ...; 2 3bool has_groups = qf_transfer_op_has_groups(op);
- Parameters:
op – A pointer to the transfer-vertex operator to check.
- Returns:
Whether the operator tracks group indices.
-
uint32_t qf_transfer_op_num_groups(const QfTransferVertexOperator *op)¶
Gets the number of groups from an operator.
See also
The explanation on Group operator terms: use the operator structure.
Example¶
1QfTransferVertexOperator *op = ...; 2 3uint32_t num_groups = qf_transfer_op_num_groups(op);
Note
The number of groups is evaluated lazily as the largest occurring group index plus 1.
- Parameters:
op – A pointer to the transfer-vertex operator whose number of groups to get.
- Returns:
The number of group indices from the operator’s
groupsattribute.
-
void qf_transfer_op_get_groups(const QfTransferVertexOperator *op, uint32_t **groups_out, uint64_t *groups_len)¶
Gets the group indices for all operator terms.
See also
The explanation on Group operator terms: use the operator structure.
Example¶
1QfTransferVertexOperator *op = ...; 2uint32_t *groups_out; 3uint64_t groups_len; 4 5qf_transfer_op_get_groups(op, &groups_out, &groups_len);
Note
This function borrows the operator’s internal buffer rather than copying it. The returned pointer stays valid only until the operator is modified or freed; do not free it yourself.
- Parameters:
op – A pointer to the transfer-vertex operator whose group indices to get.
groups_out – A pointer to the integer array into which to write the group indices.
groups_len – A pointer to the integer into which to write the length of the output array.
-
QfExitCode qf_transfer_op_set_groups(QfTransferVertexOperator *op, const uint32_t *groups_in, uint64_t groups_len)¶
Sets the
groupsattribute of the provided operator.The length is validated here because nothing downstream re-checks it: too few indices would silently drop the trailing terms wherever terms are iterated together with their groups, and too many would make
qf_transfer_op_num_groups()report groups that no term carries.See also
The explanation on Group operator terms: use the operator structure.
Example¶
1QfTransferVertexOperator *op = ...; 2 3uint32_t num_terms = 4; 4uint32_t groups_in[4] = {0, 1, 0, 1}; 5qf_transfer_op_set_groups(op, groups_in, num_terms);
- Parameters:
op – A pointer to the transfer-vertex operator whose
groupsattribute to write.groups_in – A pointer to the
groupsinteger array to write into the operator.groups_len – The number of terms in the
groups_inarray.
- Returns:
An exit code.
QfExitCode_Successupon successQfExitCode_ValueErrorifgroups_lendiffers from the number of terms in the operator
-
void qf_transfer_op_del_groups(QfTransferVertexOperator *op)¶
Deletes the
groupsattribute from the provided operator.See also
The explanation on Group operator terms: use the operator structure.
Example¶
1QfTransferVertexOperator *op = ...; 2 3qf_transfer_op_del_groups(op);
- Parameters:
op – A pointer to the transfer-vertex operator whose
groupsattribute to delete.
-
void qf_transfer_op_split_out_groups(const QfTransferVertexOperator *op, const uint32_t *group_indices, uint64_t num_indices, QfTransferVertexOperator **group_ops_out)¶
Splits this operator into a list of new operators based on its
groupsattribute.A duplicate index in
group_indicesis written once per occurrence ingroup_ops_out. Requesting only a small number of groups out of a much larger total is significantly cheaper than requesting all of them, since terms belonging to a group that is not requested are skipped rather than appended anywhere.See also
The explanation on Group operator terms: use the operator structure.
Example¶
1QfTransferVertexOperator *op = ...; 2 3uint32_t groups_in[4] = {0, 1, 0, 1}; 4qf_transfer_op_set_groups(op, groups_in, 4); 5 6// build every group, in index order 7QfTransferVertexOperator *group_ops[2]; 8qf_transfer_op_split_out_groups(op, NULL, 0, group_ops); 9 10// build only group 1 11uint32_t group_indices[1] = {1}; 12QfTransferVertexOperator *group_op[1]; 13qf_transfer_op_split_out_groups(op, group_indices, 1, group_op);
- Parameters:
op – A pointer to the transfer-vertex operator whose
groupsto split out.group_indices – A pointer to the array of group indices for which to build operators, in the desired output order. May be
NULL, in which case every group is built, in index order (equivalent to passing every index from0to :c:func:qf_transfer_op_num_groups- 1).num_indices – The number of indices in the
group_indicesarray. Ignored ifgroup_indicesisNULL.group_ops_out – A pointer to the array of :c:struct:
QfTransferVertexOperatorinto which to write the operators for each requested group. Must be sized tonum_indiceswhengroup_indicesis non-NULL, or to :c:func:qf_transfer_op_num_groupswhen it isNULL.
-
void qf_transfer_op_add_term(QfTransferVertexOperator *op, uint64_t num_indices, const uint32_t *left_indices, const uint32_t *right_indices, const QkComplex64 *coeff)¶
Adds a term to an existing operator.
Any of the pointer arguments can be
NULLif and only if their corresponding length is zero.Caution
This function resets the operator’s
groupsattribute toNULL.Example¶
1QfTransferVertexOperator *one = qf_transfer_op_one(); 2 3QfTransferVertexOperator *op = qf_transfer_op_zero(); 4QkComplex64 coeff = {1.0, 0.0}; 5 6qf_transfer_op_add_term(op, 0, NULL, NULL, &coeff); 7 8assert(qf_transfer_op_equal(op, one));
- Parameters:
op – A pointer to the transfer-vertex operator to be modified.
num_indices – The length of both index arrays.
left_indices – A pointer to an array of left-hand mode indices. The length of this array should be
num_indices.right_indices – A pointer to an array of right-hand mode indices. The length of this array should be
num_indices.coeff – A pointer to the complex coefficient.
-
QfTransferVertexOperator *qf_transfer_op_add(const QfTransferVertexOperator *left, const QfTransferVertexOperator *right)¶
Adds two operators together.
Example¶
1QfTransferVertexOperator *one = qf_transfer_op_one(); 2QfTransferVertexOperator *zero = qf_transfer_op_zero(); 3 4QfTransferVertexOperator *result = qf_transfer_op_add(one, zero); 5 6assert(qf_transfer_op_equal(result, one));
- Parameters:
left – A pointer to the left operator.
right – A pointer to the right operator.
- Returns:
A pointer to the resulting operator.
-
QfTransferVertexOperator *qf_transfer_op_scaled_add(const QfTransferVertexOperator *left, const QfTransferVertexOperator *right, const QkComplex64 *factor)¶
Adds two operators together, scaling the coefficients of the right one.
This fuses the scaling into the addition, which avoids building a fully scaled copy of
rightjust to append it. Passing a factor of-1therefore subtracts, which is why no separate subtraction function is provided.Example¶
1QfTransferVertexOperator *one = qf_transfer_op_one(); 2QfTransferVertexOperator *other = qf_transfer_op_one(); 3 4// Subtracting via a factor of -1 leaves the two terms cancelling each other out. 5QkComplex64 factor = {-1.0, 0.0}; 6QfTransferVertexOperator *result = qf_transfer_op_scaled_add(one, other, &factor); 7 8QfTransferVertexOperator *simplified = qf_transfer_op_simplify(result, 1e-10); 9assert(qf_transfer_op_len(simplified) == 0);
Note
Like
qf_transfer_op_add(), this appends the terms ofrightwithout combining them with those ofleft, so the result tracks no group indices. Callqf_transfer_op_simplify()to collect equal terms afterwards.- Parameters:
left – A pointer to the left operator.
right – A pointer to the right operator.
factor – A pointer to the factor to scale the right operator’s coefficients with.
- Returns:
A pointer to the resulting operator,
left + factor * right.
-
void qf_transfer_op_add_inplace(QfTransferVertexOperator *left, const QfTransferVertexOperator *right)¶
Adds an operator into another one, in place.
The in-place counterpart of
qf_transfer_op_add(), which saves copyingleftinto a freshly allocated result.Caution
This function resets the operator’s
groupsattribute toNULL.Example¶
1QfTransferVertexOperator *left = qf_transfer_op_one(); 2QfTransferVertexOperator *right = qf_transfer_op_one(); 3 4qf_transfer_op_add_inplace(left, right); 5 6assert(qf_transfer_op_len(left) == 2);
- Parameters:
left – A pointer to the operator to add into.
right – A pointer to the operator to add.
-
void qf_transfer_op_scaled_add_inplace(QfTransferVertexOperator *left, const QfTransferVertexOperator *right, const QkComplex64 *factor)¶
Adds an operator into another one in place, scaling the coefficients of the right one.
The in-place counterpart of
qf_transfer_op_scaled_add(), computingleft + factor * rightwithout allocating a result. As there, a factor of-1subtracts.Caution
This function resets the operator’s
groupsattribute toNULL.Example¶
1QfTransferVertexOperator *left = qf_transfer_op_one(); 2QfTransferVertexOperator *right = qf_transfer_op_one(); 3 4// Subtract, leaving two terms that cancel each other out. 5QkComplex64 factor = {-1.0, 0.0}; 6qf_transfer_op_scaled_add_inplace(left, right, &factor); 7 8QfTransferVertexOperator *simplified = qf_transfer_op_simplify(left, 1e-10); 9assert(qf_transfer_op_len(simplified) == 0);
- Parameters:
left – A pointer to the operator to add into.
right – A pointer to the operator to add.
factor – A pointer to the factor to scale the right operator’s coefficients with.
-
void qf_transfer_op_mul_inplace(QfTransferVertexOperator *op, const QkComplex64 *scalar)¶
Multiplies an operator by a scalar, in place.
The in-place counterpart of
qf_transfer_op_mul(), which saves copying the operator into a freshly allocated result.Example¶
1QfTransferVertexOperator *op = qf_transfer_op_one(); 2QkComplex64 scalar = {2.0, 0.0}; 3 4qf_transfer_op_mul_inplace(op, &scalar);
Note
Unlike the two in-place additions above, this preserves the
groupsattribute: scaling the coefficients leaves the number of terms, and hence the one-index-per-term invariant, untouched.- Parameters:
op – A pointer to the operator to scale.
scalar – A pointer to the scalar.
-
QfTransferVertexOperator *qf_transfer_op_mul(const QfTransferVertexOperator *op, const QkComplex64 *scalar)¶
Multiplies an operator by a scalar.
Example¶
1QfTransferVertexOperator *one = qf_transfer_op_one(); 2QkComplex64 coeff = {2.0, 0.0}; 3QfTransferVertexOperator *result = qf_transfer_op_mul(one, &coeff); 4 5QfTransferVertexOperator *expected = qf_transfer_op_zero(); 6qf_transfer_op_add_term(expected, 0, NULL, NULL, &coeff); 7 8assert(qf_transfer_op_equal(result, expected));
- Parameters:
op – A pointer to the operator.
scalar – A pointer to the scalar.
- Returns:
A pointer to the resulting operator.
-
QfTransferVertexOperator *qf_transfer_op_compose(const QfTransferVertexOperator *left, const QfTransferVertexOperator *right)¶
Composes two operators with each other.
Example¶
1QfTransferVertexOperator *one = qf_transfer_op_one(); 2QfTransferVertexOperator *zero = qf_transfer_op_zero(); 3 4QfTransferVertexOperator *result = qf_transfer_op_compose(one, zero); 5 6assert(qf_transfer_op_equal(result, zero));
Note
The composition of two operators tracks no groups, even when both operands do.
- Parameters:
left – A pointer to the left operator.
right – A pointer to the right operator.
- Returns:
A pointer to
left.compose(right), which equals the operatorresult = right @ leftin terms of the matrix multiplication@. In other words,rightis applied first. To obtainleft @ right, swap the arguments.
-
QfTransferVertexOperator *qf_transfer_op_adjoint(const QfTransferVertexOperator *op)¶
Returns the Hermitian conjugate (or adjoint) of an operator.
This affects the terms and coefficients as follows:
the generators in each term reverse their order
the coefficients are complex conjugated
Example¶
1QfTransferVertexOperator *op = qf_transfer_op_zero(); 2QkComplex64 coeff = {0.0, 1.0}; 3qf_transfer_op_add_term(op, 0, NULL, NULL, &coeff); 4 5QfTransferVertexOperator *adjoint = qf_transfer_op_adjoint(op); 6 7QfTransferVertexOperator *expected = qf_transfer_op_zero(); 8QkComplex64 coeff_adj = {0.0, -1.0}; 9qf_transfer_op_add_term(expected, 0, NULL, NULL, &coeff_adj); 10 11assert(qf_transfer_op_equal(adjoint, expected));
Note
Reversing the operator string is essential: the transfer and vertex generators anticommute when they share an index, so
BA != ABin general.- Parameters:
op – A pointer to the operator.
- Returns:
A pointer to the created operator.
-
void qf_transfer_op_ichop(QfTransferVertexOperator *op, double atol)¶
Removes terms whose coefficient magnitude lies below the provided threshold.
Caution
This functions truncates coefficients greedily! If the acted upon operator might contain separate coefficients for duplicate terms consider calling
qf_transfer_op_simplify()instead!Example¶
1QfTransferVertexOperator *op = qf_transfer_op_zero(); 2QkComplex64 coeff = {1e-8, 0.0}; 3qf_transfer_op_add_term(op, 0, NULL, NULL, &coeff); 4 5qf_transfer_op_ichop(op, 1e-6); 6 7QfTransferVertexOperator *expected = qf_transfer_op_zero(); 8 9assert(qf_transfer_op_equal(op, expected));
- Parameters:
op – A pointer to the operator.
atol – The absolute tolerance for coefficient truncation.
-
QfTransferVertexOperator *qf_transfer_op_simplify(const QfTransferVertexOperator *op, double atol)¶
Returns an equivalent but simplified operator.
The simplification process first sums all coefficients that belong to equal terms and then only retains those whose total coefficient exceeds the specified tolerance (just like
qf_transfer_op_ichop()).When an operator has been arithmetically manipulated or constructed in a way that does not guarantee unique terms, this method should be called before applying any method that filters numerically small coefficients to avoid loss of information.
Example¶
1QfTransferVertexOperator *op = qf_transfer_op_zero(); 2QkComplex64 coeff = {1e-5, 0.0}; 3for (int i = 0; i < 100; i++) { 4 qf_transfer_op_add_term(op, 0, NULL, NULL, &coeff); 5} 6 7QfTransferVertexOperator *canon = qf_transfer_op_simplify(op, 1e-4); 8 9assert(qf_transfer_op_len(canon) == 1);
Note
This groups terms by their exact stored index arrays. Call
qf_transfer_op_normal_ordered()first to bring mathematically equal terms into a common form.- Parameters:
op – A pointer to the transfer-vertex operator to be simplified.
atol – The absolute tolerance for coefficient truncation.
- Returns:
An equivalent but simplified operator.
-
QfTransferVertexOperator *qf_transfer_op_normal_ordered(const QfTransferVertexOperator *op, bool reduce)¶
Returns an equivalent operator with normal ordered terms.
The
reduceflag contracts adjacent generators. There are exactly two rules: \(V_j V_j = 1\) and \(T_{jk} T_{jk} = 1/4\) (two identical adjacent factors contract to a scalar), and \(T_{jk} T_{kj} = -\frac{1}{4} V_j V_k\) (two anti-parallel transfer operators become a pair of vertex operators).Example¶
1// `T(0,1) T(1,0)` reduces to `-1/4 V(0) V(1)` 2QfTransferVertexOperator *op = qf_transfer_op_zero(); 3uint32_t left[2] = {0, 1}; 4uint32_t right[2] = {1, 0}; 5QkComplex64 coeff = {4.0, 0.0}; 6qf_transfer_op_add_term(op, 2, left, right, &coeff); 7 8QfTransferVertexOperator *ordered = qf_transfer_op_normal_ordered(op, true); 9 10QfTransferVertexOperator *expected = qf_transfer_op_zero(); 11uint32_t left_exp[2] = {0, 1}; 12uint32_t right_exp[2] = {0, 1}; 13QkComplex64 coeff_exp = {-1.0, 0.0}; 14qf_transfer_op_add_term(expected, 2, left_exp, right_exp, &coeff_exp); 15 16assert(qf_transfer_op_equal(ordered, expected));
Note
Unlike
qf_edge_op_normal_ordered(), this function takes noascendingparameter. There is no orientation convention to fix: \(T_{jk}\) and \(T_{kj}\) are different operators rather than two representations of one.Note
There is no fusion rule. Two transfer operators sharing a single mode never collapse into one, so a product like \(T_{jk} T_{jl}\) cannot be shortened.
- Parameters:
op – A pointer to the operator.
reduce – Whether to contract adjacent generators via the algebra’s identities.
- Returns:
A pointer to the created operator.
-
bool qf_transfer_op_is_hermitian(const QfTransferVertexOperator *op, double atol)¶
Checks whether an operator is Hermitian.
Example¶
1// `V(0) T(0,1)` is *not* Hermitian: the two generators share the index 0 and therefore 2// anticommute. 3QfTransferVertexOperator *op = qf_transfer_op_zero(); 4uint32_t left[2] = {0, 0}; 5uint32_t right[2] = {0, 1}; 6QkComplex64 coeff = {1.0, 0.0}; 7qf_transfer_op_add_term(op, 2, left, right, &coeff); 8 9assert(!qf_transfer_op_is_hermitian(op, 1e-10));
Note
This check is implemented using
qf_transfer_op_equiv()on theqf_transfer_op_normal_ordered()difference ofopand itsqf_transfer_op_adjoint()andqf_transfer_op_zero().- Parameters:
op – A pointer to the transfer-vertex operator to be checked.
atol – The absolute tolerance upto which coefficients are considered equal.
- Returns:
Whether the provided operator is Hermitian.
-
bool qf_transfer_op_equal(const QfTransferVertexOperator *left, const QfTransferVertexOperator *right)¶
Compare two operators for equality.
Equality in this context means an exact match of the internal data arrays.
Example¶
1QfTransferVertexOperator *one = qf_transfer_op_one(); 2QfTransferVertexOperator *zero = qf_transfer_op_zero(); 3 4assert(qf_transfer_op_equal(one, one)); 5assert(!qf_transfer_op_equal(one, zero));
- Parameters:
left – A pointer to the left operator.
right – A pointer to the right operator.
- Returns:
Whether the two operators are equal.
-
bool qf_transfer_op_equiv(const QfTransferVertexOperator *left, const QfTransferVertexOperator *right, double atol)¶
Compare two operators for equivalence.
Equivalence in this context means approximate equality up to the specified absolute tolerance. To be more precise, this method returns
True, when all the absolute values of the coefficients in the differenceother - selfare below the specified thresholdatol.Example¶
1QfTransferVertexOperator *zero = qf_transfer_op_zero(); 2 3QfTransferVertexOperator *op = qf_transfer_op_zero(); 4QkComplex64 coeff = {1e-7, 0.0}; 5qf_transfer_op_add_term(op, 0, NULL, NULL, &coeff); 6 7assert(qf_transfer_op_equiv(op, zero, 1e-6)); 8assert(!qf_transfer_op_equiv(op, zero, 1e-8));
- Parameters:
left – A pointer to the left operator.
right – A pointer to the right operator.
atol – The absolute tolerance for coefficient equivalence.
- Returns:
Whether the two operators are equivalent.
-
size_t qf_transfer_op_len(const QfTransferVertexOperator *op)¶
Returns the length (or number of terms) of the provided operator.
Example¶
1QfTransferVertexOperator *op = qf_transfer_op_zero(); 2uint32_t left[2] = {0, 1}; 3uint32_t right[2] = {1, 2}; 4QkComplex64 coeff = {1.0, 0.0}; 5qf_transfer_op_add_term(op, 2, left, right, &coeff); 6 7assert(qf_transfer_op_len(op) == 1);
- Parameters:
op – A pointer to the transfer-vertex operator.
- Returns:
The length (or number of terms) of the operator.
-
QfExitCode qf_transfer_op_relabel_modes(QfTransferVertexOperator *op, uint64_t num_modes, const uint32_t *permutation)¶
Relabels the modes of the provided operator.
Example¶
1QfTransferVertexOperator *op = qf_transfer_op_zero(); 2uint32_t left[2] = {0, 2}; 3uint32_t right[2] = {1, 3}; 4QkComplex64 coeff = {1.0, 0.0}; 5qf_transfer_op_add_term(op, 2, left, right, &coeff); 6 7uint32_t permutation[4] = {3, 2, 1, 0}; 8 9QfExitCode exit = qf_transfer_op_relabel_modes(op, 4, permutation); 10 11assert(exit == QfExitCode_Success);
Note
Both index arrays are relabelled. Unlike most operations, this preserves the operator’s
groupsattribute, since relabelling permutes mode indices without reordering, splitting or merging terms.- Parameters:
op – A pointer to the transfer-vertex operator.
num_modes – The number of mode indices in the provided permutation list.
permutation – The index permutation list.
- Returns:
An exit code.
QfExitCode_Successupon successQfExitCode_DuplicateIndexErrorif duplicate indices were found in the permutationQfExitCode_IndexErrorfor any other index errors, such as invalid indices.