qml.matrix

matrix(op, wire_order=None)[source]

The dense matrix representation of an operation or quantum circuit.

Note

This method always returns a dense matrix. For workflows with sparse objects, consider using sparse_matrix().

Parameters:
  • op (Operator or QNode or QuantumTape or Callable or PauliWord or PauliSentence) – A quantum operator or quantum circuit.

  • wire_order (Sequence[Any], optional) –

    Order of the wires in the quantum circuit. The default wire order depends on the type of op:

    • If op is a QNode, then the wire order is determined by the associated device’s wires, if provided.

    • Otherwise, the wire order is determined by the order in which wires appear in the circuit.

    • See the usage details for more information.

Returns:

If an operator, PauliWord or PauliSentence is provided as input, the matrix is returned directly in the form of a tensor. Otherwise, the transformed circuit is returned as described in qml.transform. Executing this circuit will provide its matrix representation.

Return type:

TensorLike or qnode (QNode) or quantum function (Callable) or tuple[List[QuantumTape], function]

Example

Given an instantiated operator, qml.matrix returns the matrix representation:

>>> op = qml.RX(0.54, wires=0)
>>> qml.matrix(op)
array([[0.9637709+0.j        , 0.       -0.26673144j],
       [0.       -0.26673144j, 0.9637709+0.j        ]])

It can also be used in a functional form:

>>> x = torch.tensor(0.6, requires_grad=True)
>>> matrix_fn = qml.matrix(qml.RX)
>>> matrix_fn(x, wires=0)
tensor([[0.9553+0.0000j, 0.0000-0.2955j],
        [0.0000-0.2955j, 0.9553+0.0000j]], grad_fn=<StackBackward0>)

In its functional form, it is fully differentiable with respect to gate arguments:

>>> loss = torch.real(torch.trace(matrix_fn(x, wires=0)))
>>> loss.backward()
>>> x.grad
tensor(-0.2955)

This operator transform can also be applied to QNodes, tapes, and quantum functions that contain multiple operations; see Usage Details below for more details.

qml.matrix can also be used with PauliWord and PauliSentence instances. Internally, we are using their to_mat() methods.

>>> X0 = PauliWord({0:"X"})
>>> np.allclose(qml.matrix(X0), X0.to_mat())
True

qml.matrix can also be used with QNodes, tapes, or quantum functions that contain multiple operations.

Consider the following quantum function:

def circuit(theta):
    qml.RX(theta, wires=1)
    qml.Z(0)

We can use qml.matrix to generate a new function that returns the unitary matrix corresponding to the function circuit:

>>> matrix_fn = qml.matrix(circuit, wire_order=[1, 0])
>>> theta = np.pi / 4
>>> matrix_fn(theta)
array([[ 0.92387953+0.j        ,  0.        +0.j        ,
     0.        -0.38268343j,  0.        +0.j        ],
   [ 0.        +0.j        , -0.92387953+0.j        ,
     0.        +0.j        ,  0.        +0.38268343j],
   [ 0.        -0.38268343j,  0.        +0.j        ,
     0.92387953+0.j        ,  0.        +0.j        ],
   [ 0.        +0.j        ,  0.        +0.38268343j,
     0.        +0.j        , -0.92387953+0.j        ]])

You can also get the unitary matrix for operations on a subspace of a larger Hilbert space. For example, with the same function circuit and wire_order=["a", 0, "b", 1] you obtain the \(16\times 16\) matrix for the operation \(I\otimes Z\otimes I\otimes R_X(\theta)\).

This unitary matrix can also be used in differentiable calculations. For example, consider the following cost function:

def circuit(theta):
    qml.RY(theta, wires=0)

def cost(theta):
    matrix = qml.matrix(circuit, wire_order=[0])(theta)
    return pnp.real(pnp.trace(matrix))

Since this cost function returns a real scalar as a function of theta, we can differentiate it:

>>> theta = pnp.array(0.3, requires_grad=True)
>>> # Expected value is 2 * cos(0.3 / 2)
>>> cost(theta)
np.float64(1.97...)
>>> # The gradient is -sin(0.3 / 2)
>>> qml.grad(cost, argnum=0)(theta)
tensor(-0.14943813, requires_grad=True)

Contents

Using PennyLane

Release news

Development

API

Internals