qml.qsvt

qsvt(A, poly, encoding_wires=None, block_encoding=None, **kwargs)[source]

Implements the Quantum Singular Value Transformation (QSVT) for a matrix or Hamiltonian A, using a polynomial defined by poly and a block encoding specified by block_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 within qsvt, is not JIT-compatible, which prevents poly from being traceable in qsvt. However, A is 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_wires depending on the block encoding used.

  • block_encoding (str) –

    Specifies the type of block encoding to use. Options include:

    • "prepselprep": Embeds the Hamiltonian A using PrepSelPrep. Default encoding for Hamiltonians.

    • "qubitization": Embeds the Hamiltonian A using Qubitization.

    • "embedding": Embeds the matrix A using BlockEncode. Template not hardware compatible. Default encoding for matrices.

    • "fable": Embeds the matrix A using FABLE. Template hardware compatible.

Returns

A quantum operator implementing QSVT on the matrix A with the specified encoding and projector phases.

Return type

(Operator)

See also

QSVT

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]]

If the input A is a Hamiltonian, the valid block_encoding values are "prepselprep" and "qubitization". In this case, encoding_wires refers to the control parameter in the templates PrepSelPrep and Qubitization, respectively. These wires represent the auxiliary qubits necessary for the block encoding of the Hamiltonian. The number of encoding_wires required 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 A is a matrix, the valid values for block_encoding are "embedding" and "fable". In this case, the encoding_wires parameter corresponds to the wires attribute in the templates BlockEncode and FABLE, 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.8000000000000004

Contents

Using PennyLane

Release news

Development

API

Internals