Mapper Library¶
The C API provides efficient implementations of commonly used operator representation mapper routines.
Map a |
|
Map a |
|
Map a |
|
Map a |
|
Map a |
|
Map a |
|
Map a |
|
Map a |
|
Map a |
|
Map a |
|
Map a |
-
QfFermionOperator *qf_edge_vertex_to_fermion(const QfEdgeVertexOperator *edge_op)¶
Map a
QfEdgeVertexOperatorto aQfFermionOperator.Definition¶
This function decomposes the edge and vertex operators in terms of the fermionic creation and annihilation operators, as defined here.
Example¶
1// define some kind of edge-vertex operator 2QfEdgeVertexOperator *edge_op = qf_edge_op_one(); 3 4// and map it to a fermionic operator 5QfFermionOperator *fer_op = qf_edge_vertex_to_fermion(edge_op);
Note
The mapped operator is not simplified. Because each generator expands into a sum of fermionic terms, the result generally contains duplicate terms; call
qf_ferm_op_normal_ordered()followed byqf_ferm_op_simplify()to reduce it.- Parameters:
edge_op – A pointer to the edge-vertex operator to be mapped.
- Returns:
A pointer to the mapped fermionic operator.
-
QfMajoranaOperator *qf_edge_vertex_to_majorana(const QfEdgeVertexOperator *edge_op)¶
Map a
QfEdgeVertexOperatorto aQfMajoranaOperator.Definition¶
This function decomposes the edge and vertex operators in terms of the Majorana operators, as defined here.
Example¶
1// define some kind of edge-vertex operator 2QfEdgeVertexOperator *edge_op = qf_edge_op_one(); 3 4// and map it to a Majorana operator 5QfMajoranaOperator *maj_op = qf_edge_vertex_to_majorana(edge_op);
Note
The mapped operator is not simplified; see
qf_maj_op_normal_ordered()andqf_maj_op_simplify().- Parameters:
edge_op – A pointer to the edge-vertex operator to be mapped.
- Returns:
A pointer to the mapped Majorana operator.
-
QfExitCode qf_ferm_op_jordan_wigner(const QfFermionOperator *op, uint32_t num_qubits, QkObs **out)¶
Applies the Jordan-Wigner transformation to an operator.
Map a
QfFermionOperatorto a QkObs under the Jordan-Wigner transformation. [JW-ferm]Definition¶
The Jordan-Wigner transformation maps fermionic creation and annihilation operators to spin (or in this case, qubit) operators:
\[a^\dagger_j \rightarrow \bigotimes_{k\lt j} \sigma^Z_k \otimes \sigma^-_j ~~\text{and}~~ a_j \rightarrow \bigotimes_{k\lt j} \sigma^Z_k \otimes \sigma^+_j \, ,\]where \(a^\dagger_j\) (\(a_j\)) is the fermionic creation (annihilation) operator acting on the \(j\)-th spin-less fermionic mode, \(\sigma^P\) with \(P \in \{X,Y,Z\}\) are the spin-\(\frac{1}{2}\) Pauli operators and \(\sigma^\pm = (\sigma^X \pm \mathrm{i} \sigma^Y) / 2\).
This mapping preserves the fermionic anti-commutation relations by introducing a chain of \(\sigma^Z\) operators on all qubits preceding the acted-upon index \(j\).
[JW-ferm]P. Jordan and E. Wigner, Über das Paulische Äquivalenzverbot, Zeitschrift für Physik 47, No. 9. (1928), pp. 631–651, doi:10.1007/BF01331938.
Memory usage¶
The result is not guaranteed to be fully simplified: duplicate terms are merged as it is assembled, to bound the memory required, but some may remain. Call
qk_obs_canonicalizeif you need them all combined. The exact number of terms returned may therefore vary with the number of threads used, which does not affect the operator that the result represents.This mapping is parallelized for speed, and that choice costs memory. Each worker thread accumulates into an observable of its own, and the terms are handed to whichever thread is free rather than partitioned by which Pauli strings they produce, so every thread ends up holding roughly a full copy of the mapped operator. Peak memory therefore grows with the number of threads: expect on the order of the mapped operator’s size times the thread count, plus the input operator.
If memory matters more than wall-clock time, reduce the thread count through rayon’s
RAYON_NUM_THREADSenvironment variable – peak memory falls roughly in proportion, and the mapping takes correspondingly longer – or map the operator in batches and add the partial results together yourself, which bounds the peak by the batch size at the cost of repeating the merging work.Example¶
1// define some kind of fermionic operator 2QfFermionOperator *hamil = qf_ferm_op_one(); 3 4// and map it to a qubit operator 5QkObs *result; 6QfExitCode exit = qf_ferm_op_jordan_wigner(hamil, 4, &result); 7 8assert(exit == QfExitCode_Success);
- Parameters:
op – A pointer to the fermionic operator to be mapped.
num_qubits – The number of qubits of the resulting operator. This must be strictly greater than the largest mode index acted upon by
op.out – A pointer to where the created qubit operator will be written on success. It is left untouched if the transformation fails.
- Returns:
An exit code. This is
>0if an error occurred. In particular, aQfExitCode_ValueErroris returned ifnum_qubitsis too small to hold the operator’s support.
-
QfExitCode qf_maj_op_jordan_wigner(const QfMajoranaOperator *op, uint32_t num_qubits, QkObs **out)¶
Applies the Jordan-Wigner transformation to a Majorana operator.
Map a
QfMajoranaOperatorto a QkObs under the Jordan-Wigner transformation. [JW-maj]Definition¶
With the
QfMajoranaOperatorconvention that even indices carry \(\gamma_j = a^\dagger_j + a_j\) and odd ones \(\gamma'_j = i(a^\dagger_j - a_j)\), the Majorana index \(m\) acts on the fermionic mode \(\lfloor m/2 \rfloor\) and maps onto a single Pauli string,\[\gamma_j \rightarrow \bigotimes_{k\lt j} \sigma^Z_k \otimes \sigma^X_j ~~\text{and}~~ \gamma'_j \rightarrow \bigotimes_{k\lt j} \sigma^Z_k \otimes \sigma^Y_j \, .\]This also avoids an intermediate blowup relative to converting to a
QfFermionOperatorfirst: each fermionic action maps onto a two-term sum, so that route inflates a single Pauli string into up to \(4^L\) terms for a term built from \(L\) Majorana operators. The saving grows with the length of the terms; for single-operator terms the two routes cost about the same.[JW-maj]P. Jordan and E. Wigner, Über das Paulische Äquivalenzverbot, Zeitschrift für Physik 47, No. 9. (1928), pp. 631–651, doi:10.1007/BF01331938.
Memory usage¶
See
qf_ferm_op_jordan_wigner(); the same parallelization and merging behaviour applies.Example¶
1// define some kind of Majorana operator 2QfMajoranaOperator *hamil = qf_maj_op_one(); 3 4// and map it to a qubit operator 5QkObs *result; 6QfExitCode exit = qf_maj_op_jordan_wigner(hamil, 4, &result); 7 8assert(exit == QfExitCode_Success);
- Parameters:
op – A pointer to the Majorana operator to be mapped.
num_qubits – The number of qubits of the resulting operator. Note that this is counted in fermionic modes, so it must be strictly greater than the largest Majorana index acted upon by
opdivided by two.out – A pointer to where the created qubit operator will be written on success. It is left untouched if the transformation fails.
- Returns:
An exit code. This is
>0if an error occurred. In particular, aQfExitCode_ValueErroris returned ifnum_qubitsis too small to hold the operator’s support.
-
QfExitCode qf_edge_op_jordan_wigner(const QfEdgeVertexOperator *op, uint32_t num_qubits, QkObs **out)¶
Applies the Jordan-Wigner transformation to an edge-vertex operator.
Map a
QfEdgeVertexOperatorto a QkObs under the Jordan-Wigner transformation. [JW-edge]Definition¶
Writing \(l_\text{min}\) and \(l_\text{max}\) for the smaller and larger of the two indices, the generalized edge operators map onto single Pauli strings,
\[\begin{align} V_l = E_{ll} &\rightarrow \sigma^Z_l \, , \nonumber \\ E_{lr} &\rightarrow \mp \, \sigma^Y_{l_\text{min}} \left( \bigotimes_{l_\text{min} \lt k \lt l_\text{max}} \sigma^Z_k \right) \sigma^X_{l_\text{max}} \nonumber \end{align}\]where the sign is negative for \(l \lt r\) and positive otherwise. The \(\sigma^Z\) chains of the two underlying Majorana operators cancel below the lower index, which is why the \(\sigma^Z\) string spans only the modes strictly between the two endpoints.
[JW-edge]P. Jordan and E. Wigner, Über das Paulische Äquivalenzverbot, Zeitschrift für Physik 47, No. 9. (1928), pp. 631–651, doi:10.1007/BF01331938.
[Gandon-edge]L. Gandon et al., Fermionic quantum simulation with flow sets, arXiv:2512.11418.
Memory usage¶
See
qf_ferm_op_jordan_wigner(); the same parallelization and merging behaviour applies.Example¶
1// define some kind of edge-vertex operator 2QfEdgeVertexOperator *hamil = qf_edge_op_one(); 3 4// and map it to a qubit operator 5QkObs *result; 6QfExitCode exit = qf_edge_op_jordan_wigner(hamil, 4, &result); 7 8assert(exit == QfExitCode_Success);
Note
Reversing the two indices leaves the Pauli string unchanged and flips only the sign, which is the antisymmetry \(E_{lr} = -E_{rl}\). Contrast
qf_transfer_op_jordan_wigner(), where the coefficient is the same for both orientations and the Pauli letters change instead.Note
These Pauli strings differ from those in Eq. (10) of [Gandon-edge] by an exchange of \(\sigma^X\) and \(\sigma^Y\) on the two endpoints. This is a single-qubit basis choice – both conventions satisfy every defining relation of the algebra – and the one used here is the one consistent with
qf_edge_vertex_to_fermion(), so that mapping an operator directly agrees with converting it to aQfFermionOperatorfirst.- Parameters:
op – A pointer to the edge-vertex operator to be mapped.
num_qubits – The number of qubits of the resulting operator. This must be strictly greater than the largest mode index acted upon by
op.out – A pointer to where the created qubit operator will be written on success. It is left untouched if the transformation fails.
- Returns:
An exit code. This is
>0if an error occurred. In particular, aQfExitCode_ValueErroris returned ifnum_qubitsis too small to hold the operator’s support.
-
QfExitCode qf_transfer_op_jordan_wigner(const QfTransferVertexOperator *op, uint32_t num_qubits, QkObs **out)¶
Applies the Jordan-Wigner transformation to a transfer-vertex operator.
Map a
QfTransferVertexOperatorto a QkObs under the Jordan-Wigner transformation. [JW-transfer]Definition¶
Writing \(l_\text{min}\) and \(l_\text{max}\) for the smaller and larger of the two indices, the generalized transfer operators map onto single Pauli strings,
\[\begin{align} V_l = T_{ll} &\rightarrow \sigma^Z_l \, , \nonumber \\ T_{lr} &\rightarrow -\frac{1}{2} \, \sigma^P_{l_\text{min}} \left( \bigotimes_{l_\text{min} \lt k \lt l_\text{max}} \sigma^Z_k \right) \sigma^P_{l_\text{max}} \nonumber \end{align}\]where \(P = X\) for \(l \lt r\) and \(P = Y\) otherwise.
[JW-transfer]P. Jordan and E. Wigner, Über das Paulische Äquivalenzverbot, Zeitschrift für Physik 47, No. 9. (1928), pp. 631–651, doi:10.1007/BF01331938.
[Gandon-transfer]L. Gandon et al., Fermionic quantum simulation with flow sets, arXiv:2512.11418.
Memory usage¶
See
qf_ferm_op_jordan_wigner(); the same parallelization and merging behaviour applies.Example¶
1// define some kind of transfer-vertex operator 2QfTransferVertexOperator *hamil = qf_transfer_op_one(); 3 4// and map it to a qubit operator 5QkObs *result; 6QfExitCode exit = qf_transfer_op_jordan_wigner(hamil, 4, &result); 7 8assert(exit == QfExitCode_Success);
Note
The index order works the opposite way round to
qf_edge_op_jordan_wigner(): the coefficient is \(-1/2\) for both orientations and it is the Pauli letters that swap. \(T_{lr}\) and \(T_{rl}\) are genuinely different operators, with no antisymmetry relating them.Note
As for
qf_edge_op_jordan_wigner(), these Pauli strings differ from Eq. (10) of [Gandon-transfer] by a single-qubit basis choice; the convention used here is the one consistent withqf_transfer_vertex_to_fermion().- Parameters:
op – A pointer to the transfer-vertex operator to be mapped.
num_qubits – The number of qubits of the resulting operator. This must be strictly greater than the largest mode index acted upon by
op.out – A pointer to where the created qubit operator will be written on success. It is left untouched if the transformation fails.
- Returns:
An exit code. This is
>0if an error occurred. In particular, aQfExitCode_ValueErroris returned ifnum_qubitsis too small to hold the operator’s support.
-
QfMajoranaOperator *qf_fermion_to_majorana(const QfFermionOperator *fer_op)¶
Map a
QfFermionOperatorto aQfMajoranaOperator.Definition¶
This function implements the simple transformation:
\[a^\dagger_j \rightarrow \frac{1}{2} (\gamma_j - i \gamma'_j) ~~\text{and}~~ a_j \rightarrow \frac{1}{2} (\gamma_j + i \gamma'_j)\]where \(a^\dagger_j\) (\(a_j\)) is the fermionic creation (annihilation) operator acting on the \(j\)-th spin-less fermionic mode, and \(\gamma_j\)/\(\gamma'_j\) are the two Majorana fermion operators. In the case of the
QfMajoranaOperatorthese will be stored on the even and odd Majorana modes, respectively.Example¶
1// define some kind of fermionic operator 2QfFermionOperator *fer_op = qf_ferm_op_one(); 3 4// and map it to a majorana operator 5QfMajoranaOperator *maj_op = qf_fermion_to_majorana(fer_op);
- Parameters:
fer_op – A pointer to the fermionic operator to be mapped.
- Returns:
A pointer to the mapped majorana operator.
-
QfFermionOperator *qf_majorana_to_fermion(const QfMajoranaOperator *maj_op)¶
Map a
QfMajoranaOperatorto aQfFermionOperator.Definition¶
This function implements the simple transformation:
\[\gamma_j \rightarrow a^\dagger_j + a_j ~~\text{and}~~ \gamma'_j \rightarrow i (a^\dagger_j - a_j)\]where \(\gamma_j\)/\(\gamma'_j\) are the two Majorana fermion operators (stored on the even and odd modes, respectively), and \(a^\dagger_j\) (\(a_j\)) is the fermionic creation (annihilation) operator acting on the \(j\)-th spin-less fermionic mode.
Example¶
1// define some kind of majorana operator 2QfMajoranaOperator *maj_op = qf_maj_op_one(); 3 4// and map it to a fermion operator 5QfFermionOperator *fer_op = qf_majorana_to_fermion(maj_op);
- Parameters:
maj_op – A pointer to the majorana operator to be mapped.
- Returns:
A pointer to the mapped fermion operator.
-
QfFermionOperator *qf_transfer_vertex_to_fermion(const QfTransferVertexOperator *transfer_op)¶
Map a
QfTransferVertexOperatorto aQfFermionOperator.Definition¶
This function decomposes the transfer and vertex operators in terms of the fermionic creation and annihilation operators, as defined here.
Example¶
1// define some kind of transfer-vertex operator 2QfTransferVertexOperator *transfer_op = qf_transfer_op_one(); 3 4// and map it to a fermionic operator 5QfFermionOperator *fer_op = qf_transfer_vertex_to_fermion(transfer_op);
Note
The mapped operator is not simplified. Because each generator expands into a sum of fermionic terms, the result generally contains duplicate terms; call
qf_ferm_op_normal_ordered()followed byqf_ferm_op_simplify()to reduce it.- Parameters:
transfer_op – A pointer to the transfer-vertex operator to be mapped.
- Returns:
A pointer to the mapped fermionic operator.
-
QfMajoranaOperator *qf_transfer_vertex_to_majorana(const QfTransferVertexOperator *transfer_op)¶
Map a
QfTransferVertexOperatorto aQfMajoranaOperator.Definition¶
This function decomposes the transfer and vertex operators in terms of the Majorana operators, as defined here.
Example¶
1// define some kind of transfer-vertex operator 2QfTransferVertexOperator *transfer_op = qf_transfer_op_one(); 3 4// and map it to a Majorana operator 5QfMajoranaOperator *maj_op = qf_transfer_vertex_to_majorana(transfer_op);
Note
The mapped operator is not simplified; see
qf_maj_op_normal_ordered()andqf_maj_op_simplify().- Parameters:
transfer_op – A pointer to the transfer-vertex operator to be mapped.
- Returns:
A pointer to the mapped Majorana operator.
-
QfEdgeVertexOperator *qf_transfer_vertex_to_edge_vertex(const QfTransferVertexOperator *transfer_op)¶
Map a
QfTransferVertexOperatorto aQfEdgeVertexOperator.Definition¶
This function rewrites each transfer operator in terms of the edge and vertex operators. A vertex operator maps to itself, whereas a transfer operator \(T_{jk}\) becomes a length-two product of an edge and a vertex operator.
Example¶
1// define some kind of transfer-vertex operator 2QfTransferVertexOperator *transfer_op = qf_transfer_op_one(); 3 4// and map it to an edge-vertex operator 5QfEdgeVertexOperator *edge_op = qf_transfer_vertex_to_edge_vertex(transfer_op);
Note
This is the one mapper that stays within the interaction-operator representations, so it is the natural route to compare the two: mapping a transfer operator to an edge-vertex operator and then on to a fermionic one agrees with mapping it to a fermionic operator directly.
- Parameters:
transfer_op – A pointer to the transfer-vertex operator to be mapped.
- Returns:
A pointer to the mapped edge-vertex operator.