Closed isaacdevlugt closed 1 year ago
So what's happening is that simplification happens immediately during construction via dunder methods.
To see some more examples or this, consider:
>>> 2 * qml.Identity((0,1,2)) @ qml.PauliX(3)
(2) [X3]
Since it's simplified on construction, the identity goes away completely. When only identities exist in the operator, then we simplify to an identity on a single wire to avoid getting rid of the operator completely.
If this is causing a problem, you can either directly create the Hamiltonian without simplification upon construction with qml.Hamiltonian(coeffs, ops, simplify=False)
or use an operator arithmetic scalar product qml.sprod(2, qml.Identity((0,1,2)))
.
Was this causing problems in any specific use case?
To fix it, we would probably need to turn off automatic simplification.
The problem where I was noticing this was similar to this:
n_qubits = 3
ham = 2.0 * qml.Identity(wires=range(n_qubits)) # just noticed that this happens without scalar mult as well
ham += 0.5 * qml.PauliX(0) @ qml.PauliX(1)
>>> ham.coeffs, ham.ops
(array([2. , 0.5]), [Identity(wires=[0]), PauliX(wires=[0]) @ PauliX(wires=[1])])
If I want to add a constant shift to a Hamiltonian, what's the best way? I feel like this should work.
The thing to remember is that we have implicit Identities everywhere nothing else exists.
You can double check this with the matrices:
>>> h1 = 2.0 * qml.Identity((0,1)) + qml.PauliX(0) @ qml.PauliX(1)
>>> h2 = qml.Hamiltonian([2.0, 1.0], [qml.Identity(0) @ qml.Identity(1), qml.PauliX(0) @ qml.PauliX(1)])
>>> qml.math.allclose(qml.matrix(h1), qml.matrix(h2))
True
So even though h1
has an identity simplified away during construction, it is exactly the same Hamiltonian as h2.
we have implicit Identities everywhere nothing else exists
Should we do that? What was the motivation for this?
@trbromley What I mean by that is that qml.PauliX(0) @ qml.Identity(1)
is basically the same thing as qml.PauliX(0)
.
Having to write out identities on every conceivable wire is going to be extremely inefficient and hard to understand.
Take for example qml.matrix(qml.PauliX(0), wire_order=[0,1])
. That uses an implicit Identity on wire 1.
Without implicitly identities something like qml.PauliX(0) + qml.PauliY(1)
would make no sense. What that sum actually means is qml.PauliX(0) @ qml.Identity(1) + qml.Identity(0) @ qml.PauliY(1)
.
Hmmm, I see your points @albi3ro. There's a balance to strike with performance, other functionalities, and legibility and expected experience. I trust your call on this one! Feel free to close this issue 🙂
Expected behavior
The Identity operator should apply to all specified wires.
Actual behavior
It doesn't apply to all specified wires.
Additional information
No response
Source code
No response
Tracebacks
No response
System information
Existing GitHub issues