QfMajoranaOperator
QfMajoranaOperator
struct QfMajoranaOperator
A Majorana fermion operator.
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 by a linear combination of products of Majorana operators [1], which can be defined in terms of the standard fermionic second-quantization creation and annihilation operators (see also .QfFermionOperator):
The key property that a Majorana fermion is its own antiparticle becomes immediately apparent:
This result in the following anti-commutation relations for Majorana fermions:
This makes the definition of the entire operator the following:
where is the (complex) coefficient making up the linear combination of products of . The index can take any value between 0 and the number of majorana fermionic modes acted upon by the operator minus 1.
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:
Column 1 | Column 2 |
|---|---|
coeffs | A vector of complex coefficients consisting of two 64-bit floating point numbers. |
modes | A vector of 32-bit integers storing the majorana mode indices acted upon. |
boundaries | A vector of integers indicating the boundaries in actions and indices. |
The integers in modes index the Majorana modes, . When using the convenience function gamma(), even (odd) indices are used for ().
You can access read-only copies of these internal arrays via their respective functions:
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_maj_op_simplify().
Construction
A new operator can be constructed directly by specifying the corresponding arrays outlined above. Alternatively, an empty QfMajoranaOperator can be initialized with qf_maj_op_zero() and terms can be added iteratively via qf_maj_op_add_term().
Column 1 | Column 2 |
|---|---|
qf_maj_op_new() | Constructs a new operator from the provided arrays. |
qf_maj_op_zero() | Constructs the additive identity operator. |
qf_maj_op_one() | Constructs the multiplicative identity operator. |
qf_maj_op_add_term() | Adds a term to an existing QfMajoranaOperator. |
A QfMajoranaOperator can be freed with qf_maj_op_free().
Arithmetics
The following functions provide arithmetic manipulation:
Column 1 | Column 2 |
|---|---|
qf_maj_op_add() | Adds two operators together. |
qf_maj_op_mul() | Multiplies an operator by a scalar. |
qf_maj_op_compose() | Composes two operators with each other. |
qf_maj_op_adjoint() | Returns the Hermitian conjugate operator. |
Manipulation
The following functions provide operator manipulation logic:
Column 1 | Column 2 |
|---|---|
qf_maj_op_ichop() | Removes terms with small coefficient magnitudes. |
qf_maj_op_simplify() | Returns an equivalent but simplified operator. |
qf_maj_op_normal_ordered() | Returns an equivalent operator with normal ordered terms. |
qf_maj_op_relabel_modes() | Relabels the modes of an operator. |
Properties
The following functions exist to check certain properties of an operator.
Column 1 | Column 2 |
|---|---|
qf_maj_op_is_hermitian() | Returns whether an operator is Hermitian. |
qf_maj_op_max_rank() | Returns the maximum rank of the terms in this operator. |
qf_maj_op_is_even() | Returns whether an operator is even. |
[1]
https://en.wikipedia.org/wiki/Majorana_fermion
Members
qf_maj_op_new
QfMajoranaOperator *qf_maj_op_new(uint64_t num_terms, uint64_t num_modes, const QkComplex64 *coeffs, const uint32_t *modes, 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.
Example
1uint64_t num_terms = 3;
2uint64_t num_modes = 4;
3uint32_t modes[4] = {0, 1, 2, 3};
4QkComplex64 coeffs[3] = {{1.0, 0.0}, {-1.0, 0.0}, {0.0, -1.0}};
5uint32_t boundaries[4] = {0, 0, 2, 4};
6QfMajoranaOperator *op = qf_maj_op_new(num_terms, num_modes, coeffs,
7 modes, boundaries);Parameters
- num_terms – The number of terms in the operator.
- num_modes – The number of modes summed over all terms.
- coeffs – A pointer to an array of term coefficients. The length of this array should be
num_terms. - modes – A pointer to an array of modes over all terms. The length of this array should be
num_modes. - boundaries – A pointer to an array of the boundaries between terms. The length of this array should be
num_terms + 1.
qf_maj_op_free
void qf_maj_op_free(QfMajoranaOperator *op)
Frees an existing operator.
Example
1QfMajoranaOperator *op = qf_maj_op_one();
2qf_maj_op_free(op);Parameters
- op – A pointer to the Majorana operator to be freed.
qf_maj_op_get_coeffs
void qf_maj_op_get_coeffs(const QfMajoranaOperator *op, QkComplex64 **coeffs_out, uint64_t *coeffs_len)
Provides read-only access to the operator’s coefficients.
The explanation of the internal data structure, here.
Example
1uint64_t num_terms = 2;
2uint64_t num_modes = 0;
3QkComplex64 coeffs[2] = {{1.0, 0.0}, {0.0, -1.0}};
4uint32_t boundaries[3] = {0, 0, 0};
5QfMajoranaOperator *op =
6 qf_maj_op_new(num_terms, num_modes, coeffs, NULL, boundaries);
7
8QkComplex64 *coeffs_out;
9uint64_t *coeffs_len;
10
11qf_maj_op_get_coeffs(op, &coeffs_out, &coeffs_len);
12
13assert(coeffs_len == 2);This function returns a copy of the internal data.
Parameters
- op – A pointer to the majorana 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.
qf_maj_op_get_modes
void qf_maj_op_get_modes(const QfMajoranaOperator *op, uint32_t **modes_out, uint64_t *modes_len)
Provides read-only access to the operator’s acted-upon mode indices.
The explanation of the internal data structure, here.
Example
1uint64_t num_terms = 2;
2bool actions[2] = {true, false};
3uint32_t modes[2] = {0, 1};
4QkComplex64 coeffs[2] = {{1.0, 0.0}, {0.0, -1.0}};
5uint32_t boundaries[3] = {0, 0, 2};
6QfMajoranaOperator *op =
7 qf_maj_op_new(num_terms, num_actions, coeffs, modes, boundaries);
8
9QkComplex64 *modes_out;
10uint64_t *modes_len;
11
12qf_maj_op_get_modes(op, &modes_out, &modes_len);
13
14assert(modes_len == 2);This function returns a copy of the internal data.
Parameters
- op – A pointer to the majorana operator whose modes to access.
- modes_out – A pointer to the array of boolean values into which to write the modes.
- modes_len – A pointer to the integer into which to write the length of the output array.
qf_maj_op_get_boundaries
void qf_maj_op_get_boundaries(const QfMajoranaOperator *op, size_t **boundaries_out, uint64_t *boundaries_len)
Provides read-only access to the indices indicating the boundaries between operator terms.
The explanation of the internal data structure, here.
Example
1uint64_t num_terms = 2;
2uint64_t num_modes = 2;
3uint32_t modes[2] = {0, 1};
4QkComplex64 coeffs[2] = {{1.0, 0.0}, {0.0, -1.0}};
5uint32_t boundaries[3] = {0, 0, 2};
6QfMajoranaOperator *op =
7 qf_maj_op_new(num_terms, num_modes, coeffs, modes, boundaries);
8
9QkComplex64 *boundaries_out;
10uint64_t *boundaries_len;
11
12qf_maj_op_get_boundaries(op, &boundaries_out, &boundaries_len);
13
14assert(boundaries_len == 3);This function returns a copy of the internal data.
Parameters
- op – A pointer to the majorana operator whose boundaries to access.
- boundaries_out – A pointer to the array of boolean values into which to write the boundaries.
- boundaries_len – A pointer to the integer into which to write the length of the output array.
qf_maj_op_num_support
uint32_t qf_maj_op_num_support(const QfMajoranaOperator *op)
Gets the size of the support of an operator.
Use this to size the output buffer of qf_maj_op_get_support(), which does not report a length of its own.
Example
1uint32_t modes[3] = {2, 0, 2};
2QkComplex64 coeffs[2] = {{1.0, 0.0}, {1.0, 0.0}};
3uint32_t boundaries[3] = {0, 2, 3};
4QfMajoranaOperator *op = qf_maj_op_new(2, 3, coeffs, modes, boundaries);
5
6uint32_t num_support = qf_maj_op_num_support(op);
7
8assert(num_support == 2);Parameters
- op – A pointer to the Majorana operator whose support size to get.
Returns
The number of distinct mode indices acted upon by the operator.
qf_maj_op_get_support
void qf_maj_op_get_support(const QfMajoranaOperator *op, uint32_t *support_out)
Gets the support of an operator, i.e. the Majorana 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 modes[3] = {2, 0, 2};
2QkComplex64 coeffs[2] = {{1.0, 0.0}, {1.0, 0.0}};
3uint32_t boundaries[3] = {0, 2, 3};
4QfMajoranaOperator *op = qf_maj_op_new(2, 3, coeffs, modes, boundaries);
5
6uint32_t num_support = qf_maj_op_num_support(op);
7uint32_t *support_out = malloc(num_support * sizeof(uint32_t));
8
9qf_maj_op_get_support(op, support_out);
10
11assert(support_out[0] == 0);
12assert(support_out[1] == 2);
13
14free(support_out);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_maj_op_num_support() first.
These are the Majorana mode indices, not the fermionic ones: they are not divided by two. A Majorana operator on fermionic mode j therefore reports the indices 2 * j and/or 2 * j + 1.
Parameters
- op – A pointer to the Majorana 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_maj_op_num_supportelements.
qf_maj_op_zero
QfMajoranaOperator *qf_maj_op_zero(void)
Constructs the additive identity operator.
Adding the operator that is constructed by this method to another one has no effect.
Example
1QfMajoranaOperator *zero = qf_maj_op_zero();
2
3QfMajoranaOperator *op_plus_zero = qf_maj_op_add(op, zero);
4
5assert(qf_maj_op_equal(op, op_plus_zero));Returns
A pointer to the created operator.
qf_maj_op_one
QfMajoranaOperator *qf_maj_op_one(void)
Constructs the multiplicative identity operator.
Composing the operator that is constructed by this method with another one has no effect.
Example
1QfMajoranaOperator *one = qf_maj_op_one();
2
3QfMajoranaOperator *op_times_one = qf_maj_op_compose(op, one);
4
5assert(qf_maj_op_equal(op, op_times_one));Returns
A pointer to the created operator.
qf_maj_op_has_groups
bool qf_maj_op_has_groups(const QfMajoranaOperator *op)
Checks whether this operator tracks group indices.
The explanation on Group operator terms: use the operator structure.
Example
1QfMajoranaOperator *op = ...;
2
3bool has_groups = qf_maj_op_has_groups(op);Parameters
- op – A pointer to the majorana operator to be checked.
Returns
Whether the provided operator has a groups attribute.
qf_maj_op_num_groups
uint32_t qf_maj_op_num_groups(const QfMajoranaOperator *op)
Gets the number of groups from an operator.
The explanation on Group operator terms: use the operator structure.
Example
1QfMajoranaOperator *op = ...;
2
3uint32_t num_groups = qf_maj_op_num_groups(op);The number of groups is evaluated lazily as the largest occurring group index plus 1.
Parameters
- op – A pointer to the majorana operator whose number of groups to get.
Returns
The number of group indices from the operator’s groups attribute.
qf_maj_op_get_groups
void qf_maj_op_get_groups(const QfMajoranaOperator *op, uint32_t **groups_out, uint64_t *groups_len)
Gets the group indices for all operator terms.
The explanation on Group operator terms: use the operator structure.
Example
1QfMajoranaOperator *op = ...;
2uint32_t *groups_out;
3uint32_t groups_len;
4
5qf_maj_op_get_groups(op, &groups_out, &groups_len);Parameters
- op – A pointer to the majorana 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.
qf_maj_op_set_groups
QfExitCode qf_maj_op_set_groups(QfMajoranaOperator *op, const uint32_t *groups_in, uint64_t groups_len)
Sets the groups attribute 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_maj_op_num_groups() report groups that no term carries.
The explanation on Group operator terms: use the operator structure.
Example
1QfMajoranaOperator *op = ...;
2
3uint32_t num_terms = 4;
4uint32_t groups_in[4] = {0, 1, 0, 1};
5qf_maj_op_set_groups(op, groups_in, num_terms);Parameters
- op – A pointer to the majorana 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
qf_maj_op_del_groups
void qf_maj_op_del_groups(QfMajoranaOperator *op)
Deletes the groups attribute from the provided operator.
The explanation on Group operator terms: use the operator structure.
Example
1QfMajoranaOperator *op = ...;
2
3qf_maj_op_del_groups(op);Parameters
- op – A pointer to the majorana operator whose
groupsattribute to delete.
qf_maj_op_split_out_groups
void qf_maj_op_split_out_groups(const QfMajoranaOperator *op, const uint32_t *group_indices, uint64_t num_indices, QfMajoranaOperator **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.
The explanation on Group operator terms: use the operator structure.
Example
1uint64_t num_terms = 4;
2uint64_t num_modes = 8;
3uint32_t modes[8] = {0, 1, 2, 3, 1, 0, 3, 2};
4QkComplex64 coeffs[4] = {{1.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}};
5uint32_t boundaries[5] = {0, 2, 4, 6, 8};
6QfMajoranaOperator *op = qf_maj_op_new(num_terms, num_modes, coeffs, modes, boundaries);
7
8uint32_t groups_in[4] = {0, 1, 0, 1};
9qf_maj_op_set_groups(op, groups_in, num_terms);
10
11// build every group, in index order
12QfMajoranaOperator *group_ops[2];
13qf_maj_op_split_out_groups(op, NULL, 0, group_ops);
14
15// build only group 1
16uint32_t group_indices[1] = {1};
17QfMajoranaOperator *group_op[1];
18qf_maj_op_split_out_groups(op, group_indices, 1, group_op);Parameters
- op – A pointer to the majorana 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_maj_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:
QfMajoranaOperatorinto which to write the operators for each requested group. Must be sized tonum_indiceswhengroup_indicesis non-NULL, or to :c:func:qf_maj_op_num_groupswhen it isNULL.
qf_maj_op_add_term
void qf_maj_op_add_term(QfMajoranaOperator *op, uint64_t num_modes, const uint32_t *modes, 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.
This function resets the operator’s groups attribute to NULL.
Example
1QfMajoranaOperator *one = qf_maj_op_one();
2
3QfMajoranaOperator *op = qf_maj_op_zero();
4uint32_t modes[0] = {};
5QkComplex64 coeff = {1.0, 0.0};
6
7qf_maj_op_add_term(op, 0, modes, &coeff);
8
9assert(qf_maj_op_equal(op, one));Parameters
- op – A pointer to the Majorana operator to be modified.
- num_modes – The length of the modes array.
- modes – A pointer to an array of mode indices. The length of this array should be
num_modes. - coeff – A pointer to the complex coefficient.
qf_maj_op_add
QfMajoranaOperator *qf_maj_op_add(const QfMajoranaOperator *left, const QfMajoranaOperator *right)
Adds two operators together.
Example
1QfMajoranaOperator *one = qf_maj_op_one();
2QfMajoranaOperator *zero = qf_maj_op_zero();
3
4QfMajoranaOperator *result = qf_maj_op_add(one, zero);
5
6assert(qf_maj_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.
qf_maj_op_scaled_add
QfMajoranaOperator *qf_maj_op_scaled_add(const QfMajoranaOperator *left, const QfMajoranaOperator *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 right just to append it. Passing a factor of -1 therefore subtracts, which is why no separate subtraction function is provided.
Example
1QfMajoranaOperator *one = qf_maj_op_one();
2QfMajoranaOperator *other = qf_maj_op_one();
3
4// Subtracting via a factor of -1 leaves the two terms cancelling each other out.
5QkComplex64 factor = {-1.0, 0.0};
6QfMajoranaOperator *result = qf_maj_op_scaled_add(one, other, &factor);
7
8QfMajoranaOperator *simplified = qf_maj_op_simplify(result, 1e-10);
9assert(qf_maj_op_len(simplified) == 0);Like qf_maj_op_add(), this appends the terms of right without combining them with those of left, so the result tracks no group indices. Call qf_maj_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.
qf_maj_op_add_inplace
void qf_maj_op_add_inplace(QfMajoranaOperator *left, const QfMajoranaOperator *right)
Adds an operator into another one, in place.
The in-place counterpart of qf_maj_op_add(), which saves copying left into a freshly allocated result.
This function resets the operator’s groups attribute to NULL.
Example
1QfMajoranaOperator *left = qf_maj_op_one();
2QfMajoranaOperator *right = qf_maj_op_one();
3
4qf_maj_op_add_inplace(left, right);
5
6assert(qf_maj_op_len(left) == 2);Parameters
- left – A pointer to the operator to add into.
- right – A pointer to the operator to add.
qf_maj_op_scaled_add_inplace
void qf_maj_op_scaled_add_inplace(QfMajoranaOperator *left, const QfMajoranaOperator *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_maj_op_scaled_add(), computing left + factor * right without allocating a result. As there, a factor of -1 subtracts.
This function resets the operator’s groups attribute to NULL.
Example
1QfMajoranaOperator *left = qf_maj_op_one();
2QfMajoranaOperator *right = qf_maj_op_one();
3
4// Subtract, leaving two terms that cancel each other out.
5QkComplex64 factor = {-1.0, 0.0};
6qf_maj_op_scaled_add_inplace(left, right, &factor);
7
8QfMajoranaOperator *simplified = qf_maj_op_simplify(left, 1e-10);
9assert(qf_maj_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.
qf_maj_op_mul_inplace
void qf_maj_op_mul_inplace(QfMajoranaOperator *op, const QkComplex64 *scalar)
Multiplies an operator by a scalar, in place.
The in-place counterpart of qf_maj_op_mul(), which saves copying the operator into a freshly allocated result.
Example
1QfMajoranaOperator *op = qf_maj_op_one();
2QkComplex64 scalar = {2.0, 0.0};
3
4qf_maj_op_mul_inplace(op, &scalar);Unlike the two in-place additions above, this preserves the groups attribute: 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.
qf_maj_op_mul
QfMajoranaOperator *qf_maj_op_mul(const QfMajoranaOperator *op, const QkComplex64 *scalar)
Multiplies an operator by a scalar.
Example
1QfMajoranaOperator *one = qf_maj_op_one();
2QkComplex64 coeff = {2.0, 0.0};
3QfMajoranaOperator *result = qf_maj_op_mul(one, &coeff);
4
5QfMajoranaOperator *expected = qf_maj_op_zero();
6uint32_t modes[0] = {};
7qf_maj_op_add_term(expected, 0, modes, &coeff);
8
9assert(qf_maj_op_equal(result, expected));Parameters
- op – A pointer to the operator.
- scalar – A pointer to the scalar.
Returns
A pointer to the resulting operator.
qf_maj_op_compose
QfMajoranaOperator *qf_maj_op_compose(const QfMajoranaOperator *left, const QfMajoranaOperator *right)
Composes two operators with each other.
Example
1QfMajoranaOperator *one = qf_maj_op_one();
2QfMajoranaOperator *zero = qf_maj_op_zero();
3
4QfMajoranaOperator *result = qf_maj_op_compose(one, zero);
5
6assert(qf_maj_op_equal(result, zero));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 operator result = right @ left in terms of the matrix multiplication @. In other words, right is applied first. To obtain left @ right, swap the arguments.
qf_maj_op_adjoint
QfMajoranaOperator *qf_maj_op_adjoint(const QfMajoranaOperator *op)
Returns the Hermitian conjugate (or adjoint) of an operator.
This affects the terms and coefficients as follows:
- the actions in each term reverse their order
- the coefficients are complex conjugated
Example
1QfMajoranaOperator *op = qf_maj_op_zero();
2uint32_t modes[0] = {};
3QkComplex64 coeff = {0.0, 1.0};
4qf_maj_op_add_term(op, 0, modes, &coeff);
5
6QfMajoranaOperator *adjoint = qf_maj_op_adjoint(op);
7
8QfMajoranaOperator *expected = qf_maj_op_zero();
9QkComplex64 coeff_adj = {0.0, -1.0};
10qf_maj_op_add_term(expected, 0, modes, &coeff_adj);
11
12assert(qf_maj_op_equal(adjoint, expected));Parameters
- op – A pointer to the operator.
Returns
A pointer to the created operator.
qf_maj_op_ichop
void qf_maj_op_ichop(QfMajoranaOperator *op, double atol)
Removes terms whose coefficient magnitude lies below the provided threshold.
This functions truncates coefficients greedily! If the acted upon operator might contain separate coefficients for duplicate terms consider calling qf_maj_op_simplify() instead!
Example
1QfMajoranaOperator *op = qf_maj_op_zero();
2uint32_t modes[0] = {};
3QkComplex64 coeff = {1e-8};
4qf_maj_op_add_term(op, 0, modes, &coeff);
5
6qf_maj_op_ichop(op, 1e-6);
7
8QfMajoranaOperator *expected = qf_maj_op_zero();
9
10assert(qf_maj_op_equal(op, expected));Parameters
- op – A pointer to the operator.
- atol – The absolute tolerance for coefficient truncation.
qf_maj_op_simplify
QfMajoranaOperator *qf_maj_op_simplify(const QfMajoranaOperator *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_maj_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. See the example below which showcases how qf_maj_op_ichop() can truncate terms that sum to a total coefficient magnitude which should not be truncated:
1uint64_t num_terms = 100000;
2uint64_t num_modes = 0;
3uint32_t modes[0] = {};
4QkComplex64 coeffs[100000];
5uint32_t boundaries[100001];
6for (int i = 0; i < 100000; i++) {
7 coeffs[i].re = 1e-5;
8 coeffs[i].im = 0.0;
9 boundaries[i] = 0;
10}
11boundaries[100000] = 0;
12QfMajoranaOperator *op =
13 qf_maj_op_new(num_terms, num_modes, coeffs, modes, boundaries);
14
15QfMajoranaOperator *canon = qf_maj_op_simplify(op, 1e-4);
16
17QfMajoranaOperator *one = qf_maj_op_one();
18bool canon_is_equal = qf_maj_op_equiv(canon, one, 1e-6);
19
20qf_maj_op_ichop(op, 1e-4);
21
22QfMajoranaOperator *zero = qf_maj_op_zero();
23bool ichop_is_equal = qf_maj_op_equiv(op, zero, 1e-6);Parameters
- op – A pointer to the Majorana operator to be simplified.
- atol – The absolute tolerance for coefficient truncation.
Returns
An equivalent but simplified operator.
qf_maj_op_normal_ordered
QfMajoranaOperator *qf_maj_op_normal_ordered(const QfMajoranaOperator *op, bool ascending, bool reduce)
Returns an equivalent operator with normal ordered terms.
The normal order of an operator term is defined such that all actions are ordered lexicographically. Whether they ascend or descend depends on the value of the ascending parameter.
Example
1QfMajoranaOperator *op = qf_maj_op_zero();
2uint32_t modes[4] = {0, 2, 1, 3};
3QkComplex64 coeff = {1.0, 0.0};
4qf_maj_op_add_term(op, 4, modes, &coeff);
5
6QfMajoranaOperator *normal_ordered = qf_maj_op_normal_ordered(op, false, true);
7
8QkComplex64 coeff_minus = {-1.0, 0.0};
9QfMajoranaOperator *expected = qf_maj_op_zero();
10uint32_t modes_exp[4] = {3, 2, 1, 0};
11qf_maj_op_add_term(expected, 4, modes_exp, &coeff_minus);
12
13assert(qf_maj_op_equal(normal_ordered, expected));Parameters
- op – A pointer to the operator.
- ascending – Whether indices should ascend or descend.
- reduce – Whether to reduce each term to its minimal form by removing actions that square to the identity.
Returns
A pointer to the created operator.
qf_maj_op_is_hermitian
bool qf_maj_op_is_hermitian(const QfMajoranaOperator *op, double atol)
Checks whether an operator is Hermitian.
Example
1QfMajoranaOperator *op = qf_maj_op_zero();
2uint32_t modes1[2] = {0, 1};
3QkComplex64 coeff1 = {0.0, 1.00001};
4qf_maj_op_add_term(op, 2, modes1, &coeff1);
5uint32_t modes2[2] = {0, 1};
6QkComplex64 coeff2 = {0.0, -1};
7qf_maj_op_add_term(op, 2, modes2, &coeff2);
8
9assert(qf_maj_op_is_hermitian(op, 1e-4));
10assert(!qf_maj_op_is_hermitian(op, 1e-8));This check is implemented using qf_maj_op_equiv() on the qf_maj_op_normal_ordered() difference of op and its qf_maj_op_adjoint() and qf_maj_op_zero().
Parameters
- op – A pointer to the Majorana operator to be checked.
- atol – The absolute tolerance upto which coefficients are considered equal.
Returns
Whether the provided operator is Hermitian.
qf_maj_op_max_rank
uint32_t qf_maj_op_max_rank(const QfMajoranaOperator *op)
Checks the maximum rank of an operator.
Example
1QfMajoranaOperator *op = qf_maj_op_zero();
2uint32_t modes[4] = {0, 1, 2, 3};
3QkComplex64 coeff = {1.0, 0.0};
4qf_maj_op_add_term(op, 4, modes, &coeff);
5
6assert(qf_maj_op_max_rank(op), 4);The length of the longest term can depend on the operator’s form which means that (for example) operator simplification or normal-ordering can result in a different maximum rank.
Parameters
- op – A pointer to the Majorana operator to be checked.
Returns
The maximum rank of the operator.
qf_maj_op_is_even
bool qf_maj_op_is_even(const QfMajoranaOperator *op)
Checks whether an operator is even.
Example
1QfMajoranaOperator *op = qf_maj_op_zero();
2QkComplex64 coeff = {1.0, 0.0};
3uint32_t modes1[2] = {0, 1};
4qf_maj_op_add_term(op, 2, modes1, &coeff);
5
6assert(qf_maj_op_is_even(op));
7
8uint32_t modes2[1] = {2};
9qf_maj_op_add_term(op, 2, modes2, &coeff);
10
11assert(!qf_maj_op_is_even(op));An operator is considered even when all of its terms contain an even number of actions.
Parameters
- op – A pointer to the Majorana operator to be checked.
Returns
Whether the provided operator is even.
qf_maj_op_equal
bool qf_maj_op_equal(const QfMajoranaOperator *left, const QfMajoranaOperator *right)
Compare two operators for equality.
Example
1QfMajoranaOperator *one = qf_maj_op_one();
2QfMajoranaOperator *zero = qf_maj_op_zero();
3
4assert(qf_maj_op_equal(one, one));
5assert(!qf_maj_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.
qf_maj_op_equiv
bool qf_maj_op_equiv(const QfMajoranaOperator *left, const QfMajoranaOperator *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
1QfMajoranaOperator *zero = qf_maj_op_zero();
2
3QfMajoranaOperator *op = qf_maj_op_zero();
4uint32_t modes[0] = {};
5QkComplex64 coeff = {1e-7, 0.0};
6qf_maj_op_add_term(op, 0, modes, &coeff);
7
8assert(qf_maj_op_equiv(op, zero, 1e-6));
9assert(!qf_maj_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.
qf_maj_op_len
size_t qf_maj_op_len(const QfMajoranaOperator *op)
Returns the length (or number of terms) of the provided operator.
Example
1QfMajoranaOperator *op = qf_maj_op_zero();
2uint32_t modes[4] = {0, 1, 2, 3};
3QkComplex64 coeff = {1.0, 0.0};
4qf_maj_op_add_term(op, 4, modes, &coeff);
5
6assert(qf_maj_op_len(op) == 1);Parameters
- op – A pointer to the Majorana operator.
Returns
The length (or number of terms) of the operator.
qf_maj_op_relabel_modes
QfExitCode qf_maj_op_relabel_modes(QfMajoranaOperator *op, uint64_t num_modes, const uint32_t *permutation)
Relabels the modes of the provided operator.
Example
1QfMajoranaOperator *op = qf_maj_op_zero();
2uint32_t modes[4] = {0, 1, 2, 3};
3QkComplex64 coeff = {1.0, 0.0};
4qf_maj_op_add_term(op, 4, modes, &coeff);
5
6uint32_t permutation[4] = {3, 2, 1, 0};
7
8QfExitCode exit = qf_maj_op_relabel_modes(op, 4, permutation);
9
10assert(exit == QfExitCode_Success);Parameters
- op – A pointer to the Majorana 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.