Ordering Functions

QfFermionOperator *qf_ferm_op_canonical_order(const QfFermionOperator *op)

Returns a copy of a fermionic operator with its terms in a canonical order.

The terms are sorted into a canonical order that depends only on each term’s structure (the operator string it represents) and not on its coefficient. The order is therefore deterministic for a given set of terms regardless of how the operator was assembled. The terms themselves are left untouched — this only reorders them, it does not simplify or normal-order the operator.

 1QfFermionOperator *op = qf_ferm_op_zero();
 2bool actions[2] = {true, false};
 3uint32_t modes_a[2] = {1, 0};
 4QkComplex64 coeff_a = {1.0, 0.0};
 5qf_ferm_op_add_term(op, 2, actions, modes_a, &coeff_a);
 6uint32_t modes_b[2] = {0, 1};
 7QkComplex64 coeff_b = {2.0, 0.0};
 8qf_ferm_op_add_term(op, 2, actions, modes_b, &coeff_b);
 9
10QfFermionOperator *ordered = qf_ferm_op_canonical_order(op);

Note

Any group indices (see qf_ferm_op_get_groups()) are preserved: each term carries its group index along as it moves, since a group index is a per-term tag independent of term order. Terms of the same group are simply no longer contiguous afterwards. If the input has no groups, neither does the result.

Parameters:
  • op – A pointer to the operator whose terms are to be reordered.

Returns:

A pointer to the created operator.

QfMajoranaOperator *qf_maj_op_canonical_order(const QfMajoranaOperator *op)

Returns a copy of a Majorana operator with its terms in a canonical order.

The terms are sorted into a canonical order that depends only on each term’s structure (the operator string it represents) and not on its coefficient. The order is therefore deterministic for a given set of terms regardless of how the operator was assembled. The terms themselves are left untouched — this only reorders them, it does not simplify or normal-order the operator.

1QfMajoranaOperator *op = qf_maj_op_zero();
2uint32_t modes_a[2] = {1, 0};
3QkComplex64 coeff_a = {1.0, 0.0};
4qf_maj_op_add_term(op, 2, modes_a, &coeff_a);
5uint32_t modes_b[2] = {0, 1};
6QkComplex64 coeff_b = {2.0, 0.0};
7qf_maj_op_add_term(op, 2, modes_b, &coeff_b);
8
9QfMajoranaOperator *ordered = qf_maj_op_canonical_order(op);

Note

Any group indices (see qf_maj_op_get_groups()) are preserved: each term carries its group index along as it moves, since a group index is a per-term tag independent of term order. Terms of the same group are simply no longer contiguous afterwards. If the input has no groups, neither does the result.

Parameters:
  • op – A pointer to the operator whose terms are to be reordered.

Returns:

A pointer to the created operator.

QfEdgeVertexOperator *qf_edge_op_canonical_order(const QfEdgeVertexOperator *op)

Returns a copy of an edge-vertex operator with its terms in a canonical order.

The terms are sorted into a canonical order that depends only on each term’s structure (the operator string it represents) and not on its coefficient. The order is therefore deterministic for a given set of terms regardless of how the operator was assembled. The terms themselves are left untouched — this only reorders them, it does not simplify or normal-order the operator.

 1QfEdgeVertexOperator *op = qf_edge_op_zero();
 2uint32_t left_a[1] = {1};
 3uint32_t right_a[1] = {2};
 4QkComplex64 coeff_a = {1.0, 0.0};
 5qf_edge_op_add_term(op, 1, left_a, right_a, &coeff_a);
 6uint32_t left_b[1] = {0};
 7uint32_t right_b[1] = {1};
 8QkComplex64 coeff_b = {2.0, 0.0};
 9qf_edge_op_add_term(op, 1, left_b, right_b, &coeff_b);
10
11QfEdgeVertexOperator *ordered = qf_edge_op_canonical_order(op);

Note

Any group indices (see qf_edge_op_get_groups()) are preserved: each term carries its group index along as it moves, since a group index is a per-term tag independent of term order. Terms of the same group are simply no longer contiguous afterwards. If the input has no groups, neither does the result.

Parameters:
  • op – A pointer to the operator whose terms are to be reordered.

Returns:

A pointer to the created operator.

QfTransferVertexOperator *qf_transfer_op_canonical_order(const QfTransferVertexOperator *op)

Returns a copy of a transfer-vertex operator with its terms in a canonical order.

The terms are sorted into a canonical order that depends only on each term’s structure (the operator string it represents) and not on its coefficient. The order is therefore deterministic for a given set of terms regardless of how the operator was assembled. The terms themselves are left untouched — this only reorders them, it does not simplify or normal-order the operator.

 1QfTransferVertexOperator *op = qf_transfer_op_zero();
 2uint32_t left_a[1] = {1};
 3uint32_t right_a[1] = {2};
 4QkComplex64 coeff_a = {1.0, 0.0};
 5qf_transfer_op_add_term(op, 1, left_a, right_a, &coeff_a);
 6uint32_t left_b[1] = {0};
 7uint32_t right_b[1] = {1};
 8QkComplex64 coeff_b = {2.0, 0.0};
 9qf_transfer_op_add_term(op, 1, left_b, right_b, &coeff_b);
10
11QfTransferVertexOperator *ordered = qf_transfer_op_canonical_order(op);

Note

Any group indices (see qf_transfer_op_get_groups()) are preserved: each term carries its group index along as it moves, since a group index is a per-term tag independent of term order. Terms of the same group are simply no longer contiguous afterwards. If the input has no groups, neither does the result.

Parameters:
  • op – A pointer to the operator whose terms are to be reordered.

Returns:

A pointer to the created operator.

QfFermionOperator *qf_ferm_op_group_order(const QfFermionOperator *op)

Returns a copy of a fermionic operator with its terms ordered by group index.

The terms are sorted by their group index alone, which makes each group one contiguous run of terms and the group indices non-decreasing. The sort is stable, so terms within a group keep their relative order. The terms themselves are left untouched — this only reorders them, it does not simplify or normal-order the operator.

Group indices say only which terms belong together, so this changes the operator’s layout, not its value. What the layout buys is lookup cost: qf_ferm_op_split_out_groups() has to scan every term to find the requested groups in general, but on a group-ordered operator each group’s terms form one range it can locate by binary search, so a lookup costs what the requested groups cost rather than what the held terms cost.

 1QfFermionOperator *op = qf_ferm_op_zero();
 2bool actions[2] = {true, false};
 3uint32_t modes_a[2] = {0, 1};
 4QkComplex64 coeff_a = {1.0, 0.0};
 5qf_ferm_op_add_term(op, 2, actions, modes_a, &coeff_a);
 6uint32_t modes_b[2] = {1, 0};
 7QkComplex64 coeff_b = {2.0, 0.0};
 8qf_ferm_op_add_term(op, 2, actions, modes_b, &coeff_b);
 9uint32_t groups[2] = {1, 0};
10qf_ferm_op_set_groups(op, groups, 2);
11
12QfFermionOperator *ordered = qf_ferm_op_group_order(op);

Note

An operator tracking no group indices (see qf_ferm_op_get_groups()) has nothing to order by and is returned as an unchanged copy. The result tracks no groups either.

Parameters:
  • op – A pointer to the operator whose terms are to be reordered.

Returns:

A pointer to the created operator.

QfMajoranaOperator *qf_maj_op_group_order(const QfMajoranaOperator *op)

Returns a copy of a Majorana operator with its terms ordered by group index.

The terms are sorted by their group index alone, which makes each group one contiguous run of terms and the group indices non-decreasing. The sort is stable, so terms within a group keep their relative order. The terms themselves are left untouched — this only reorders them, it does not simplify or normal-order the operator.

Group indices say only which terms belong together, so this changes the operator’s layout, not its value. What the layout buys is lookup cost: qf_maj_op_split_out_groups() has to scan every term to find the requested groups in general, but on a group-ordered operator each group’s terms form one range it can locate by binary search, so a lookup costs what the requested groups cost rather than what the held terms cost.

 1QfMajoranaOperator *op = qf_maj_op_zero();
 2uint32_t modes_a[2] = {0, 1};
 3QkComplex64 coeff_a = {1.0, 0.0};
 4qf_maj_op_add_term(op, 2, modes_a, &coeff_a);
 5uint32_t modes_b[2] = {2, 3};
 6QkComplex64 coeff_b = {2.0, 0.0};
 7qf_maj_op_add_term(op, 2, modes_b, &coeff_b);
 8uint32_t groups[2] = {1, 0};
 9qf_maj_op_set_groups(op, groups, 2);
10
11QfMajoranaOperator *ordered = qf_maj_op_group_order(op);

Note

An operator tracking no group indices (see qf_maj_op_get_groups()) has nothing to order by and is returned as an unchanged copy. The result tracks no groups either.

Parameters:
  • op – A pointer to the operator whose terms are to be reordered.

Returns:

A pointer to the created operator.

QfEdgeVertexOperator *qf_edge_op_group_order(const QfEdgeVertexOperator *op)

Returns a copy of an edge-vertex operator with its terms ordered by group index.

The terms are sorted by their group index alone, which makes each group one contiguous run of terms and the group indices non-decreasing. The sort is stable, so terms within a group keep their relative order. The terms themselves are left untouched — this only reorders them, it does not simplify or normal-order the operator.

Group indices say only which terms belong together, so this changes the operator’s layout, not its value. What the layout buys is lookup cost: qf_edge_op_split_out_groups() has to scan every term to find the requested groups in general, but on a group-ordered operator each group’s terms form one range it can locate by binary search, so a lookup costs what the requested groups cost rather than what the held terms cost.

 1QfEdgeVertexOperator *op = qf_edge_op_zero();
 2uint32_t left_a[1] = {0};
 3uint32_t right_a[1] = {1};
 4QkComplex64 coeff_a = {1.0, 0.0};
 5qf_edge_op_add_term(op, 1, left_a, right_a, &coeff_a);
 6uint32_t left_b[1] = {1};
 7uint32_t right_b[1] = {2};
 8QkComplex64 coeff_b = {2.0, 0.0};
 9qf_edge_op_add_term(op, 1, left_b, right_b, &coeff_b);
10uint32_t groups[2] = {1, 0};
11qf_edge_op_set_groups(op, groups, 2);
12
13QfEdgeVertexOperator *ordered = qf_edge_op_group_order(op);

Note

An operator tracking no group indices (see qf_edge_op_get_groups()) has nothing to order by and is returned as an unchanged copy. The result tracks no groups either.

Parameters:
  • op – A pointer to the operator whose terms are to be reordered.

Returns:

A pointer to the created operator.

QfTransferVertexOperator *qf_transfer_op_group_order(const QfTransferVertexOperator *op)

Returns a copy of a transfer-vertex operator with its terms ordered by group index.

The terms are sorted by their group index alone, which makes each group one contiguous run of terms and the group indices non-decreasing. The sort is stable, so terms within a group keep their relative order. The terms themselves are left untouched — this only reorders them, it does not simplify or normal-order the operator.

Group indices say only which terms belong together, so this changes the operator’s layout, not its value. What the layout buys is lookup cost: qf_transfer_op_split_out_groups() has to scan every term to find the requested groups in general, but on a group-ordered operator each group’s terms form one range it can locate by binary search, so a lookup costs what the requested groups cost rather than what the held terms cost.

 1QfTransferVertexOperator *op = qf_transfer_op_zero();
 2uint32_t left_a[1] = {0};
 3uint32_t right_a[1] = {1};
 4QkComplex64 coeff_a = {1.0, 0.0};
 5qf_transfer_op_add_term(op, 1, left_a, right_a, &coeff_a);
 6uint32_t left_b[1] = {1};
 7uint32_t right_b[1] = {2};
 8QkComplex64 coeff_b = {2.0, 0.0};
 9qf_transfer_op_add_term(op, 1, left_b, right_b, &coeff_b);
10uint32_t groups[2] = {1, 0};
11qf_transfer_op_set_groups(op, groups, 2);
12
13QfTransferVertexOperator *ordered = qf_transfer_op_group_order(op);

Note

An operator tracking no group indices (see qf_transfer_op_get_groups()) has nothing to order by and is returned as an unchanged copy. The result tracks no groups either.

Parameters:
  • op – A pointer to the operator whose terms are to be reordered.

Returns:

A pointer to the created operator.