metric_tensor= <pennylane.transforms.batch_transform.batch_transform object>¶
Returns a function that computes the block-diagonal approximation of the metric tensor of a given QNode or quantum tape.
diag_approx (bool) – if True, use the diagonal approximation. If
diagonal approximation of the metric tensor is computed. (block) –
hybrid (bool) –
Specifies whether classical processing inside a QNode should be taken into account when transforming a QNode.
True, and classical processing is detected, the Jacobian of the classical processing will be computed and included. When evaluated, the returned metric tensor will be with respect to the QNode arguments.
False, any internal QNode classical processing will be ignored. When evaluated, the returned metric tensor will be with respect to the gate arguments, and not the QNode arguments.
Function which accepts the same arguments as the QNode. When called, this function will return the metric tensor.
- Return type
Consider the following QNode:
dev = qml.device("default.qubit", wires=3) @qml.qnode(dev, interface="autograd") def circuit(weights): # layer 1 qml.RX(weights, wires=0) qml.RX(weights, wires=1) qml.CNOT(wires=[0, 1]) qml.CNOT(wires=[1, 2]) # layer 2 qml.RZ(weights, wires=0) qml.RZ(weights, wires=2) qml.CNOT(wires=[0, 1]) qml.CNOT(wires=[1, 2]) return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)), qml.expval(qml.PauliY(2))
We can use the
metric_tensortransform to generate a new function that returns the metric tensor of this QNode:
>>> met_fn = qml.metric_tensor(circuit) >>> weights = np.array([0.1, 0.2, 0.4, 0.5], requires_grad=True) >>> met_fn(weights) tensor([[0.25 , 0. , 0. , 0. ], [0. , 0.25 , 0. , 0. ], [0. , 0. , 0.0025, 0.0024], [0. , 0. , 0.0024, 0.0123]], requires_grad=True)
The returned metric tensor is also fully differentiable in all interfaces. For example, we can compute the gradient of the
(3, 2)element with respect to the QNode
>>> grad_fn = qml.grad(lambda x: met_fn(x)[3, 2]) >>> grad_fn(weights) array([[ 0.04867729, -0.00049502, 0. ], [ 0. , 0. , 0. ]])
This transform can also be applied to low-level
QuantumTapeobjects. This will result in no implicit quantum device evaluation. Instead, the processed tapes, and post-processing function, which together define the metric tensor are directly returned:
>>> params = np.array([1.7, 1.0, 0.5], requires_grad=True) >>> with qml.tape.QuantumTape() as tape: ... qml.RX(params, wires=0) ... qml.RY(params, wires=0) ... qml.CNOT(wires=[0, 1]) ... qml.PhaseShift(params, wires=1) ... qml.expval(qml.PauliX(0)) >>> tapes, fn = qml.metric_tensor(tape) >>> tapes [<QuantumTape: wires=[0, 1], params=0>, <QuantumTape: wires=[0, 1], params=1>, <QuantumTape: wires=[0, 1], params=3>]
This can be useful if the underlying circuits representing the metric tensor computation need to be analyzed.
The output tapes can then be evaluated and post-processed to retrieve the metric tensor:
>>> dev = qml.device("default.qubit", wires=2) >>> fn(qml.execute(tapes, dev, None)) array([[0.25 , 0. , 0. ], [0. , 0.00415023, 0. ], [0. , 0. , 0.24878844]])