Repository: Qiskit/qiskit

Issue:
[WIP] Qobj class, schema validation, and update backends to accept qobj
<!--- Provide a general summary of your changes in the Title above -->
This is a replacement for two previous PRs (#144 and #326) that attempted to implement features related to qobj. In light of recent changes to the qiskit core, and recent changes to the qobj spec itslef, we are going to attempt to integrate qobj as an object in the qiskit flow, pass a serialized form of it to backends, and validate them against updated schemas.

@diego-plan9 and @ewinston can you please help port over the files from your previous PRs that we should have here? @atilag can you please ensure the jobprocessor and tests are up to date? I will work on the schemas and parsing of the results received from backends.

## Description
<!--- Describe your changes in detail -->

## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->

## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->

## Screenshots (if appropriate):

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the **CONTRIBUTING** document.
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.


Discussion:
Closing this WIP in order to issue a new one without conflicts and with only the `QObj` implementation.

Resolving patch:
diff --git a/qiskit/opflow/expectations/aer_pauli_expectation.py b/qiskit/opflow/expectations/aer_pauli_expectation.py
--- a/qiskit/opflow/expectations/aer_pauli_expectation.py
+++ b/qiskit/opflow/expectations/aer_pauli_expectation.py
@@ -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:


Test patch:
diff --git a/test/python/opflow/test_aer_pauli_expectation.py b/test/python/opflow/test_aer_pauli_expectation.py
--- a/test/python/opflow/test_aer_pauli_expectation.py
+++ b/test/python/opflow/test_aer_pauli_expectation.py
@@ -38,6 +38,7 @@
     Y,
     Z,
     Zero,
+    MatrixOp,
 )
 from qiskit.utils import QuantumInstance
 
@@ -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])