qml.qinfo.transforms.trace_distance

trace_distance(qnode0, qnode1, wires0, wires1)[source]

Compute the trace distance for two QNode returning a state() (a state can be a state vector or a density matrix, depending on the device) acting on quantum systems with the same size.

\[T(\rho, \sigma)=\frac12\|\rho-\sigma\|_1 =\frac12\text{Tr}\left(\sqrt{(\rho-\sigma)^{\dagger}(\rho-\sigma)}\right)\]

where \(\|\cdot\|_1\) is the Schatten \(1\)-norm.

The trace distance measures how close two quantum states are. In particular, it upper-bounds the probability of distinguishing two quantum states.

Parameters
  • qnode0 (QNode) – A QNode returning a state().

  • qnode1 (QNode) – A QNode returning a state().

  • wires0 (Sequence[int]) – the subsystem of the first QNode.

  • wires1 (Sequence[int]) – the subsystem of the second QNode.

Returns

A function that takes as input the joint arguments of the two QNodes, and returns the trace distance between their output states.

Return type

func

Example

Consider the following QNode:

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev)
def circuit(param):
    qml.RY(param, wires=0)
    qml.CNOT(wires=[0, 1])
    return qml.state()

The qml.qinfo.trace_distance transform can be used to compute the trace distance between the output states of the QNode:

>>> trace_distance_circuit = qml.qinfo.trace_distance(circuit, circuit, wires0=[0], wires1=[0])

The returned function takes two tuples as input, the first being the arguments to the first QNode and the second being the arguments to the second QNode:

>>> x, y = np.array(0.4), np.array(0.6)
>>> trace_distance_circuit((x,), (y,))
0.047862689546603415

This transform is fully differentiable:

def wrapper(x, y):
    return trace_distance_circuit((x,), (y,))
>>> wrapper(x, y)
0.047862689546603415
>>> qml.grad(wrapper)(x, y)
(tensor(-0.19470917, requires_grad=True),
 tensor(0.28232124, requires_grad=True))