qrisp.gqsp.GQSVT#
- GQSVT(A: BlockEncoding | FermionicOperator | QubitOperator, p: ArrayLike, kind: Literal['Polynomial', 'Chebyshev'] = 'Polynomial', parity: Literal['odd', 'even'] = 'odd', rescale: bool = True) BlockEncoding[source]#
Returns a BlockEncoding representing a polynomial transformation of the operator via Generalized Quantum Singular Value Transform.
For a block-encoded operator \(A\) with Singular Value Decomposition \(A = U \Sigma V^{\dagger}\) for unitaries \(U, V\), and a (complex) polynomial \(p(z)\), this method returns a BlockEncoding of either operator:
\(p_{odd}(A)=V p_{odd}(\Sigma) U^{\dagger}\)
\(p_{even}(A)=V p_{even}(\Sigma) V^{\dagger}\)
where \(p=p_{odd}+p_{even}\) is decomposed into odd and even parity parts.
Warning
If the parity is odd, this deviates from
qrisp.algorithms.gqsp.qsvt.QSVT(), which returns a BlockEncoding of \(p_{odd}(A)=U p_{odd}(\Sigma) V^{\dagger}\), i.e., the Hermitian conjugate.- Parameters:
- ABlockEncoding | FermionicOperator | QubitOperator
The operator to be transformed. Unlike in (G)QET, this operator does not need to be Hermitian.
- pArrayLike
1-D array containing the polynomial coefficients, ordered from lowest order term to highest.
- kind{“Polynomial”, “Chebyshev”}
The basis in which the coefficients are defined.
"Polynomial": \(p(z) = \sum c_i z^i\)"Chebyshev": \(p(z) = \sum c_i T_i(z)\), where \(T_i\) are Chebyshev polynomials of the first kind.
Default is
"Polynomial".- parity{“odd”, “even”}
The parity part of \(p=p_{odd}+p_{even}\) to be applied.
"odd": The odd part \(p_{odd}(A)\) is applied."even": The even part \(p_{even}(A)\) is applied.
Default is
"odd".- rescalebool
If True (default), the method returns a block-encoding of \(p(A)\). If False, the method returns a block-encoding of \(p(A/\alpha)\) where \(\alpha\) is the normalization factor for the block-encoding of the operator \(A\).
- Returns:
- BlockEncoding
A new BlockEncoding instance representing the transformed operator \(p(A)\).
Examples
Define a non-Hermitian matrix \(A\) and a vector \(\vec{b}\). The matrix \(A\) has singular value decomposition \(A = U \Sigma V^{\dagger}\) for unitary matrices \(U, V\).
import numpy as np N = 4 A = np.eye(N, k=1) + 3 * np.eye(N) A[N-1,0] = 1 b = np.array([1,0,0,0]) print(A) # [[3. 1. 0. 0.] # [0. 3. 1. 0.] # [0. 0. 3. 1.] # [1. 0. 0. 3.]]
Generate a BlockEncoding of \(A\) and use GQSVT to obtain a BlockEncoding of \(p(A)=V p(\Sigma) U^{\dagger}\) for an odd parity polynomial.
from qrisp import * from qrisp.block_encodings import BlockEncoding from qrisp.gqsp import GQSVT def U0(qv): pass def U1(qv): qv-=1 BE = BlockEncoding.from_lcu(np.array([3,1]), [U0,U1]) BE_poly = GQSVT(BE, np.array([0.,1.,0.,1.]), parity="odd") # Prepare initial system state |b> def operand_prep(): qv = QuantumFloat(2) prepare(qv, b) return qv @terminal_sampling def main(): operand = BE_poly.apply_rus(operand_prep)() return operand res_dict = main() amps = np.sqrt([res_dict.get(i, 0) for i in range(len(b))]) print(amps) # [0.85184734 0.47324852 0.07098728 0.21296184]
Finally, compare the quantum simulation result with the classical solution:
# Compute the SVD U, S, Vh = np.linalg.svd(A) # Apply polynomial z + z^3 to singular values S_poly = S + S ** 3 # Reconstruct transformed matrix A_poly = (U @ np.diag(S_poly) @ Vh).conj().T res = A_poly @ b / np.linalg.norm(A_poly @ b) print(res) # [0.85184734, 0.47324852, 0.07098728, 0.21296184]
Warning
For non-Hermitian matrices performing Singular Value Transform is not the same as applying a matrix polynomial.
A_poly = A + A @ A @ A res = A_poly @ b / np.linalg.norm(A_poly @ b) print(res) # [0.71388113 0.02379604 0.21416434 0.66628906]