Spin fermion transforms¶

Chemistry problems involve electrons, which are fermions, while quantum computers work in the language of qubits (or, equivalently, spins or two-level systems).

The qat.fermion module of QLM comes with a few tools to go from the fermionic representation to the spin representation. In particular, three transformations are implemented:

  • Jordan-Wigner transformation,
  • parity transformation,
  • Bravyi-Kitaev transformation.

Fermionic hamiltonian to spin Hamiltonian¶

Let us look at a simple example with a single $c^\dagger_0 c_1 + \frac{1}{2}c^\dagger_0 c^\dagger_1 c_0 c_1$ operator acting on 3 qubits.

In [1]:
import numpy as np

from qat.core import Term
from qat.fermion.hamiltonians import FermionHamiltonian

# We define an arbitrary fermionic Hamiltonian H_f
nqbits = 3
H_fermion = FermionHamiltonian(nqbits, [Term(1.0, "Cc", [0, 1]), Term(0.5, "CCcc", [0, 1, 0, 1])])

print(f"H_fermion = {H_fermion}")
H_fermion = 1.0 * (Cc|[0, 1]) +
0.5 * (CCcc|[0, 1, 0, 1])

We can convert the fermionic Hamiltonian operator to a spin Hamiltonian operator using the method .to_spin. By default the Jordan-Wigner transform is used.

In [2]:
# Using the Jordan-Wigner transform
H_spin = H_fermion.to_spin("jordan-wigner")

# Using the Bravyi-Kitaev transform
H_spin = H_fermion.to_spin("bravyi-kitaev")

# Using the parity transform
H_spin = H_fermion.to_spin("parity")

print(f"H_spin = {H_spin}")
H_spin = (-0.125+0j) * I^3 +
-0.25j * (Y|[0]) +
(-0.25+0j) * (XZ|[0, 1]) +
(0.25+0j) * (X|[0]) +
0.25j * (YZ|[0, 1]) +
(-0.125+0j) * (Z|[1]) +
(0.125+0j) * (Z|[0]) +
(0.125+0j) * (ZZ|[0, 1])

Otherwise, one can directly use the transformation functions.

In [3]:
from qat.fermion.transforms import transform_to_jw_basis, transform_to_parity_basis, transform_to_bk_basis

# Using the Jordan-Wigner transform
H_spin = transform_to_jw_basis(H_fermion)

# Using the Bravyi-Kitaev transform
H_spin = transform_to_bk_basis(H_fermion)

# Using the parity transform
H_spin = transform_to_parity_basis(H_fermion)

print(f"H_spin = {H_spin}")
H_spin = (-0.125+0j) * I^3 +
-0.25j * (Y|[0]) +
(-0.25+0j) * (XZ|[0, 1]) +
(0.25+0j) * (X|[0]) +
0.25j * (YZ|[0, 1]) +
(-0.125+0j) * (Z|[1]) +
(0.125+0j) * (Z|[0]) +
(0.125+0j) * (ZZ|[0, 1])

Electronic-structure Hamiltonian to spin Hamiltonian¶

You can also transform Hamiltonians of the ElectronicStructureHamiltonian type.

In [4]:
from qat.fermion.hamiltonians import ElectronicStructureHamiltonian

hpq = np.array(
    [
        [0.0, 1.0, 0.0, 0.0],
        [1.0, 0.0, 1.0, 0.0],
        [0.0, 1.0, 0.0, 1.0],
        [0.0, 0.0, 1.0, 0.0],
    ]
)

hpqrs = np.zeros((4, 4, 4, 4))
hpqrs[0, 1, 1, 0] = 0.6
hpqrs[1, 0, 0, 1] = 0.6
hpqrs[2, 0, 0, 2] = 0.6

# We define the fermionic operator H_f, an `ElectronicStructureHamiltonian` object.
H_elec = ElectronicStructureHamiltonian(hpq, hpqrs)

Just like before we convert the fermionic operator $H_f$ to a spin Hamiltonian operator using the method .to_spin.

In [5]:
# Using the Jordan-Wigner transform
H_spin = H_elec.to_spin("jordan-wigner")

# # Using the Bravyi-Kitaev transform
H_spin = H_elec.to_spin("bravyi-kitaev")

# # Using the parity transform
H_spin = H_elec.to_spin("parity")

print(f"H_spin = {H_spin}")
H_spin = (0.22499999999999998+0j) * I^4 +
(0.5+0j) * (X|[0]) +
(-0.5+0j) * (XZ|[0, 1]) +
(0.5+0j) * (X|[1]) +
(-0.5+0j) * (ZXZ|[0, 1, 2]) +
(0.5+0j) * (X|[2]) +
(-0.5+0j) * (ZXZ|[1, 2, 3]) +
(0.15+0j) * (Z|[1]) +
(-0.15+0j) * (ZZ|[0, 1]) +
(0.075+0j) * (ZZZ|[0, 1, 2]) +
(-0.22499999999999998+0j) * (Z|[0]) +
(-0.075+0j) * (ZZ|[1, 2])

Or, using the transformation functions directly:

In [6]:
from qat.fermion.transforms import transform_to_jw_basis, transform_to_parity_basis, transform_to_bk_basis

# Using the Jordan-Wigner transform
H_spin = transform_to_jw_basis(H_elec)

# Using the Bravyi-Kitaev transform
H_spin = transform_to_bk_basis(H_elec)

# Using the parity transform
H_spin = transform_to_parity_basis(H_elec)

print(f"H_spin = {H_spin}")
H_spin = (0.22499999999999998+0j) * I^4 +
(0.5+0j) * (X|[0]) +
(-0.5+0j) * (XZ|[0, 1]) +
(0.5+0j) * (X|[1]) +
(-0.5+0j) * (ZXZ|[0, 1, 2]) +
(0.5+0j) * (X|[2]) +
(-0.5+0j) * (ZXZ|[1, 2, 3]) +
(0.15+0j) * (Z|[1]) +
(-0.15+0j) * (ZZ|[0, 1]) +
(0.075+0j) * (ZZZ|[0, 1, 2]) +
(-0.22499999999999998+0j) * (Z|[0]) +
(-0.075+0j) * (ZZ|[1, 2])

Note : Some fermionic Hamiltonian can be casted into an electronic-structure Hamiltonian form.¶

In [7]:
?H_fermion.to_electronic
In [8]:
H = H_fermion.to_electronic()