bowtie_qgt.bowtieqgt¶
Bowtie Quantum Geometric Tensor (QGT) computation module.
This module computes the Quantum Geometric Tensor (QGT), McLachlan gradients and the energy variance of a parameterized quantum circuit with the “bowtie” method. Each parameter and each Hamiltonian term gets an auxiliary circuit (a bowtie) restricted to its light cone, so the cost is exponential in the light-cone width rather than in the total number of qubits.
All quantities come out of a single complex matrix, the generalized QGT: the
connected QGT of the circuit extended by one first-order Trotter step of the
Hamiltonian. See BowtieQGT for the conventions.
Example
>>> bowtie = BowtieQGT(qc, hamiltonian)
>>> generalized_qgt, energy = bowtie.evaluate(parameter_values)
>>> qgt = bowtie.extract_qgt(generalized_qgt)
>>> b = bowtie.extract_gradient(generalized_qgt, which="real_time")
>>> theta_dot = np.linalg.solve(qgt + 1e-6 * np.eye(len(b)), b)
Main Class¶
- class bowtie_qgt.bowtieqgt.BowtieQGT(qc, hamiltonian, simulator='CPU', verbosity=0)[source]¶
Quantum Geometric Tensor, gradients and variance via light-cone bowties.
- Conventions:
Let \(|\psi(\theta)\rangle = U(\theta)|0\rangle\) and \(H = \sum_j c_j h_j\) with Pauli terms \(h_j\). Extend the parameter tangents \(|\partial_i\psi\rangle\) with one tangent per Hamiltonian term, \(-i h_j|\psi\rangle\) (the derivative of \(e^{-i c_j h_j t}\) with respect to \(c_j t\), i.e. a first-order Trotter step appended to the circuit). The generalized QGT is the connected QGT of all these tangents \(\tau_a\):
\[\tilde G_{ab} = \langle\tau_a|\tau_b\rangle - \langle\tau_a|\psi\rangle\langle\psi|\tau_b\rangle,\]a complex Hermitian matrix of shape
(N + M, N + M)withNcircuit parameters andMnon-identity Hamiltonian terms, ordered likeqc.parametersand then the terms ofhamiltonian. Its blocks give:QGT: \(G = \tilde G_{:N,:N}\). Its real part is the Fubini-Study metric (the matrix of McLachlan’s principle), its imaginary part the Berry curvature. Rotations follow Qiskit’s convention \(e^{-i\theta P/2}\), so this matches
qiskit_algorithms.gradients.ReverseQGT.McLachlan gradients \(\tilde G_{:N,N:}\,c\): its real part is the real-time vector \(b_i = \mathrm{Im}(\langle\partial_i\psi|H|\psi\rangle - \langle\partial_i\psi|\psi\rangle E)\), its imaginary part the imaginary-time vector \(b_i = -\mathrm{Re}(\langle\partial_i\psi|H|\psi\rangle - \langle\partial_i\psi|\psi\rangle E)\), which equals \(-\tfrac12\,\partial_i E\) for Hermitian \(H\).
Variance: \(\mathrm{Var}[H] = c^\dagger \tilde G_{N:,N:}\, c\).
McLachlan’s principle then reads \(\mathrm{Re}(G)\,\dot\theta = b\). Identity terms of the Hamiltonian have no tangent; they only shift the energy.
- qc¶
The parameterized quantum circuit.
- hamiltonian¶
The Hamiltonian passed at construction.
- coeffs¶
Coefficients of the non-identity Hamiltonian terms, in bowtie order.
- energy_offset¶
Sum of the coefficients of identity terms.
- simulator¶
Aer simulator that runs the bowtie circuits.
- verbosity¶
Progress reporting level, see
__init__().
- bowties¶
Bowtie circuits, parameters first and then Hamiltonian terms.
- active_qubits¶
Qubits each bowtie acts on.
- non_zero_indices¶
(i, j)pairs,i >= j, whose bowties share qubits. Every other entry of the generalized QGT is exactly zero.
- slices¶
Precomputed tensor slices for each pair in
non_zero_indices.
- last_timings¶
Seconds spent in the last
evaluate()call, with keys"simulation"and"assembly".
- __init__(qc, hamiltonian, simulator='CPU', verbosity=0)[source]¶
Build and transpile the bowtie circuits.
- Parameters:
qc (
QuantumCircuit) – Parameterized circuit. Every parameter must be the bare angle of exactly onerx,ry,rz,rxx,ryyorrzzgate.hamiltonian (
SparsePauliOp) – Hamiltonian as aSparsePauliOp. Identity terms are allowed and only shift the energy.simulator (
str|AerSimulator) –"CPU"(default) or"GPU"for a default statevectorAerSimulatoron that device. For full control (precision, threads, …) pass a noiseless statevectorAerSimulatorinstead, e.g.AerSimulator(method="statevector", max_parallel_threads=8).verbosity (
int) – 0 is silent. 1 shows progress bars while building the bowties and prints the distribution of light-cone widths. 2 also reports progress and timings on everyevaluate()call.
- Raises:
ValueError – If the circuit is not supported (see
validate_circuit()), the device is not"CPU"or"GPU", or the simulator is not a noiseless statevector simulator.- Warns:
UserWarning – If the Hamiltonian is a multiple of the identity.
- evaluate(parameter_values)[source]¶
Compute the generalized QGT and the energy at the given parameters.
- Parameters:
parameter_values (
Mapping[Parameter,float] |Sequence[float]) – Values for every circuit parameter, either as a sequence ordered likeqc.parametersor as any mapping thatQuantumCircuit.assign_parametersaccepts (Parameter,ParameterVectoror parameter-name keys).- Return type:
- Returns:
(generalized_qgt, energy).generalized_qgtis the complex(N + M, N + M)matrix described inBowtieQGT; pass it to theextract_*methods.energyis \(\langle\psi|H|\psi\rangle\), a float when the Hamiltonian is Hermitian (real coefficients).- Raises:
ValueError – If a circuit parameter has no value.
- extract_qgt(generalized_qgt, part='real')[source]¶
Extract the
(N, N)QGT block.- Parameters:
generalized_qgt (
ndarray) – Matrix returned byevaluate().part (
str) –"real"(default) for the Fubini-Study metric, which is what McLachlan’s variational principle uses for both real and imaginary time."imag"for the Berry curvature,"complex"for the full QGT, as used by other variational principles.
- Return type:
- Returns:
The requested part of the QGT.
- extract_gradient(generalized_qgt, which)[source]¶
Extract McLachlan’s right-hand side
b, so thatRe(G) θ̇ = b.- Parameters:
generalized_qgt (
ndarray) – Matrix returned byevaluate().which (
str) –"real_time"for \(e^{-iHt}\) (VarQRTE) or"imag_time"for \(e^{-H\tau}\) (VarQITE). For HermitianHthe imaginary-time vector is \(-\tfrac12\nabla_\theta E\).
- Return type:
- Returns:
Real array of shape
(N,).
- extract_variance(generalized_qgt)[source]¶
Extract the energy variance \(\langle H^2\rangle - \langle H\rangle^2\).
- Parameters:
generalized_qgt (
ndarray) – Matrix returned byevaluate().- Return type:
- Returns:
The variance. It vanishes exactly on eigenstates of
H.
Overlap Helpers¶
Low-level functions used by BowtieQGT to evaluate overlaps
of bowtie states on their shared qubits.
- bowtie_qgt.bowtieqgt.connected_overlap(svAB, sliceab, svBC, slicebc)[source]¶
Compute the connected overlap
⟨ψ_AB|ψ_BC⟩ - ⟨ψ_AB|0⟩⟨0|ψ_BC⟩.Bowtie states are expressed in the frame where the variational state is
|0...0⟩, so subtracting the|0...0⟩components projects out the global-phase direction. This makes every block of the generalized QGT gauge invariant.- Parameters:
svAB – First statevector tensor.
sliceab – Slice indices for svAB.
svBC – Second statevector tensor.
slicebc – Slice indices for svBC.
- Returns:
Complex number representing the connected overlap.
- bowtie_qgt.bowtieqgt.sparse_overlap_tensors(svAB, sliceab, svBC, slicebc)[source]¶
Compute the overlap
⟨ψ_AB|ψ_BC⟩between statevectors with different support.Calculates the inner product between two statevectors by projecting them onto their common support region (region B). The Hilbert space is decomposed as:
Region A: qubits where only ψ_AB has support → projected to
|0⟩in ψ_ABRegion B: qubits where both have support → full overlap computed
Region C: qubits where only ψ_BC has support → projected to
|0⟩in ψ_BC
The slices
sliceabandslicebcproject each statevector onto region B, setting amplitudes in regions A and C to their|0⟩components.- Parameters:
svAB (
ndarray) – Statevector tensor ψ_AB reshaped to [2, 2, …, 2] with dimensions corresponding to its active qubits.sliceab – Slice for projecting ψ_AB onto region B.
svBC (
ndarray) – Statevector tensor ψ_BC reshaped to [2, 2, …, 2] with dimensions corresponding to its active qubits.slicebc – Slice for projecting ψ_BC onto region B.
- Returns:
Complex number representing the overlap
⟨ψ_AB|ψ_BC⟩computed over the common support region B.
Note
This is the core operation for computing QGT matrix entries. The sparse tensor approach avoids explicitly constructing full statevectors on the entire Hilbert space, significantly reducing memory and computation.
- bowtie_qgt.bowtieqgt.get_slice(AB, BC)[source]¶
Generate slice indices for projecting ψ_AB onto the overlap region with ψ_BC.
Computes the slice to apply to statevector ψ_AB when computing its overlap with ψ_BC. The Hilbert space is decomposed into three regions:
Region A: qubits where only ψ_AB has support (projected to
|0⟩)Region B: qubits where both ψ_AB and ψ_BC have support (overlap computed)
Region C: qubits where only ψ_BC has support (projected to
|0⟩)
For qubits in region B (intersection of AB and BC), the slice uses
slice(None)to keep all amplitudes. For qubits in region A (in AB but not in BC), the slice uses index 0 to project onto|0⟩.- Parameters:
- Returns:
List of slice objects or integers for indexing the ψ_AB tensor, in reversed order to match tensor dimension ordering:
slice(None)for qubits in the overlap region B (in both AB and BC)0for qubits in region A (in AB but not in BC)
Note
When precomputing slices for overlap
⟨ψ_AB|ψ_BC⟩, both directions must be computed and stored: one slice for ψ_AB and one for ψ_BC, since the overlap is not symmetric when the active qubit sets differ.Example
>>> # ψ_AB has support on qubits (0, 1, 2), ψ_BC on qubits (1, 2, 3,4) >>> # Region A = {0}, Region B = {1, 2}, Region C = {3,4} >>> get_slice((0, 1, 2), (1, 2, 3, 4)) [slice(None, None, None), slice(None, None, None), 0] >>> # Qubit 0 (region A) → 0, qubits 1,2 (region B) → slice(None)