Skip to content

Commit

Permalink
Fix ComposedOp.to_matrix (#9316)
Browse files Browse the repository at this point in the history
* Fix ComposedOp.to_matrix

* lint

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
Cryoris and mergify[bot] committed Jan 9, 2023
1 parent 4eb3b32 commit 244400a
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 5 deletions.
15 changes: 15 additions & 0 deletions qiskit/opflow/list_ops/composed_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from functools import partial, reduce
from typing import List, Optional, Union, cast, Dict

from numbers import Number
import numpy as np

from qiskit import QuantumCircuit
Expand Down Expand Up @@ -64,6 +65,20 @@ def settings(self) -> Dict:
# """ Tensor product with Self Multiple Times """
# raise NotImplementedError

def to_matrix(self, massive: bool = False) -> np.ndarray:
OperatorBase._check_massive("to_matrix", True, self.num_qubits, massive)

mat = self.coeff * reduce(
np.dot, [np.asarray(op.to_matrix(massive=massive)) for op in self.oplist]
)

# Note: As ComposedOp has a combo function of inner product we can end up here not with
# a matrix (array) but a scalar. In which case we make a single element array of it.
if isinstance(mat, Number):
mat = [mat]

return np.asarray(mat, dtype=complex)

def to_circuit(self) -> QuantumCircuit:
"""Returns the quantum circuit, representing the composed operator.
Expand Down
5 changes: 0 additions & 5 deletions qiskit/opflow/list_ops/list_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
""" ListOp Operator Class """

from functools import reduce
from numbers import Number
from typing import Any, Callable, Dict, Iterator, List, Optional, Set, Sequence, Union, cast

import numpy as np
Expand Down Expand Up @@ -365,10 +364,6 @@ def to_matrix(self, massive: bool = False) -> np.ndarray:
[op.to_matrix(massive=massive) * self.coeff for op in self.oplist], dtype=object
)
)
# Note: As ComposedOp has a combo function of inner product we can end up here not with
# a matrix (array) but a scalar. In which case we make a single element array of it.
if isinstance(mat, Number):
mat = [mat]
return np.asarray(mat, dtype=complex)

def to_spmatrix(self) -> Union[spmatrix, List[spmatrix]]:
Expand Down
7 changes: 7 additions & 0 deletions releasenotes/notes/fix-composedop-08e14db184c637c8.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
fixes:
- |
Fixed two bugs in the :class:`.ComposedOp` where the :meth:`.ComposedOp.to_matrix`
method did not provide the correct results for compositions with :class:`.StateFn`
and for compositions with a global coefficients.
See also `#9283 <https://github.com/Qiskit/qiskit-terra/issues/9283>_`.
24 changes: 24 additions & 0 deletions test/python/opflow/test_op_construction.py
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,30 @@ def test_empty_listops(self):
with self.subTest("eval empty TensoredOp "):
self.assertEqual(TensoredOp([]).eval(), 0.0)

def test_composed_op_to_matrix_with_coeff(self):
"""Test coefficients are properly handled.
Regression test of Qiskit/qiskit-terra#9283.
"""
x = MatrixOp(X.to_matrix())
composed = 0.5 * (x @ X)

expected = 0.5 * np.eye(2)

np.testing.assert_almost_equal(composed.to_matrix(), expected)

def test_composed_op_to_matrix_with_vector(self):
"""Test a matrix-vector composed op can be cast to matrix.
Regression test of Qiskit/qiskit-terra#9283.
"""
x = MatrixOp(X.to_matrix())
composed = x @ Zero

expected = np.array([0, 1])

np.testing.assert_almost_equal(composed.to_matrix(), expected)


class TestOpMethods(QiskitOpflowTestCase):
"""Basic method tests."""
Expand Down

0 comments on commit 244400a

Please sign in to comment.