BlockEncoding.inv#
- BlockEncoding.inv(eps: float, kappa: float) BlockEncoding[source]#
Returns a BlockEncoding approximating the matrix inversion of the operator.
For a block-encoded Hermitian matrix \(A\) with normalization factor \(\alpha\), this function returns a BlockEncoding of an operator \(\tilde{A}^{-1}\) such that \(\|\tilde{A}^{-1} - A^{-1}\| \leq \epsilon\). The inversion is implemented via Quantum Eigenvalue Transformation (QET) using a polynomial approximation of \(1/x\) over the domain \(D_{\kappa} = [-1, -1/\kappa] \cup [1/\kappa, 1]\).
- Parameters:
- epsfloat
The target precision \(\epsilon\).
- kappafloat
An upper bound for the condition number \(\kappa\) of \(A\). This value defines the “gap” around zero where the function \(1/x\) is not approximated.
- Returns:
- BlockEncoding
A new BlockEncoding instance representing an approximation of the inverse \(A^{-1}\).
Notes
Complexity: The polynomial degree scales as \(\mathcal{O}(\kappa \log(\kappa/\epsilon))\).
It is assumed that the eigenvalues of \(A/\alpha\) lie within \(D_{\kappa}\).
References
Childs et. al (2017) Quantum algorithm for systems of linear equations with exponentially improved dependence on precision.
Examples
Define a QSLP and solve it using
inv().First, define a Hermitian matrix \(A\) and a right-hand side vector \(\vec{b}\).
import numpy as np A = np.array([[0.73255474, 0.14516978, -0.14510851, -0.0391581], [0.14516978, 0.68701415, -0.04929867, -0.00999921], [-0.14510851, -0.04929867, 0.76587818, -0.03420339], [-0.0391581, -0.00999921, -0.03420339, 0.58862043]]) b = np.array([0, 1, 1, 1]) kappa = np.linalg.cond(A) print("Condition number of A: ", kappa) # Condition number of A: 1.8448536035491883
Generate a block-encoding of \(A\) and use
inv()to find a block-encoding approximating \(A^{-1}\).from qrisp import * from qrisp.block_encodings import BlockEncoding BA = BlockEncoding.from_array(A) BA_inv = BA.inv(0.01, 2) # Prepares operand variable in state |b> def prep_b(): operand = QuantumVariable(2) prepare(operand, b) return operand @terminal_sampling def main(): operand = BA_inv.apply_rus(prep_b)() return operand res_dict = main() amps = np.sqrt([res_dict.get(i, 0) for i in range(len(b))])
Finally, compare the quantum simulation result with the classical solution:
c = (np.linalg.inv(A) @ b) / np.linalg.norm(np.linalg.inv(A) @ b) print("QUANTUM SIMULATION\n", amps, "\nCLASSICAL SOLUTION\n", c) # QUANTUM SIMULATION # [0.02844496 0.55538449 0.53010186 0.64010231] # CLASSICAL SOLUTION # [0.02944539 0.55423278 0.53013239 0.64102936]