Trotterized Hubbard#

Bloqs implementing Trotterized unitary evolution under the Hubbard Hamiltonian.

The Hubbard model is given as a sum of two terms

\[ H = H_h + H_I \]

where the hopping hamiltonian is given as

\[ H_h = -\tau \sum_{\langle p, q\rangle, \sigma} \left(a_{p\sigma}^{\dagger} a_{q\sigma} + \mathrm{h.c.} \right) \]
where the sum is over nearest neighbour lattice sites (under periodic boundary conditions).

Following the reference we assume the shifted form of the interacting Hamiltonian:

\[ H_I = \frac{u}{4} \sum_{p} z_{p\uparrow}z_{p\downarrow} \]
where \(z_{p\sigma} = (2 n_{p\sigma} - 1)\).

For Trotterization we assume the plaquette splitting from the reference. The plaquette splitting rewrites \(H_h\) as a sum of \(H_h^p\) and \(H_h^g\) (for pink and gold respectively) which when combined tile the entire lattice. Each plaquette contains four sites and paritions the lattice such that each edge of the lattice belongs to a single plaquette. Each term within a grouping commutes so that the unitary can be be implemented as

\[ e^{i H_h^{x}} = \prod_{k\sigma} e^{i H_h^{x(k,\sigma)}} \]
without further trotter error.

from qualtran import Bloq, CompositeBloq, BloqBuilder, Signature, Register
from qualtran import QBit, QInt, QUInt, QAny
from qualtran.drawing import show_bloq, show_call_graph, show_counts_sigma
from typing import *
import numpy as np
import sympy
import cirq

HoppingTile#

Bloq implementing a “tile” of the one-body hopping unitary.

Implements the unitary

\[ e^{i H_h^{x}} = \prod_{k\sigma} e^{i t H_h^{x(k,\sigma)}} \]
for a particular choise of of plaquette hamiltonian \(H_h^x\), where \(x\) = pink or gold.

Parameters#

  • length: Lattice side length L.

  • angle: The prefactor scaling the Hopping hamiltonian in the unitary (t above). This should contain any relevant prefactors including the time step and any splitting coefficients.

  • tau: The Hopping hamiltonian parameter. Typically the hubbard model is defined relative to \(\tau\) so it’s defaulted to 1.

  • eps: The precision of the single qubit rotations.

  • pink: The colour of the plaquette.

Registers#

  • system: The system register of size 2 length.

References#

from qualtran.bloqs.chemistry.trotter.hubbard.hopping import HoppingTile

Example Instances#

length = 8
angle = 0.5
hopping_tile = HoppingTile(length, angle)

Graphical Signature#

from qualtran.drawing import show_bloqs
show_bloqs([hopping_tile],
           ['`hopping_tile`'])

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
hopping_tile_g, hopping_tile_sigma = hopping_tile.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(hopping_tile_g)
show_counts_sigma(hopping_tile_sigma)
../../../../_images/0f6a97ceafd88a909553cf555f9a7c522ee8f7b5ad51598f081ad9749880fafe.svg

Counts totals:

  • HoppingPlaquette: 32

HoppingPlaquette#

A bloq implementing a single plaquette unitary.

The bloq implements

\[ e^{i \kappa R_\mathrm{plaq}} \]
where \(\tau R^{k\sigma}_\mathrm{plaq} = H_h^{x(k,\sigma)}\), i.e. R is non-zero only in the subploq relevant for the particular indexed plaquette.

The plaquette operator is given by

\[ \sum_{i,j} [R_{\mathrm{plaq}}]_{i,j} a_{i\sigma}^\dagger a_{j\sigma} \]
where the non-zero sub-bloq of \(R_{\mathrm{plaq}}\) is

\[\begin{split} R_{\mathrm{plaq}} = \begin{bmatrix} 0 & 1 & 0 & 1 \\ 1 & 0 & 1 & 0 \\ 0 & 1 & 0 & 1 \\ 1 & 0 & 1 & 0 \end{bmatrix} \end{split}\]

Parameters#

  • kappa: The scalar prefactor appearing in the definition of the unitary. Usually a combination of the timestep and the hopping parameter \(\tau\).

  • eps: The precision of the single qubit rotations.

Registers#

  • qubits: A register of four qubits this unitary should act on.

References#

from qualtran.bloqs.chemistry.trotter.hubbard.hopping import HoppingPlaquette

Example Instances#

length = 8
angle = 0.15
plaquette = HoppingPlaquette(length, angle)

Graphical Signature#

from qualtran.drawing import show_bloqs
show_bloqs([plaquette],
           ['`plaquette`'])

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
plaquette_g, plaquette_sigma = plaquette.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(plaquette_g)
show_counts_sigma(plaquette_sigma)
../../../../_images/56d8d6f8a2eb401c3cfa4410690ca60e40788786bc9b32ac4dc2e9f8dfdadb0a.svg

Counts totals:

  • Rz(8): 2

  • TwoBitFFFT: 4

Interaction#

Bloq implementing the hubbard U part of the hamiltonian.

Specifically:

\[ U_I = e^{i t H_I} \]
which can be implemented using equal angle single-qubit Z rotations.

Parameters#

  • length: Lattice length \(L\).

  • angle: The prefactor scaling the Hopping hamiltonian in the unitary (t above). This should contain any relevant prefactors including the time step and any splitting coefficients.

  • hubb_u: The hubbard \(U\) parameter.

  • eps: The precision of the single qubit rotations.

Registers#

  • system: The system register of size 2 length.

References#

from qualtran.bloqs.chemistry.trotter.hubbard.interaction import Interaction

Example Instances#

length = 8
angle = 0.5
hubb_u = 4.0
interaction = Interaction(length, angle, hubb_u)

Graphical Signature#

from qualtran.drawing import show_bloqs
show_bloqs([interaction],
           ['`interaction`'])

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
interaction_g, interaction_sigma = interaction.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(interaction_g)
show_counts_sigma(interaction_sigma)
../../../../_images/8fc6c95434078521e1a855823f82e1119bc299d8f6732bdbfc0eecffad5d2b56.svg

Counts totals:

  • Rz(2.0): 64

HoppingTileHWP#

Bloq implementing a “tile” of the one-body hopping unitary using Hamming weight phasing.

Implements the unitary

\[ e^{i H_h^{x}} = \prod_{k\sigma} e^{i t H_h^{x(k,\sigma)}} \]
for a particular choise of of plaquette hamiltonian \(H_h^x\), where \(x\) = pink or gold.

Each plaquette Hamiltonian can be split into \(L^2/4\) commuting terms. Each term can be implemented using the 4-qubit HoppingPlaquette above. The HoppingPlaquette bloq contains 2 arbitrary rotations which are flanked by Clifford operations. All of the rotations within a HoppingTile have the same angle so we can use HammingWeightPhaseing to reduce the number of T gates that need to be synthesized. Accounting for spin there are then \(2 \times 2 \times L^2/4\) arbitrary rotations in each Tile, but only \(L^2/2\) of them can be applied at the same time due to the \(e^{iXX} e^{iYY}\) circuit not permitting parallel \(R_z\) gates.

Unlike in the HoppingTile implementation where we can neatly factor everything into sub-bloqs, here we would need to apply any clifford and F gates first in parallel then bulk apply the rotations in parallel using HammingWeightPhasing and then apply another layer of clifford and F gates.

Parameters#

  • length: Lattice side length L.

  • angle: The prefactor scaling the Hopping hamiltonian in the unitary (t above). This should contain any relevant prefactors including the time step and any splitting coefficients.

  • tau: The Hopping hamiltonian parameter. Typically the hubbard model is defined relative to \(\tau\) so it’s defaulted to 1.

  • eps: The precision of the single qubit rotations.

  • pink: The colour of the plaquette.

Registers#

  • system: The system register of size 2 length.

References#

from qualtran.bloqs.chemistry.trotter.hubbard.hopping import HoppingTileHWP

Example Instances#

length = 8
angle = 0.15
hopping_tile_hwp = HoppingTileHWP(length, angle)

Graphical Signature#

from qualtran.drawing import show_bloqs
show_bloqs([hopping_tile_hwp],
           ['`hopping_tile_hwp`'])

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
hopping_tile_hwp_g, hopping_tile_hwp_sigma = hopping_tile_hwp.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(hopping_tile_hwp_g)
show_counts_sigma(hopping_tile_hwp_sigma)
../../../../_images/80cb79f2f3c45e6f6f69d51912d3417a1550ea5f74d572a969fb3346b19bffd5.svg

Counts totals:

  • HammingWeightPhasing: 2

  • TwoBitFFFT: 128

InteractionHWP#

Bloq implementing the hubbard U part of the hamiltonian using Hamming weight phasing.

Specifically:

\[ U_I = e^{i t H_I} \]
which can be implemented using equal angle single-qubit Z rotations.

Each interaction term can be implemented using a e^{iZZ} gate, which decomposes into a single Rz gate flanked by cliffords. There are L^2 equal angle rotations in total all of which may be applied in parallel using HWP.

Parameters#

  • length: Lattice length L.

  • angle: The rotation angle for unitary.

  • hubb_u: The hubbard U parameter.

  • eps: The precision for single qubit rotations.

Registers#

  • system: The system register of size 2 length.

References#

from qualtran.bloqs.chemistry.trotter.hubbard.interaction import InteractionHWP

Example Instances#

length = 8
angle = 0.52728
hubb_u = 4.0
interaction_hwp = InteractionHWP(length, angle, hubb_u)

Graphical Signature#

from qualtran.drawing import show_bloqs
show_bloqs([interaction_hwp],
           ['`interaction_hwp`'])

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
interaction_hwp_g, interaction_hwp_sigma = interaction_hwp.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(interaction_hwp_g)
show_counts_sigma(interaction_hwp_sigma)
../../../../_images/de9f4aa98c7bfc47ff258a791be2608973f1db52b1e9f5a7d914175d60b24574.svg

Counts totals:

  • HammingWeightPhasing: 2