Repository: Qiskit/qiskit-terra (python)

Issue:
SparsePauliOp casting of coeffs causes errors for dtype=real
### Environment

- **Qiskit Terra version**: 0.22
- **Python version**: All
- **Operating system**: All

### What is happening?

The current init for `SparsePauliOp` has handling for storing coefficient arrays using their input dtype, but this is used to cast the coeffs to that type after moving the Pauli phase to the coeffs. This can cause errors if the dtype is not complex.

### How can we reproduce the issue?

Here is an example which gives an incorrect answer:
```python
# Initialize ops, with coeffs with dtype double
a = SparsePauliOp(['X'], np.array([1]))
b = SparsePauliOp(['Y'], np.array([1]))
a.dot(b)
```
This raises a warning
```
# Raises waring
.../sparse_pauli_op.py:131: ComplexWarning: Casting complex values to real discards the imaginary part
  self._coeffs = np.asarray((-1j) ** (phase - count_y) * coeffs, dtype=coeffs.dtype)
```
and returns the incorrect value
```
SparsePauliOp(['Z'],
              coeffs=[0])
```

### What should happen?

For the above example the correct answer should be
```
SparsePauliOp(['Z'],
              coeffs=[0.+1.j])
```

### Any suggestions?

Removing the explicit dype in the line from the warning should fix this, which would allow double coeffs to be converted to complex if required.

I suspect this support was added in the first place to handle object arrays for parameters, and I think that should still be supported if the dtype arg is not used since the asarray should default to an object array in that case.

Pull request:
Fix #8992 (SparsePauliOp.dot with real coefficients) (backport #8998)
This is an automatic backport of pull request #8998 done by [Mergify](https://mergify.com).


---


<details>
<summary>Mergify commands and options</summary>

<br />

More conditions and actions can be found in the [documentation](https://docs.mergify.com/).

You can also trigger Mergify actions by commenting on this pull request:

- `@Mergifyio refresh` will re-evaluate the rules
- `@Mergifyio rebase` will rebase this PR on its base branch
- `@Mergifyio update` will merge the base branch into this PR
- `@Mergifyio backport <destination>` will backport this PR on `<destination>` branch

Additionally, on Mergify [dashboard](https://dashboard.mergify.com/) you can:

- look at your merge queues
- generate the Mergify configuration with the config editor.

Finally, you can contact us on https://mergify.com
</details>

Patch:
diff --git a/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py b/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py
index 228a8badb..dd2ac3bc6 100644
--- a/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py
+++ b/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py
@@ -112,7 +112,7 @@ class SparsePauliOp(LinearOp):
 
         pauli_list = PauliList(data.copy() if copy and hasattr(data, "copy") else data)
 
-        dtype = coeffs.dtype if isinstance(coeffs, np.ndarray) else complex
+        dtype = object if isinstance(coeffs, np.ndarray) and coeffs.dtype == object else complex
 
         if coeffs is None:
             coeffs = np.ones(pauli_list.size, dtype=dtype)
diff --git a/releasenotes/notes/fix-sparse-pauli-real-63c31d87801671b1.yaml b/releasenotes/notes/fix-sparse-pauli-real-63c31d87801671b1.yaml
new file mode 100644
index 000000000..cd6b71100
--- /dev/null
+++ b/releasenotes/notes/fix-sparse-pauli-real-63c31d87801671b1.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+  - |
+    Fix :meth:`.SparsePauliOp.dot` between operators with real coefficients.
+    To fix this, the dtype that :class:`SparsePauliOp` can take is restricted to
+    ``np.complex128`` and ``object``.


Test patch:
diff --git a/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py b/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py
index bf58220d1..2548ac4ff 100644
--- a/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py
+++ b/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py
@@ -940,6 +940,13 @@ class TestSparsePauliOpMethods(QiskitTestCase):
                 )
             )
 
+    def test_dot_real(self):
+        """Test dot for real coefficiets."""
+        x = SparsePauliOp("X", np.array([1]))
+        y = SparsePauliOp("Y", np.array([1]))
+        iz = SparsePauliOp("Z", 1j)
+        self.assertEqual(x.dot(y), iz)
+
 
 if __name__ == "__main__":
     unittest.main()