def test_hamiltonian_mix_return(self, use_csingle):
        """Test expected serialization for a Hamiltonian return"""

        ham1 = qml.Hamiltonian(
            [0.3, 0.5, 0.4],
            [
                qml.Hermitian(np.eye(4), wires=[0, 1]) @ qml.PauliY(2),
                qml.PauliX(0) @ qml.PauliY(2),
                qml.Hermitian(np.ones((8, 8)), wires=range(3)),
            ],
        )
        ham2 = qml.Hamiltonian(
            [0.7, 0.3],
            [qml.PauliX(0) @ qml.Hermitian(np.eye(4), wires=[1, 2]), qml.PauliY(0) @ qml.PauliX(2)],
        )

        with qml.tape.QuantumTape() as tape:
            qml.expval(ham1)
            qml.expval(ham2)

        obs_str = "HamiltonianC64" if use_csingle else "HamiltonianC128"
        hamiltonian_obs = HamiltonianC64 if use_csingle else HamiltonianC128
        named_obs = NamedObsC64 if use_csingle else NamedObsC128
        hermitian_obs = HermitianObsC64 if use_csingle else HermitianObsC128
        tensor_prod_obs = TensorProdObsC64 if use_csingle else TensorProdObsC128
        r_dtype = np.float32 if use_csingle else np.float64
        c_dtype = np.complex64 if use_csingle else np.complex128

        s = _serialize_observables(tape, self.wires_dict, use_csingle=use_csingle)

        s_expected1 = hamiltonian_obs(
            np.array([0.3, 0.5, 0.4], dtype=r_dtype),
            [
                tensor_prod_obs(
                    [
                        hermitian_obs(np.eye(4, dtype=c_dtype).ravel(), [0, 1]),
                        named_obs("PauliY", [2]),
                    ]
                ),
                tensor_prod_obs([named_obs("PauliX", [0]), named_obs("PauliY", [2])]),
                hermitian_obs(np.ones(64, dtype=c_dtype), [0, 1, 2]),
            ],
        )
        s_expected2 = hamiltonian_obs(
            np.array([0.7, 0.3], dtype=r_dtype),
            [
                tensor_prod_obs(
                    [
                        named_obs("PauliX", [0]),
                        hermitian_obs(np.eye(4, dtype=c_dtype).ravel(), [1, 2]),
                    ]
                ),
                tensor_prod_obs([named_obs("PauliY", [0]), named_obs("PauliX", [2])]),
            ],
        )

        assert s[0] == s_expected1
        assert s[1] == s_expected2
    def test_basic_return(self, monkeypatch, ObsFunc):
        """Test expected serialization for a simple return"""
        with qml.tape.QuantumTape() as tape:
            qml.expval(qml.PauliZ(0))

        mock_obs = mock.MagicMock()

        use_csingle = True if ObsFunc == NamedObsC64 else False
        obs_str = "NamedObsC64" if ObsFunc == NamedObsC64 else "NamedObsC128"

        with monkeypatch.context() as m:
            m.setattr(pennylane_lightning._serialize, obs_str, mock_obs)
            _serialize_observables(tape, self.wires_dict, use_csingle=use_csingle)

        s = mock_obs.call_args[0]
        s_expected = ("PauliZ", [0])
        ObsFunc(*s_expected)

        assert s == s_expected
    def test_tensor_return(self, monkeypatch, use_csingle):
        """Test expected serialization for a tensor product return"""
        with qml.tape.QuantumTape() as tape:
            qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

        mock_obs = mock.MagicMock()

        ObsFunc = TensorProdObsC64 if use_csingle else TensorProdObsC128
        named_obs = NamedObsC64 if use_csingle else NamedObsC128
        obs_str = "TensorProdObsC64" if use_csingle else "TensorProdObsC128"

        with monkeypatch.context() as m:
            m.setattr(pennylane_lightning._serialize, obs_str, mock_obs)
            _serialize_observables(tape, self.wires_dict, use_csingle=use_csingle)

        s = mock_obs.call_args[0]
        s_expected = ([named_obs("PauliZ", [0]), named_obs("PauliZ", [1])],)
        ObsFunc(*s_expected)

        assert s == s_expected
    def test_chunk_obs(self, monkeypatch, use_csingle, ObsChunk):
        """Test chunking of observable array"""
        with qml.tape.QuantumTape() as tape:
            qml.expval(qml.PauliZ(0) @ qml.PauliX(1))
            qml.expval(qml.PauliY(wires=1))
            qml.expval(qml.PauliX(0) @ qml.Hermitian([[0, 1], [1, 0]], wires=3) @ qml.Hadamard(2))
            qml.expval(qml.Hermitian(qml.PauliZ.compute_matrix(), wires=0) @ qml.Identity(1))

        s = _serialize_observables(tape, self.wires_dict, use_csingle=use_csingle)

        obtained_chunks = pennylane_lightning.lightning_qubit._chunk_iterable(s, ObsChunk)
        assert len(list(obtained_chunks)) == int(np.ceil(len(s) / ObsChunk))
    def test_hamiltonian_tensor_return(self, use_csingle):
        """Test expected serialization for a Hamiltonian return"""

        with qml.tape.QuantumTape() as tape:
            ham = qml.Hamiltonian(
                [0.3, 0.5, 0.4],
                [
                    qml.Hermitian(np.eye(4), wires=[0, 1]) @ qml.PauliY(2),
                    qml.PauliX(0) @ qml.PauliY(2),
                    qml.Hermitian(np.ones((8, 8)), wires=range(3)),
                ],
            )
            qml.expval(ham @ qml.PauliZ(3))

        obs_str = "HamiltonianC64" if use_csingle else "HamiltonianC128"
        hamiltonian_obs = HamiltonianC64 if use_csingle else HamiltonianC128
        named_obs = NamedObsC64 if use_csingle else NamedObsC128
        hermitian_obs = HermitianObsC64 if use_csingle else HermitianObsC128
        tensor_prod_obs = TensorProdObsC64 if use_csingle else TensorProdObsC128
        r_dtype = np.float32 if use_csingle else np.float64
        c_dtype = np.complex64 if use_csingle else np.complex128

        s = _serialize_observables(tape, self.wires_dict, use_csingle=use_csingle)

        # Expression (ham @ obs) is converted internally by Pennylane
        # where obs is appended to each term of the ham
        s_expected = hamiltonian_obs(
            np.array([0.3, 0.5, 0.4], dtype=r_dtype),
            [
                tensor_prod_obs(
                    [
                        hermitian_obs(np.eye(4, dtype=c_dtype).ravel(), [0, 1]),
                        named_obs("PauliY", [2]),
                        named_obs("PauliZ", [3]),
                    ]
                ),
                tensor_prod_obs(
                    [named_obs("PauliX", [0]), named_obs("PauliY", [2]), named_obs("PauliZ", [3])]
                ),
                tensor_prod_obs(
                    [hermitian_obs(np.ones(64, dtype=c_dtype), [0, 1, 2]), named_obs("PauliZ", [3])]
                ),
            ],
        )

        assert s[0] == s_expected
    def test_mixed_tensor_return(self, use_csingle):
        """Test expected serialization for a mixture of Hermitian and Pauli return"""
        with qml.tape.QuantumTape() as tape:
            qml.expval(qml.Hermitian(np.eye(4), wires=[0, 1]) @ qml.PauliY(2))

        c_dtype = np.complex64 if use_csingle else np.complex128
        tensor_prod_obs = TensorProdObsC64 if use_csingle else TensorProdObsC128
        hermitian_obs = HermitianObsC64 if use_csingle else HermitianObsC128
        named_obs = NamedObsC64 if use_csingle else NamedObsC128

        s = _serialize_observables(tape, self.wires_dict, use_csingle=use_csingle)

        s_expected = tensor_prod_obs(
            [hermitian_obs(np.eye(4, dtype=c_dtype).ravel(), [0, 1]), named_obs("PauliY", [2])]
        )

        assert s[0] == s_expected
    def test_hermitian_return(self, use_csingle):
        """Test expected serialization for a Hermitian return"""
        with qml.tape.QuantumTape() as tape:
            qml.expval(qml.Hermitian(np.eye(4), wires=[0, 1]))

        hermitian_obs = HermitianObsC64 if use_csingle else HermitianObsC128
        c_dtype = np.complex64 if use_csingle else np.complex128

        s = _serialize_observables(tape, self.wires_dict, use_csingle=use_csingle)
        s_expected = hermitian_obs(
            np.array(
                [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0],
                dtype=c_dtype,
            ),
            [0, 1],
        )
        s[0] == s_expected
    def test_tensor_non_tensor_return(self, use_csingle):
        """Test expected serialization for a mixture of tensor product and non-tensor product
        return"""
        with qml.tape.QuantumTape() as tape:
            qml.expval(qml.PauliZ(0) @ qml.PauliX(1))
            qml.expval(qml.Hadamard(1))

        tensor_prod_obs = TensorProdObsC64 if use_csingle else TensorProdObsC128
        named_obs = NamedObsC64 if use_csingle else NamedObsC128

        s = _serialize_observables(tape, self.wires_dict, use_csingle=use_csingle)

        s_expected = [
            tensor_prod_obs([named_obs("PauliZ", [0]), named_obs("PauliX", [1])]),
            named_obs("Hadamard", [1]),
        ]

        assert s == s_expected