Repository: Qiskit/qiskit — pull request #13436 (python)
Title: Fix the calculation for identity operator's expectation value (backport #13345)

\n\n### Summary\n\nFix a bug in `qiskit.quantum_info` in the calculation of expectation value of the identity operator.\n\nFixes #13029 \n\n\n\n### Details and comments\nCurrently,  `qiskit.quantum_info` yields incorrect results for the expectation value of an identity operator for a given state vector. It returns the norm of the state vector; however, it ought to return the square of the norm.\n\nTherefore, I am changing the following line  \n\nhttps://github.com/Qiskit/qiskit/blob/1be2c5aa103f1991f2fdc75a77a09f82635b8431/qiskit/quantum_info/states/statevector.py#L478-L479\n\nto \n```Python\n   if x_mask + z_mask == 0: \n       return pauli_phase * np.linalg.norm(self.data) ** 2\n```\n<hr>This is an automatic backport of pull request #13345 done by [Mergify](https://mergify.com).

Resolved issues:
title: Statevector._expectation_value_pauli returns incorrect result in certain cases
body: The calculation for the expectation value of the __identity operator__ seems incorrect when the statevector is __not normalized__ to 1.\r\n\r\nI think the reason is that one should use the norm squared rather than the norm in the following lines.\r\nhttps://github.com/Qiskit/qiskit/blob/1be2c5aa103f1991f2fdc75a77a09f82635b8431/qiskit/quantum_info/states/statevector.py#L478-L479\r\n\r\n---\r\n\r\nThe whole function is attached below to provide context.\r\n\r\nhttps://github.com/Qiskit/qiskit/blob/1be2c5aa103f1991f2fdc75a77a09f82635b8431/qiskit/quantum_info/states/statevector.py#L458-L491

Hints:

Fix patch:
diff --git a/qiskit/quantum_info/states/statevector.py b/qiskit/quantum_info/states/statevector.py\nindex 901ce95af424..1265d677abe4 100644\n--- a/qiskit/quantum_info/states/statevector.py\n+++ b/qiskit/quantum_info/states/statevector.py\n@@ -476,7 +476,7 @@ def _expectation_value_pauli(self, pauli, qargs=None):\n         pauli_phase = (-1j) ** pauli.phase if pauli.phase else 1\n \n         if x_mask + z_mask == 0:\n-            return pauli_phase * np.linalg.norm(self.data)\n+            return pauli_phase * np.linalg.norm(self.data) ** 2\n \n         if x_mask == 0:\n             return pauli_phase * expval_pauli_no_x(self.data, self.num_qubits, z_mask)\n

Test patch:
diff --git a/releasenotes/notes/fix_identity_operator_9e2ec9770ac046a6.yaml b/releasenotes/notes/fix_identity_operator_9e2ec9770ac046a6.yaml\nnew file mode 100644\nindex 000000000000..69779a793cc3\n--- /dev/null\n+++ b/releasenotes/notes/fix_identity_operator_9e2ec9770ac046a6.yaml\n@@ -0,0 +1,5 @@\n+---\n+fixes:\n+  - |\n+    Fixed a bug that caused :meth:`.Statevector.expectation_value` to yield incorrect results\n+    for the identity operator when the statevector was not normalized.\ndiff --git a/test/python/quantum_info/states/test_statevector.py b/test/python/quantum_info/states/test_statevector.py\nindex 29d5d42f3783..d16b3b3453ec 100644\n--- a/test/python/quantum_info/states/test_statevector.py\n+++ b/test/python/quantum_info/states/test_statevector.py\n@@ -1152,6 +1152,31 @@ def test_expval_pauli_qargs(self, qubits):\n         expval = state.expectation_value(op, qubits)\n         self.assertAlmostEqual(expval, target)\n \n+    def test_expval_identity(self):\n+        """Test whether the calculation for identity operator has been fixed"""\n+\n+        # 1 qubit case test\n+        state_1 = Statevector.from_label("0")\n+        state_1_n1 = 2 * state_1  # test the same state with different norms\n+        state_1_n2 = (1 + 2j) * state_1\n+        identity_op_1 = SparsePauliOp.from_list([("I", 1)])\n+        expval_state_1 = state_1.expectation_value(identity_op_1)\n+        expval_state_1_n1 = state_1_n1.expectation_value(identity_op_1)\n+        expval_state_1_n2 = state_1_n2.expectation_value(identity_op_1)\n+        self.assertAlmostEqual(expval_state_1, 1.0 + 0j)\n+        self.assertAlmostEqual(expval_state_1_n1, 4 + 0j)\n+        self.assertAlmostEqual(expval_state_1_n2, 5 + 0j)\n+\n+        # Let's try a multi-qubit case\n+        n_qubits = 3\n+        state_coeff = 3 - 4j\n+        op_coeff = 2 - 2j\n+        state_test = state_coeff * Statevector.from_label("0" * n_qubits)\n+        op_test = SparsePauliOp.from_list([("I" * n_qubits, op_coeff)])\n+        expval = state_test.expectation_value(op_test)\n+        target = op_coeff * np.abs(state_coeff) ** 2\n+        self.assertAlmostEqual(expval, target)\n+\n     @data(*(qargs for i in range(4) for qargs in permutations(range(4), r=i + 1)))\n     def test_probabilities_qargs(self, qargs):\n         """Test probabilities method with qargs"""\n