# `qml.prod` vs direct operators product

When creating multi-product of observables, I found something acting out of my expectation. I think it should be clear to just demonstrate it with some codes below:

### Case 1

``````before = qml.PauliX(wires=0)
after = before @ qml.PauliZ(wires=2)

print(f"Before = {before}")
print(f"After = {after}")
``````
``````Before = PauliX(wires=[0])
After = PauliX(wires=[0]) @ PauliZ(wires=[2])
``````

It works fine as my expectation, `before` is still `before`.

### Case 2

``````before = qml.PauliX(wires=0) @ qml.PauliY(wires=1)
after = before @ qml.PauliZ(wires=2)

print(f"Before = {before}")
print(f"After = {after}")
``````
``````Before = PauliX(wires=[0]) @ PauliY(wires=[1]) @ PauliZ(wires=[2])
After = PauliX(wires=[0]) @ PauliY(wires=[1]) @ PauliZ(wires=[2])
``````

Now `before` is not `before` anymore, but seems to be contaminated.

### Case 3

If we write a for loop to see the behavior in more qubits:

``````from functools import reduce
for num_wires in range(1, 5):
before = reduce(lambda x, y: x @ y, [qml.PauliX(wires=i) for i in range(num_wires)])
after = before @ qml.PauliZ(wires=num_wires)

print(f"`before` with {num_wires} wires:")
print(f"Before = {before}")
print(f"After = {after}")
print()
``````
```````before` with 1 wires:
Before = PauliX(wires=[0])
After = PauliX(wires=[0]) @ PauliZ(wires=[1])

`before` with 2 wires:
Before = PauliX(wires=[0]) @ PauliX(wires=[1]) @ PauliZ(wires=[2])
After = PauliX(wires=[0]) @ PauliX(wires=[1]) @ PauliZ(wires=[2])

`before` with 3 wires:
Before = PauliX(wires=[0]) @ PauliX(wires=[1]) @ PauliX(wires=[2]) @ PauliZ(wires=[3])
After = PauliX(wires=[0]) @ PauliX(wires=[1]) @ PauliX(wires=[2]) @ PauliZ(wires=[3])

`before` with 4 wires:
Before = PauliX(wires=[0]) @ PauliX(wires=[1]) @ PauliX(wires=[2]) @ PauliX(wires=[3]) @ PauliZ(wires=[4])
After = PauliX(wires=[0]) @ PauliX(wires=[1]) @ PauliX(wires=[2]) @ PauliX(wires=[3]) @ PauliZ(wires=[4])
``````

We see that when `before` is a product of more than 1 observables, `before` will be contaminated from other behavior.

### Solution

Instead, if we change the syntax from `x @ y` to `qml.prod(x, y)`, it works correctly.

``````for num_wires in range(1, 5):
before = reduce(lambda x, y: x @ y, [qml.PauliX(wires=i) for i in range(num_wires)])
after = qml.prod(before, qml.PauliZ(wires=num_wires))

print(f"`before` with {num_wires} wires:")
print(f"Before = {before}")
print(f"After = {after}")
print()
``````
```````before` with 1 wires:
Before = PauliX(wires=[0])
After = PauliX(wires=[0]) @ PauliZ(wires=[1])

`before` with 2 wires:
Before = PauliX(wires=[0]) @ PauliX(wires=[1])
After = (PauliX(wires=[0]) @ PauliX(wires=[1])) @ PauliZ(wires=[2])

`before` with 3 wires:
Before = PauliX(wires=[0]) @ PauliX(wires=[1]) @ PauliX(wires=[2])
After = (PauliX(wires=[0]) @ PauliX(wires=[1]) @ PauliX(wires=[2])) @ PauliZ(wires=[3])

`before` with 4 wires:
Before = PauliX(wires=[0]) @ PauliX(wires=[1]) @ PauliX(wires=[2]) @ PauliX(wires=[3])
After = (PauliX(wires=[0]) @ PauliX(wires=[1]) @ PauliX(wires=[2]) @ PauliX(wires=[3])) @ PauliZ(wires=[4])
``````

### Conclusion

Iām not sure whether this is an intended design that we should use `qml.prod(x, y)` instead of `x @ y`, maybe I have miss somewhere in the document. If there is some detail discussion about this, it would be nice for me to take a look, thanks in advance.

### PennyLane version

``````Name: PennyLane
Version: 0.33.1
Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.
Home-page: https://github.com/PennyLaneAI/pennylane
Author:
Author-email:
Location: /Users/yianchen/.pyenv/versions/3.9.12/lib/python3.9/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:           macOS-12.6-x86_64-i386-64bit
Python version:          3.9.12
Numpy version:           1.23.5
Scipy version:           1.11.4
Installed devices:
- default.gaussian (PennyLane-0.33.1)
- default.mixed (PennyLane-0.33.1)
- default.qubit (PennyLane-0.33.1)
- default.qubit.jax (PennyLane-0.33.1)
- default.qubit.legacy (PennyLane-0.33.1)
- default.qubit.tf (PennyLane-0.33.1)
- default.qubit.torch (PennyLane-0.33.1)
- default.qutrit (PennyLane-0.33.1)
- null.qubit (PennyLane-0.33.1)
- lightning.qubit (PennyLane-Lightning-0.33.1)
``````

Thanks for the post @Yian_Chen .

You can change the behaviour of the operator dunder methods (`@`) by running `qml.operation.enable_new_opmath()`. This will give you sums, products, and scalar products instead of `Tensor` and `Hamiltonian`.

You can see the documentation for this function: qml.operation.enable_new_opmath ā PennyLane 0.34.0 documentation

We hope to change the default behavior in the near future.

1 Like

Hi @Christina , thank you, this works for me