Skip to content

Commit

Permalink
Add support for non-hermitian operators in AerPauliExpectation (#7857)
Browse files Browse the repository at this point in the history
* Added support for non-hermitian operators in AerPauliExpectation

Fixes #415

QEOM creates a dictionary of operators to evaluate on the groundstate.
When using the noisy simulators (qasm_simulator or aer_simulator), one
could either use PauliExpectation (with noise) or AerPauliExpectation
(without noise). PauliExpectation works with non-hermitian operators
but internal methods of AerPauliExpectation raised an Error.
This is a workaround to this limitation.
Note that using include_custom=True on qasm allows the VQE to use a
local AerPauliExpectation without using the "expectation" input.
This does not apply to QEOM and one should explicitly define the
"expectation" input of the VQE for it to apply globally.

* Added support for non-hermitian operators in AerPauliExpectation

Fixes #415

QEOM creates a dictionary of operators to evaluate on the groundstate.
When using the noisy simulators (qasm_simulator or aer_simulator), one
could either use PauliExpectation (with noise) or AerPauliExpectation
(without noise). PauliExpectation works with non-hermitian operators
but internal methods of AerPauliExpectation raised an Error.
This is a workaround to this limitation.
Note that using include_custom=True on qasm allows the VQE to use a
local AerPauliExpectation without using the "expectation" input.
This does not apply to QEOM and one should explicitly define the
"expectation" input of the VQE for it to apply globally.

* Add a test case for non-hermitian operators.

* Add a test case for non-hermitian operators.

* Add a test case for non-hermitian operators.

* Update test/python/opflow/test_aer_pauli_expectation.py

Co-authored-by: Julien Gacon <gaconju@gmail.com>

* Update aer_pauli_expectation.py

Use a generator instead of list

* Update qiskit/opflow/expectations/aer_pauli_expectation.py

Co-authored-by: Julien Gacon <gaconju@gmail.com>

* Update releasenotes/notes/add-support-non-hermitian-op-aerpauliexpectation-653d8e16de4eca07.yaml

Co-authored-by: Julien Gacon <gaconju@gmail.com>

* Add a test case for PauliOp

* Change the test cases from using ~StateFn() to using StateFn(, is_measurement=True)

* Fix the formatting

Co-authored-by: Julien Gacon <gaconju@gmail.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Apr 8, 2022
1 parent 10624ae commit d8b4fdc
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 2 deletions.
27 changes: 25 additions & 2 deletions qiskit/opflow/expectations/aer_pauli_expectation.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,36 @@ def convert(self, operator: OperatorBase) -> OperatorBase:
AerSnapshot-based expectation circuits.
Args:
operator: The operator to convert.
operator: The operator to convert. If it contains non-hermitian terms, the
operator is decomposed into hermitian and anti-hermitian parts.
Returns:
The converted operator.
"""

if isinstance(operator, OperatorStateFn) and operator.is_measurement:
return self._replace_pauli_sums(operator.primitive) * operator.coeff
if isinstance(operator.primitive, ListOp):
is_herm = all((op.is_hermitian() for op in operator.primitive.oplist))
else:
is_herm = operator.primitive.is_hermitian()

if not is_herm:
pauli_sum_re = (
self._replace_pauli_sums(
1 / 2 * (operator.primitive + operator.primitive.adjoint()).reduce()
)
* operator.coeff
)
pauli_sum_im = (
self._replace_pauli_sums(
1 / 2j * (operator.primitive - operator.primitive.adjoint()).reduce()
)
* operator.coeff
)
pauli_sum = (pauli_sum_re + 1j * pauli_sum_im).reduce()
else:
pauli_sum = self._replace_pauli_sums(operator.primitive) * operator.coeff
return pauli_sum
elif isinstance(operator, ListOp):
return operator.traverse(self.convert)
else:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
features:
- |
Added the support of non-hermitian operators for :class:`~qiskit.opflow.AerPauliExpectation`.
This for instance enables using Aer's fast snapshot expectation value in algorithms such as
:class:`~qiskit.algorithms.QEOM`.
24 changes: 24 additions & 0 deletions test/python/opflow/test_aer_pauli_expectation.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
Y,
Z,
Zero,
MatrixOp,
)
from qiskit.utils import QuantumInstance

Expand Down Expand Up @@ -120,6 +121,29 @@ def test_pauli_expect_state_vector(self):

np.testing.assert_array_almost_equal(sampled.eval(), [0, 0, 1, -1], decimal=1)

def test_pauli_expect_non_hermitian_matrixop(self):
"""pauli expect state vector with non hermitian operator test"""
states_op = ListOp([One, Zero, Plus, Minus])

op_mat = np.array([[0, 1], [2, 3]])
op = MatrixOp(op_mat)

converted_meas = self.expect.convert(StateFn(op, is_measurement=True) @ states_op)
sampled = self.sampler.convert(converted_meas)

np.testing.assert_array_almost_equal(sampled.eval(), [3, 0, 3, 0], decimal=1)

def test_pauli_expect_non_hermitian_pauliop(self):
"""pauli expect state vector with non hermitian operator test"""
states_op = ListOp([One, Zero, Plus, Minus])

op = 1j * X

converted_meas = self.expect.convert(StateFn(op, is_measurement=True) @ states_op)
sampled = self.sampler.convert(converted_meas)

np.testing.assert_array_almost_equal(sampled.eval(), [0, 0, 1j, -1j], decimal=1)

def test_pauli_expect_op_vector_state_vector(self):
"""pauli expect op vector state vector test"""
paulis_op = ListOp([X, Y, Z, I])
Expand Down

0 comments on commit d8b4fdc

Please sign in to comment.