Second Quantization

Second quantization looks at the problem of electronic structure through a different lens. Rather than assigning each of the $N_e$ electrons to a specific state (or orbital), second quantization tracks each orbital and stores whether there is an electron present in each of them and at the same time automatically ensures symmetry properties of the corresponding wave function. This is important because it allows quantum chemistry models to be specified without having to worry about anti-symmetrizing the input state (as is required for fermions) and also because second quantization allows such models to be simulated using small quantum computers.

As an example of second quantization in action, let's assume that $\psi_0\cdots \psi_{N-1}$ are an orthonormal set of spatial orbitals. These orbitals are chosen to represent the system as accurately as possible within the finite basis set considered. A common example of such orbitals are atomic orbitals which form an eigenbasis for the hydrogen atom. Because electrons have two spin states, two electrons can be crammed into each such spatial orbital. That is to say, the valid basis states are of the form $\psi_{0,\uparrow},\ldots,\psi_{N-1,\uparrow}, \psi_{0,\downarrow},\ldots,\psi_{N-1,\downarrow}$ where $\uparrow$ and $\downarrow$ are labels that specify the two eigenstates of the spin degree of freedom. This combined index of $(j,\sigma)$ for $\sigma \in {\uparrow,\downarrow}$ is called a spin-orbital because it stores both the spatial as well as the spin degree of freedom. In the chemistry library, spin-orbitals are stored in a SpinOrbital data structure, and are created as follows.

// The code snippets in this section require the following namespaces.
// Make sure to include these at the top of your file or namespace.
using Microsoft.Quantum.Chemistry;
using Microsoft.Quantum.Chemistry.OrbitalIntegrals;
    // First, we assign an orbital index, say `5`. Note that we use 0-indexing,
    // so this is the 6th orbital.
    var orbitalIdx = 5;

    // Second, we assign a spin index, say `Spin.u` for spin up or `Spin.d` for spin down.
    var spin = Spin.d;

    // the spin-orbital (5, ↓) is then
    var spinOrbital = new SpinOrbital(orbitalIdx, spin);

    // A tuple `(int, Spin)` is also implicitly recognized as a spin-orbital.
    (int, Spin) tuple = (orbitalIdx, spin);

    // We explicitly specify the type of `spinOrbital1` to demonstrate
    // the implicit cast to `SpinOrbital`.
    SpinOrbital spinOrbital1 = tuple;

This means that we can formally think of the basis for both the spin and spatial part of the wave function as $\psi_{0} \cdots \psi_{2N-1}$ where each of the indices now is an enumeration of a $(j,\sigma)$. One possible enumeration is $g(j,\sigma) = j+N\sigma'$. Another possible enumeration is $h(j,\sigma) = 2*j + \sigma$. The quantum chemistry library can use these conventions, and the spin-orbitals in such an encoding can be instantiated as follows.

    // Let us use the spin orbital created in the previous snippet.
    var spinOrbital = new SpinOrbital(5, Spin.d);

    // Let us set the total number of orbitals to be say, `7`.
    var nOrbitals = 7;

    // This converts a spin-orbital index to a unique integer, in this case `12`,
    // using the formula `g(j,σ)`.
    var integerIndexHalfUp = spinOrbital.ToInt(IndexConvention.HalfUp);

    // This converts a spin-orbital index to a unique integer, in this case `11`,
    // using the formula `h(j,σ)`.
    var integerIndexUpDown = spinOrbital.ToInt(IndexConvention.UpDown);

    // The default conversion uses the formula `h(j,σ)`, in this case `11`.
    var integerIndexDefault = spinOrbital.ToInt();

For fermionic systems, the Pauli exclusion principle prevents more than one electron from being present in any spin-orbital at the same time. This means that we can write the two legal states for $\psi_1$ as

\begin{equation} \psi_1 \rightarrow \begin{cases} \ket{0}_1 & \text{if $\psi_1$ is not occupied,} \\ \ket{1}_1 & \text{if $\psi_1$ is occupied.} \end{cases} \end{equation}

This encoding is great for quantum computers because it means that we can store the electronic occupation as a single quantum bit.

The occupation states for the $2N$ spin orbitals can similarly be stored in $2N$ qubits. As an example, if $N=2$ then the state

$$ \ket{0} \ket{1} \ket{1} \ket{0}, $$

would correspond to spin orbitals $1$ and $2$ being occupied with the remainder empty. Similarly, the state

$$ \ket{0} \equiv \ket{0}_0 \cdots \ket{0}_{N-1}, $$

has no electrons and is known as the 'vacuum state'.

A beautiful side-effect of second quantization is that we no longer have to explicitly keep track of the anti-symmetry of the quantum state. This is because, as we will see, the anti-symmetry of the state represents itself instead through the anti-commutation rules of the operators that create and destroy electronic occupations of a spin orbital.

Fermionic operators

The two fundamental operators that act on the second-quantized basis vectors are known as creation and annihilation operators. These operators insert or destroy electrons at a particular location. These are denoted $a^\dagger_j$ and $a_j$ respectively.

For example,

$$ a^\dagger_1 \ket{0}_1 = \ket{1}_1,\quad a^\dagger_1 \ket{1}_1 = 0,\quad a_1 \ket{0}_1 = 0,\quad a_1 \ket{1}_1 = \ket{0}_1. $$

Note that here $a^\dagger_1 \ket{1}_1=0$ and $a_1 \ket{0}_1$ yield the zero-vector not $\ket{0}_1$. Such operators are therefore neither Hermitian nor unitary. We represent general creation and annihilation operators using the LadderOperator<TIndex> type. For instance, a single creation operator is represented as follow.

// The code snippets in this section require the following namespaces.
// Make sure to include these at the top of your file or namespace.
using Microsoft.Quantum.Chemistry;
using Microsoft.Quantum.Chemistry.OrbitalIntegrals;
using Microsoft.Quantum.Chemistry.LadderOperators;
using Microsoft.Quantum.Chemistry.Fermion;
// We load this namespace for convenience methods for manipulating arrays.
using System.Linq;
    // Let us use the spin orbital created in the previous snippet.
    var spinOrbitalInteger = new SpinOrbital(5, Spin.d).ToInt();

    // We specify either a creation or annihilation operator using 
    // the enumerable type `RaisingLowering.u` or `RaisingLowering.d`
    // respectively;
    var creationEnum = RaisingLowering.u;

    // The type representing a creation operator is then initialized 
    // as follows. Here, we index these operators with integers.
    // Hence we initialize the generic ladder operator with an
    // integer index type.
    var ladderOperator0 = new LadderOperator<int>(creationEnum, spinOrbitalInteger);

    // An alternate constructor for a LadderOperator instead uses
    // a tuple.
    var ladderOperator1 = new LadderOperator<int>((creationEnum, spinOrbitalInteger));

Also using such operators we can express

$$ \ket{0} \ket{1} \ket{1} \ket{0} = a^\dagger_1 a^\dagger_2 \ket{0}^{\otimes 4}. $$

This sequence of operators would be constructed within the Hamiltonian simulation library using C# code that is similar to the single-spin orbital case considered above:

    // Let us initialize an array of tuples representing the
    // desired sequence of creation operators.
    var indices = new[] { (RaisingLowering.u, 1), (RaisingLowering.u, 2) };

    // We can convert this array of tuples to a sequence of ladder
    // operators using the `ToLadderSequence()` methods.
    var ladderSequences = indices.ToLadderSequence();

    // Sequences of ladder operators are quite general. For instance,
    // they could be bosonic operators, instead of fermionic operators.
    // We specialize them by constructing a `FermionTerm` representing 
    // a fermion creation operator on the index `2` followed by `1`.
    var fermionTerm = new FermionTerm(ladderSequences);

For a system of $k$ Fermions, in second quantization the action of the creation operator $a^\dagger_i$ is given by

$$ a^\dagger_i \ket{n_1, n_2, \ldots, 0_i, \ldots, n_k } = (-1)^{S_i} \ket{n_1, n_2, \ldots, 1_i, \ldots, n_k}, $$

and

$$ a^\dagger_i \ket{n_1, n_2, \ldots, 1_i, \ldots, n_k } = 0, $$

where $S_i = \sum_{j<i} a^\dagger_j a_j$ measures the total number of Fermions that are in the state of a single particle and that have an index $j < i$.

A third operator is also often used in second quantized representations. This operator is known as the number operator and is defined by

$$ n_i = a^\dagger_i a_i. $$

This operator counts the occupation of a given spin orbital, which is to say

\begin{align} n_i \ket{0}_i &= 0\nonumber\\ n_i \ket{1}_i &= \ket{1}_i. \end{align}

Similar to the above FermionTerm examples, this number operator is constructed as follows.

    // Let us use a new method to compactly create a sequence of ladder
    // operators. Note that we have omitted specifying whether the 
    // operators are raising or lowering. In this case, the first half
    // will be raising operators, and the second half will be lowering 
    // operators.
    var indices = new[] { 1, 1 }.ToLadderSequence();

    // We now construct a `FermionTerm` representing an annihilation operator
    // on the index 1 followed by the creation operator on the index 1.
    var fermionTerm0 = new FermionTerm(indices);

A subtlety emerges though when using creation or annihilation operators in fermionic systems. We require that any valid quantum state is anti-symmetric under exchange of labels. This means that

$$ a^\dagger_2 a^\dagger_1 \ket{0} = -a^\dagger_1 a^\dagger_2 \ket{0}. $$

Such operators are said to 'anti-commute' and in general for any $i, j$ we have that

$$ a^\dagger_i a^\dagger_j = -(1-\delta_{i,j})a^\dagger_j a^\dagger_i,\quad a^\dagger_i a_j =\delta_{i,j} - a_j a^\dagger_i. $$

Thus the following two LadderSequence<TIndex> instances are considered inequivalent

    // Let us initialize an array of tuples representing the
    // desired sequence of creation operators.
    var indices = new[] { (RaisingLowering.u, 1), (RaisingLowering.u, 2) };

    // We now construct a `LadderSequence` representing a creation operator
    // on the index 1 followed by 2, then a term with the reverse ordering.
    var ladderSequence = indices.ToLadderSequence();
    var ladderSequenceReversed = indices.Reverse().ToLadderSequence();

    // The following Boolean is `false`.
    var equal = ladderSequence == ladderSequenceReversed;

The requirement that each of the creation operators anti-commute means that using a second quantized representation does obviate the challenges faced by the anti-symmetry of Fermions. Instead the challenge re-emerges in our definition of the creation operators.

Using the anti-commutation rules, some LadderSequence instances actually correspond to the same sequence of fermionic operators, sometimes up to a minus sign. For instance, consider the Hamiltonian $a_0^\dagger a_1^\dagger a_1 a_0 = - a_1^\dagger a_0^\dagger a_1 a_0$. This motivates us to define a canonical ordering for every FermionTerm. Any FermionTerm is automatically put into canonical order as follows.

    // We now construct two `FermionTerms` that are equivalent with respect to
    // anti-commutation up to a sign change.
    var fermionTerm0 = new FermionTerm(new[] { 0, 1, 1, 0 }.ToLadderSequence());
    var fermionTerm1 = new FermionTerm(new[] { 1, 0, 1, 0 }.ToLadderSequence());

    // The following Boolean is `true`.
    var sequenceEqual = fermionTerm0 == fermionTerm1;

    // The change in sign is not compared above, but is an internally tracked
    // property of `FermionTerm`.
    int sign0 = fermionTerm0.Coefficient;
    var sign1 = fermionTerm1.Coefficient;

    // The following Boolean is `false`.
    var signEqual = sign0 == sign1;

Second-Quantized Fermionic Hamiltonian

It is perhaps unsurprising that the Hamiltonian in Quantum Models for Electronic Systems can be written in terms of creation and annihilation operators. In particular, if $\psi_j$ are the spin orbitals that form the basis then

$$ \hat{H} = \sum_{pq} h_{pq}a^\dagger_p a_q + \frac{1}{2}\sum_{pqrs} h_{pqrs}a^\dagger_p a^\dagger_q a_ra_s +h_\textrm{nuc},\label{eq:totalHam} $$

where $h_\textrm{nuc}$ is the nuclear energy (which is a constant under the Born-Oppenheimer approximation) and

$$ h_{pq} = \int_{-\infty}^\infty \psi^*_p(x_1) \left(-\frac{\nabla^2}{2} +V(x_1)\right) \psi_q(x_1)\mathrm{d}^3x_1, $$

where $V(x)$ is the mean-field potential, and

$$ h_{pqrs} = \int_{-\infty}^\infty \int_{-\infty}^\infty\psi_p^*(x_1)\psi_q^*(x_2) \left(\frac{1}{|x_1-x_2|} \right)\psi_r(x_2)\psi_s(x_1)\mathrm{d}^3x_1\mathrm{d}^3x_2.\label{eq:integrals} $$

The terms $h_{pq}$ are referred to as one-electron integrals because all such terms only involve single electrons and likewise $h_{pqrs}$ are the two-electron integrals. They are called integrals because computing the values of these coefficients requires an integral. The one electron terms describe the kinetic energy of the individual electrons and their interactions with the electric fields of the nuclei. The two-electron integrals on the other hand describe the interactions between the electrons.

An intuition for what these terms mean can be gleaned from the creation and annihilation operators that comprise each of them. For example, $h_{pq}a^\dagger_p a_q$ describes the electron hopping from spin orbital $q$ to spin orbital $p$. Similarly, the term $h_{pqrs} a^\dagger_p a^\dagger_q a_r a_s$ (for distinct $p,q,r,s$) describes two electrons in spin orbitals $r$ and $s$ scattering off of each other and ending up in spin orbitals $p$ and $q$. If $r=q$ and $p=s$ then $h_{prrp} a^\dagger_p a^\dagger_r a_r a_p = h_{prrp} n_p n_r$ gives the energy penalty associated with the two electrons being near each other, but does not describe a dynamical process.

We may represent such Hamiltonians using the FermionHamiltonian class, which is essentially a list containing all the desired FermionTerm instances. As Hamiltonians are Hermitian by definition, we index terms using the more specialized type HermitianFermionTerm that also uses Hermitian symmetry when checking whether terms are equivalent.

Let us construct a few illustrative examples. Consider the Hamiltonian $\hat{H} = a_0^\dagger a_1 + a_1^\dagger a_0$.

// The code snippets in this section require the following namespaces.
// Make sure to include these at the top of your file or namespace.
using Microsoft.Quantum.Chemistry;
using Microsoft.Quantum.Chemistry.LadderOperators;
using Microsoft.Quantum.Chemistry.Fermion;
// We load this namespace for convenience methods for manipulating arrays.
using System.Linq;
    // We create a `FermionHamiltonian` instance to store the fermion terms.
    var hamiltonian = new FermionHamiltonian();

    // We construct the terms to be added.
    var fermionTerm0 = new FermionTerm(new[] { 1, 0 }.ToLadderSequence());
    var fermionTerm1 = new FermionTerm(new[] { 0, 1 }.ToLadderSequence());

    // These fermion terms are not equal. The following Boolean is `false`.
    var sequenceEqual = fermionTerm0 == fermionTerm1;

    // However, these terms are equal under Hermitian symmetry.
    // We also take the opportunity to demonstrate equivalent constructors
    // for hermitian fermion terms
    var hermitianFermionTerm0 = new HermitianFermionTerm(fermionTerm0);
    var hermitianFermionTerm1 = new HermitianFermionTerm(new[] { 0, 1 });

    // These Hermitian fermion terms are equal. The following Boolean is `true`.
    var hermitianSequenceEqual = hermitianFermionTerm0 == hermitianFermionTerm1;

    // We add the terms to the Hamiltonian with the appropriate coefficient.
    // Note that these terms are identical.
    hamiltonian.Add(hermitianFermionTerm0, 1.0);
    hamiltonian.Add(hermitianFermionTerm1, 1.0);

We may simplify this construction using the fact that Hamiltonian operators are Hermitian operators. When adding terms to the Hamiltonian using Add, any non-Hermitian term such as fermionTerm0 is assumed to be paired with its Hermitian conjugate. Thus the following snippet also represents the same Hamiltonian:

    // We create a `FermionHamiltonian` instance to store the fermion terms.
    var hamiltonian = new FermionHamiltonian();

    // We construct the term to be added -- note the doubled coefficient.
    hamiltonian.Add(new HermitianFermionTerm(new[] { 1, 0 }), 2.0);

Using the anti-commutation rules, some FermionTerm instances in the Hamiltonian actually correspond to the same sequence of fermionic operators, sometimes up to a minus sign. For instance, consider the Hamiltonian $H=a_0^\dagger a_1^\dagger a_1 a_0 - a_1^\dagger a_0^\dagger a_1 a_0 =2a_0^\dagger a_1^\dagger a_1 a_0$, which is a sum of terms constructed above. It may not always be clear to the user that these are equivalent terms, and so they may be added to the Hamiltonian separately. Alternatively, one may be interested in modifying already-existing terms in the Hamiltonian. In these cases, we may combine equivalent terms as follows.

    // We create a `FermionHamiltonian` instance to store the fermion terms.
    var hamiltonian = new FermionHamiltonian();

    // We now create two Hermitian fermion terms that are equivalent with respect to
    // anti-commutation and Hermitian symmetry.
    var terms = new[] {
        (new[] { 0, 1, 1, 0 }, 1.0),
        (new[] { 1, 0, 1, 0 }, 1.0) }
    .Select(o => (new HermitianFermionTerm(o.Item1.ToLadderSequence()), o.Item2.ToDoubleCoeff()));

    // Now add `terms` to the Hamiltonian.
    hamiltonian.AddRange(terms);

    // There is only one unique term. `nTerms == 1` is `true`.
    var nTerms = hamiltonian.CountTerms();

By combining coefficients of equivalent terms, we reduce the total number of terms in the Hamiltonian. Later on, this reduces the number of quantum gates required to simulate the Hamiltonian.

Internal Representation

A fermionic Hamiltonian with one- and two-body interactions is represented in second-quantized notation as

$$ H=\sum_{pq}h_{pq}a^\dagger_{p}a_{q}+\frac{1}{2}\sum_{pqrs}h_{pqrs}a^\dagger_{p}a^\dagger_{q}a_{r}a_{s}. $$

In this notation, there are at most $N^2+N^4$ coefficients. However, many of these coefficients may be collected as they correspond to the same operator. For instance, in the case where $p,q,r,s$ are distinct indices, we may use the anti-commutation rules to show that:

$$ a^\dagger_{p}a^\dagger_{q}a_{r}a_{s} = -a^\dagger_{q}a^\dagger_{p}a_{r}a_{s} = -a^\dagger_{p}a^\dagger_{q}a_{s}a_{r} = a^\dagger_{q}a^\dagger_{p}a_{s}a_{r}. $$

Furthermore, as $H$ is Hermitian, every non-Hermitian fermionic operator, say $h_{pqrs}a^\dagger_{p}a^\dagger_{q}a_{r}a_{s}$, has a Hermitian conjugate that is also found in $H$. In order to uniquely index groups of terms characterized by these symmetries, we define a canonical ordering on the indices $(i_1,\cdots,i_n,j_1,\cdots,j_m)$ of any sequence of $n+m$ fermionic operators $a^\dagger_{i_1}\cdots a^\dagger_{i_n}a_{j_1}\cdots a_{j_m}$as follows:

  • All creation operators $a^\dagger_{i_\cdot}$ are placed before all annihilation operators $a_{j_\cdot}$.
  • All creation operator indices are sorted in ascending order, that is $i_1< i_2< \cdots < i_n$.
  • All annihilation operator indices are sorted in descending order, that is $j_1> j_2 \cdots > j_m$.
  • The left-most index is less than or equal to the right-most index, that is $i_1\le j_m$.

Let us identify this set of canonically ordered indices as

$$ (i_1,\cdots,i_n,j_1,\cdots,j_m) \in S_{n,m}. $$

With this canonical ordering, the fermionic Hamiltonian may be expressed as

$$ H=\sum_{(p,q)\in S_{1,1}}h'_{pq}\frac{a^\dagger_{p}a_{q}+a^\dagger_{q}a_{p}}{2}+\sum_{(p,q,r,s)\in S_{2,2}}h'_{pqrs}\frac{a^\dagger_{p}a^\dagger_{q}a_{r}a_{s}+a^\dagger_{s}a^\dagger_{r}a_{q}a_{p}}{2}, $$

with suitably adapted one- and two-electron integrals $h'_{pq}$ and $h'_{pqrs}$, respectively.