TernaryTreeEncoding¶
- class TernaryTreeEncoding(tree, mode_map=None)¶
Bases:
objectA ternary tree compiled into the Pauli images of its Majorana operators.
Pairing the tree’s legs into Majorana operators and building their Pauli strings is done once, here, rather than per mapped operator. Pass one of these to the ternary-tree mappers.
The pairing follows Algorithm 1 of the Bonsai paper [1]: from each node, descend its
Xlink and thenZlinks until reaching a leg, which carries \(\gamma\) of that node’s mode; theYlink likewise gives \(\gamma'\). This is what makes \(|0\cdots0\rangle\) the fermionic vacuum, so it is not an adjustable convention.Usage¶
>>> from qiskit_fermions.mappers import TernaryTree, TernaryTreeEncoding >>> enc = TernaryTreeEncoding(TernaryTree.breadth_first(4, 3)) >>> enc.num_modes, enc.max_weight (4, 2)
The encoding is built once and reused across every operator mapped through it, so the pairing and string construction are not repeated per call. The qubit count of a mapped operator is given to the mapper rather than fixed here, so one encoding serves registers of any width from
num_modesupwards.Attributes
- max_weight¶
The largest Pauli weight of any single Majorana operator.
- num_modes¶
The number of fermionic modes this encoding covers.
Methods
- majorana_image(majorana)¶
Return the Pauli image of Majorana operator
majorana, as(qubit, label)pairs.The index is
2 * mode + is_prime, matchinggamma(). The string is ordered by ascending qubit.>>> from qiskit_fermions.mappers import TernaryTree, TernaryTreeEncoding >>> enc = TernaryTreeEncoding(TernaryTree.chain(3, "Z")) >>> enc.majorana_image(4) [(0, 'Z'), (1, 'Z'), (2, 'X')]
The coefficient is always exactly \(1\): a leg’s string is a product of Paulis on distinct qubits, so it is Hermitian and squares to the identity with no phase to correct.
- total_parity(num_qubits)¶
Build the total fermionic parity observable of this encoding.
A tree’s \(2N+1\) legs pair into \(2N\) Majorana operators, leaving exactly one over, and that leftover is the total parity \(\prod_j (1 - 2 n_j)\).
- Parameters:
num_qubits – the number of qubits for the resulting observable. Must be at least the encoding’s mode count; a larger value pads with the identity.
- Returns:
a single Pauli string with a \(\pm 1\) coefficient.
- Return type:
The total-parity observable
- Raises:
ValueError – if
num_qubitsis below the encoding’s mode count.
An observable to measure, not a constraint to impose¶
Both eigenvalues of this operator are physical, so do not project a state onto the \(+1\) sector. A ternary-tree encoding spends one qubit per mode and is a unitary isomorphism onto the whole \(2^N\)-dimensional space: both parity sectors are represented, each with multiplicity \(2^{N-1}\), and there is no unphysical subspace to project away.
Local encodings that add ancilla qubits do work that way. The flow sets in the 1D and 2D Fermi-Hubbard guides use more qubits than modes, which makes the extra dimensions unphysical and a stabilizer subspace the thing that keeps the encoding faithful. Ternary trees add no such qubits and have no such subspace.
Note also that the string is not in general the all-\(Z\) string. It is the leg reached by the all-\(Z\) path, which carries the identity on every node not on that path.
Usage¶
On the Jordan-Wigner chain it is the full \(Z\) string:
>>> from qiskit_fermions.mappers import TernaryTree, TernaryTreeEncoding >>> TernaryTreeEncoding(TernaryTree.chain(4, "Z")).total_parity(4) <SparseObservable with 1 term on 4 qubits: (1+0j)(Z_3 Z_2 Z_1 Z_0)>
On the balanced tree at four modes it is not:
>>> TernaryTreeEncoding(TernaryTree.breadth_first(4, 3)).total_parity(4) <SparseObservable with 1 term on 4 qubits: (1+0j)(Z_3 Z_0)>
The coefficient is \(\pm 1\) and depends on the tree, so it is computed rather than assumed.