diff --git a/qiskit/opflow/primitive_ops/tapered_pauli_sum_op.py b/qiskit/opflow/primitive_ops/tapered_pauli_sum_op.py index f1ebef3fb3c2..3ec4ab2943a0 100644 --- a/qiskit/opflow/primitive_ops/tapered_pauli_sum_op.py +++ b/qiskit/opflow/primitive_ops/tapered_pauli_sum_op.py @@ -360,12 +360,12 @@ def taper(self, operator: PauliSumOp) -> OperatorBase: "Z2 symmetries, single qubit pauli and single qubit list cannot be empty." ) - if operator.is_zero(): - logger.warning("The operator is empty, return the empty operator directly.") - return operator - - for clifford in self.cliffords: - operator = cast(PauliSumOp, clifford @ operator @ clifford) + # If the operator is zero then we can skip the following. We still need to taper the + # operator to reduce its size i.e. the number of qubits so for example 0*"IIII" could + # taper to 0*"II" when symmetries remove two qubits. + if not operator.is_zero(): + for clifford in self.cliffords: + operator = cast(PauliSumOp, clifford @ operator @ clifford) if self._tapering_values is None: tapered_ops_list = [ diff --git a/releasenotes/notes/taper_empty_operator_fix-53ce20e5d2b68fd6.yaml b/releasenotes/notes/taper_empty_operator_fix-53ce20e5d2b68fd6.yaml new file mode 100644 index 000000000000..16e49452d3b2 --- /dev/null +++ b/releasenotes/notes/taper_empty_operator_fix-53ce20e5d2b68fd6.yaml @@ -0,0 +1,11 @@ +--- +fixes: + - | + When tapering an empty/zero operator, the code, on detecting it was zero, logged a + warning and returned the original operator. Such operators are commonly found in + the auxiliary operators, when using Qiskit Nature, and the above behavior caused VQE + to throw an exception as tapered non-zero operators were a different number of qubits + from the tapered zero operators (since taper has returned the input operator unchanged). + The code will now correctly taper a zero operator such that the number of qubits is + reduced as expected and matches to tapered non-zero operators e.g 0*"IIII" when we are + tapering by 3 qubits will become 0*"I". diff --git a/test/python/opflow/test_z2_symmetries.py b/test/python/opflow/test_z2_symmetries.py index fb6b654e534b..d46f4b6b0e8a 100644 --- a/test/python/opflow/test_z2_symmetries.py +++ b/test/python/opflow/test_z2_symmetries.py @@ -55,3 +55,16 @@ def test_find_Z2_symmetries(self): ) expected_op = TaperedPauliSumOp(primitive, z2_symmetries) self.assertEqual(tapered_op, expected_op) + + def test_taper_empty_operator(self): + """Test tapering of empty operator""" + z2_symmetries = Z2Symmetries( + symmetries=[Pauli("IIZI"), Pauli("IZIZ"), Pauli("ZIII")], + sq_paulis=[Pauli("IIXI"), Pauli("IIIX"), Pauli("XIII")], + sq_list=[1, 0, 3], + tapering_values=[1, -1, -1], + ) + empty_op = PauliSumOp.from_list([("IIII", 0.0)]) + tapered_op = z2_symmetries.taper(empty_op) + expected_op = PauliSumOp.from_list([("I", 0.0)]) + self.assertEqual(tapered_op, expected_op)