Trotter Bloqs#

Bloqs for Trotter simulation of the real space grid Hamiltonian.

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

PolynmomialEvaluationInverseSquareRoot#

Bloq to evaluate a polynomial approximation to inverse Square root from QROM.

Parameters#

  • in_bitsize: The number of bits encoding the input registers.

  • out_bitsize: The number of bits encoding the input registers.

Registers#

  • in_c{0,1,2,3}: QROM input containing the 4 polynomial coefficients.

  • out: Output register to store polynomial approximation to inverse square root.

References#

from qualtran.bloqs.chemistry.trotter.grid_ham.inverse_sqrt import PolynmomialEvaluationInverseSquareRoot

Example Instances#

poly_inv_sqrt = PolynmomialEvaluationInverseSquareRoot(7, 8, 12)

Graphical Signature#

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

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
poly_inv_sqrt_g, poly_inv_sqrt_sigma = poly_inv_sqrt.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(poly_inv_sqrt_g)
show_counts_sigma(poly_inv_sqrt_sigma)
../../../../_images/189b49293c50bcf2131f1a818ebf5955f763542c8fd18ab8437a59fa8ee78a30.svg

Counts totals:

  • Add: 3

  • MultiplyTwoReals: 3

NewtonRaphsonApproxInverseSquareRoot#

Bloq implementing a single Newton-Raphson step to approximate the inverse square root.

Given a (polynomial) approximation for \(1/\sqrt{x}\) (which will be \(y_0\)) below we can approximate the inverse square root by

\[ y_{n+1} = \frac{1}{2}y_n\left(3-y_n^2 x\right) \]

For the case of computing the Coulomb potential we want

\[ \frac{1}{|r_i-r_j|} = \frac{1}{\sqrt{\sum_k^3 (x^{k}_i-x^{k}_j)^2}} \]

where \(x^{k}_i\) is the \(i\)-th electron’s coordinate in 3D and \(k \in \{x,y,z\}\). Thus the input register should store \(\sum_{k=x,y,z} (x^{k}_i-x^{k}_j)^2\).

Parameters#

  • x_sq_bitsize: The number of bits encoding the input (integer) register holding (x^2).

  • poly_bitsize: The number of bits encoding the input (fp-real) register holding y0 (the output of PolynomialEvaluation).

  • output_bitsize: The number of bits to store the output of the NewtonRaphson step.

Registers#

  • x_sq: an input_bitsize size register storing the value x^2.

  • poly: an poly_bitsize size register storing the value x^2.

  • target: a target_bitsize size register storing the output of the newton raphson step.

References#

from qualtran.bloqs.chemistry.trotter.grid_ham.inverse_sqrt import NewtonRaphsonApproxInverseSquareRoot

Example Instances#

nr_inv_sqrt = NewtonRaphsonApproxInverseSquareRoot(7, 8, 12)

Graphical Signature#

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

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
nr_inv_sqrt_g, nr_inv_sqrt_sigma = nr_inv_sqrt.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(nr_inv_sqrt_g)
show_counts_sigma(nr_inv_sqrt_sigma)
../../../../_images/8ef251e54dccb4066fd90ebca22a2a5dad3c7ee5ddcf0fac5a730dbe483e16e3.svg

Counts totals:

  • Add: 1

  • MultiplyTwoReals: 2

  • ScaleIntByReal: 1

  • SquareRealNumber: 1

QuantumVariableRotation#

Bloq implementing Quantum Variable Rotation

\[ \sum_j c_j|\phi_j\rangle \rightarrow \sum_j e^{i \xi \phi_j} c_j | \phi_j\rangle \]

This is the basic implementation in Fig. 14 of the reference.

Parameters#

  • bitsize: The number of bits encoding the phase angle \(\phi_j\).

Registers#

  • phi: a bitsize size register storing the angle \(\phi_j\).

References#

from qualtran.bloqs.chemistry.trotter.grid_ham.qvr import QuantumVariableRotation

Example Instances#

qvr = QuantumVariableRotation(12)

Graphical Signature#

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

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
qvr_g, qvr_sigma = qvr.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(qvr_g)
show_counts_sigma(qvr_sigma)
../../../../_images/da3cfd6c99bea58e736d632209c7b0d3d35846f3f929619c9f2aaf9f49552103.svg

Counts totals:

  • Rz(_theta0): 12

KineticEnergy#

Bloq for the Kinetic energy unitary defined in the reference.

Parameters#

  • num_elec: The number of electrons.

  • num_grid: The number of grid points in each of the x, y and z directions. In total, for a cubic grid, there are \(N = \mathrm{num\_grid}^3\) grid points. The number of bits required (in each spatial dimension) is thus log N + 1, where the + 1 is for the sign bit.

Registers#

  • system: The system register of size eta * 3 * nb

References#

from qualtran.bloqs.chemistry.trotter.grid_ham import KineticEnergy

Example Instances#

nelec = 12
ngrid_x = 2 * 8 + 1
kinetic_energy = KineticEnergy(nelec, ngrid_x)

Graphical Signature#

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

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
kinetic_energy_g, kinetic_energy_sigma = kinetic_energy.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(kinetic_energy_g)
show_counts_sigma(kinetic_energy_sigma)
../../../../_images/29184ab149578a2b7e5d792b55f709118d956a8233013785bf3e61a44434d824.svg

Counts totals:

  • Free: 12

  • QuantumVariableRotation: 12

  • SumOfSquares: 12

PairPotential#

Potential Energy bloq for single pair of particles i and j.

Parameters#

  • bitsize: The number of bits for a single component of the system register.

  • qrom_data: The polynomial coefficients to load by QROM.

  • poly_bitsize: The number of bits of precision for the polynomial coefficients.

  • label: A label for the bloqs short name. The potential bloq can encode any sort of Coulomb interaction (electron-electron, election-ion, ion-ion,…) so can be reused. This label is to distinguish these different cases.

Registers#

  • system_i: The ith electron’s register.

  • system_j: The jth electron’s register.

References#

from qualtran.bloqs.chemistry.trotter.grid_ham.potential import PairPotential, build_qrom_data_for_poly_fit
from qualtran.bloqs.chemistry.trotter.grid_ham.inverse_sqrt import get_inverse_square_root_poly_coeffs

Example Instances#

bitsize = 7
poly_bitsize = 15
poly_coeffs = get_inverse_square_root_poly_coeffs()
qrom_data = build_qrom_data_for_poly_fit(2 * bitsize + 2, poly_bitsize, poly_coeffs)
qrom_data = tuple(tuple(int(k) for k in d) for d in qrom_data)
pair_potential = PairPotential(bitsize=bitsize, qrom_data=qrom_data, poly_bitsize=poly_bitsize)

Graphical Signature#

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

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
pair_potential_g, pair_potential_sigma = pair_potential.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(pair_potential_g)
show_counts_sigma(pair_potential_sigma)
../../../../_images/fa572df073357f4bfe8f190a75ceafe8e47d33093db82a4546f6c1c2c620f3b9.svg

Counts totals:

  • Allocate: 1

  • Allocate: 5

  • Free: 1

  • Free: 1

  • Free: 5

  • NewtonRaphsonApproxInverseSquareRoot: 1

  • OutOfPlaceAdder: 3

  • OutOfPlaceAdder: 3

  • PolynmomialEvaluationInverseSquareRoot: 1

  • QROM((65536,), ((), (), (), ()), (15, 15, 15, 15)): 1

  • QuantumVariableRotation: 1

  • SumOfSquares: 1

PotentialEnergy#

Bloq for a Coulombic Unitary.

This is a basic implementation which just iterates through num_elec * (num_elec - 1) electron pairs.

Parameters#

  • num_elec: The number of electrons.

  • num_grid: The number of grid points in each of the x, y and z directions. In total, for a cubic grid there are N = num_grid**3 grid points. The number of bits required (in each spatial dimension) is thus log N + 1, where the + 1 is for the sign bit.

  • label: A label for the bloqs short name. The potential bloq can encode any sort of Coulomb interaction (electron-electron, election-ion, ion-ion,…) so can be reused. This label is to distinguish these different cases.

Registers#

  • system: The system register of size eta * 3 * nb

References#

from qualtran.bloqs.chemistry.trotter.grid_ham import PotentialEnergy

Example Instances#

nelec = 12
ngrid_x = 2 * 8 + 1
potential_energy = PotentialEnergy(nelec, ngrid_x)

Graphical Signature#

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

Call Graph#

from qualtran.resource_counting.generalizers import ignore_split_join
potential_energy_g, potential_energy_sigma = potential_energy.call_graph(max_depth=1, generalizer=ignore_split_join)
show_call_graph(potential_energy_g)
show_counts_sigma(potential_energy_sigma)
../../../../_images/0b28c4c33013d3409921e881f1ce90be771939b896a2b9bfeac1f62c8cc16cb1.svg

Counts totals:

  • PairPotential: 66