I want to calculate the Quantum Fisher Information (QFI) for the density matrix of a circuit that includes noise components. However, I encountered an error, which I suspect is due to the presence of mixed states. Is there a way to accurately compute the QFI in this context?
# import pennylane as qml
from pennylane import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
dev = qml.device("default.mixed", wires=2)
@qml.qnode(dev)
def circ(params):
qml.RY(params[0], wires=1)
qml.CNOT(wires=(1,0))
qml.RY(params[1], wires=1)
qml.RZ(params[2], wires=1)
qml.PhaseFlip(1-p,wires=0)
qml.PhaseFlip(1-p,wires=1)
return qml.density_matrix(wires=[0,1])
params=np.random.uniform(0,1,3)
p=0.5
qfim = qml.qinfo.quantum_fisher(circ)(params)
Error Message full error message below:
# Put full error message here
```MatrixUndefinedError Traceback (most recent call last)
Cell In[11], line 1
----> 1 qfim = qml.qinfo.quantum_fisher(circ)(params)
File /opt/conda/lib/python3.10/site-packages/pennylane/qnode.py:1039, in QNode.__call__(self, *args, **kwargs)
1034 full_transform_program._set_all_argnums(
1035 self, args, kwargs, argnums
1036 ) # pylint: disable=protected-access
1038 # pylint: disable=unexpected-keyword-arg
-> 1039 res = qml.execute(
1040 (self._tape,),
1041 device=self.device,
1042 gradient_fn=self.gradient_fn,
1043 interface=self.interface,
1044 transform_program=full_transform_program,
1045 config=config,
1046 gradient_kwargs=self.gradient_kwargs,
1047 override_shots=override_shots,
1048 **self.execute_kwargs,
1049 )
1051 res = res[0]
1053 # convert result to the interface in case the qfunc has no parameters
File /opt/conda/lib/python3.10/site-packages/pennylane/interfaces/execution.py:635, in execute(tapes, device, gradient_fn, interface, transform_program, config, grad_on_execution, gradient_kwargs, cache, cachesize, max_diff, override_shots, expand_fn, max_expansion, device_batch_transform, device_vjp)
632 tapes, post_processing = transform_program(tapes)
633 else:
634 # TODO: Remove once old device are removed
--> 635 tapes, program_post_processing = transform_program(tapes)
636 tapes, program_pre_processing, config = _batch_transform(
637 tapes, device, config, override_shots, device_batch_transform
638 )
640 def post_processing(results):
File /opt/conda/lib/python3.10/site-packages/pennylane/transforms/core/transform_program.py:435, in TransformProgram.__call__(self, tapes)
433 if self._argnums is not None and self._argnums[i] is not None:
434 tape.trainable_params = self._argnums[i][j]
--> 435 new_tapes, fn = transform(tape, *targs, **tkwargs)
436 execution_tapes.extend(new_tapes)
438 fns.append(fn)
File /opt/conda/lib/python3.10/site-packages/pennylane/qinfo/transforms.py:748, in quantum_fisher(tape, device, *args, **kwargs)
744 return 4 * processing_fn(res)
746 return tapes, processing_fn_multiply
--> 748 res = adjoint_metric_tensor(tape, *args, **kwargs)
750 def processing_fn_multiply(r): # pylint: disable=function-redefined
751 r = qml.math.stack(r)
File /opt/conda/lib/python3.10/site-packages/pennylane/transforms/core/transform_dispatcher.py:112, in TransformDispatcher.__call__(self, *targs, **tkwargs)
109 transformed_tapes, processing_fn = self._transform(obj, *targs, **tkwargs)
111 if self.is_informative:
--> 112 return processing_fn(transformed_tapes)
113 return transformed_tapes, processing_fn
115 if isinstance(obj, qml.QNode):
File /opt/conda/lib/python3.10/site-packages/pennylane/gradients/adjoint_metric_tensor.py:227, in adjoint_metric_tensor.<locals>.processing_fn(tapes)
225 psi = qml.devices.qubit.apply_operation(outer_op, psi)
226 for op in group_after_trainable_op[j]:
--> 227 psi = qml.devices.qubit.apply_operation(op, psi)
229 # postprocessing: combine L and T into the metric tensor.
230 # We require outer(conj(T), T) here, but as we skipped the factor 1j above,
231 # the stored T is real-valued. Thus we have -1j*1j*outer(T, T) = outer(T, T)
232 metric_tensor = L - qml.math.tensordot(T, T, 0)
File /opt/conda/lib/python3.10/functools.py:889, in singledispatch.<locals>.wrapper(*args, **kw)
885 if not args:
886 raise TypeError(f'{funcname} requires at least '
887 '1 positional argument')
--> 889 return dispatch(args[0].__class__)(*args, **kw)
File /opt/conda/lib/python3.10/site-packages/pennylane/devices/qubit/apply_operation.py:198, in apply_operation(op, state, is_state_batched, debugger)
150 @singledispatch
151 def apply_operation(
152 op: qml.operation.Operator, state, is_state_batched: bool = False, debugger=None
153 ):
154 """Apply and operator to a given state.
155
156 Args:
(...)
196
197 """
--> 198 return _apply_operation_default(op, state, is_state_batched, debugger)
File /opt/conda/lib/python3.10/site-packages/pennylane/devices/qubit/apply_operation.py:208, in _apply_operation_default(op, state, is_state_batched, debugger)
202 """The default behaviour of apply_operation, accessed through the standard dispatch
203 of apply_operation, as well as conditionally in other dispatches."""
204 if (
205 len(op.wires) < EINSUM_OP_WIRECOUNT_PERF_THRESHOLD
206 and math.ndim(state) < EINSUM_STATE_WIRECOUNT_PERF_THRESHOLD
207 ) or (op.batch_size and is_state_batched):
--> 208 return apply_operation_einsum(op, state, is_state_batched=is_state_batched)
209 return apply_operation_tensordot(op, state, is_state_batched=is_state_batched)
File /opt/conda/lib/python3.10/site-packages/pennylane/devices/qubit/apply_operation.py:72, in apply_operation_einsum(op, state, is_state_batched)
60 def apply_operation_einsum(op: qml.operation.Operator, state, is_state_batched: bool = False):
61 """Apply ``Operator`` to ``state`` using ``einsum``. This is more efficent at lower qubit
62 numbers.
63
(...)
70 array[complex]: output_state
71 """
---> 72 mat = op.matrix()
74 total_indices = len(state.shape) - is_state_batched
75 num_indices = len(op.wires)
File /opt/conda/lib/python3.10/site-packages/pennylane/operation.py:785, in Operator.matrix(self, wire_order)
765 def matrix(self, wire_order=None):
766 r"""Representation of the operator as a matrix in the computational basis.
767
768 If ``wire_order`` is provided, the numerical representation considers the position of the
(...)
783 tensor_like: matrix representation
784 """
--> 785 canonical_matrix = self.compute_matrix(*self.parameters, **self.hyperparameters)
787 if wire_order is None or self.wires == Wires(wire_order):
788 return canonical_matrix
File /opt/conda/lib/python3.10/site-packages/pennylane/operation.py:754, in Operator.compute_matrix(*params, **hyperparams)
738 @staticmethod
739 def compute_matrix(*params, **hyperparams): # pylint:disable=unused-argument
740 r"""Representation of the operator as a canonical matrix in the computational basis (static method).
741
742 The canonical matrix is the textbook matrix representation that does not consider wires.
(...)
752 tensor_like: matrix representation
753 """
--> 754 raise MatrixUndefinedError
MatrixUndefinedError:
And, finally, make sure to include the versions of your packages. Specifically, show us the output of `qml.about()`.
Name: PennyLane
Version: 0.34.0
Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.
Home-page: https://github.com/PennyLaneAI/pennylane
Author:
Author-email:
License: Apache License 2.0
Location: /opt/conda/lib/python3.10/site-packages
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, rustworkx, scipy, semantic-version, toml, typing-extensions
Required-by: PennyLane-Lightning
Platform info: Linux-4.14.336-253.554.amzn2.x86_64-x86_64-with-glibc2.35
Python version: 3.10.13
Numpy version: 1.26.2
Scipy version: 1.11.4
Installed devices:
- lightning.qubit (PennyLane-Lightning-0.34.0)
- default.gaussian (PennyLane-0.34.0)
- default.mixed (PennyLane-0.34.0)
- default.qubit (PennyLane-0.34.0)
- default.qubit.autograd (PennyLane-0.34.0)
- default.qubit.jax (PennyLane-0.34.0)
- default.qubit.legacy (PennyLane-0.34.0)
- default.qubit.tf (PennyLane-0.34.0)
- default.qubit.torch (PennyLane-0.34.0)
- default.qutrit (PennyLane-0.34.0)
- null.qubit (PennyLane-0.34.0)