Repository: PennyLaneAI/pennylane

Issue:
QNodes with `default.qubit` and `default.qubit.legacy` give different results 
### Expected behavior

They should give the same results.

### Actual behavior

They give different results.

### Additional information

Seems to be that BasisState followed by some (? — RandomLayers and some instances of QubitUnitary ) operation give different results.

### Source code

```shell
import pennylane as qml
import pennylane.numpy as np

new_device = qml.device("default.qubit", wires=2)
legacy_device = qml.device("default.qubit.legacy", wires=2)

def random_unitary():
    weights = np.array([[0.1, -2.1, 1.4]])
    qml.RandomLayers(weights=weights, wires=0)

def circuit(state):
    qml.BasisState(state, wires=1) 
    random_unitary()
    # getting rid of BasisState and/or random_unitary produces no discrepancy

@qml.qnode(new_device)
def circuit_new_device(state):
    circuit(state)
    return qml.state()

@qml.qnode(legacy_device)
def circuit_legacy_device(state):
    circuit(state)
    return qml.state()

res_new_device = circuit_new_device(np.array([1]))
res_legacy_device = circuit_legacy_device(np.array([1]))

print(res_new_device == res_legacy_device) # [False False False False]
```


### Tracebacks

```shell
N/A
```


### System information

```shell
Name: PennyLane
Version: 0.33.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: /Users/isaac/.virtualenvs/pennylane-stable/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-14.1-x86_64-i386-64bit
Python version:          3.9.14
Numpy version:           1.23.5
Scipy version:           1.10.0
Installed devices:
- default.gaussian (PennyLane-0.34.0.dev0)
- default.mixed (PennyLane-0.34.0.dev0)
- default.qubit (PennyLane-0.34.0.dev0)
- default.qubit.autograd (PennyLane-0.34.0.dev0)
- default.qubit.jax (PennyLane-0.34.0.dev0)
- default.qubit.legacy (PennyLane-0.34.0.dev0)
- default.qubit.tf (PennyLane-0.34.0.dev0)
- default.qubit.torch (PennyLane-0.34.0.dev0)
- default.qutrit (PennyLane-0.34.0.dev0)
- null.qubit (PennyLane-0.34.0.dev0)
- lightning.qubit (PennyLane-Lightning-0.33.1)
```


### Existing GitHub issues

- [X] I have searched existing GitHub issues to make sure the issue does not already exist.


Discussion:
Just checked that my code example produces the correct results with https://github.com/PennyLaneAI/pennylane/pull/4781 🚀 
Thanks @isaacdevlugt! This is a great thing to spot, and something that would be great to be tested for in the tests. Thanks @albi3ro for fixing quickly.

Resolving patch:
diff --git a/pennylane/devices/qubit/simulate.py b/pennylane/devices/qubit/simulate.py
--- a/pennylane/devices/qubit/simulate.py
+++ b/pennylane/devices/qubit/simulate.py
@@ -153,7 +153,7 @@ def get_final_state(circuit, debugger=None, interface=None):
     if len(circuit) > 0 and isinstance(circuit[0], qml.operation.StatePrepBase):
         prep = circuit[0]
 
-    state = create_initial_state(circuit.op_wires, prep, like=INTERFACE_TO_LIKE[interface])
+    state = create_initial_state(sorted(circuit.op_wires), prep, like=INTERFACE_TO_LIKE[interface])
 
     # initial state is batched only if the state preparation (if it exists) is batched
     is_state_batched = bool(prep and prep.batch_size is not None)
diff --git a/pennylane/ops/op_math/symbolicop.py b/pennylane/ops/op_math/symbolicop.py
--- a/pennylane/ops/op_math/symbolicop.py
+++ b/pennylane/ops/op_math/symbolicop.py
@@ -195,6 +195,10 @@ def _check_and_compute_batch_size(self, scalar):
             )
         return scalar_size
 
+    @property
+    def has_matrix(self):
+        return self.base.has_matrix or isinstance(self.base, qml.Hamiltonian)
+
     @property
     def hash(self):
         return hash(
diff --git a/pennylane/transforms/defer_measurements.py b/pennylane/transforms/defer_measurements.py
--- a/pennylane/transforms/defer_measurements.py
+++ b/pennylane/transforms/defer_measurements.py
@@ -66,7 +66,7 @@ def _collect_mid_measure_info(tape: QuantumTape):
     any_repeated_measurements = False
     is_postselecting = False
 
-    for op in tape.operations:
+    for op in tape:
         if isinstance(op, MidMeasureMP):
             if op.postselect is not None:
                 is_postselecting = True


Test patch:
diff --git a/tests/devices/default_qubit/test_default_qubit.py b/tests/devices/default_qubit/test_default_qubit.py
--- a/tests/devices/default_qubit/test_default_qubit.py
+++ b/tests/devices/default_qubit/test_default_qubit.py
@@ -317,6 +317,17 @@ def circuit(p):
         assert qml.math.get_interface(res) == "tensorflow"
         assert qml.math.allclose(res, -1)
 
+    def test_basis_state_wire_order(self):
+        """Test that the wire order is correct with a basis state if the tape wires have a non standard order."""
+
+        dev = DefaultQubit()
+
+        tape = qml.tape.QuantumScript([qml.BasisState([1], wires=1), qml.PauliZ(0)], [qml.state()])
+
+        expected = np.array([0, 1, 0, 0], dtype=np.complex128)
+        res = dev.execute(tape)
+        assert qml.math.allclose(res, expected)
+
 
 class TestSampleMeasurements:
     """A copy of the `qubit.simulate` tests, but using the device"""
diff --git a/tests/ops/op_math/test_symbolic_op.py b/tests/ops/op_math/test_symbolic_op.py
--- a/tests/ops/op_math/test_symbolic_op.py
+++ b/tests/ops/op_math/test_symbolic_op.py
@@ -139,6 +139,13 @@ class DummyOp(Operator):
         op = SymbolicOp(base)
         assert op.has_matrix == has_mat
 
+    def test_has_matrix_hamiltonian(self):
+        """Test that it has a matrix if the base is a hamiltonian."""
+
+        H = qml.Hamiltonian([1.0], [qml.PauliX(0)])
+        op = TempScalar(H, 2)
+        assert op.has_matrix
+
     @pytest.mark.parametrize("is_herm", (True, False))
     def test_is_hermitian(self, is_herm):
         """Test that symbolic op is hermitian if the base is hermitian."""
diff --git a/tests/transforms/test_defer_measurements.py b/tests/transforms/test_defer_measurements.py
--- a/tests/transforms/test_defer_measurements.py
+++ b/tests/transforms/test_defer_measurements.py
@@ -1348,6 +1348,25 @@ def qnode2(x):
             for actual, expected in zip(qnode2.qtape.circuit, expected_circuit)
         )
 
+    def test_measurements_add_new_qubits(self):
+        """Test that qubit reuse related logic is applied if a wire with mid-circuit
+        measurements is included in terminal measurements."""
+        tape = qml.tape.QuantumScript(
+            ops=[qml.Hadamard(0), MidMeasureMP(0)], measurements=[qml.density_matrix(wires=[0])]
+        )
+        expected = np.eye(2) / 2
+
+        tapes, _ = qml.defer_measurements(tape)
+
+        dev = qml.device("default.qubit")
+        res = qml.execute(tapes, dev)
+
+        assert np.allclose(res, expected)
+
+        deferred_tape = tapes[0]
+        assert deferred_tape.operations == [qml.Hadamard(0), qml.CNOT([0, 1])]
+        assert deferred_tape.measurements == [qml.density_matrix(wires=[0])]
+
     def test_wire_is_reset(self):
         """Test that a wire is reset to the |0> state without any local phases
         after measurement if reset is requested."""
@@ -1484,7 +1503,7 @@ def test_custom_wire_labels_allowed_without_reset():
         qml.Hadamard("a")
         ma = qml.measure("a", reset=False)
         qml.cond(ma, qml.PauliX)("b")
-        qml.probs(wires="a")
+        qml.probs(wires="b")
 
     tape = qml.tape.QuantumScript.from_queue(q)
     tapes, _ = qml.defer_measurements(tape)
@@ -1493,7 +1512,7 @@ def test_custom_wire_labels_allowed_without_reset():
     assert len(tape) == 3
     assert qml.equal(tape[0], qml.Hadamard("a"))
     assert qml.equal(tape[1], qml.CNOT(["a", "b"]))
-    assert qml.equal(tape[2], qml.probs(wires="a"))
+    assert qml.equal(tape[2], qml.probs(wires="b"))
 
 
 def test_custom_wire_labels_fails_with_reset():