Repository: Qiskit/qiskit-optimization
Pull request #467 (2023-01-23 10:11:43)

Update `to_ising` and `from_ising` to support `SparsePauliOp`
<!--
⚠️ If you do not respect this template, your pull request will be closed.
⚠️ Your pull request title should be short detailed and understandable for all.
⚠️ Also, please add it in the CHANGELOG file under Unreleased section.
⚠️ If your pull request fixes an open issue, please link to the issue.

✅ I have added the tests to cover my changes.
✅ I have updated the documentation accordingly.
✅ I have read the CONTRIBUTING document.
-->

### Summary

- Adds `opflow` option to `to_ising` to control the output is `SparsePauliOp` or Opflow's operator.
- Allows `from_ising` to receive `quantum_info`'s operators.

This is part of #433.
The legacy minimum eigensolver of Terra supports only opflow (not `SparsePauliOp`).
We will deprecate the legacy minimum eigensover and opflow when they are deprecated in Terra.

### Details and comments




coveralls: ## Pull Request Test Coverage Report for [Build 3985477364](https://coveralls.io/builds/56186000)

* **17** of **17**   **(100.0%)**  changed or added relevant lines in **2** files are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage increased (+**0.02%**) to **92.083%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/56186000/badge)](https://coveralls.io/builds/56186000) |
| :-- | --: |
| Change from base [Build 3960451014](https://coveralls.io/builds/56109384): |  0.02% |
| Covered Lines: | 4350 |
| Relevant Lines: | 4724 |

---
##### 💛  - [Coveralls](https://coveralls.io)

t-imamichi: I updated the option name from `quantum_info` to `opflow` because I thought it is easier to understand why it will be deprecated when opflow is deprecated in terra.
I also changed the code to display a warning message if `opflow` option is not set explicitly.
t-imamichi: Good catch. But, it is a bit complicated to rename reno. So, I will merge it without renaming it.

Patch:
diff --git a/qiskit_optimization/algorithms/minimum_eigen_optimizer.py b/qiskit_optimization/algorithms/minimum_eigen_optimizer.py
index 3e081b2..d1b9526 100644
--- a/qiskit_optimization/algorithms/minimum_eigen_optimizer.py
+++ b/qiskit_optimization/algorithms/minimum_eigen_optimizer.py
@@ -1,6 +1,6 @@
 # This code is part of Qiskit.
 #
-# (C) Copyright IBM 2020, 2022.
+# (C) Copyright IBM 2020, 2023.
 #
 # This code is licensed under the Apache License, Version 2.0. You may
 # obtain a copy of this license in the LICENSE.txt file in the root directory
@@ -222,7 +222,7 @@ class MinimumEigenOptimizer(OptimizationAlgorithm):
         problem_ = self._convert(problem, self._converters)
 
         # construct operator and offset
-        operator, offset = problem_.to_ising()
+        operator, offset = problem_.to_ising(opflow=True)
 
         return self._solve_internal(operator, offset, problem_, problem)
 
diff --git a/qiskit_optimization/algorithms/warm_start_qaoa_optimizer.py b/qiskit_optimization/algorithms/warm_start_qaoa_optimizer.py
index c244df1..6c41b9d 100644
--- a/qiskit_optimization/algorithms/warm_start_qaoa_optimizer.py
+++ b/qiskit_optimization/algorithms/warm_start_qaoa_optimizer.py
@@ -1,6 +1,6 @@
 # This code is part of Qiskit.
 #
-# (C) Copyright IBM 2021, 2022.
+# (C) Copyright IBM 2021, 2023.
 #
 # This code is licensed under the Apache License, Version 2.0. You may
 # obtain a copy of this license in the LICENSE.txt file in the root directory
@@ -311,7 +311,7 @@ class WarmStartQAOAOptimizer(MinimumEigenOptimizer):
         pre_solutions = opt_result.samples[:num_pre_solutions]
 
         # construct operator and offset
-        operator, offset = converted_problem.to_ising()
+        operator, offset = converted_problem.to_ising(opflow=True)
 
         results: List[MinimumEigenOptimizationResult] = []
         for pre_solution in pre_solutions:
diff --git a/qiskit_optimization/problems/quadratic_program.py b/qiskit_optimization/problems/quadratic_program.py
index 57a98ab..0aff785 100644
--- a/qiskit_optimization/problems/quadratic_program.py
+++ b/qiskit_optimization/problems/quadratic_program.py
@@ -1,6 +1,6 @@
 # This code is part of Qiskit.
 #
-# (C) Copyright IBM 2019, 2022.
+# (C) Copyright IBM 2019, 2023.
 #
 # This code is licensed under the Apache License, Version 2.0. You may
 # obtain a copy of this license in the LICENSE.txt file in the root directory
@@ -23,6 +23,8 @@ import numpy as np
 from docplex.mp.model_reader import ModelReader
 from numpy import ndarray
 from qiskit.opflow import OperatorBase
+from qiskit.quantum_info import SparsePauliOp
+from qiskit.quantum_info.operators.base_operator import BaseOperator
 from scipy.sparse import spmatrix
 
 import qiskit_optimization.optionals as _optionals
@@ -78,7 +80,7 @@ class QuadraticProgram:
         self._objective = QuadraticObjective(self)
 
     def __repr__(self) -> str:
-        from ..translators.prettyprint import expr2str, DEFAULT_TRUNCATE
+        from ..translators.prettyprint import DEFAULT_TRUNCATE, expr2str
 
         objective = expr2str(
             constant=self._objective.constant,
@@ -1007,13 +1009,21 @@ class QuadraticProgram:
 
         return substitute_variables(self, constants, variables)
 
-    def to_ising(self) -> Tuple[OperatorBase, float]:
+    def to_ising(
+        self, opflow: Optional[bool] = None
+    ) -> Tuple[Union[OperatorBase, SparsePauliOp], float]:
         """Return the Ising Hamiltonian of this problem.
 
         Variables are mapped to qubits in the same order, i.e.,
         i-th variable is mapped to i-th qubit.
         See https://github.com/Qiskit/qiskit-terra/issues/1148 for details.
 
+        Args:
+            opflow: The output object is an OpFlow's operator if True.
+                Otherwise, it is ``SparsePauliOp``.
+                Refer to :func:`~qiskit_optimization.translators.to_ising`
+                for the default value.
+
         Returns:
             qubit_op: The qubit operator for the problem
             offset: The constant value in the Ising Hamiltonian.
@@ -1025,11 +1035,11 @@ class QuadraticProgram:
         # pylint: disable=cyclic-import
         from ..translators.ising import to_ising
 
-        return to_ising(self)
+        return to_ising(self, opflow=opflow)
 
     def from_ising(
         self,
-        qubit_op: OperatorBase,
+        qubit_op: Union[OperatorBase, BaseOperator],
         offset: float = 0.0,
         linear: bool = False,
     ) -> None:
diff --git a/qiskit_optimization/translators/ising.py b/qiskit_optimization/translators/ising.py
index ee8768e..52cdf39 100644
--- a/qiskit_optimization/translators/ising.py
+++ b/qiskit_optimization/translators/ising.py
@@ -1,6 +1,6 @@
 # This code is part of Qiskit.
 #
-# (C) Copyright IBM 2019, 2022.
+# (C) Copyright IBM 2019, 2023.
 #
 # This code is licensed under the Apache License, Version 2.0. You may
 # obtain a copy of this license in the LICENSE.txt file in the root directory
@@ -13,25 +13,36 @@
 """Translator between an Ising Hamiltonian and a quadratic program"""
 
 import math
-from typing import Tuple
+from typing import Optional, Tuple, Union
+from warnings import warn
 
 import numpy as np
+from qiskit.opflow import ListOp, OperatorBase, PauliOp, PauliSumOp
+from qiskit.quantum_info import Pauli, SparsePauliOp
+from qiskit.quantum_info.operators.base_operator import BaseOperator
 
-from qiskit.opflow import I, ListOp, OperatorBase, PauliOp, PauliSumOp, SummedOp
-from qiskit.quantum_info import Pauli
 from qiskit_optimization.exceptions import QiskitOptimizationError
 from qiskit_optimization.problems.quadratic_program import QuadraticProgram
 
 
-def to_ising(quad_prog: QuadraticProgram) -> Tuple[OperatorBase, float]:
+def to_ising(
+    quad_prog: QuadraticProgram, opflow: Optional[bool] = None
+) -> Tuple[Union[PauliSumOp, SparsePauliOp], float]:
     """Return the Ising Hamiltonian of this problem.
 
     Variables are mapped to qubits in the same order, i.e.,
     i-th variable is mapped to i-th qubit.
     See https://github.com/Qiskit/qiskit-terra/issues/1148 for details.
 
+    .. note::
+
+        The default value of ``opflow`` argument is currently set ``True``, but it will
+        first be changed to ``False`` and then deprecated in future releases.
+
     Args:
         quad_prog: The problem to be translated.
+        opflow: The output object is a ``PauliSumOp`` operator if True.
+            Otherwise, it is ``SparsePauliOp``. (default: True)
 
     Returns:
         A tuple (qubit_op, offset) comprising the qubit operator for the problem
@@ -42,6 +53,15 @@ def to_ising(quad_prog: QuadraticProgram) -> Tuple[OperatorBase, float]:
             in the problem.
         QiskitOptimizationError: If constraints exist in the problem.
     """
+    if opflow is None:
+        opflow = True
+        warn(
+            "`opflow` argument of `to_ising` is not set explicitly. "
+            "It is currently set True, but the default value will be changed to False. "
+            "We suggest using `SparsePauliOp` instead of Opflow operators.",
+            stacklevel=2,
+        )
+
     # if problem has variables that are not binary, raise an error
     if quad_prog.get_num_vars() > quad_prog.get_num_binary_vars():
         raise QiskitOptimizationError(
@@ -61,10 +81,10 @@ def to_ising(quad_prog: QuadraticProgram) -> Tuple[OperatorBase, float]:
         )
 
     # initialize Hamiltonian.
-    num_nodes = quad_prog.get_num_vars()
+    num_vars = quad_prog.get_num_vars()
     pauli_list = []
     offset = 0.0
-    zero = np.zeros(num_nodes, dtype=bool)
+    zero = np.zeros(num_vars, dtype=bool)
 
     # set a sign corresponding to a maximized or minimized problem.
     # sign == 1 is for minimized problem. sign == -1 is for maximized problem.
@@ -79,7 +99,7 @@ def to_ising(quad_prog: QuadraticProgram) -> Tuple[OperatorBase, float]:
         weight = coef * sense / 2
         z_p[idx] = True
 
-        pauli_list.append(PauliOp(Pauli((z_p, zero)), -weight))
+        pauli_list.append(SparsePauliOp(Pauli((z_p, zero)), -weight))
         offset += weight
 
     # create Pauli terms
@@ -92,36 +112,35 @@ def to_ising(quad_prog: QuadraticProgram) -> Tuple[OperatorBase, float]:
             z_p = zero.copy()
             z_p[i] = True
             z_p[j] = True
-            pauli_list.append(PauliOp(Pauli((z_p, zero)), weight))
+            pauli_list.append(SparsePauliOp(Pauli((z_p, zero)), weight))
 
         z_p = zero.copy()
         z_p[i] = True
-        pauli_list.append(PauliOp(Pauli((z_p, zero)), -weight))
+        pauli_list.append(SparsePauliOp(Pauli((z_p, zero)), -weight))
 
         z_p = zero.copy()
         z_p[j] = True
-        pauli_list.append(PauliOp(Pauli((z_p, zero)), -weight))
+        pauli_list.append(SparsePauliOp(Pauli((z_p, zero)), -weight))
 
         offset += weight
 
-    # Remove paulis whose coefficients are zeros.
-    qubit_op = sum(pauli_list)
-
-    # qubit_op could be the integer 0, in this case return an identity operator of
-    # appropriate size
-    if isinstance(qubit_op, OperatorBase):
-        qubit_op = qubit_op.reduce()
+    if pauli_list:
+        # Remove paulis whose coefficients are zeros.
+        qubit_op = sum(pauli_list).simplify(atol=0)
     else:
         # If there is no variable, we set num_nodes=1 so that qubit_op should be an operator.
         # If num_nodes=0, I^0 = 1 (int).
-        num_nodes = max(1, num_nodes)
-        qubit_op = 0 * I ^ num_nodes
+        num_vars = max(1, num_vars)
+        qubit_op = SparsePauliOp("I" * num_vars, 0)
+
+    if opflow:
+        qubit_op = PauliSumOp(qubit_op)
 
     return qubit_op, offset
 
 
 def from_ising(
-    qubit_op: OperatorBase,
+    qubit_op: Union[OperatorBase, BaseOperator],
     offset: float = 0.0,
     linear: bool = False,
 ) -> QuadraticProgram:
@@ -131,6 +150,13 @@ def from_ising(
     i-th variable is mapped to i-th qubit.
     See https://github.com/Qiskit/qiskit-terra/issues/1148 for details.
 
+    .. note::
+
+        The ``qubit_op`` argument can currently accept Opflow operators (``OperatorBase`` type),
+        but have been superseded by Qiskit Terra quantum_info ``BaseOperators`` such as
+        ``SparsePauliOp``. Opflow operator support will be deprecated in a future release
+        and subsequently removed after that.
+
     Args:
         qubit_op: The qubit operator of the problem.
         offset: The constant term in the Ising Hamiltonian.
@@ -148,9 +174,25 @@ def from_ising(
         QiskitOptimizationError: if any Pauli term has an imaginary coefficient
         NotImplementedError: If the input operator is a ListOp
     """
-    if isinstance(qubit_op, PauliSumOp):
-        qubit_op = qubit_op.to_pauli_op()
+    # quantum_info
+    if isinstance(qubit_op, BaseOperator):
+        if not isinstance(qubit_op, SparsePauliOp):
+            qubit_op = SparsePauliOp(qubit_op)
 
+    # opflow
+    if isinstance(qubit_op, OperatorBase):
+        warn(
+            "The `qubit_op` argument can currently accept Opflow operators (`OperatorBase` type), "
+            "but have been superseded by Qiskit Terra quantum_info `BaseOperators` such as "
+            "`SparsePauliOp`. Opflow operator support will be deprecated in a future release "
+            "and subsequently removed after that.",
+            category=PendingDeprecationWarning,
+            stacklevel=2,
+        )
+    if isinstance(qubit_op, PauliSumOp):
+        qubit_op = qubit_op.primitive * qubit_op.coeff
+    if isinstance(qubit_op, PauliOp):
+        qubit_op = SparsePauliOp(qubit_op.primitive, qubit_op.coeff)
     # No support for ListOp yet, this can be added in future
     # pylint: disable=unidiomatic-typecheck
     if type(qubit_op) == ListOp:
@@ -162,21 +204,15 @@ def from_ising(
     quad_prog = QuadraticProgram()
     quad_prog.binary_var_list(qubit_op.num_qubits)
 
-    if not isinstance(qubit_op, SummedOp):
-        pauli_list = [qubit_op.to_pauli_op()]
-    else:
-        pauli_list = qubit_op.to_pauli_op()
-
     # prepare a matrix of coefficients of Pauli terms
     # `pauli_coeffs_diag` is the diagonal part
     # `pauli_coeffs_triu` is the upper triangular part
     pauli_coeffs_diag = [0.0] * qubit_op.num_qubits
     pauli_coeffs_triu = {}
 
-    for pauli_op in pauli_list:
-        pauli_op = pauli_op.to_pauli_op()
-        pauli = pauli_op.primitive
-        coeff = pauli_op.coeff
+    for pauli_op in qubit_op:
+        pauli = pauli_op.paulis[0]
+        coeff = pauli_op.coeffs[0]
 
         if not math.isclose(coeff.imag, 0.0, abs_tol=1e-10):
             raise QiskitOptimizationError(f"Imaginary coefficient exists: {pauli_op}")
diff --git a/releasenotes/notes/support-sprase-pauli-op-00d29000d48c93ca.yaml b/releasenotes/notes/support-sprase-pauli-op-00d29000d48c93ca.yaml
new file mode 100644
index 0000000..d8aa2d0
--- /dev/null
+++ b/releasenotes/notes/support-sprase-pauli-op-00d29000d48c93ca.yaml
@@ -0,0 +1,14 @@
+---
+features:
+  - |
+    Updated :func:`~.to_ising` to support optionally returning ``qiskit.quantum_info.SparsePauliOp``.
+    This is achieved by a new ``opflow`` argument to :func:`~.to_ising` to control if the output is
+    the Opflow operator, as has been done in the past,  (if ``True``) or ``SparsePauliOp`` (if ``False``).
+    The default value of ``opflow`` argument is currently ``True``, but it will
+    first be changed to ``False``. The parameter will be deprecated and removed in a future release.
+  - |
+    Updated :func:`~.from_ising` to support optionally accepting ``qiskit.quantum_info.SparsePauliOp``.
+    The ``qubit_op`` argument can currently accept the Opflow operators (``OperatorBase`` type),
+    but have been superseded by Qiskit Terra quantum_info ``BaseOperators`` such as
+    ``SparsePauliOp``. The Opflow operator support will be deprecated in a future release
+    and subsequently removed after that.


Test patch:
diff --git a/test/converters/test_converters.py b/test/converters/test_converters.py
index 8086166..d651977 100644
--- a/test/converters/test_converters.py
+++ b/test/converters/test_converters.py
@@ -1,6 +1,6 @@
 # This code is part of Qiskit.
 #
-# (C) Copyright IBM 2020, 2022.
+# (C) Copyright IBM 2020, 2023.
 #
 # This code is licensed under the Apache License, Version 2.0. You may
 # obtain a copy of this license in the LICENSE.txt file in the root directory
@@ -62,7 +62,7 @@ class TestConverters(QiskitOptimizationTestCase):
         op = conv.convert(op)
         conv = MaximizeToMinimize()
         op = conv.convert(op)
-        _, shift = op.to_ising()
+        _, shift = op.to_ising(opflow=True)
         self.assertEqual(shift, 0.0)
 
     def test_valid_variable_type(self):
@@ -71,12 +71,12 @@ class TestConverters(QiskitOptimizationTestCase):
         with self.assertRaises(QiskitOptimizationError):
             op = QuadraticProgram()
             op.integer_var(0, 10, "int_var")
-            _ = op.to_ising()
+            _ = op.to_ising(opflow=True)
         # Continuous variable
         with self.assertRaises(QiskitOptimizationError):
             op = QuadraticProgram()
             op.continuous_var(0, 10, "continuous_var")
-            _ = op.to_ising()
+            _ = op.to_ising(opflow=True)
 
     def test_inequality_binary(self):
         """Test InequalityToEqualityConverter with binary variables"""
@@ -397,7 +397,7 @@ class TestConverters(QiskitOptimizationTestCase):
         op.linear_constraint(linear, Constraint.Sense.EQ, 3, "sum1")
         penalize = LinearEqualityToPenalty(penalty=1e5)
         op2 = penalize.convert(op)
-        qubitop, offset = op2.to_ising()
+        qubitop, offset = op2.to_ising(opflow=True)
         self.assertEqual(qubitop, QUBIT_OP_MAXIMIZE_SAMPLE)
         self.assertEqual(offset, OFFSET_MAXIMIZE_SAMPLE)
 
diff --git a/test/translators/test_ising.py b/test/translators/test_ising.py
index a7e8453..f9652a1 100644
--- a/test/translators/test_ising.py
+++ b/test/translators/test_ising.py
@@ -1,6 +1,6 @@
 # This code is part of Qiskit.
 #
-# (C) Copyright IBM 2021, 2022.
+# (C) Copyright IBM 2021, 2023.
 #
 # This code is licensed under the Apache License, Version 2.0. You may
 # obtain a copy of this license in the LICENSE.txt file in the root directory
@@ -15,17 +15,30 @@
 from test.optimization_test_case import QiskitOptimizationTestCase
 
 import numpy as np
+from ddt import data, ddt
+from qiskit.opflow import I, OperatorBase, PauliSumOp, Z
+from qiskit.quantum_info import Pauli, SparsePauliOp
+from qiskit.quantum_info.operators.base_operator import BaseOperator
 
-from qiskit.opflow import PauliSumOp, I, Z
 from qiskit_optimization.exceptions import QiskitOptimizationError
 from qiskit_optimization.problems import QuadraticProgram
 from qiskit_optimization.translators import from_ising, to_ising
 
 
+@ddt
 class TestIsingTranslator(QiskitOptimizationTestCase):
     """Test from_ising and to_ising"""
 
-    def test_to_ising(self):
+    @staticmethod
+    def op_from_list(lst, opflow):
+        """generate an operator from a list"""
+        if opflow:
+            return PauliSumOp.from_list(lst)
+        else:
+            return SparsePauliOp.from_list(lst)
+
+    @data(True, False)
+    def test_to_ising(self, opflow):
         """test to_ising"""
 
         with self.subTest("minimize"):
@@ -35,8 +48,9 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             q_p.binary_var(name="x")
             q_p.binary_var(name="y")
             q_p.minimize(linear={"x": 1}, quadratic={("x", "y"): 1})
-            op, offset = to_ising(q_p)
-            op_ref = PauliSumOp.from_list([("ZI", -0.25), ("IZ", -0.75), ("ZZ", 0.25)])
+            op, offset = to_ising(q_p, opflow)
+            self.assertIsInstance(op, OperatorBase if opflow else BaseOperator)
+            op_ref = SparsePauliOp.from_list([("ZI", -0.25), ("IZ", -0.75), ("ZZ", 0.25)])
             np.testing.assert_allclose(op.to_matrix(), op_ref.to_matrix())
             self.assertAlmostEqual(offset, 0.75)
 
@@ -47,12 +61,14 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             q_p.binary_var(name="x")
             q_p.binary_var(name="y")
             q_p.maximize(linear={"x": 1}, quadratic={("x", "y"): 1})
-            op, offset = to_ising(q_p)
-            op_ref = PauliSumOp.from_list([("ZI", 0.25), ("IZ", 0.75), ("ZZ", -0.25)])
+            op, offset = to_ising(q_p, opflow)
+            self.assertIsInstance(op, OperatorBase if opflow else BaseOperator)
+            op_ref = SparsePauliOp.from_list([("ZI", 0.25), ("IZ", 0.75), ("ZZ", -0.25)])
             np.testing.assert_allclose(op.to_matrix(), op_ref.to_matrix())
             self.assertAlmostEqual(offset, -0.75)
 
-    def test_to_ising2(self):
+    @data(True, False)
+    def test_to_ising2(self, opflow):
         """test to_ising 2"""
 
         with self.subTest("minimize"):
@@ -62,8 +78,9 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             q_p.binary_var(name="x")
             q_p.binary_var(name="y")
             q_p.minimize(constant=1, linear={"x": -2, "y": -2}, quadratic={("x", "y"): 4})
-            op, offset = to_ising(q_p)
-            op_ref = PauliSumOp.from_list([("ZZ", 1.0)])
+            op, offset = to_ising(q_p, opflow)
+            self.assertIsInstance(op, OperatorBase if opflow else BaseOperator)
+            op_ref = SparsePauliOp.from_list([("ZZ", 1.0)])
             np.testing.assert_allclose(op.to_matrix(), op_ref.to_matrix())
             self.assertAlmostEqual(offset, 0.0)
 
@@ -74,16 +91,18 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             q_p.binary_var(name="x")
             q_p.binary_var(name="y")
             q_p.maximize(constant=1, linear={"x": -2, "y": -2}, quadratic={("x", "y"): 4})
-            op, offset = to_ising(q_p)
-            op_ref = PauliSumOp.from_list([("ZZ", -1.0)])
+            op, offset = to_ising(q_p, opflow)
+            self.assertIsInstance(op, OperatorBase if opflow else BaseOperator)
+            op_ref = SparsePauliOp.from_list([("ZZ", -1.0)])
             np.testing.assert_allclose(op.to_matrix(), op_ref.to_matrix())
             self.assertAlmostEqual(offset, 0.0)
 
-    def test_from_ising(self):
+    @data(True, False)
+    def test_from_ising(self, opflow):
         """test from_ising"""
         # minimize: x + x * y
         # subject to: x, y \in {0, 1}
-        op = PauliSumOp.from_list([("ZI", -0.25), ("IZ", -0.75), ("ZZ", 0.25)])
+        op = self.op_from_list([("ZI", -0.25), ("IZ", -0.75), ("ZZ", 0.25)], opflow)
         with self.subTest("linear: True"):
             q_p = from_ising(op, 0.75, linear=True)
             self.assertEqual(q_p.get_num_vars(), op.num_qubits)
@@ -102,11 +121,12 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             np.testing.assert_allclose(q_p.objective.linear.to_array(), [0, 0])
             np.testing.assert_allclose(q_p.objective.quadratic.to_array(), [[1, 1], [0, 0]])
 
-    def test_from_ising2(self):
+    @data(True, False)
+    def test_from_ising2(self, opflow):
         """test from_ising 2"""
         # minimize: 1 - 2 * x1 - 2 * x2 + 4 * x1 * x2
         # subject to: x, y \in {0, 1}
-        op = PauliSumOp.from_list([("ZZ", 1)])
+        op = self.op_from_list([("ZZ", 1)], opflow)
         with self.subTest("linear: True"):
             q_p = from_ising(op, 0, linear=True)
             self.assertEqual(q_p.get_num_vars(), op.num_qubits)
@@ -125,28 +145,33 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             np.testing.assert_allclose(q_p.objective.linear.to_array(), [0, 0])
             np.testing.assert_allclose(q_p.objective.quadratic.to_array(), [[-2, 4], [0, -2]])
 
-    def test_from_ising_pauli_with_invalid_paulis(self):
+    @data(True, False)
+    def test_from_ising_pauli_with_invalid_paulis(self, opflow):
         """test from_ising with invalid Pauli terms"""
         with self.assertRaises(QiskitOptimizationError):
-            op = PauliSumOp.from_list([("IX", 1)])
+            op = self.op_from_list([("IX", 1)], opflow)
             _ = from_ising(op, 0)
 
         with self.assertRaises(QiskitOptimizationError):
-            op = PauliSumOp.from_list([("IY", 1)])
+            op = self.op_from_list([("IY", 1)], opflow)
             _ = from_ising(op, 0)
 
         with self.assertRaises(QiskitOptimizationError):
-            op = PauliSumOp.from_list([("ZZZ", 1)])
+            op = self.op_from_list([("ZZZ", 1)], opflow)
             _ = from_ising(op, 0)
 
         with self.assertRaises(QiskitOptimizationError):
-            op = PauliSumOp.from_list([("IZ", 1j)])
+            op = self.op_from_list([("IZ", 1j)], opflow)
             _ = from_ising(op, 0)
 
-    def test_pauli_I_Z(self):
+    @data(True, False)
+    def test_pauli_I_Z(self, opflow):
         """test from_ising and to_ising with Pauli I and Z"""
         with self.subTest("0 * I, linear=False"):
-            q_p = from_ising(0 * I, linear=False)
+            if opflow:
+                q_p = from_ising(SparsePauliOp("I", 0), linear=False)
+            else:
+                q_p = from_ising(0 * I, linear=False)
             self.assertEqual(q_p.get_num_vars(), 1)
             self.assertEqual(q_p.get_num_linear_constraints(), 0)
             self.assertEqual(q_p.get_num_quadratic_constraints(), 0)
@@ -154,12 +179,15 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             np.testing.assert_allclose(q_p.objective.linear.to_array(), [0])
             np.testing.assert_allclose(q_p.objective.quadratic.to_array(), [[0]])
 
-            op, offset = to_ising(q_p)
+            op, offset = to_ising(q_p, opflow=True)
             np.testing.assert_allclose(op.to_matrix(), np.zeros((2, 2)))
             self.assertAlmostEqual(offset, 0)
 
         with self.subTest("0 * I, linear=True"):
-            q_p = from_ising(0 * I, linear=True)
+            if opflow:
+                q_p = from_ising(SparsePauliOp("I", 0), linear=True)
+            else:
+                q_p = from_ising(0 * I, linear=True)
             self.assertEqual(q_p.get_num_vars(), 1)
             self.assertEqual(q_p.get_num_linear_constraints(), 0)
             self.assertEqual(q_p.get_num_quadratic_constraints(), 0)
@@ -167,12 +195,15 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             np.testing.assert_allclose(q_p.objective.linear.to_array(), [0])
             np.testing.assert_allclose(q_p.objective.quadratic.to_array(), [[0]])
 
-            op, offset = to_ising(q_p)
+            op, offset = to_ising(q_p, opflow=True)
             np.testing.assert_allclose(op.to_matrix(), np.zeros((2, 2)))
             self.assertAlmostEqual(offset, 0)
 
         with self.subTest("2 * I, linear=False"):
-            q_p = from_ising(2 * I, linear=False)
+            if opflow:
+                q_p = from_ising(SparsePauliOp("I", 2), linear=False)
+            else:
+                q_p = from_ising(2 * I, linear=False)
             self.assertEqual(q_p.get_num_vars(), 1)
             self.assertEqual(q_p.get_num_linear_constraints(), 0)
             self.assertEqual(q_p.get_num_quadratic_constraints(), 0)
@@ -180,12 +211,15 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             np.testing.assert_allclose(q_p.objective.linear.to_array(), [0])
             np.testing.assert_allclose(q_p.objective.quadratic.to_array(), [[0]])
 
-            op, offset = to_ising(q_p)
+            op, offset = to_ising(q_p, opflow=True)
             np.testing.assert_allclose(op.to_matrix(), np.zeros((2, 2)))
             self.assertAlmostEqual(offset, 2)
 
         with self.subTest("2 * I, linear=True"):
-            q_p = from_ising(2 * I, linear=True)
+            if opflow:
+                q_p = from_ising(SparsePauliOp("I", 2), linear=True)
+            else:
+                q_p = from_ising(2 * I, linear=True)
             self.assertEqual(q_p.get_num_vars(), 1)
             self.assertEqual(q_p.get_num_linear_constraints(), 0)
             self.assertEqual(q_p.get_num_quadratic_constraints(), 0)
@@ -193,12 +227,15 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             np.testing.assert_allclose(q_p.objective.linear.to_array(), [0])
             np.testing.assert_allclose(q_p.objective.quadratic.to_array(), [[0]])
 
-            op, offset = to_ising(q_p)
+            op, offset = to_ising(q_p, opflow=True)
             np.testing.assert_allclose(op.to_matrix(), np.zeros((2, 2)))
             self.assertAlmostEqual(offset, 2)
 
         with self.subTest("Z, linear=False"):
-            q_p = from_ising(Z)
+            if opflow:
+                q_p = from_ising(Pauli("Z"), linear=False)
+            else:
+                q_p = from_ising(Z, linear=False)
             self.assertEqual(q_p.get_num_vars(), 1)
             self.assertEqual(q_p.get_num_linear_constraints(), 0)
             self.assertEqual(q_p.get_num_quadratic_constraints(), 0)
@@ -206,12 +243,15 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             np.testing.assert_allclose(q_p.objective.linear.to_array(), [0])
             np.testing.assert_allclose(q_p.objective.quadratic.to_array(), [[-2]])
 
-            op, offset = to_ising(q_p)
+            op, offset = to_ising(q_p, opflow=True)
             np.testing.assert_allclose(op.to_matrix(), Z.to_matrix())
             self.assertAlmostEqual(offset, 0)
 
         with self.subTest("Z, linear=True"):
-            q_p = from_ising(Z, linear=True)
+            if opflow:
+                q_p = from_ising(Pauli("Z"), linear=True)
+            else:
+                q_p = from_ising(Z, linear=True)
             self.assertEqual(q_p.get_num_vars(), 1)
             self.assertEqual(q_p.get_num_linear_constraints(), 0)
             self.assertEqual(q_p.get_num_quadratic_constraints(), 0)
@@ -219,12 +259,15 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             np.testing.assert_allclose(q_p.objective.linear.to_array(), [-2])
             np.testing.assert_allclose(q_p.objective.quadratic.to_array(), [[0]])
 
-            op, offset = to_ising(q_p)
+            op, offset = to_ising(q_p, opflow=True)
             np.testing.assert_allclose(op.to_matrix(), Z.to_matrix())
             self.assertAlmostEqual(offset, 0)
 
         with self.subTest("3 * II, linear=False"):
-            q_p = from_ising(3 * I ^ I)
+            if opflow:
+                q_p = from_ising(SparsePauliOp("II", 3), linear=False)
+            else:
+                q_p = from_ising(3 * I ^ I, linear=False)
             self.assertEqual(q_p.get_num_vars(), 2)
             self.assertEqual(q_p.get_num_linear_constraints(), 0)
             self.assertEqual(q_p.get_num_quadratic_constraints(), 0)
@@ -232,12 +275,15 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             np.testing.assert_allclose(q_p.objective.linear.to_array(), [0, 0])
             np.testing.assert_allclose(q_p.objective.quadratic.to_array(), [[0, 0], [0, 0]])
 
-            op, offset = to_ising(q_p)
+            op, offset = to_ising(q_p, opflow=True)
             np.testing.assert_allclose(op.to_matrix(), np.zeros((4, 4)))
             self.assertAlmostEqual(offset, 3)
 
         with self.subTest("3 * II, linear=True"):
-            q_p = from_ising(3 * I ^ I)
+            if opflow:
+                q_p = from_ising(SparsePauliOp("II", 3), linear=True)
+            else:
+                q_p = from_ising(3 * I ^ I, linear=True)
             self.assertEqual(q_p.get_num_vars(), 2)
             self.assertEqual(q_p.get_num_linear_constraints(), 0)
             self.assertEqual(q_p.get_num_quadratic_constraints(), 0)
@@ -245,12 +291,15 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             np.testing.assert_allclose(q_p.objective.linear.to_array(), [0, 0])
             np.testing.assert_allclose(q_p.objective.quadratic.to_array(), [[0, 0], [0, 0]])
 
-            op, offset = to_ising(q_p)
+            op, offset = to_ising(q_p, opflow=True)
             np.testing.assert_allclose(op.to_matrix(), np.zeros((4, 4)))
             self.assertAlmostEqual(offset, 3)
 
         with self.subTest("IZ, linear=False"):
-            q_p = from_ising(I ^ Z)
+            if opflow:
+                q_p = from_ising(Pauli("IZ"), linear=False)
+            else:
+                q_p = from_ising(I ^ Z, linear=False)
             self.assertEqual(q_p.get_num_vars(), 2)
             self.assertEqual(q_p.get_num_linear_constraints(), 0)
             self.assertEqual(q_p.get_num_quadratic_constraints(), 0)
@@ -258,12 +307,15 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             np.testing.assert_allclose(q_p.objective.linear.to_array(), [0, 0])
             np.testing.assert_allclose(q_p.objective.quadratic.to_array(), [[-2, 0], [0, 0]])
 
-            op, offset = to_ising(q_p)
+            op, offset = to_ising(q_p, opflow=True)
             np.testing.assert_allclose(op.to_matrix(), (I ^ Z).to_matrix())
             self.assertAlmostEqual(offset, 0)
 
         with self.subTest("IZ, linear=True"):
-            q_p = from_ising(I ^ Z, linear=True)
+            if opflow:
+                q_p = from_ising(Pauli("IZ"), linear=True)
+            else:
+                q_p = from_ising(I ^ Z, linear=True)
             self.assertEqual(q_p.get_num_vars(), 2)
             self.assertEqual(q_p.get_num_linear_constraints(), 0)
             self.assertEqual(q_p.get_num_quadratic_constraints(), 0)
@@ -271,28 +323,39 @@ class TestIsingTranslator(QiskitOptimizationTestCase):
             np.testing.assert_allclose(q_p.objective.linear.to_array(), [-2, 0])
             np.testing.assert_allclose(q_p.objective.quadratic.to_array(), [[0, 0], [0, 0]])
 
-            op, offset = to_ising(q_p)
+            op, offset = to_ising(q_p, opflow=True)
             np.testing.assert_allclose(op.to_matrix(), (I ^ Z).to_matrix())
             self.assertAlmostEqual(offset, 0)
 
-    def test_to_ising_wo_variable(self):
+    @data(True, False)
+    def test_to_ising_wo_variable(self, opflow):
         """test to_ising with problems without variables"""
         with self.subTest("empty problem"):
             q_p = QuadraticProgram()
-            op, offset = to_ising(q_p)
+            op, offset = to_ising(q_p, opflow)
             np.testing.assert_allclose(op.to_matrix(), np.zeros((2, 2)))
             self.assertAlmostEqual(offset, 0)
 
         with self.subTest("min 3"):
             q_p = QuadraticProgram()
             q_p.minimize(constant=3)
-            op, offset = to_ising(q_p)
+            op, offset = to_ising(q_p, opflow)
             np.testing.assert_allclose(op.to_matrix(), np.zeros((2, 2)))
             self.assertAlmostEqual(offset, 3)
 
         with self.subTest("max -1"):
             q_p = QuadraticProgram()
             q_p.maximize(constant=-1)
-            op, offset = to_ising(q_p)
+            op, offset = to_ising(q_p, opflow)
             np.testing.assert_allclose(op.to_matrix(), np.zeros((2, 2)))
             self.assertAlmostEqual(offset, 1)
+
+    def test_warning(self):
+        """Test warning message"""
+        q_p = QuadraticProgram()
+        with self.assertWarns(UserWarning):
+            _ = to_ising(q_p)
+
+        op = PauliSumOp.from_list([("Z", 1)])
+        with self.assertWarns(PendingDeprecationWarning):
+            _ = from_ising(op)