Skip to content

Commit

Permalink
remove opflow
Browse files Browse the repository at this point in the history
  • Loading branch information
t-imamichi committed Aug 31, 2023
1 parent 9c6a69a commit b06b2f2
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 264 deletions.
2 changes: 1 addition & 1 deletion qiskit_optimization/algorithms/minimum_eigen_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ def solve(self, problem: QuadraticProgram) -> MinimumEigenOptimizationResult:
problem_ = self._convert(problem, self._converters)

# construct operator and offset
operator, offset = problem_.to_ising(opflow=False)
operator, offset = problem_.to_ising()

return self._solve_internal(operator, offset, problem_, problem)

Expand Down
20 changes: 1 addition & 19 deletions qiskit_optimization/algorithms/optimization_algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from typing import Any, Dict, List, Optional, Tuple, Type, Union, cast

import numpy as np
from qiskit.opflow import DictStateFn, StateFn
from qiskit.quantum_info import Statevector
from qiskit.result import QuasiDistribution

Expand Down Expand Up @@ -524,7 +523,7 @@ def _interpret_samples(

@staticmethod
def _eigenvector_to_solutions(
eigenvector: Union[QuasiDistribution, Statevector, dict, np.ndarray, StateFn],
eigenvector: Union[QuasiDistribution, Statevector, dict, np.ndarray],
qubo: QuadraticProgram,
min_probability: float = _MIN_PROBABILITY,
) -> List[SolutionSample]:
Expand All @@ -540,26 +539,9 @@ def _eigenvector_to_solutions(
state as bitstring along with the QUBO evaluated at that bitstring and the
probability of sampling this bitstring from the eigenvector.
Examples:
>>> op = MatrixOp(numpy.array([[1, 1], [1, -1]]) / numpy.sqrt(2))
>>> eigenvectors = {'0': 12, '1': 1}
>>> print(eigenvector_to_solutions(eigenvectors, op))
[('0', 0.7071067811865475, 0.9230769230769231),
('1', -0.7071067811865475, 0.07692307692307693)]
>>> op = MatrixOp(numpy.array([[1, 1], [1, -1]]) / numpy.sqrt(2))
>>> eigenvectors = numpy.array([1, 1] / numpy.sqrt(2), dtype=complex)
>>> print(eigenvector_to_solutions(eigenvectors, op))
[('0', 0.7071067811865475, 0.4999999999999999),
('1', -0.7071067811865475, 0.4999999999999999)]
Raises:
TypeError: If the type of eigenvector is not supported.
"""
if isinstance(eigenvector, DictStateFn):
eigenvector = eigenvector.primitive
elif isinstance(eigenvector, StateFn):
eigenvector = eigenvector.to_matrix()

def generate_solution(bitstr, qubo, probability):
x = np.fromiter(list(bitstr[::-1]), dtype=int)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ def solve(self, problem: QuadraticProgram) -> MinimumEigenOptimizationResult:
pre_solutions = opt_result.samples[:num_pre_solutions]

# construct operator and offset
operator, offset = converted_problem.to_ising(opflow=False)
operator, offset = converted_problem.to_ising()

results: List[MinimumEigenOptimizationResult] = []
for pre_solution in pre_solutions:
Expand Down
22 changes: 3 additions & 19 deletions qiskit_optimization/applications/graph_optimization_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@
"""An abstract class for graph optimization application classes."""

from abc import abstractmethod
from typing import Union, Optional, Dict, List
from typing import Dict, List, Optional, Union

import networkx as nx
import numpy as np

import qiskit_optimization.optionals as _optionals
from .optimization_application import OptimizationApplication

from ..algorithms import OptimizationResult
from ..deprecation import DeprecatedType, deprecate_method
from .optimization_application import OptimizationApplication


class GraphOptimizationApplication(OptimizationApplication):
Expand Down Expand Up @@ -79,19 +79,3 @@ def graph(self) -> nx.Graph:
A graph for a problem
"""
return self._graph

@staticmethod
@deprecate_method(
"0.3.0", DeprecatedType.FUNCTION, "networkx.gnm_random_graph", "in NetworkX, directly"
)
def random_graph(num_nodes: int, num_edges: int, seed: Optional[int] = None) -> nx.Graph:
"""
Args:
num_nodes: The number of nodes in a graph
num_edges: The number of edges in a graph
seed: seed for a random graph
Returns:
A random graph of NetworkX
"""
return nx.gnm_random_graph(num_nodes, num_edges, seed)
5 changes: 0 additions & 5 deletions qiskit_optimization/applications/optimization_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from typing import Dict, Union

import numpy as np
from qiskit.opflow import StateFn
from qiskit.quantum_info import Statevector
from qiskit.result import QuasiDistribution

Expand Down Expand Up @@ -95,10 +94,6 @@ def sample_most_likely(
binary_string = max(state_vector.items(), key=lambda kv: kv[1])[0]
x = np.asarray([int(y) for y in reversed(list(binary_string))])
return x
elif isinstance(state_vector, StateFn):
binary_string = list(state_vector.sample().keys())[0]
x = np.asarray([int(y) for y in reversed(list(binary_string))])
return x
elif isinstance(state_vector, np.ndarray):
n = int(np.log2(state_vector.shape[0]))
k = np.argmax(np.abs(state_vector))
Expand Down
15 changes: 3 additions & 12 deletions qiskit_optimization/problems/quadratic_program.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
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
Expand Down Expand Up @@ -1009,21 +1008,13 @@ def substitute_variables(

return substitute_variables(self, constants, variables)

def to_ising(
self, opflow: Optional[bool] = None
) -> Tuple[Union[OperatorBase, SparsePauliOp], float]:
def to_ising(self) -> Tuple[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.
Expand All @@ -1035,11 +1026,11 @@ def to_ising(
# pylint: disable=cyclic-import
from ..translators.ising import to_ising

return to_ising(self, opflow=opflow)
return to_ising(self)

def from_ising(
self,
qubit_op: Union[OperatorBase, BaseOperator],
qubit_op: BaseOperator,
offset: float = 0.0,
linear: bool = False,
) -> None:
Expand Down
59 changes: 3 additions & 56 deletions qiskit_optimization/translators/ising.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,25 @@
"""Translator between an Ising Hamiltonian and a quadratic program"""

import math
from typing import Optional, Tuple, Union
from warnings import warn
from typing import Tuple

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_optimization.exceptions import QiskitOptimizationError
from qiskit_optimization.problems.quadratic_program import QuadraticProgram


def to_ising(
quad_prog: QuadraticProgram, opflow: Optional[bool] = None
) -> Tuple[Union[PauliSumOp, SparsePauliOp], float]:
def to_ising(quad_prog: QuadraticProgram) -> Tuple[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
Expand All @@ -53,15 +42,6 @@ def to_ising(
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(
Expand Down Expand Up @@ -133,14 +113,11 @@ def to_ising(
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: Union[OperatorBase, BaseOperator],
qubit_op: BaseOperator,
offset: float = 0.0,
linear: bool = False,
) -> QuadraticProgram:
Expand All @@ -150,13 +127,6 @@ 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.
Expand All @@ -172,35 +142,12 @@ def from_ising(
QiskitOptimizationError: if there are Pauli Xs or Ys in any Pauli term
QiskitOptimizationError: if there are more than 2 Pauli Zs in any Pauli term
QiskitOptimizationError: if any Pauli term has an imaginary coefficient
NotImplementedError: If the input operator is a ListOp
"""
# 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 operators have been deprecated in Qiskit Terra 0.24.0 "
"and subsequently removed after that.",
category=DeprecationWarning,
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:
raise NotImplementedError(
"Conversion of a ListOp is not supported, convert each "
"operator in the ListOp separately."
)

quad_prog = QuadraticProgram()
quad_prog.binary_var_list(qubit_op.num_qubits)

Expand Down
2 changes: 0 additions & 2 deletions test/applications/test_optimization_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import numpy as np
from ddt import data, ddt
from qiskit.opflow import StateFn
from qiskit.result import QuasiDistribution

from qiskit_optimization.applications import OptimizationApplication
Expand All @@ -29,7 +28,6 @@ class TestOptimizationApplication(QiskitOptimizationTestCase):

@data(
np.array([0, 0, 1, 0]),
StateFn([0, 0, 1, 0]),
{"10": 0.8, "01": 0.2},
QuasiDistribution({"10": 0.8, "01": 0.2}),
)
Expand Down
8 changes: 4 additions & 4 deletions test/converters/test_converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def test_empty_problem(self):
op = conv.convert(op)
conv = MaximizeToMinimize()
op = conv.convert(op)
_, shift = op.to_ising(opflow=True)
_, shift = op.to_ising()
self.assertEqual(shift, 0.0)

def test_valid_variable_type(self):
Expand All @@ -73,12 +73,12 @@ def test_valid_variable_type(self):
with self.assertRaises(QiskitOptimizationError):
op = QuadraticProgram()
op.integer_var(0, 10, "int_var")
_ = op.to_ising(opflow=True)
_ = op.to_ising()
# Continuous variable
with self.assertRaises(QiskitOptimizationError):
op = QuadraticProgram()
op.continuous_var(0, 10, "continuous_var")
_ = op.to_ising(opflow=True)
_ = op.to_ising()

def test_inequality_binary(self):
"""Test InequalityToEqualityConverter with binary variables"""
Expand Down Expand Up @@ -399,7 +399,7 @@ def test_optimizationproblem_to_ising(self):
op.linear_constraint(linear, Constraint.Sense.EQ, 3, "sum1")
penalize = LinearEqualityToPenalty(penalty=1e5)
op2 = penalize.convert(op)
qubitop, offset = op2.to_ising(opflow=False)
qubitop, offset = op2.to_ising()
self.assertTrue(qubitop.equiv(QUBIT_OP_MAXIMIZE_SAMPLE))
self.assertEqual(offset, OFFSET_MAXIMIZE_SAMPLE)

Expand Down
Loading

0 comments on commit b06b2f2

Please sign in to comment.