First Quantized Hamiltonian#

SELECT and PREPARE for the first quantized chemistry Hamiltonian.

Here we assume the Born-Oppenheimer Hamiltonian and seek to simulate a collection of \(\eta\) electrons and \(L\) static nuclei with a Hamiltonian given by:

\[ H_{BO} = T + U + V + \frac{1}{2} \sum_{\ell\ne\kappa=1}^L\frac{\zeta_\ell\zeta_\kappa}{\lVert R_\ell - R_\kappa \rVert} \]

In the first quantized approach we assume periodic boundary conditions and use a plane wave Galerkin discretization. A plane wave basis function is given by

\[ \phi_p(r) = \frac{1}{\sqrt{\Omega}} e^{-i k_p\cdot r} \]
where \(r\) is a position vector in real space, \(\Omega\) is the simulation cell volume and \(k_p\) is a reciprocal lattice vector. In three dimensions we have
\[ k_p = \frac{2\pi p }{\Omega} \]
for \(p \in G\) and
\[ G = [-\frac{N^{1/3} - 1}{2},\frac{N^{1/3} - 1}{2}]^3 \subset \mathcal{Z}^3. \]
and \(N\) is the total number of planewaves.

With these definitions we can write the components of the Hamiltonian as:

\[ T = \sum_{i}^\eta\sum_{p\in G}\frac{\lVert k_p\rVert^2}{2} |p\rangle\langle p|_i \]
which defines the kinetic energy of the electrons,
\[ U = -\frac{4\pi}{\Omega} \sum_{\ell=1}^L \sum_{i}^\eta \sum_{p,q\in G, p\ne q} \left( \zeta_{\ell} \frac{e^{i k_{q-p}\cdot R_\ell}}{\lVert k_{p-q}\rVert^2} |p\rangle\langle q|_i \right) \]
describes the interaction of the electrons and the nuclei, and,
\[ V = \frac{2\pi}{\Omega} \sum_{i\ne j=1}^\eta \sum_{p,q\in G, p\ne q} \sum_{\nu \in G_0} \left( \frac{1}{\lVert k_{\nu}\rVert^2} |p + \nu\rangle\langle p|_i |q -\nu\rangle\langle q|_i \right) \]
describes the electron-electron interaction. The notation \(|p\rangle\langle p|_i\) is shorthand for \(I_1\otimes\cdots\otimes |p\rangle \langle p |_j \otimes \cdots \otimes I_\eta\). The system is represented using a set of \(\eta\) signed integer registers each of size \(3 n_p\) where \(n_p = \lceil \log (N^{1/3} + 1) \rceil\), with the factor of 3 accounting for the 3 spatial dimensions.

In the first quantized approach, fermion antisymmetry is encoded through initial state preparation. Spin labels are also absent and should be accounted for during state preparation. The cost of initial state preparation is typically ignored.

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

PrepareFirstQuantization#

State preparation for the first quantized chemistry Hamiltonian.

Prepares the state in Eq. 48 of the reference.

Parameters#

  • num_bits_p: The number of bits to represent each dimension of the momentum register.

  • eta: The number of electrons.

  • num_atoms: The number of atoms. \(L\) in the reference.

  • lambda_zeta: sum of nuclear charges.

  • m_param: \(\mathcal{M}\) in the reference.

  • num_bits_nuc_pos: The number of bits of precision for representing the nuclear coordinates.

  • num_bits_t: The number of bits of precision for the state preparation over the register selecting between the different components of the Hamiltonian.

  • num_bits_rot_aa: The number of bits of precision for the rotation for amplitude amplification.

  • sum_of_l1_coeffs: The one-norm of the Hamiltonian coefficients to prepare (often called lambda in the literature.)

Registers#

  • tuv: Flag register for selecting between kinetic and potential terms in the Hamiltonian.

  • uv: Flag register for selecting between the different potential components of the Hamiltonian.

  • i: A register for selecting electronic registers.

  • j: A register for selecting electronic registers.

  • w: A register for selecting x, y and z components of the momentum register.

  • r: A register for controlling elements of the momentum register. Used for block encodiding kinetic energy operator.

  • s: A register for controlling elements of the momentum register. Used for block encodiding kinetic energy operator.

  • mu: A register used for implementing nested boxes for the momentum state preparation.

  • nu_x: x component of the momentum register for Coulomb potential.

  • nu_y: y component of the momentum register for Coulomb potential.

  • nu_z: z component of the momentum register for Coulomb potential.

  • m: an ancilla register in a uniform superposition.

  • l: The register for selecting the nuclei.

References#

from qualtran.bloqs.chemistry.pbc.first_quantization import PrepareFirstQuantization

Example Instances#

num_bits_p = 6
eta = 10
num_atoms = 10
lambda_zeta = 10
prep_first_quant = PrepareFirstQuantization(num_bits_p, eta, num_atoms, lambda_zeta)

Graphical Signature#

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

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
prep_first_quant_g, prep_first_quant_sigma = prep_first_quant.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(prep_first_quant_g)
show_counts_sigma(prep_first_quant_sigma)
../../../../_images/321372f24f7f451bab257a204c4e28417a9f58d29a56f3316e9c40e8adafe5c9.svg

Counts totals:

  • PrepareTFirstQuantization: 1

  • PrepareTUVSuperpositions: 1

  • PrepareUVFirstQuantization: 1

  • UniformSuperpostionIJFirstQuantization: 1

SelectFirstQuantization#

SELECT operation for the first quantized chemistry Hamiltonian.

Parameters#

  • num_bits_p: The number of bits to represent each dimension of the momentum register.

  • eta: The number of electrons.

  • num_atoms: The number of atoms. \(L\) in the reference.

  • lambda_zeta: sum of nuclear charges.

  • m_param: \(\mathcal{M}\) in the reference.

  • num_bits_nuc_pos: The number of bits of precision for representing the nuclear coordinates.

  • num_bits_t: The number of bits of precision for the state preparation over the register selecting between the different components of the Hamiltonian.

  • num_bits_rot_aa: The number of bits of precision for the rotation for amplitude amplification.

Registers#

  • tuv: Flag register for selecting between kinetic and potential terms in the Hamiltonian.

  • uv: Flag register for selecting between the different potential components of the Hamiltonian.

  • i_ne_j: Register flagging \(i \ne j\)

  • plus_t: A register prepared in the \(|+\rangle\) state.

  • i: A register for selecting electronic registers.

  • j: A register for selecting electronic registers.

  • w: A register for selecting x, y and z components of the momentum register.

  • r: A register for controlling elements of the momentum register. Used for block encodiding kinetic energy operator.

  • s: A register for controlling elements of the momentum register. Used for block encodiding kinetic energy operator.

  • mu: A register used for implementing nested boxes for the momentum state preparation.

  • nu_x: x component of the momentum register for Coulomb potential.

  • nu_y: y component of the momentum register for Coulomb potential.

  • nu_z: z component of the momentum register for Coulomb potential.

  • m: an ancilla register in a uniform superposition.

  • l: The register for selecting the nuclei.

  • sys: The system register. Will store \(\eta\) registers (x, y and z) compents of size num_bits_p.

References#

from qualtran.bloqs.chemistry.pbc.first_quantization import SelectFirstQuantization

Example Instances#

num_bits_p = 6
eta = 10
num_atoms = 10
lambda_zeta = 10
sel_first_quant = SelectFirstQuantization(num_bits_p, eta, num_atoms, lambda_zeta)

Graphical Signature#

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

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
sel_first_quant_g, sel_first_quant_sigma = sel_first_quant.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(sel_first_quant_g)
show_counts_sigma(sel_first_quant_sigma)
../../../../_images/50c0cd669373312a75b0e91f497ffcd465a826f13c1a6e0369c32de1ad21668d.svg

Counts totals:

  • Allocate: 1

  • Allocate: 6

  • Free: 1

  • Free: 6

  • MultiplexedCSwap3D: 4

  • SelectTFirstQuantization: 1

  • SelectUVFirstQuantization: 1

PrepareTFirstQuantization#

PREPARE for the kinetic energy operator for the first quantized chemistry Hamiltonian.

This prepares the state

\[ |+\rangle\sum_{j=1}^{\eta}|j\rangle\sum_{w=0}^{2}|w\rangle \sum_{r=0}^{n_{p}-2}2^{r/2}|r\rangle \sum_{s=0}^{n_{p}-2}2^{s/2}|s\rangle \]

We assume that the uniform superposition over (\(i\) and) \(j\) has already occured via UniformSuperPositionIJFirstQuantization.

Parameters#

  • num_bits_p: The number of bits to represent each dimension of the momentum register.

  • eta: The number of electrons.

  • num_bits_rot_aa: The number of bits of precision for the single qubit rotation for amplitude amplification. Called \(b_r\) in the reference.

Registers#

  • w: a register to index one of three components of the momenta.

  • r: a register encoding bits for each component of the momenta.

  • s: a register encoding bits for each component of the momenta.

References#

from qualtran.bloqs.chemistry.pbc.first_quantization.prepare_t import PrepareTFirstQuantization

Example Instances#

num_bits_p = 5
eta = 10

prepare_t = PrepareTFirstQuantization(num_bits_p=num_bits_p, eta=eta)

Graphical Signature#

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

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
prepare_t_g, prepare_t_sigma = prepare_t.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(prepare_t_g)
show_counts_sigma(prepare_t_sigma)
../../../../_images/60239f5850370be18323f16a2680c8af538e134ce734ca22d3491035743b4a04.svg

Counts totals:

  • PreparePowerTwoState: 2

  • Toffoli: 13

PrepareUVFirstQuantization#

PREPARE the U and V parts of the Hamiltonian.

Parameters#

  • num_bits_p: The number of bits to represent each dimension of the momentum register.

  • eta: The number of electrons.

  • num_atoms: The number of atoms. \(L\) in the reference.

  • m_param: \(\mathcal{M}\) in the reference.

  • lambda_zeta: sum of nuclear charges.

  • num_bits_nuc_pos: The number of bits of precision for representing the nuclear coordinates.

Registers#

  • mu: The state controlling the nested boxes procedure.

  • nu: The momentum transfer register.

  • m: an ancilla register in a uniform superposition.

  • l: The register for atomic species.

  • flag_nu: Flag for success of the state preparation.

References#

from qualtran.bloqs.chemistry.pbc.first_quantization.prepare_uv import PrepareUVFirstQuantization

Example Instances#

num_bits_p = 5
eta = 10
num_atoms = 10
lambda_zeta = 10
m_param = 2**8
num_bits_nuc_pos = 16

prepare_uv = PrepareUVFirstQuantization(
    num_bits_p=num_bits_p,
    eta=eta,
    num_atoms=num_atoms,
    m_param=m_param,
    lambda_zeta=lambda_zeta,
    num_bits_nuc_pos=num_bits_nuc_pos,
)

Graphical Signature#

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

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
prepare_uv_g, prepare_uv_sigma = prepare_uv.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(prepare_uv_g)
show_counts_sigma(prepare_uv_sigma)
../../../../_images/803b16f23aed9a339ff8d42f48b7c13429f265ceee78841a01fd41f5734ba27d.svg

Counts totals:

  • PrepareNuState: 1

  • PrepareZetaState: 1

SelectTFirstQuantization#

SELECT for the kinetic energy operator for the first quantized chemistry Hamiltonian.

Parameters#

  • num_bits_p: The number of bits to represent each dimension of the momentum register.

  • eta: The number of electrons.

Registers#

  • sys: The system register.

  • plus: A \(|+\rangle\) state.

  • flag_T: a flag to control on the success of the \(T\) state preparation.

References#

from qualtran.bloqs.chemistry.pbc.first_quantization.select_t import SelectTFirstQuantization

Example Instances#

num_bits_p = 5
eta = 10

select_t = SelectTFirstQuantization(num_bits_p=num_bits_p, eta=eta)

Graphical Signature#

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

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
select_t_g, select_t_sigma = select_t.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(select_t_g)
show_counts_sigma(select_t_sigma)
../../../../_images/c9af0d5f27c9bfa8cd85bea7ce1e5d865f1946998a80f54b7a9a679bf1f54800.svg

Counts totals:

  • Toffoli: 22

SelectUVFirstQuantization#

SELECT for the U and V operators for the first quantized chemistry Hamiltonian.

This does not include the controlled swaps from p_i and q_j system registers into ancilla registers and back again. Hence there is no system register.

Parameters#

  • num_bits_p: The number of bits to represent each dimension of the momentum register.

  • eta: The number of electrons.

  • num_atoms: The number of atoms.

  • num_bits_nuc_pos: The number of bits to store each component of the nuclear positions. \(n_R\) in the reference.

Registers:

References#

from qualtran.bloqs.chemistry.pbc.first_quantization.select_uv import SelectUVFirstQuantization

Example Instances#

num_bits_p = 5
eta = 10
num_bits_nuc_pos = 16

select_uv = SelectUVFirstQuantization(
    num_bits_p=num_bits_p, eta=eta, num_atoms=eta, num_bits_nuc_pos=num_bits_nuc_pos
)

Graphical Signature#

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

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
select_uv_g, select_uv_sigma = select_uv.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(select_uv_g)
show_counts_sigma(select_uv_sigma)
../../../../_images/8ca514ee7beea2e9726d1c338f792c4678a22aef1f65a82a9bed80b97676217a.svg

Counts totals:

  • Add: 6

  • ApplyNuclearPhase: 1

  • SignedIntegerToTwosComplement: 6

  • SignedIntegerToTwosComplement: 6

  • Toffoli: 36

PrepareZetaState#

PREPARE the superpostion over \(l\) weighted by \(\zeta_l\).

See https://github.com/quantumlib/Qualtran/issues/473.

Parameters#

  • num_bits_p: The number of bits to represent each dimension of the momentum register.

  • eta: The number of electrons.

  • m_param: \(\mathcal{M}\) in the reference.

  • lambda_zeta: sum of nuclear charges.

Registers#

  • l: the register indexing the atomic number.

References#

from qualtran.bloqs.chemistry.pbc.first_quantization.prepare_zeta import PrepareZetaState

Example Instances#

num_atoms = 10
lambda_zeta = 10
num_bits_nuc_pos = 8

prepare_zeta = PrepareZetaState(
    num_atoms=num_atoms, lambda_zeta=lambda_zeta, num_bits_nuc_pos=num_bits_nuc_pos
)

Graphical Signature#

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

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
prepare_zeta_g, prepare_zeta_sigma = prepare_zeta.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(prepare_zeta_g)
show_counts_sigma(prepare_zeta_sigma)
../../../../_images/35ffed63447b44580a62eb49578572dba29e0b8d78bb54c325ca2a33b971187e.svg

Counts totals:

  • Toffoli: 10