Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ComposedOp.to_matrix #9316

Merged
merged 6 commits into from
Jan 9, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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