QfEdgeVertexOperator

struct QfEdgeVertexOperator

An edge-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 edge-vertex (\(E_{jk}\), \(V_j\)) operators:

\[\begin{align} V_j &= -i \gamma_{2j-1} \gamma_{2j} = 1 - 2 a^\dagger_j a_j \, , \nonumber \\ E_{jk} &= -i \gamma_{2j-1} \gamma_{2k-1} = -i (a_j a_k + a_j a^\dagger_k + a^\dagger_j a_k + a^\dagger_j a^\dagger_k) = -E_{kj} \nonumber \end{align}\]

which fulfill the following mixed fermionic-bosonic commutation relations for \(j \neq k \neq l \neq m\): [1]

\[\begin{align} \left\{ E_{jk}, V_k \right\} &= 0 \nonumber \\ \left\{ E_{jk}, E_{kl} \right\} &= 0 \nonumber \\ \left[ V_k, V_l \right] &= 0 \nonumber \\ \left[ E_{jk}, V_l \right] &= 0 \nonumber \\ \left[ E_{jk}, E_{lm} \right] &= 0 \nonumber \, . \end{align}\]

In summary, edge and vertex operators commute, unless they share exactly one index, in which case they anticommute.

Note

The relations above are stated for \(j \neq k \neq l \neq m\), so they do not cover two edge operators spanning the same pair of modes. Those commute: since \(E_{kj} = -E_{jk}\), such a pair is collinear, and every operator commutes with itself. This is why the condition is “exactly one” shared index rather than “at least one”.

We can abuse the notation a little bit and define \(V_j = E_{jj}\) which reflects how the internal data structure of this operator works. This makes the definition of the entire operator the following:

\[\text{\texttt{EdgeVertexOperator}} = \sum_i c_i \bigotimes_{lr} E_{lr} \, ,\]

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 \(E_{lr}\) as generalized edge 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:

coeffs

A vector of complex coefficients consisting of two 64-bit floating point numbers.

left_indices

A vector of 32-bit integers storing the left fermionic mode indices (\(l\)).

right_indices

A vector of 32-bit integers storing the right fermionic mode indices (\(r\)).

boundaries

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_edge_op_simplify().

Construction

A new operator can be constructed directly by specifying the corresponding arrays outlined above. Alternatively, an empty QfEdgeVertexOperator can be initialized with qf_edge_op_zero() and terms can be added iteratively via qf_edge_op_add_term().

qf_edge_op_new()

Constructs a new operator from the provided arrays.

qf_edge_op_zero()

Constructs the additive identity operator.

qf_edge_op_one()

Constructs the multiplicative identity operator.

qf_edge_op_add_term()

Adds a term to an existing QfEdgeVertexOperator.

Note

A QfEdgeVertexOperator can be freed with qf_edge_op_free().

Arithmetics

The following functions provide arithmetic manipulation:

qf_edge_op_add()

Adds two operators together.

qf_edge_op_mul()

Multiplies an operator by a scalar.

qf_edge_op_compose()

Composes two operators with each other.

qf_edge_op_adjoint()

Returns the Hermitian conjugate operator.

Manipulation

The following functions provide operator manipulation logic:

qf_edge_op_ichop()

Removes terms with small coefficient magnitudes.

qf_edge_op_simplify()

Returns an equivalent but simplified operator.

qf_edge_op_normal_ordered()

Returns an equivalent operator with normal ordered terms.

qf_edge_op_relabel_modes()

Relabels the modes of an operator.

Properties

The following functions exist to check certain properties of an operator.

qf_edge_op_is_hermitian()

Returns whether an operator is Hermitian.

qf_edge_op_len()

Returns the number of terms in this operator.

Mapping

The following functions map this operator into another representation:


Members

QfEdgeVertexOperator *qf_edge_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 NULL if and only if their corresponding length is zero.

A generator with equal indices is a vertex operator, \(V_j = E_{jj}\); one with differing indices is a (generalized) edge operator, \(E_{jk}\).

Example

1// this builds `1.0 + (-1.0) * V(0) E(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};
8QfEdgeVertexOperator *op = qf_edge_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_edge_op_free(QfEdgeVertexOperator *op)

Frees an existing operator.

Example

1QfEdgeVertexOperator *op = qf_edge_op_one();
2qf_edge_op_free(op);

Parameters:
  • op – A pointer to the edge-vertex operator to be freed.

void qf_edge_op_get_coeffs(const QfEdgeVertexOperator *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};
 4QfEdgeVertexOperator *op =
 5    qf_edge_op_new(num_terms, 0, coeffs, NULL, NULL, boundaries);
 6
 7QkComplex64 *coeffs_out;
 8uint64_t coeffs_len;
 9
10qf_edge_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 edge-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_edge_op_get_left_indices(const QfEdgeVertexOperator *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};
 7QfEdgeVertexOperator *op = qf_edge_op_new(num_terms, num_indices, coeffs,
 8                                          left_indices, right_indices, boundaries);
 9
10uint32_t *left_out;
11uint64_t left_len;
12
13qf_edge_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 edge-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_edge_op_get_right_indices(const QfEdgeVertexOperator *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};
 7QfEdgeVertexOperator *op = qf_edge_op_new(num_terms, num_indices, coeffs,
 8                                          left_indices, right_indices, boundaries);
 9
10uint32_t *right_out;
11uint64_t right_len;
12
13qf_edge_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 edge-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_edge_op_get_boundaries(const QfEdgeVertexOperator *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};
 7QfEdgeVertexOperator *op = qf_edge_op_new(num_terms, num_indices, coeffs,
 8                                          left_indices, right_indices, boundaries);
 9
10size_t *boundaries_out;
11uint64_t boundaries_len;
12
13qf_edge_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 edge-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.

QfEdgeVertexOperator *qf_edge_op_zero(void)

Constructs the additive identity operator.

Adding the operator that is constructed by this method to another one has no effect.

Example

1QfEdgeVertexOperator *zero = qf_edge_op_zero();
2
3QfEdgeVertexOperator *op_plus_zero = qf_edge_op_add(op, zero);
4
5assert(qf_edge_op_equal(op, op_plus_zero));

Returns:

A pointer to the created operator.

QfEdgeVertexOperator *qf_edge_op_one(void)

Constructs the multiplicative identity operator.

Composing the operator that is constructed by this method with another one has no effect.

Example

1QfEdgeVertexOperator *one = qf_edge_op_one();
2
3QfEdgeVertexOperator *op_times_one = qf_edge_op_compose(op, one);
4
5assert(qf_edge_op_equal(op, op_times_one));

Returns:

A pointer to the created operator.

bool qf_edge_op_has_groups(const QfEdgeVertexOperator *op)

Checks whether an operator has its groups attribute set.

Example

1QfEdgeVertexOperator *op = ...;
2
3bool has_groups = qf_edge_op_has_groups(op);

Parameters:
  • op – A pointer to the edge-vertex operator to check.

Returns:

Whether the operator tracks group indices.

uint32_t qf_edge_op_num_groups(const QfEdgeVertexOperator *op)

Gets the number of groups from an operator.

Example

1QfEdgeVertexOperator *op = ...;
2
3uint32_t num_groups = qf_edge_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 edge-vertex operator whose number of groups to get.

Returns:

The number of group indices from the operator’s groups attribute.

void qf_edge_op_group_weights(const QfEdgeVertexOperator *op, double *weights_out)

Gets the mean absolute coefficient magnitude of each group.

The i-th entry is the sum of abs(coeff) over the terms in group i, divided by the number of terms in that group. This is the sampling weight of a randomized product formula (e.g. qDRIFT) that draws whole groups rather than individual terms, and is computed in a single pass over the operator rather than by reducing qf_edge_op_get_coeffs() and qf_edge_op_get_groups() (one value per ungrouped term each) on the caller’s side.

Example

1QfEdgeVertexOperator *op = ...;
2
3uint32_t groups_in[4] = {0, 1, 0, 1};
4qf_edge_op_set_groups(op, groups_in, 4);
5
6double weights[2];
7qf_edge_op_group_weights(op, weights);

Note

A group index that no term carries weighs 0.0, which keeps it out of the sample.

Parameters:
  • op – A pointer to the edge-vertex operator whose group weights to compute.

  • weights_out – A pointer to the array of doubles into which to write the weights. Must be sized to :c:func:qf_edge_op_num_groups.

void qf_edge_op_get_groups(const QfEdgeVertexOperator *op, uint32_t **groups_out, uint64_t *groups_len)

Gets the group indices for all operator terms.

Example

1QfEdgeVertexOperator *op = ...;
2uint32_t *groups_out;
3uint64_t groups_len;
4
5qf_edge_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 edge-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.

void qf_edge_op_set_groups(QfEdgeVertexOperator *op, const uint32_t *groups_in, uint64_t groups_len)

Sets the groups attribute of the provided operator.

Example

1QfEdgeVertexOperator *op = ...;
2
3uint32_t num_terms = 4;
4uint32_t groups_in[4] = {0, 1, 0, 1};
5qf_edge_op_set_groups(op, groups_in, num_terms);

Parameters:
  • op – A pointer to the edge-vertex operator whose groups attribute to write.

  • groups_in – A pointer to the groups integer array to write into the operator.

  • groups_len – The number of terms in the groups_in array.

void qf_edge_op_del_groups(QfEdgeVertexOperator *op)

Deletes the groups attribute from the provided operator.

Example

1QfEdgeVertexOperator *op = ...;
2
3qf_edge_op_del_groups(op);

Parameters:
  • op – A pointer to the edge-vertex operator whose groups attribute to delete.

void qf_edge_op_split_out_groups(const QfEdgeVertexOperator *op, const uint32_t *group_indices, uint64_t num_indices, QfEdgeVertexOperator **group_ops_out)

Splits this operator into a list of new operators based on its groups attribute.

A duplicate index in group_indices is written once per occurrence in group_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.

Example

 1QfEdgeVertexOperator *op = ...;
 2
 3uint32_t groups_in[4] = {0, 1, 0, 1};
 4qf_edge_op_set_groups(op, groups_in, 4);
 5
 6// build every group, in index order
 7QfEdgeVertexOperator *group_ops[2];
 8qf_edge_op_split_out_groups(op, NULL, 0, group_ops);
 9
10// build only group 1
11uint32_t group_indices[1] = {1};
12QfEdgeVertexOperator *group_op[1];
13qf_edge_op_split_out_groups(op, group_indices, 1, group_op);

Parameters:
  • op – A pointer to the edge-vertex operator whose groups to 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 from 0 to :c:func:qf_edge_op_num_groups - 1).

  • num_indices – The number of indices in the group_indices array. Ignored if group_indices is NULL.

  • group_ops_out – A pointer to the array of :c:struct:QfEdgeVertexOperator into which to write the operators for each requested group. Must be sized to num_indices when group_indices is non-NULL, or to :c:func:qf_edge_op_num_groups when it is NULL.

void qf_edge_op_add_term(QfEdgeVertexOperator *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 NULL if and only if their corresponding length is zero.

Caution

This function resets the operator’s groups attribute to NULL.

Example

1QfEdgeVertexOperator *one = qf_edge_op_one();
2
3QfEdgeVertexOperator *op = qf_edge_op_zero();
4QkComplex64 coeff = {1.0, 0.0};
5
6qf_edge_op_add_term(op, 0, NULL, NULL, &coeff);
7
8assert(qf_edge_op_equal(op, one));

Parameters:
  • op – A pointer to the edge-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.

QfEdgeVertexOperator *qf_edge_op_add(const QfEdgeVertexOperator *left, const QfEdgeVertexOperator *right)

Adds two operators together.

Example

1QfEdgeVertexOperator *one = qf_edge_op_one();
2QfEdgeVertexOperator *zero = qf_edge_op_zero();
3
4QfEdgeVertexOperator *result = qf_edge_op_add(one, zero);
5
6assert(qf_edge_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.

QfEdgeVertexOperator *qf_edge_op_mul(const QfEdgeVertexOperator *op, const QkComplex64 *scalar)

Multiplies an operator by a scalar.

Example

1QfEdgeVertexOperator *one = qf_edge_op_one();
2QkComplex64 coeff = {2.0, 0.0};
3QfEdgeVertexOperator *result = qf_edge_op_mul(one, &coeff);
4
5QfEdgeVertexOperator *expected = qf_edge_op_zero();
6qf_edge_op_add_term(expected, 0, NULL, NULL, &coeff);
7
8assert(qf_edge_op_equal(result, expected));

Parameters:
  • op – A pointer to the operator.

  • scalar – A pointer to the scalar.

Returns:

A pointer to the resulting operator.

QfEdgeVertexOperator *qf_edge_op_compose(const QfEdgeVertexOperator *left, const QfEdgeVertexOperator *right)

Composes two operators with each other.

Example

1QfEdgeVertexOperator *one = qf_edge_op_one();
2QfEdgeVertexOperator *zero = qf_edge_op_zero();
3
4QfEdgeVertexOperator *result = qf_edge_op_compose(one, zero);
5
6assert(qf_edge_op_equal(result, zero));

Parameters:
  • left – A pointer to the left operator.

  • right – A pointer to the right operator.

Returns:

A pointer to the resulting operator.

QfEdgeVertexOperator *qf_edge_op_adjoint(const QfEdgeVertexOperator *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

 1QfEdgeVertexOperator *op = qf_edge_op_zero();
 2QkComplex64 coeff = {0.0, 1.0};
 3qf_edge_op_add_term(op, 0, NULL, NULL, &coeff);
 4
 5QfEdgeVertexOperator *adjoint = qf_edge_op_adjoint(op);
 6
 7QfEdgeVertexOperator *expected = qf_edge_op_zero();
 8QkComplex64 coeff_adj = {0.0, -1.0};
 9qf_edge_op_add_term(expected, 0, NULL, NULL, &coeff_adj);
10
11assert(qf_edge_op_equal(adjoint, expected));

Note

Reversing the operator string is essential: the edge and vertex generators anticommute when they share exactly one index, so BA != AB in general.

Parameters:
  • op – A pointer to the operator.

Returns:

A pointer to the created operator.

void qf_edge_op_ichop(QfEdgeVertexOperator *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_edge_op_simplify() instead!

Example

1QfEdgeVertexOperator *op = qf_edge_op_zero();
2QkComplex64 coeff = {1e-8, 0.0};
3qf_edge_op_add_term(op, 0, NULL, NULL, &coeff);
4
5qf_edge_op_ichop(op, 1e-6);
6
7QfEdgeVertexOperator *expected = qf_edge_op_zero();
8
9assert(qf_edge_op_equal(op, expected));

Parameters:
  • op – A pointer to the operator.

  • atol – The absolute tolerance for coefficient truncation.

QfEdgeVertexOperator *qf_edge_op_simplify(const QfEdgeVertexOperator *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_edge_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

1QfEdgeVertexOperator *op = qf_edge_op_zero();
2QkComplex64 coeff = {1e-5, 0.0};
3for (int i = 0; i < 100; i++) {
4  qf_edge_op_add_term(op, 0, NULL, NULL, &coeff);
5}
6
7QfEdgeVertexOperator *canon = qf_edge_op_simplify(op, 1e-4);
8
9assert(qf_edge_op_len(canon) == 1);

Note

This groups terms by their exact stored index arrays. Two terms that are mathematically equal but stored with different generator orientations (recall E_kj = -E_jk) are not recognized as duplicates; call qf_edge_op_normal_ordered() first to bring them into a common form.

Parameters:
  • op – A pointer to the edge-vertex operator to be simplified.

  • atol – The absolute tolerance for coefficient truncation.

Returns:

An equivalent but simplified operator.

QfEdgeVertexOperator *qf_edge_op_normal_ordered(const QfEdgeVertexOperator *op, bool ascending, bool reduce)

Returns an equivalent operator with normal ordered terms.

The ascending flag fixes the orientation convention of the generalized edge operators: because \(E_{kj} = -E_{jk}\), every edge operator has two representations, and this picks \(j < k\) (true) or \(j > k\) (false), absorbing the sign into the coefficient. Vertex operators \(V_j = E_{jj}\) are unaffected.

The reduce flag additionally contracts adjacent generators, which is what makes the result a genuine canonical form. The rules are \(V_j V_j = 1\), \(E_{jk} E_{jk} = 1\), \(E_{jk} E_{kj} = -1\), and the fusion rule \(E_{ab} E_{bc} = -i E_{ac}\) for distinct \(a, b, c\).

See also

qf_transfer_op_normal_ordered(), which takes no ascending flag because the transfer operators \(T_{jk}\) and \(T_{kj}\) are genuinely different operators rather than two representations of one.

Example

 1// `E(1,0)` normal-orders to `-E(0,1)` when ascending
 2QfEdgeVertexOperator *op = qf_edge_op_zero();
 3uint32_t left[1] = {1};
 4uint32_t right[1] = {0};
 5QkComplex64 coeff = {1.0, 0.0};
 6qf_edge_op_add_term(op, 1, left, right, &coeff);
 7
 8QfEdgeVertexOperator *ordered = qf_edge_op_normal_ordered(op, true, true);
 9
10QfEdgeVertexOperator *expected = qf_edge_op_zero();
11uint32_t left_exp[1] = {0};
12uint32_t right_exp[1] = {1};
13QkComplex64 coeff_exp = {-1.0, 0.0};
14qf_edge_op_add_term(expected, 1, left_exp, right_exp, &coeff_exp);
15
16assert(qf_edge_op_equal(ordered, expected));

Parameters:
  • op – A pointer to the operator.

  • ascending – Whether the indices of each edge operator should ascend or descend.

  • reduce – Whether to contract adjacent generators via the algebra’s identities.

Returns:

A pointer to the created operator.

bool qf_edge_op_is_hermitian(const QfEdgeVertexOperator *op, double atol)

Checks whether an operator is Hermitian.

Example

1// `V(0) E(0,1)` is *not* Hermitian: the two generators share the index 0 and therefore
2// anticommute.
3QfEdgeVertexOperator *op = qf_edge_op_zero();
4uint32_t left[2] = {0, 0};
5uint32_t right[2] = {0, 1};
6QkComplex64 coeff = {1.0, 0.0};
7qf_edge_op_add_term(op, 2, left, right, &coeff);
8
9assert(!qf_edge_op_is_hermitian(op, 1e-10));

Note

This check is implemented using qf_edge_op_equiv() on the qf_edge_op_normal_ordered() difference of op and its qf_edge_op_adjoint() and qf_edge_op_zero().

Parameters:
  • op – A pointer to the edge-vertex operator to be checked.

  • atol – The absolute tolerance upto which coefficients are considered equal.

Returns:

Whether the provided operator is Hermitian.

bool qf_edge_op_equal(const QfEdgeVertexOperator *left, const QfEdgeVertexOperator *right)

Compare two operators for equality.

Equality in this context means an exact match of the internal data arrays.

Example

1QfEdgeVertexOperator *one = qf_edge_op_one();
2QfEdgeVertexOperator *zero = qf_edge_op_zero();
3
4assert(qf_edge_op_equal(one, one));
5assert(!qf_edge_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_edge_op_equiv(const QfEdgeVertexOperator *left, const QfEdgeVertexOperator *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 difference other - self are below the specified threshold atol.

Example

1QfEdgeVertexOperator *zero = qf_edge_op_zero();
2
3QfEdgeVertexOperator *op = qf_edge_op_zero();
4QkComplex64 coeff = {1e-7, 0.0};
5qf_edge_op_add_term(op, 0, NULL, NULL, &coeff);
6
7assert(qf_edge_op_equiv(op, zero, 1e-6));
8assert(!qf_edge_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_edge_op_len(const QfEdgeVertexOperator *op)

Returns the length (or number of terms) of the provided operator.

Example

1QfEdgeVertexOperator *op = qf_edge_op_zero();
2uint32_t left[2] = {0, 1};
3uint32_t right[2] = {1, 2};
4QkComplex64 coeff = {1.0, 0.0};
5qf_edge_op_add_term(op, 2, left, right, &coeff);
6
7assert(qf_edge_op_len(op) == 1);

Parameters:
  • op – A pointer to the edge-vertex operator.

Returns:

The length (or number of terms) of the operator.

QfExitCode qf_edge_op_relabel_modes(QfEdgeVertexOperator *op, uint64_t num_modes, const uint32_t *permutation)

Relabels the modes of the provided operator.

Example

 1QfEdgeVertexOperator *op = qf_edge_op_zero();
 2uint32_t left[2] = {0, 2};
 3uint32_t right[2] = {1, 3};
 4QkComplex64 coeff = {1.0, 0.0};
 5qf_edge_op_add_term(op, 2, left, right, &coeff);
 6
 7uint32_t permutation[4] = {3, 2, 1, 0};
 8
 9QfExitCode exit = qf_edge_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 groups attribute, since relabelling permutes mode indices without reordering, splitting or merging terms.

Parameters:
  • op – A pointer to the edge-vertex operator.

  • num_modes – The number of mode indices in the provided permutation list.

  • permutation – The index permutation list.

Returns:

An exit code.