qml.qsvt¶
- qsvt(A, poly, encoding_wires, block_encoding=None, angle_solver='root-finding')[source]¶
Implements the Quantum Singular Value Transformation (QSVT) for a matrix or Hamiltonian
A, using a polynomial defined bypolyand a block encoding specified byblock_encoding.\[\begin{split}\begin{pmatrix} A & * \\ * & * \\ \end{pmatrix} \xrightarrow{QSVT} \begin{pmatrix} \text{poly}(A) + i \dots & * \\ * & * \\ \end{pmatrix}\end{split}\]The polynomial transformation is encoded as the real part of the top left term after applying the operator.
This function calculates the required phase angles from the polynomial using
poly_to_angles().Note
The function
poly_to_angles(), used withinqsvt, is not JIT-compatible, which preventspolyfrom being traceable inqsvt. However,Ais traceable and can be optimized by JIT within this function.- Parameters:
A (Union[tensor_like, Operator]) – The matrix on which the QSVT will be applied. This can be an array or an object that has a Pauli representation. See
pauli_decompose().poly (tensor_like) – coefficients of the polynomial ordered from lowest to highest power
encoding_wires (Sequence[int]) – The qubit wires used for the block encoding. See Usage Details below for more information on
encoding_wiresdepending on the block encoding used.block_encoding (str) –
Specifies the type of block encoding to use. Options include:
"prepselprep": Embeds the HamiltonianAusingPrepSelPrep. Default encoding for Hamiltonians."qubitization": Embeds the HamiltonianAusingQubitization."embedding": Embeds the matrixAusingBlockEncode. Template not hardware compatible. Default encoding for matrices."fable": Embeds the matrixAusingFABLE. Template hardware compatible.
angle_solver (str) –
Specifies the method used to calculate the angles of the routine via
poly_to_angles. Options include:"root-finding": effective for polynomials of degree up to \(\sim 1000\)"iterative": effective for polynomials of degree higher than \(\sim 1000\)
- Returns:
A quantum operator implementing QSVT on the matrix
Awith the specified encoding and projector phases.- Return type:
(Operator)
See also
Example:
# P(x) = -x + 0.5 x^3 + 0.5 x^5 poly = np.array([0, -1, 0, 0.5, 0, 0.5]) hamiltonian = qml.dot([0.3, 0.7], [qml.Z(1), qml.X(1) @ qml.Z(2)]) dev = qml.device("default.qubit") @qml.qnode(dev) def circuit(): qml.qsvt(hamiltonian, poly, encoding_wires=[0], block_encoding="prepselprep") return qml.state() matrix = qml.matrix(circuit, wire_order=[0, 1, 2])()
>>> print(matrix[:4, :4].real) [[-0.1625 0. -0.3793 0. ] [ 0. -0.1625 0. 0.3793] [-0.3793 0. 0.1625 0. ] [ 0. 0.3793 0. 0.1625]]
Usage Details
If the input
Ais a Hamiltonian, the validblock_encodingvalues are"prepselprep"and"qubitization". In this case,encoding_wiresrefers to thecontrolparameter in the templatesPrepSelPrepandQubitization, respectively. These wires represent the auxiliary qubits necessary for the block encoding of the Hamiltonian. The number ofencoding_wiresrequired must be \(\lceil \log_2(m) \rceil\), where \(m\) is the number of terms in the Hamiltonian.# P(x) = -1 + 0.2 x^2 + 0.5 x^4 poly = np.array([-1, 0, 0.2, 0, 0.5]) hamiltonian = qml.dot([0.3, 0.4, 0.3], [qml.Z(2), qml.X(2) @ qml.Z(3), qml.X(2)]) dev = qml.device("default.qubit") @qml.qnode(dev) def circuit(): qml.qsvt(hamiltonian, poly, encoding_wires=[0, 1], block_encoding="prepselprep") return qml.state() matrix = qml.matrix(circuit, wire_order=[0, 1, 2, 3])()
>>> print(np.round(matrix[:4, :4], 4).real) [[-0.7158 0. -0. 0. ] [ 0. -0.975 0. -0. ] [ 0. 0. -0.7158 0. ] [ 0. 0. 0. -0.975 ]]
Alternatively, if the input
Ais a matrix, the valid values forblock_encodingare"embedding"and"fable". In this case, theencoding_wiresparameter corresponds to thewiresattribute in the templatesBlockEncodeandFABLE, respectively. Note that for QSVT to work, the input matrix must be Hermitian.# P(x) = -1 + 0.2 x^2 + 0.5 x^4 poly = np.array([-0.1, 0, 0.2, 0, 0.5]) A = np.array([[-0.1, 0, 0, 0.1], [0, 0.2, 0, 0], [0, 0, -0.2, -0.2], [0.1, 0, -0.2, -0.1]]) dev = qml.device("default.qubit") @qml.qnode(dev) def circuit(): qml.qsvt(A, poly, encoding_wires=[0, 1, 2, 3, 4], block_encoding="fable") return qml.state() matrix = qml.matrix(circuit, wire_order=[0, 1, 2, 3, 4])()
>>> print(np.round(matrix[:4, :4], 4).real) [[-0.0954 0. -0.0056 -0.0054] [-0. -0.0912 0. 0. ] [-0.0056 0. -0.0788 0.0164] [-0.0054 0. 0.0164 -0.0842]]
Note that for the FABLE block encoding to function correctly, it must comply with the following:
\[d \|A\|^2 \leq 1,\]where \(d\) is the maximum dimension of \(A\) and \(\|A\|\) is the 2-norm of \(A\). In the previous example this is satisfied since \(d = 4\) and \(\|A\|^2 = 0.2\):
>>> print(4 * np.linalg.norm(A, ord='fro')**2) 0.80...