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)
Counts totals:
Add: 3MultiplyTwoReals: 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
For the case of computing the Coulomb potential we want
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)
Counts totals:
Add: 1MultiplyTwoReals: 2ScaleIntByReal: 1SquareRealNumber: 1
QuantumVariableRotation#
Bloq implementing Quantum Variable Rotation
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)
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)
Counts totals:
Free: 12QuantumVariableRotation: 12SumOfSquares: 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)
Counts totals:
Allocate: 1Allocate: 5Free: 1Free: 1Free: 5NewtonRaphsonApproxInverseSquareRoot: 1OutOfPlaceAdder: 3OutOfPlaceAdder: 3PolynmomialEvaluationInverseSquareRoot: 1QROM((65536,), ((), (), (), ()), (15, 15, 15, 15)): 1QuantumVariableRotation: 1SumOfSquares: 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)
Counts totals:
PairPotential: 66