Hamiltonian addition-in-place does not match definition as a sum

I’m trying to construct an observable as a sum of Paulis in version 0.22.1 but it doesn’t seem to work as expected when I add Paulis iteratively:

H = qml.PauliZ(0) + qml.PauliZ(1)
H += qml.PauliZ(2)
H.wires # wires=[0,1]
>>> <Wires = [0, 1]>
qml.matrix(H)
>>> WireError: Wire with label 2 not found in <Wires = [0, 1]>.

I just want to use the qml.matrix utility to do some pauli matrix algebra but this behavior confuses me - am I doing something wrong?

Note that the following works perfectly fine, but not if I need a very large sum:

H = qml.PauliZ(0) + qml.PauliZ(1) + qml.PauliZ(2)
qml.matrix(H)

Full traceback:

WireError                                 Traceback (most recent call last)
Input In [56], in <module>
----> 1 qml.matrix(H)

File ~/projects/envs/xanadu-3.8/lib/python3.8/site-packages/pennylane/transforms/op_transforms.py:213, in op_transform.__call__(self, *targs, **tkwargs)
    210     obj, *targs = targs
    212 if isinstance(obj, (qml.operation.Operator, qml.tape.QuantumTape)) or callable(obj):
--> 213     return self._create_wrapper(obj, *targs, **tkwargs)
    215 # Input is not an operator nor a QNode nor a quantum tape nor a qfunc.
    216 # Assume Python decorator syntax:
    217 #
   (...)
    229 # Prepend the input to the transform args,
    230 # and create a wrapper function.
    231 if obj is not None:

File ~/projects/envs/xanadu-3.8/lib/python3.8/site-packages/pennylane/transforms/op_transforms.py:412, in op_transform._create_wrapper(self, obj, wire_order, *targs, **tkwargs)
    409     if wire_order is not None:
    410         tkwargs["wire_order"] = wire_order
--> 412     wrapper = self.fn(obj, *targs, **tkwargs)
    414 elif isinstance(obj, qml.tape.QuantumTape):
    415     # Input is a quantum tape. Get the quantum tape.
    416     tape, verified_wire_order = self._make_tape(obj, wire_order)

File ~/projects/envs/xanadu-3.8/lib/python3.8/site-packages/pennylane/transforms/op_transforms.py:274, in op_transform.fn(self, obj, *args, **kwargs)
    265     return self.tape_fn(obj.expand(), *args, **kwargs)
    267 except (
    268     AttributeError,
    269     qml.operation.OperatorPropertyUndefined,
   (...)
    272     # if obj.expand() does not exist, a required operation property was not found,
    273     # or the tape transform function does not exist, simply raise the original exception
--> 274     raise e1 from None

File ~/projects/envs/xanadu-3.8/lib/python3.8/site-packages/pennylane/transforms/op_transforms.py:258, in op_transform.fn(self, obj, *args, **kwargs)
    240 """Evaluate the underlying operator transform function.
    241 
    242 If a corresponding tape transform for the operator has been registered
   (...)
    255     any: the result of evaluating the transform
    256 """
    257 try:
--> 258     return self._fn(obj, *args, **kwargs)
    260 except Exception as e1:  # pylint: disable=broad-except
    262     try:
    263         # attempt to decompose the operation and call
    264         # the tape transform function if defined

File ~/projects/envs/xanadu-3.8/lib/python3.8/site-packages/pennylane/ops/functions/matrix.py:124, in matrix(op, wire_order)
    121     op = 1.0 * op  # convert to a Hamiltonian
    123 if isinstance(op, qml.Hamiltonian):
--> 124     return qml.utils.sparse_hamiltonian(op, wires=wire_order).toarray()
    126 return op.get_matrix(wire_order=wire_order)

File ~/projects/envs/xanadu-3.8/lib/python3.8/site-packages/pennylane/utils.py:173, in sparse_hamiltonian(H, wires)
    169 mat = [scipy.sparse.eye(2, format="coo")] * n
    171 for i, wire in enumerate(op.wires):
    172     # find index of this wire in the ordering
--> 173     idx = wires.index(wire)
    174     mat[idx] = obs[i]
    176 matrix += functools.reduce(lambda i, j: scipy.sparse.kron(i, j, format="coo"), mat) * coeff

File ~/projects/envs/xanadu-3.8/lib/python3.8/site-packages/pennylane/wires.py:230, in Wires.index(self, wire)
    228     return self._labels.index(wire)
    229 except ValueError as e:
--> 230     raise WireError(f"Wire with label {wire} not found in {self}.") from e

WireError: Wire with label 2 not found in <Wires = [0, 1]>.

Thanks for reporting this @EvanPeters – this is definitely a bug! I have made a bugfix here: https://github.com/PennyLaneAI/pennylane/pull/2410

1 Like