14Translating electrons into qubits

Encoding fermions must preserve their signs and operator algebra.

~28 min reading13 sections3 knowledge checks

Progress is saved only in this browser. No account or tracking.

The preceding occupations determine a sign

Concept plate 14
1Mode 00Mode 11Mode 20Mode 3Count earlier occupations1 earlier electron: sign = -1
A Jordan-Wigner-style string tracks parity before a target mode. In the illustrated 1,0,1,0 occupation, removing the mode-2 electron crosses one occupied earlier mode and contributes a minus sign. Mode order here increases left to right.
  • 1Modes: 0, 1, 2, 3
  • 2Preceding occupation count: 1
  • 3Fermionic sign: minus
Original technical lesson · 1 contextual figure addedDownload original MarkdownJump to the interactive model

The same chemistry, a different language

Our nitrogen molecule has not changed. It is still neutral, singlet N₂ at 1.85 Å. The original cc-pVDZ model had 28 spatial molecular orbitals. The active-space workflow studied earlier produced a six-electron, six-spatial-orbital model, with three active alpha and three active beta electrons. That reduced chemical model, not the complete 28-orbital problem, will now be translated into qubit operators. The separate notebook at 1.270025 Å remains a different calculation.

A fermion-to-qubit mapping specifies how an electronic state and every operator acting on it are represented by qubits. It does not select a better basis, recover omitted correlation, or solve the Schrödinger equation. With an exact, compatible mapping, the same model has the same predictions in different coordinates. Numerical screening during mapping is a separate approximation.

For the ordinary mappings in this lesson, six spatial orbitals mean twelve spin-orbital modes and twelve occupation-register qubits. There are still six active electrons. Neither number includes scratch or phase-estimation registers. Had we mapped the full 28-spatial-orbital model without reduction, the occupation register would instead have 56 qubits.

This distinction becomes concrete in the repository’s nitrogen mapping tutorial: it constructs a Hamiltonian from the selected orbitals, explicitly creates a MajoranaMapping, maps the active operator, retains the core-energy scalar separately, and validates in the appropriate electron-number sector. We will unpack that sequence rather than treat mapping as a mysterious conversion command. No tutorial, mapper, or test is being executed in this lesson.

From coordinates to occupations

In first quantization, one describes a fixed number of electrons using their coordinates and spin variables. Antisymmetry is a condition on the many-electron wavefunction: exchanging two electrons changes its sign. A determinant is one way to enforce it.

In second quantization, one first chooses an ordered list of one-electron modes, such as spin orbitals, and describes which modes are occupied. The underlying physics has not been quantized twice. The language has changed from named particle coordinates to occupation numbers and operations that change them.

With MM spin-orbital modes, an occupation basis state is

∣f0,f1,…,fM−1⟩,fj∈{0,1}.|f_0,f_1,\ldots,f_{M-1}\rangle, \qquad f_j\in\{0,1\}.

Here fjf_j says whether mode jj contains an electron. The exclusion principle permits at most one electron in a particular spin orbital. Two electrons of opposite spin may occupy the same spatial orbital because they occupy different modes.

The space containing all these occupation states is Fock space. It contains sectors with zero, one, two, and more electrons. This is not the SCF Fock matrix, which was an effective one-electron operator. The similar names refer to different objects.

A twelve-mode occupation register has 212=40962^{12}=4096 basis states. The sector with three alpha electrons in six alpha modes and three beta electrons in six beta modes has only

(63)(63)=400\binom{6}{3}\binom{6}{3}=400

states. These are illustrative combinatorial counts for the recorded active-space size, not a newly computed molecular result. An untapered qubit Hamiltonian ordinarily acts on all 4096 states. The mapping does not automatically remove the other electron sectors, and fixing alpha/beta populations does not by itself enforce a particular total-spin eigenvalue.

The ordering is part of the definition. We use

∣f0,…,fM−1⟩=(a0†)f0⋯(aM−1†)fM−1∣vac⟩.|f_0,\ldots,f_{M-1}\rangle =(a_0^\dagger)^{f_0}\cdots(a_{M-1}^\dagger)^{f_{M-1}}|\mathrm{vac}\rangle.

The vacuum ∣vac⟩|\mathrm{vac}\rangle has no occupied modes. The dagger denotes an adjoint. The operator aj†a_j^\dagger creates occupation in mode jj, and aja_j removes it. These are mathematical building blocks; a number-conserving molecular Hamiltonian does not manufacture net electrons.

Define the preceding-occupation count Pj=∑k<jfkP_j=\sum_{k<j}f_k. Then

aj∣f⟩=(−1)Pjfj∣f0,…,0j,…⟩,a_j|f\rangle=(-1)^{P_j}f_j |f_0,\ldots,0_j,\ldots\rangle,
aj†∣f⟩=(−1)Pj(1−fj)∣f0,…,1j,…⟩.a_j^\dagger|f\rangle=(-1)^{P_j}(1-f_j) |f_0,\ldots,1_j,\ldots\rangle.

The factors fjf_j and 1−fj1-f_j enforce empty/occupied restrictions. The sign encodes fermionic exchange. It is not an optional cosmetic phase: different paths between determinants interfere, so inconsistent signs change matrix elements and energies.

Consider the hand-worked four-mode state ∣1,0,1,0⟩|1,0,1,0\rangle, written in increasing mode order, not as a software bitstring. Removing the electron from mode 2 crosses one preceding occupied mode, giving −∣1,0,0,0⟩-|1,0,0,0\rangle. Creating in mode 3 crosses two and gives +∣1,0,1,1⟩+|1,0,1,1\rangle. Creating in already occupied mode 2 gives zero.

The two-mode state ∣1,1⟩|1,1\rangle makes the algebra especially visible: a1a0∣1,1⟩=∣0,0⟩a_1a_0|1,1\rangle=|0,0\rangle, whereas a0a1∣1,1⟩=−∣0,0⟩a_0a_1|1,1\rangle=-|0,0\rangle. Operators act rightmost first. Their sum vanishes. In general the canonical anticommutation relations are

{ap,aq}=0,{ap†,aq†}=0,{ap,aq†}=δpqI.\{a_p,a_q\}=0,\qquad \{a_p^\dagger,a_q^\dagger\}=0,\qquad \{a_p,a_q^\dagger\}=\delta_{pq}I.

The braces mean {A,B}=AB+BA\{A,B\}=AB+BA; δpq\delta_{pq} is one when the indices agree and zero otherwise. A correct mapping must preserve these relations, or their appropriate even-operator relations inside an encoded subspace.

Writing the operator without losing a factor or an index

Let KK denote the active spatial-orbital count. Let p,q,r,sp,q,r,s run over local active indices from zero to K−1K-1, and σ,τ\sigma,\tau denote alpha or beta spin. For the real, spin-conserving molecular integral paths considered here, write

Hmodel=EcoreI+Hactive,H_{\mathrm{model}}=E_{\mathrm{core}}I+H_{\mathrm{active}},
Hactive=∑pq,σhpqσapσ†aqσ+12∑pqrs,στgpqrsστapσ†arτ†asτaqσ.H_{\mathrm{active}} =\sum_{pq,\sigma}h^\sigma_{pq}a^\dagger_{p\sigma}a_{q\sigma} +\frac12\sum_{pqrs,\sigma\tau}g^{\sigma\tau}_{pqrs} a^\dagger_{p\sigma}a^\dagger_{r\tau}a_{s\tau}a_{q\sigma}.

Here hh contains the one-electron terms, including the effect of frozen inactive electrons when applicable. The raw, not antisymmetrized, Coulomb integral is in chemist order:

gpqrsστ=(pσqσ∣rτsτ).g^{\sigma\tau}_{pqrs}=(p_\sigma q_\sigma|r_\tau s_\tau).

The first pair belongs to electron coordinate 1 and the second to coordinate 2. The factor one-half accounts for the two ways of ordering the electron pair in this unrestricted sum. Formulas using antisymmetrized integrals often have a factor one-quarter and different index labels. They are not interchangeable array conventions.

The real restricted implementation shares spatial orbitals and integral blocks between spins. The unrestricted implementation keeps distinct alpha, beta, and mixed blocks. The mixed aabb tensor has the alpha pair on the left and beta pair on the right; exchanging whole pairs constructs the opposite-spin ordering. This matches the current producer/mapper paths, not every older explanatory comment in the repository.

Local active index 0 means the first entry of the selected active list. In our refined model it can correspond to full molecular-orbital index 4. Feeding the full index 4 where a local index 0 is required describes the wrong matrix element.

The native mapper uses excitation operators Epqσ=apσ†aqσE^\sigma_{pq}=a^\dagger_{p\sigma}a_{q\sigma} and the identity

apσ†arτ†asτaqσ=EpqσErsτ−δστδqrEpsσ.a^\dagger_{p\sigma}a^\dagger_{r\tau}a_{s\tau}a_{q\sigma} =E^\sigma_{pq}E^\tau_{rs}-\delta_{\sigma\tau}\delta_{qr}E^\sigma_{ps}.

That subtraction explains an otherwise surprising implementation detail: the restricted engine folds a two-electron contraction into its effective one-body matrix before mapping. It is algebraic bookkeeping, not an additional chemical approximation. See the native mapping engine.

Most importantly, the ordinary qubit_mapper/qdk path deliberately maps only HactiveH_{\mathrm{active}}. Its Hamiltonian-taking C++ entry point sets the supplied scalar to zero. Nuclear repulsion and frozen-inactive contributions remain in hamiltonian.get_core_energy(). ECP effects, if present in a different model, have already entered its chosen integrals/constants; mapping does not add another universal ECP correction. Our nitrogen example is all-electron before freezing the selected inactive orbitals.

There may nevertheless be an identity Pauli term in the output: mapping occupation operators generates one. That identity coefficient is not a substitute for the omitted core scalar. The core-energy test uses one-body integrals that produce an identity coefficient of 1 and a separately supplied core energy of 5; it asserts that the mapped identity coefficient remains 1. Lower-level array-based C++ overloads can accept a nonzero scalar, which explains why their tests look different.

Pauli arithmetic: the target language

A Pauli word is a product of I,X,Y,ZI,X,Y,Z, with at most one factor on each qubit. Operators on different qubits commute because they act on different tensor factors. Operators on the same qubit do not: XY=iZXY=iZ, but YX=−iZYX=-iZ; X2=Y2=Z2=IX^2=Y^2=Z^2=I.

For example,

(X0Z1)(Y0X1)=(iZ0)(iY1)=−Z0Y1.(X_0Z_1)(Y_0X_1) =(iZ_0)(iY_1)=-Z_0Y_1.

This illustrative multiplication shows why merely XOR-ing letter labels is insufficient: phases must also be accumulated. The repository’s native Pauli implementation merges sparse words by qubit index and implements these cyclic and anticyclic signs explicitly.

A qubit operator has the form

Hq=∑tctPt,H_q=\sum_t c_tP_t,

where tt labels terms, PtP_t is a Pauli word, and ctc_t its coefficient. The individual Pauli words are Hermitian. After identical words have been combined, their coefficients must be real for a Hermitian Hamiltonian. Complex intermediate coefficients are normal during multiplication; surviving imaginary coefficients cannot simply be discarded on the assumption that all input is valid chemistry.

Two repository objects serve different purposes. PauliOperator.X(0) constructs a symbolic Pauli expression. Products and sums build expression trees; .distribute() expands products of sums, .simplify() performs Pauli arithmetic and combines terms, and .prune_threshold(epsilon) removes small terms. This is useful for deriving or constructing small operators. QubitOperator, in contrast, wraps an operator representation container. Its Pauli-decomposition form holds dense string labels and a coefficient array, plus encoding, ordering, grouping, and optional tapering metadata. A different sum-of-squares container does not automatically expose a Pauli list.

There is an important explicit text-convention boundary. PauliOperator.to_canonical_terms(4) puts qubit 0 on the left. QubitOperator labels put qubit 0 on the right. The expression X0Z2X_0Z_2 is therefore XIZI in the first interface and IZIX in the second. The model-Hamiltonian conversion helper actually reverses canonical strings when crossing that boundary. Explicit index positions are more reliable than the overloaded word “little-endian.”

This instructional excerpt follows that implementation; it is not executed here:

from qdk_chemistry.data import PauliOperator, QubitOperator
import numpy as np

expr = PauliOperator.X(0) * PauliOperator.Z(2)
terms = expr.simplify().to_canonical_terms(4)
operator = QubitOperator(
    pauli_strings=[label[::-1] for _, label in terms],
    coefficients=np.array([complex(coefficient) for coefficient, _ in terms]),
)

This arbitrary spin operator has no claimed fermionic encoding. Attaching the text jordan-wigner would not prove it was derived from a particular fermionic Hamiltonian.

The current Pauli container validates matching term counts, nonempty equal-length labels, and valid Pauli characters. Addition concatenates terms rather than simplifying them; equiv combines duplicates for comparison. is_hermitian checks each stored coefficient, so duplicate imaginary terms that cancel should be combined before relying on that check. get_real_coefficients explicitly discards imaginary parts. Its property named schatten_norm computes the sum of absolute stored coefficients; it is not the general matrix Schatten trace norm. Duplicates can therefore affect that reported quantity.

The wrapper preserves a historical qubit_hamiltonian wire-format identifier even though the current class is QubitOperator. Serialization should preserve the actual container and encoding metadata, not just an informal printed list.

Jordan–Wigner: making the fermionic sign visible

In Jordan–Wigner encoding, qubit jj stores occupation fjf_j. A local lowering operator is (X+iY)/2(X+iY)/2, and a local raising operator is (X−iY)/2(X-iY)/2. Neither alone knows how many lower-index modes are occupied. The missing factor is a string of Z operators:

aj=(∏k<jZk)Xj+iYj2,aj†=(∏k<jZk)Xj−iYj2.a_j=\left(\prod_{k<j}Z_k\right)\frac{X_j+iY_j}{2}, \qquad a_j^\dagger=\left(\prod_{k<j}Z_k\right)\frac{X_j-iY_j}{2}.

Each preceding occupied qubit contributes a minus sign because Z∣1⟩=−∣1⟩Z|1\rangle=-|1\rangle. Thus the Z string implements precisely (−1)Pj(-1)^{P_j}. Empty products, such as for mode 0, mean identity.

A Z prefix is an occupation-parity calculator#

Supplementary · Analytical illustration

Apply a₂ to occupations in increasing mode order
Mode0123
Before1010
Z prefix−1+1targetlater
After1000

a₂ |1,0,1,0⟩ = −|1,0,0,0⟩

Prefix product: (−1) × (+1) = −1. One electron was removed; the order convention stays fixed.

Model and source. Occupations [1,0,1,0] in increasing mode order from left to right, not a software bitstring convention. Removing mode 2 crosses one occupied earlier mode, so the amplitude changes sign.

How to read this. Every occupied earlier mode contributes −1; every empty earlier mode contributes +1. This is how the mapping retains fermionic ordering.

Return to this explanation

Multiplying the raising and lowering expressions gives the number operator

nj=aj†aj=I−Zj2.n_j=a_j^\dagger a_j=\frac{I-Z_j}{2}.

This returns zero on an empty mode and one on an occupied mode. The Z prefixes cancel. For a real hopping term between p<qp<q, the result is

ap†aq+aq†ap=12(XpZp+1⋯Zq−1Xq+YpZp+1⋯Zq−1Yq).a_p^\dagger a_q+a_q^\dagger a_p =\frac12\left(X_pZ_{p+1}\cdots Z_{q-1}X_q +Y_pZ_{p+1}\cdots Z_{q-1}Y_q\right).

“Hopping” here means moving occupation between modes; molecular orbitals need not be localized sites. The interior parity string remains when the modes are nonadjacent. Its length illustrates the tradeoff: direct occupation storage is simple, but some mapped operators reach across many qubits.

A hand-worked one-spatial-orbital model ties everything together. Let its one-body integral be ϵ\epsilon, its Coulomb integral UU, and its two spin modes be alpha and beta. Then

Hactive=ϵ(nα+nβ)+Unαnβ,H_{\mathrm{active}}=\epsilon(n_\alpha+n_\beta)+U n_\alpha n_\beta,
Hq=(ϵ+U4)I−(ϵ2+U4)(Zα+Zβ)+U4ZαZβ.H_q=\left(\epsilon+\frac U4\right)I -\left(\frac\epsilon2+\frac U4\right)(Z_\alpha+Z_\beta) +\frac U4 Z_\alpha Z_\beta.

The half in the original two-electron sum has not halved the final opposite-spin interaction: both spin orderings contribute. With illustrative values ϵ=−1\epsilon=-1, U=0.4U=0.4, and Ecore=0.1E_{\mathrm{core}}=0.1, the Pauli coefficients are −0.9,0.4,0.4,0.1-0.9,0.4,0.4,0.1. Empty, singly occupied, and doubly occupied active states have energies 0, −1, and −1.6 before adding the core scalar. The doubly occupied total is −1.5. These numbers are toy arithmetic, not nitrogen energies or executed outputs.

Why the API calls the encoding a MajoranaMapping

Define two Hermitian operators for each fermionic mode:

γ2j=aj+aj†,γ2j+1=−i(aj−aj†).\gamma_{2j}=a_j+a_j^\dagger, \qquad \gamma_{2j+1}=-i(a_j-a_j^\dagger).

They satisfy {γj,γk}=2δjkI\{\gamma_j,\gamma_k\}=2\delta_{jk}I, and

aj=γ2j+iγ2j+12,aj†=γ2j−iγ2j+12.a_j=\frac{\gamma_{2j}+i\gamma_{2j+1}}2, \qquad a_j^\dagger=\frac{\gamma_{2j}-i\gamma_{2j+1}}2.

These are Majorana operators as a mathematical decomposition of ordinary fermionic operators. Their use does not imply that the eventual processor uses physical Majorana devices.

For Jordan–Wigner, the even Majorana is the preceding Z string followed by X, and the odd Majorana is the same string followed by Y. The two-mode factory table, in rightmost-qubit-zero labels, is exactly IX, IY, XZ, YZ. The factory implementation constructs those sparse words directly, and Python Majorana tests assert that reference table and its anticommutation algebra.

A bilinear contains two Majoranas. The common primitive is Bjk=iγjγkB_{jk}=i\gamma_j\gamma_k, for distinct indices. It is Hermitian for a valid Majorana representation. In particular, B2j,2j+1=−ZjB_{2j,2j+1}=-Z_j for Jordan–Wigner, so nj=(I+B2j,2j+1)/2n_j=(I+B_{2j,2j+1})/2.

The MajoranaMapping data class precomputes all upper-triangle bilinears. mapping.majorana(k) returns a sparse word when individual Majoranas are available. mapping.bilinear(j,k) returns a complex coefficient and sparse word; reversing its arguments changes the sign. Equal indices are deliberately rejected by that bilinear accessor. Products of bilinears suffice for this even, number-conserving Hamiltonian, allowing the engine to support some encodings that do not expose individual Majoranas.

The native mapping method, step by step

The algorithm family is qubit_mapper; its default implementation is qdk. The separate MajoranaMapping argument is required. There is no need to mutate an encoding-name setting on the mapper. Its two numerical settings are threshold=1e-12 and integral_threshold=1e-12, both doubles. See the Python adapter and factory contract.

First, the adapter gets KK from the active one-body matrix and requires mapping.num_modes == 2*K. It determines the restricted/unrestricted strategy from the orbitals. It maps the untapered base if the supplied mapping carries tapering metadata, then handles reduction afterward.

Second, the native engine expands excitation operators through Majorana bilinears. Restricted input permits spin summation and real eightfold Coulomb symmetry; unrestricted input keeps distinct spin channels and combines opposite-spin contributions using whole-pair exchange. This is not a general complex spin–orbit or spin-flipping Hamiltonian interface: the present integral entry points consume real arrays and these spin-conserving structures.

Third, it multiplies Pauli words using binary symplectic storage. This simply means storing two bit masks: X sets an X bit, Z sets a Z bit, Y sets both, and I sets neither. XOR combines the masks, while a separate phase calculation tracks powers of ii. A hash table accumulates all contributions with the same Pauli word. Intermediate complex values are retained.

Fourth, threshold is applied to the accumulated final coefficient, not to each fractional contribution to that coefficient. The engine retains magnitudes greater than or equal to this threshold. This matters because many individually small terms can add constructively, and larger ones can cancel. integral_threshold is different: it screens input integrals, or the contracted effective one-body entries on the restricted path, before their contributions are accumulated. Late Pauli screening does not undo earlier integral screening. The equality convention also differs between individual input loops; do not build a scientific error specification around the exact threshold boundary.

Finally, sparse words are rendered using the mapping’s full qubit width and returned with complex coefficient storage, encoding=base_mapping.base_encoding, and fermion_mode_order=BLOCKED. A name is descriptive metadata for this native engine: the actual Pauli/bilinear data determines the transformation. Ordinary .run locks algorithm settings as explained in Lesson 3; configure thresholds before the call.

The implementation supports up to 1024 qubit positions through its packed-word dispatch and rejects zero-qubit maps. This is an implementation capacity, emphatically not a claim that constructing a dense 512-spatial-orbital molecular operator is cheap. A generic two-electron tensor still has quartic-size work, and the accumulated Pauli sum can itself be large. Precomputing all bilinears adds quadratic-in-mode-count table overhead, with additional word-length storage. If positive screening removes every term, the current wrapper reaches a Pauli container that rejects an empty term list; a completely screened operator is not automatically padded to a zero operator.

Container choice affects preprocessing memory. Canonical input supplies dense two-electron arrays. Cholesky input is contracted one pair-index row at a time without reconstructing the whole four-index tensor. Generic factorized input falls through to dense getters on this ordinary Pauli route. Sparse input has a restricted-only fast path that canonicalizes stored entries under real eightfold Coulomb symmetry. Unlike the sparse container’s literal getter semantics, this consumer supplies symmetry partners. Conflicting values at distinct symmetry-related positions are not averaged into a repaired tensor: the canonical position, or a deterministic selected partner, wins. Use physically consistent sparse data rather than exploit that selection rule. Negative/out-of-range sparse indices are rejected.

The factorized-storage mapper tests compare Cholesky and sparse paths with appropriate dense references. Those are source-defined checks, not tests run here. Storage efficiency does not eliminate the cost of the resulting operator or guarantee equivalent behavior for arbitrary nonsymmetric arrays.

For error accounting, a removed Pauli contribution ΔH=∑tdtPt\Delta H=\sum_t d_tP_t obeys ∥ΔH∥≤∑t∣dt∣\|\Delta H\|\leq\sum_t|d_t|, where the norm is the operator norm and every Pauli word has norm one. Thus many small dropped coefficients can matter collectively. This bound addresses that truncation only; it is not an automatic chemical-accuracy guarantee covering active-space choice, integral factorization, or the wrong symmetry sector.

Parity and Bravyi–Kitaev: changing what a qubit stores

Jordan–Wigner stores occupations directly. Parity encoding instead stores cumulative parity:

bj=f0⊕f1⊕⋯⊕fj.b_j=f_0\oplus f_1\oplus\cdots\oplus f_j.

Here ⊕\oplus is addition modulo two: two ones add to zero. The inverse is f0=b0f_0=b_0, fj=bj−1⊕bjf_j=b_{j-1}\oplus b_j. No information has been lost. Counting ones in the encoded bitstring now does not count electrons.

For a hand-worked example, the increasing-mode occupation vector f=(1,0,1,0)f=(1,0,1,0) becomes b=(1,1,0,0)b=(1,1,0,0). Its displayed rightmost-qubit-zero bitstring is 0011, whereas the Jordan–Wigner string was 0101. Both describe the same two occupied modes under different decoding rules.

CNOT gates can compute these cumulative XORs reversibly. For two modes the parity mapping is obtained by conjugating the Jordan–Wigner operators by CNOT from qubit 0 to qubit 1. The source test checks the resulting Majorana labels XX, XY, XZ, YI. For more modes, the factory builds the corresponding X tails explicitly. Parity makes some global occupation parity information local, but changing an occupation can require updating many stored parity bits; it is not uniformly more local than Jordan–Wigner.

Bravyi–Kitaev, abbreviated BK, balances occupation and parity information using a tree. A Fenwick tree stores parity over selected ranges so that both queries and updates touch logarithmically many ranges rather than every preceding or following mode. The native factory computes parity, update, and remainder sets and uses them to choose Z and X factors in each Majorana image.

For four modes, the standard BK occupation encoding is

b0=f0,b1=f0⊕f1,b2=f2,b3=f0⊕f1⊕f2⊕f3.b_0=f_0,\quad b_1=f_0\oplus f_1,\quad b_2=f_2,\quad b_3=f_0\oplus f_1\oplus f_2\oplus f_3.

Its inverse is f0=b0f_0=b_0, f1=b0⊕b1f_1=b_0\oplus b_1, f2=b2f_2=b_2, and f3=b1⊕b2⊕b3f_3=b_1\oplus b_2\oplus b_3. Our illustrative f=(1,0,1,0)f=(1,0,1,0) therefore becomes b=(1,1,1,0)b=(1,1,1,0), displayed as 0111. Three encoded ones still describe two electrons. These inverse relations agree with the four-mode number-operator Z products exercised in the mapper tests and the exact labels checked by the Qiskit interoperability tests.

The native bravyi_kitaev factory constructs on the next-power-of-two tree and removes out-of-range indices for non-power-of-two mode counts. bravyi_kitaev_tree uses a recursively balanced tree over the actual mode count. The two variants can differ, particularly away from powers of two; their names must not be interchanged merely because both contain “BK.”

Neither ordinary parity nor ordinary BK reduces the untapered qubit count below the mode count. They change Pauli support and state encoding. Shorter words can reduce some circuit costs, but term structure, hardware connectivity, state preparation, and the simulation algorithm still matter. Under an exact Clifford change of basis, Pauli words are permuted up to signs, so even their combined coefficient absolute-sum need not improve when their lengths do.

A Clifford unitary maps every Pauli word to another Pauli word, possibly with a sign, under conjugation. H, S, and CNOT generate familiar examples. If CC converts encoding A to encoding B, the consistent transformations are

∣ψB⟩=C∣ψA⟩,HB=CHAC†.|\psi_B\rangle=C|\psi_A\rangle, \qquad H_B=CH_AC^\dagger.

Changing only the operator or only its label is not that transformation. More general custom choices can also alter determinant-relative phases, not just the binary occupation labels.

What mappings are actually available

The native factories at this revision include more than the older JW/BK-only overviews suggest:

Python construction What is supplied
MajoranaMapping.jordan_wigner(M) Occupation encoding, with M qubits
MajoranaMapping.parity(M) Cumulative-parity encoding, with M qubits
MajoranaMapping.bravyi_kitaev(M) Standard Fenwick-style BK table
MajoranaMapping.bravyi_kitaev_tree(M) Balanced-tree BK table
MajoranaMapping.parity(M, symmetries) Parity table plus two-qubit-reduction metadata
MajoranaMapping.symmetry_conserving_bravyi_kitaev(M, symmetries) BK-tree table plus two-qubit-reduction metadata
MajoranaMapping.verstraete_cirac(lattice) Graph-oriented bilinear encoding with auxiliary qubits and stabilizers

The Python symmetry argument is a Symmetries object carrying alpha/beta counts; it is not the two positional integer arguments used by the corresponding C++ overload. The bindings define that boundary. Reduction factories require appropriate even mode counts and valid populations. Their table and num_qubits still describe the pre-taper basis; the mapper later reduces the operator. How the selected symmetry sector makes that legitimate belongs to Lesson 15, not to an assumption that BK alone “saves two qubits.”

Verstraete–Cirac is a distinct graph-oriented tradeoff, not a free molecular compression option. Its concrete factory requires at least three lattice sites, identifies graph edges nonadjacent in the chosen site sequence, introduces auxiliary fermionic modes, and dresses relevant bilinears with auxiliary stabilizers. A stabilizer here is an operator whose chosen eigenvalue specifies the physical encoded subspace. The factory provides bilinears, not an individual-Majorana table, and can use more qubits than physical modes. The native engine adds auxiliary-sector penalty terms when these stabilizers are present. Its full enlarged-space spectrum is therefore not simply the original molecular spectrum with fewer letters. Preparing the intended subspace and tracking those terms are additional obligations; ordinary nitrogen mapping does not need this route.

There is also qubit_mapper/sum_of_squares, a representation-specific method rather than another general encoding. Its current implementation requires a FactorizedHamiltonianContainer, an untapered mapping labelled Jordan–Wigner, and the matching doubled mode count. It returns structured factors instead of an ordinary Pauli decomposition. Unlike the ordinary Pauli mapper, its metadata energy shift includes the core constant. The implementation also has a different threshold meaning: it screens small one-body eigenvalues in that construction. We reserve its operator and circuit derivation for the later sum-of-squares lesson; thresholds and energy offsets must not be transferred between these two methods by name alone.

Custom tables: flexible does not mean automatically valid

MajoranaMapping.from_table(table, name=...) accepts two sparse Pauli words per fermionic mode. Each word is a sorted list of (qubit_index, operator_code) pairs, with X=1, Y=2, Z=3 and absent factors interpreted as identity. from_bilinears(num_modes, bilinears, name=...) instead accepts coefficient/word pairs for every j<kj<k, ordered row by row through the upper triangle. For MM modes that is (2M)(2M−1)/2(2M)(2M-1)/2 bilinears. The number of encoded qubits is inferred from the highest referenced qubit, not forced to equal the mode count.

The actual constructor guards include nonempty/even table size, positive mode count for the bilinear form, and the required number of bilinear entries. Accessors check ranges; asking for individual Majoranas of a bilinear-only map fails. The constructor does not perform a general proof of canonical anticommutation or a complete validation/normalization of arbitrary sparse-word algebra. Sorted, well-formed words and a mathematically valid encoding remain the author’s responsibility. A custom name is not evidence of correctness.

For Majorana-atomic tables, there is a compact independent algebra check. Represent words by binary masks (x,z)(x,z). Two words anticommute when

x⋅z′+z⋅x′=1(mod2).x\cdot z^{\prime}+z\cdot x^{\prime}=1\pmod 2.

The dot products count overlapping mask bits; this is the symplectic parity test. Distinct Majoranas must anticommute and each must square to identity. The repository tests explicitly multiply factory words and check those relations. Bilinear-only encodings instead need their appropriate product relations and any physical-subspace constraints; checking that the vector has the right length cannot establish them. The common engine’s name-independent dispatch is valuable precisely because it lets a validated custom representation reuse the chemical operator machinery.

Optional libraries and the order of operations

The openfermion and qiskit mapper variants are optional plugins, not native implementations hidden behind aliases. They use mapping.base_encoding as a string selector and ignore the supplied table. A manually built table with a misleading standard name can therefore produce a different result from the native engine without a mismatch error. Use factory-generated mappings when comparing backends.

The OpenFermion plugin supports base names jordan-wigner, bravyi-kitaev, and bravyi-kitaev-tree; it does not expose a parity branch here. Its conversion code constructs an interleaved spin-orbital interaction tensor with the appropriate integral permutation and one-half factor, reindexes those fermionic tensors into blocked order, then calls the external transform. It subtracts the core scalar that OpenFermion initially included. Native and plugin outputs thus follow the same ordinary active-energy convention. Compression and tolerances inside the external library are an additional boundary, not these plugins’ own threshold settings.

The Qiskit Nature plugin supports jordan-wigner, bravyi-kitaev, and parity. It builds an ElectronicEnergy, obtains its second-quantized operator, and invokes the selected external mapper. For unrestricted input it transposes the mixed aabb tensor to the bbaa arrangement expected by Qiskit’s h2_ba argument. It does not add the QDK core scalar. Neither plugin has a general arbitrary-Majorana-table implementation. Their dense getter conversions can also materialize tensors that the native Cholesky mapper avoids.

One optional-plugin pattern is therefore create("qubit_mapper", "qiskit").run(active_hamiltonian, mapping) with a supported factory mapping and the plugin actually installed. This is a source-backed calling pattern, not a claim that the dependency is available in this environment. The OpenFermion tests and Qiskit tests contain conditional registration and coefficient-comparison checks. A stale test description claiming BK-tree has no native equivalent does not override the current native factory.

A further practical limit is that external conversion can infer width from surviving nonidentity terms. In particular, the OpenFermion converter removes zero terms and derives width from the highest retained qubit index; zero and identity-only operators are not robust full-width placeholders through that path. Always verify expected width rather than assume metadata carries unused modes through every library.

Keeping the state and the Hamiltonian in the same encoding

Three concepts must remain separate: mode order, binary encoding, and string display order. Native molecular mapping uses blocked modes, alpha first and beta second. Interleaved mode order alternates alpha and beta. Parity/BK say how the ordered occupations become encoded bits. Rightmost-qubit-zero says how those bits or Pauli letters are printed. The FermionModeOrder enum describes the first distinction only.

QubitOperator.to_interleaved(K) currently permutes Pauli-string positions and marks the result interleaved. It requires width 2*K. It is a wire permutation of an already mapped operator, not a general decode/reorder/re-encode transformation and not a fermionic-sign correction. It does not recompute BK trees or prove compatibility with a freshly remapped interleaved fermionic problem. Reordering canonical fermionic creation operators can introduce occupation-dependent signs; arbitrary wire swaps are not automatically that reordering. A consistent wire permutation can be used if the state and every consumer are transformed accordingly, but the OpenFermion plugin instead reorders fermionic tensors before mapping when establishing its blocked convention.

Current ordinary state_prep implementations prepare occupation-basis states and label their circuits jordan-wigner. The base scattering helper constructs a dense index by adding each determinant occupation bit at its corresponding power-of-two position. It does not accept a MajoranaMapping and silently convert to BK. Particular state-preparation methods also have coefficient-type and size restrictions, which we will examine in Lesson 16. Internal “binary encoding” compression in a sparse-state synthesis algorithm is not, by its name alone, Bravyi–Kitaev fermionic encoding; that construction expands back to its declared output basis.

The encoding_validation module is now deprecated. Its retained validate_encoding_compatibility facade emits a warning, requires both encoding strings, and compares those strings. It does not compare mode order, active-orbital identity, width, custom tables, determinant phases, or full tapering provenance. It is not a mathematical compatibility proof, nor a promise that every consumer automatically calls it. The explicit mapping workflow improves clarity, but cannot make those obligations disappear.

For our continuing nitrogen story, the dependable baseline is therefore the selected active orbitals, a blocked Jordan–Wigner Hamiltonian, and a compatible occupation-basis state preparation. A different encoding is entirely legitimate, but the state must be transformed too. Relabelling a circuit as BK leaves every gate unchanged and does not perform the required conversion.

Following the nitrogen trace and knowing what it validates

The tutorial’s core mapping excerpt is short because the preceding choices carry its meaning:

from qdk_chemistry.algorithms import create
from qdk_chemistry.data import MajoranaMapping

# active_hamiltonian was constructed from the selected, gauge-fixed orbitals.
n_spatial = active_hamiltonian.get_one_body_integrals()[0].shape[0]
mapping = MajoranaMapping.jordan_wigner(num_modes=2 * n_spatial)
mapper = create("qubit_mapper", "qdk", threshold=1e-10, integral_threshold=1e-14)
qubit_hamiltonian = mapper.run(active_hamiltonian, mapping)
core_energy = active_hamiltonian.get_core_energy()

Those are the tutorial’s actual screening choices, not the defaults. This excerpt is instructional only. Its output is an operator, not an executed circuit, an eigenstate, or an energy measurement.

The tutorial subsequently validates the transformation by forming the sparse Pauli matrix, selecting only indices whose low six occupation bits contain three alpha electrons and high six bits contain three beta electrons, and diagonalizing that 400-state sector. It adds core_energy to the active eigenvalue and compares with the same selected-space CASCI energy. This tests representation consistency for the chosen model; it does not validate that choosing six orbitals was chemically sufficient.

That sector mask is correct for blocked Jordan–Wigner occupations. Applying the same count-of-ones mask to parity or BK bits would choose a different space. Those encodings require decoding occupations or projecting with appropriately transformed number operators. Similarly, the full-register lowest eigenvalue need not be the physical six-electron state.

QubitOperator.to_matrix uses a complex-preserving Pauli matrix utility. Dense matrices cost 4q4^q entries for qq qubits; its sparse construction also enumerates 2q2^q register states and has explicit index-capacity limits. This is a small-system check, not a scalable way to validate every large target. It is distinct from the classical qubit-solver wrappers discussed earlier, which can discard imaginary parts and do not enforce the physical electron sector. We have inspected the tutorial and tests, not run either validation route here.

We now have the central translation contract: preserve the chemical model and its constants, define an ordered fermionic space, preserve its signs in the operator algebra, attach an honest encoding description, and prepare states in that same description. Qubit mapping performs this operator translation. Circuit mapping will synthesize gates for a chosen operation derived from the operator. Tapering will reduce a symmetry sector under additional conditions. None is a synonym for the others.

The next lesson uses those distinctions to remove qubits only where a known symmetry makes the reduction legitimate. We will not throw away an apparently unused bit merely because its printed value happens to be zero in one determinant.

Make the idea your own

Supplementary learning

The original lesson above is preserved in full, with labeled supplemental figures placed beside the relevant explanations. The model and questions below are also learning aids, not newly executed chemistry results.

Group compatible Pauli terms

Interactive model

Explore the Pauli language used after mapping; grouping is downstream of a correctly encoded operator.

Illustrative model, not a scientific calculation. A greedy, input-order-dependent partition into pairwise qubit-wise commuting terms. It is valid but not necessarily a minimum grouping. Globally commuting terms can require a more general measurement basis.

Enable JavaScript to explore this model. The assumptions and original lesson remain readable without it.

Check your understanding

Supplementary learning

Reason through these 3 questions. Your answers do not mark the lesson as read, and nothing is locked.

1. What does a Jordan-Wigner parity string preserve?
2. What must agree between a prepared state and mapped Hamiltonian?
3. Does every fermion-to-qubit encoding store a mode occupation directly on the same-index qubit?

Enable JavaScript to check and save answers locally.

Source notes & references (29)

No imports or scientific/circuit/test execution. Native mapping consumes real spin-conserving integral structures, applies integral screening before final accumulated Pauli threshold, and excludes core energy on the ordinary Hamiltonian-taking route. Sparse mapper supplies symmetry partners unlike literal container getters. Explicit custom-map constructors do not prove canonical anticommutation. Pauli expression canonical strings and QubitOperator labels have opposite index direction. Ordinary state_prep remains Jordan-Wigner; deprecated compatibility facade checks encoding strings only. to_interleaved is a wire permutation, not a general fermionic remapping. Optional plugins dispatch by encoding name, not supplied tables; OpenFermion conversion infers width from surviving terms. Verstraete-Cirac requires a physical codespace and auxiliary penalties. SOS uses separate energy-shift/threshold semantics. Earlier Lesson9 mixed-spin wording was corrected to follow actual alpha-pair/beta-pair producer/consumer paths.

Public source: microsoft/qdk-chemistry, pinned to 97a3ff4fb86e. This course describes that revision, not every later release.

Look up a term

On this page

  1. The same chemistry, a different language
  2. From coordinates to occupations
  3. Writing the operator without losing a factor or an index
  4. Pauli arithmetic: the target language
  5. Jordan–Wigner: making the fermionic sign visible
  6. Why the API calls the encoding a MajoranaMapping
  7. The native mapping method, step by step
  8. Parity and Bravyi–Kitaev: changing what a qubit stores
  9. What mappings are actually available
  10. Custom tables: flexible does not mean automatically valid
  11. Optional libraries and the order of operations
  12. Keeping the state and the Hamiltonian in the same encoding
  13. Following the nitrogen trace and knowing what it validates
  14. Interactive model
  15. Knowledge check
  16. Source notes

The complete journey

Course homeGlossarySavedAbout

Search the course

Search titles and the full lesson text.

    Tab to a result, Enter to open. Escape closes search.