Skip to content
This repository has been archived by the owner on Dec 7, 2021. It is now read-only.

Operator.compose should allow indices #1144

Merged
merged 126 commits into from
Sep 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
126 commits
Select commit Hold shift + click to select a range
246dbe9
Merge pull request #1 from Qiskit/master
molar-volume Jul 4, 2020
b01af1c
Merge branch 'master' of github.com:Qiskit/qiskit-aqua
molar-volume Jul 15, 2020
e7666d7
Merge branch 'master' of github.com:Qiskit/qiskit-aqua
molar-volume Jul 18, 2020
0235fed
Merge github.com:Qiskit/qiskit-aqua
molar-volume Jul 25, 2020
9162eec
1) modified PrimitiveOp._check_zero_for_composition_and_expand, so th…
molar-volume Jul 27, 2020
5ff3d65
CircuitStateFn.tensor did not set is_measurement parameter (hence alw…
molar-volume Jul 27, 2020
95ad488
Added test for expand method on StateFn subclasses
molar-volume Jul 27, 2020
cb6a709
fixed linting
molar-volume Jul 27, 2020
f7ef909
fixed linting and mypy
molar-volume Jul 27, 2020
804054e
fixed unexpected indentation
molar-volume Jul 27, 2020
0c831f9
1) PauliOp.permute implemented
molar-volume Jul 29, 2020
e105a32
Merge branch 'master' into issue_1088
manoelmarques Jul 29, 2020
a4e7114
1) permute implemented for MatrixOp
molar-volume Aug 3, 2020
3d5548a
Merge branch 'issue_1088' of https://github.com/molar-volume/qiskit-a…
molar-volume Aug 3, 2020
8f83835
fix linting
molar-volume Aug 3, 2020
655f209
identity renamed to identity_operator in OperatorBase
molar-volume Aug 3, 2020
5b6f01e
OperatorBase.expand renamed to expand_to_dim
molar-volume Aug 3, 2020
75ab5fe
Merge branch 'master' into issue_1088
molar-volume Aug 3, 2020
34dddd2
expand_to_dim overridden for PrimitiveOps
molar-volume Aug 3, 2020
be04488
Merge branch 'issue_1088' of https://github.com/molar-volume/qiskit-a…
molar-volume Aug 3, 2020
3915c6e
1) expand_to_dim implemented for each subclass of OperatorBase
molar-volume Aug 4, 2020
47a48e6
fixed linting
molar-volume Aug 4, 2020
e197f06
OperatorStateFn permute implemented
molar-volume Aug 4, 2020
bcebc5c
1) permute for TensoredOp
molar-volume Aug 4, 2020
07eb035
1) TensoredOp.permute moved to ListOp.permute
molar-volume Aug 4, 2020
b006214
unexpected indentation fixed.
molar-volume Aug 4, 2020
a93d26a
permute defined abstract in OperatorBase
molar-volume Aug 4, 2020
b11e478
composition of PrimitiveOp with ComposedOp prepends the ComposedOp.op…
molar-volume Aug 4, 2020
c98ef81
Revert "composition of PrimitiveOp with ComposedOp prepends the Compo…
molar-volume Aug 4, 2020
253d707
fixed syntax in ListOp.permute
molar-volume Aug 4, 2020
04b660c
Merge github.com:Qiskit/qiskit-aqua
molar-volume Aug 4, 2020
3d735b9
1) compose in MatrixOp, PauliOp and CircuitOp enhanced, to be consist…
molar-volume Aug 4, 2020
a83f6ef
DRY applied
molar-volume Aug 4, 2020
bc585fb
merge branch issue_1165 into issue_1088
molar-volume Aug 5, 2020
33e7e91
Test if ListOp.permute is consistent with PrimitiveOp permute methods
molar-volume Aug 5, 2020
984e23f
test for expand_to_dim on ListOps
molar-volume Aug 5, 2020
6088384
1) changed signature of compose to allow permutations on operators
molar-volume Aug 5, 2020
3e646bd
refactoring
molar-volume Aug 5, 2020
8e34851
unit test for compose with indices
molar-volume Aug 5, 2020
c6e3718
refactoring and fixed linting
molar-volume Aug 5, 2020
f757fb8
1) StateFn.compose expands the shorter operators with identity
molar-volume Aug 5, 2020
9fe3b38
Merge branch 'master' into issue_1088
molar-volume Aug 5, 2020
f6ac702
fixed unexpected indentation
molar-volume Aug 5, 2020
62bec0c
Merge branch 'issue_1088' of https://github.com/molar-volume/qiskit-a…
molar-volume Aug 5, 2020
59dd5fc
doc html fix
molar-volume Aug 5, 2020
f269e5f
fix unexpected indentation
molar-volume Aug 5, 2020
691ab94
1) expand_to_dim renamed to expand_with_identities (expand_to_dim was…
molar-volume Aug 6, 2020
aed6940
fixed line too long
molar-volume Aug 6, 2020
1dbff1f
permute implemented for DictStateFn
molar-volume Aug 6, 2020
c599147
1) VectorStateFn.to_dict_fn and DictStateFn.to_vector_state_fn implem…
molar-volume Aug 6, 2020
7ee9ee5
fixed linting
molar-volume Aug 6, 2020
dfd7908
Merge branch 'master' into issue_1088
molar-volume Aug 6, 2020
0e03efe
cyclic import solved
molar-volume Aug 6, 2020
1ef1b30
fixed linting
molar-volume Aug 7, 2020
d856698
1) more unit tests for compose of StateFn with indices
molar-volume Aug 7, 2020
2b29251
Merge branch 'master' into issue_1088
molar-volume Aug 7, 2020
5476fcf
Merge branch 'master' into issue_1088
molar-volume Aug 7, 2020
3098688
Update qiskit/aqua/operators/evolutions/evolved_op.py
molar-volume Aug 10, 2020
133d4ef
Update qiskit/aqua/operators/list_ops/list_op.py
molar-volume Aug 10, 2020
fb9685c
Update qiskit/aqua/operators/list_ops/list_op.py
molar-volume Aug 10, 2020
d973e67
Update qiskit/aqua/operators/primitive_ops/pauli_op.py
molar-volume Aug 10, 2020
8b6265c
Update qiskit/aqua/operators/primitive_ops/matrix_op.py
molar-volume Aug 10, 2020
26ab164
implemented custom function to decompose permutations into transposit…
molar-volume Aug 10, 2020
7199ca9
Merge branch 'issue_1088' of https://github.com/molar-volume/qiskit-a…
molar-volume Aug 10, 2020
f0468d1
Merge branch 'master' into issue_1088
molar-volume Aug 11, 2020
d6950dc
explaining comment for CircuitStateFn.expand_with_identity
molar-volume Aug 11, 2020
f341e82
fix linting
molar-volume Aug 11, 2020
05c6fce
expand_with_identity made private and renamed to _expand_dim (expand_…
molar-volume Aug 11, 2020
bf82719
1) Compose method has only one set of permutation indices (for other …
molar-volume Aug 11, 2020
dabf7c6
1) modified test_op_construction because of changes in compose signature
molar-volume Aug 11, 2020
3a0f1df
Merge branch 'master' into issue_1088
molar-volume Aug 11, 2020
0d2cf1a
Merge branch 'issue_1088' of https://github.com/molar-volume/qiskit-a…
molar-volume Aug 11, 2020
1342735
_check_zero_for_composition_and_expand renamed to _expand_shorter_ope…
molar-volume Aug 11, 2020
998bf03
VectorStateFn.permute reimplemented for better performance
molar-volume Aug 11, 2020
b7629f4
Merge branch 'master' into issue_1088
molar-volume Aug 11, 2020
2301114
type hint added for front parameter of compose
molar-volume Aug 12, 2020
d7a5879
Merge branch 'master' into issue_1088
molar-volume Aug 12, 2020
793f56d
fixed linting after merge
molar-volume Aug 12, 2020
709b0a5
for arithmetic.transpositions, typehint for argument and docstring de…
molar-volume Aug 12, 2020
ee2d597
removed unnecessary apostrophes from return types
molar-volume Aug 12, 2020
6fb010c
fix mypy
molar-volume Aug 13, 2020
3591f57
Merge branch 'master' into issue_1088
molar-volume Aug 13, 2020
3905c47
fixed mypy
molar-volume Aug 13, 2020
cb3a31e
Merge branch 'issue_1088' of https://github.com/molar-volume/qiskit-a…
molar-volume Aug 13, 2020
8c82a1f
Merge branch 'master' into issue_1088
molar-volume Aug 13, 2020
90679bb
removed unused import
molar-volume Aug 13, 2020
88b782a
Update qiskit/aqua/operators/evolutions/evolved_op.py
molar-volume Aug 19, 2020
780099f
Update qiskit/aqua/operators/list_ops/composed_op.py
molar-volume Aug 19, 2020
8ad7ed3
Update qiskit/aqua/operators/state_fns/state_fn.py
molar-volume Aug 19, 2020
6b7ec70
Update qiskit/aqua/operators/state_fns/state_fn.py
molar-volume Aug 19, 2020
f47bf4a
Update qiskit/aqua/operators/state_fns/vector_state_fn.py
molar-volume Aug 19, 2020
f302b03
Update qiskit/aqua/operators/list_ops/list_op.py
molar-volume Aug 19, 2020
da22d23
Update qiskit/aqua/operators/list_ops/tensored_op.py
molar-volume Aug 19, 2020
a6beffa
Update qiskit/aqua/operators/operator_base.py
molar-volume Aug 19, 2020
3504657
Update qiskit/aqua/operators/operator_base.py
molar-volume Aug 19, 2020
667fe45
Update qiskit/aqua/operators/operator_base.py
molar-volume Aug 19, 2020
794ea4d
Update qiskit/aqua/operators/primitive_ops/circuit_op.py
molar-volume Aug 19, 2020
628b500
Update qiskit/aqua/operators/primitive_ops/matrix_op.py
molar-volume Aug 19, 2020
c488187
Update qiskit/aqua/operators/primitive_ops/matrix_op.py
molar-volume Aug 19, 2020
b3560b1
style fixed
molar-volume Aug 19, 2020
998da12
Merge branch 'issue_1088' of https://github.com/molar-volume/qiskit-a…
molar-volume Aug 19, 2020
e156914
fixed styles
molar-volume Aug 20, 2020
e3d5636
Merge branch 'master' into issue_1088
molar-volume Aug 20, 2020
ad21d72
fixed import after merge
molar-volume Aug 20, 2020
f70f48f
Update qiskit/aqua/operators/state_fns/dict_state_fn.py
molar-volume Aug 20, 2020
6ba866b
removed duplicate method to_vector_state_fn (to_matrix_op was already…
molar-volume Aug 20, 2020
3425c90
Merge branch 'issue_1088' of https://github.com/molar-volume/qiskit-a…
molar-volume Aug 20, 2020
d911933
new_self instead of self in EvolvedOp
molar-volume Aug 20, 2020
9def93c
test_op_construction refactored
molar-volume Aug 20, 2020
8691785
Merge branch 'master' into issue_1088
manoelmarques Aug 21, 2020
31941f0
Merge branch 'master' into issue_1088
woodsp-ibm Aug 21, 2020
bb826d5
fix after merge
molar-volume Aug 22, 2020
5edc535
Merge branch 'master' into issue_1088
molar-volume Sep 3, 2020
ac5f122
Update qiskit/aqua/operators/operator_base.py
molar-volume Sep 3, 2020
ebdba41
Typo: List -> Listt
Cryoris Sep 3, 2020
ff02916
Merge branch 'master' into issue_1088
woodsp-ibm Sep 3, 2020
59c5c35
Merge branch 'master' into issue_1088
molar-volume Sep 17, 2020
e87add5
raise AquaError in ListOp.permute, if ListOp contains operators with …
molar-volume Sep 17, 2020
8cb9ccf
self renamed to new_self in compose methods
molar-volume Sep 19, 2020
341f489
fix linting
molar-volume Sep 19, 2020
9faa2cb
unnecessary comment removed
molar-volume Sep 20, 2020
3a1d0ef
Merge branch 'master' into issue_1088
molar-volume Sep 20, 2020
46a49cb
remove type ignore
molar-volume Sep 20, 2020
8e726d0
avoid unnecessary permutation
molar-volume Sep 20, 2020
213f8f4
Merge branch 'master' into issue_1088
molar-volume Sep 21, 2020
3022c37
Merge branch 'master' into issue_1088
molar-volume Sep 21, 2020
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
18 changes: 14 additions & 4 deletions qiskit/aqua/operators/evolutions/evolved_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,23 @@ def tensor(self, other: OperatorBase) -> OperatorBase:

return TensoredOp([self, other])

def compose(self, other: OperatorBase) -> OperatorBase:
other = self._check_zero_for_composition_and_expand(other)
def _expand_dim(self, num_qubits: int) -> OperatorBase:
from qiskit.aqua.operators import I
return self.tensor(I ^ num_qubits)

def permute(self, permutation: List[int]) -> OperatorBase:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add docstrings to these methods (also all the compose methods 🙂 )?

Copy link
Contributor Author

@molar-volume molar-volume Aug 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, the docstrings for compose and permute are provided in OperatorBase,
and e.g. MatrixOp inherits the docstring https://qiskit.org/documentation/stubs/qiskit.aqua.operators.primitive_ops.MatrixOp.compose.html#qiskit.aqua.operators.primitive_ops.MatrixOp.compose

I am not sure if it is necessary to override docstrings for all compose methods (and for permute as well), since it was not done so far.

return EvolvedOp(self.primitive.permute(permutation), coeff=self.coeff) # type: ignore

def compose(self, other: OperatorBase,
permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase:

new_self, other = self._expand_shorter_operator_and_permute(other, permutation)
if front:
return other.compose(new_self)
if isinstance(other, ComposedOp):
return ComposedOp([self] + other.oplist) # type: ignore
return ComposedOp([new_self] + other.oplist)

return ComposedOp([self, other])
return ComposedOp([new_self, other])

def __str__(self) -> str:
prim_str = str(self.primitive)
Expand Down
23 changes: 15 additions & 8 deletions qiskit/aqua/operators/list_ops/composed_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

""" ComposedOp Class """

from typing import List, Union, cast
from typing import List, Union, cast, Optional
from functools import reduce, partial
import numpy as np

Expand Down Expand Up @@ -82,24 +82,31 @@ def to_circuit(self) -> QuantumCircuit:
def adjoint(self) -> OperatorBase:
return ComposedOp([op.adjoint() for op in reversed(self.oplist)], coeff=self.coeff)

def compose(self, other: OperatorBase) -> OperatorBase:
def compose(self, other: OperatorBase,
permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase:

new_self, other = self._expand_shorter_operator_and_permute(other, permutation)
new_self = cast(ComposedOp, new_self)

if front:
return other.compose(new_self)
# Try composing with last element in list
if isinstance(other, ComposedOp):
return ComposedOp(self.oplist + other.oplist, coeff=self.coeff * other.coeff)
return ComposedOp(new_self.oplist + other.oplist, coeff=new_self.coeff * other.coeff)

# Try composing with last element of oplist. We only try
# this if that last element isn't itself an
# ComposedOp, so we can tell whether composing the
# two elements directly worked. If it doesn't,
# continue to the final return statement below, appending other to the oplist.
if not isinstance(self.oplist[-1], ComposedOp):
comp_with_last = self.oplist[-1].compose(other)
if not isinstance(new_self.oplist[-1], ComposedOp):
comp_with_last = new_self.oplist[-1].compose(other)
# Attempt successful
if not isinstance(comp_with_last, ComposedOp):
new_oplist = self.oplist[0:-1] + [comp_with_last]
return ComposedOp(new_oplist, coeff=self.coeff)
new_oplist = new_self.oplist[0:-1] + [comp_with_last]
return ComposedOp(new_oplist, coeff=new_self.coeff)

return ComposedOp(self.oplist + [other], coeff=self.coeff)
return ComposedOp(new_self.oplist + [other], coeff=new_self.coeff)

def eval(self,
front: Union[str, dict, np.ndarray,
Expand Down
65 changes: 59 additions & 6 deletions qiskit/aqua/operators/list_ops/list_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,18 @@
""" ListOp Operator Class """

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

import numpy as np
from scipy.sparse import spmatrix

from qiskit.circuit import ParameterExpression
from qiskit.circuit import QuantumCircuit, ParameterExpression

from ..legacy.base_operator import LegacyBaseOperator
from ..operator_base import OperatorBase
from ... import AquaError
from ...utils import arithmetic


class ListOp(OperatorBase):
Expand Down Expand Up @@ -212,11 +215,61 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]:
from .tensored_op import TensoredOp
return TensoredOp([self] * other)

def compose(self, other: OperatorBase) -> OperatorBase:
def _expand_dim(self, num_qubits: int) -> 'ListOp':
return ListOp([op._expand_dim(num_qubits + self.num_qubits - op.num_qubits)
for op in self.oplist], combo_fn=self.combo_fn, coeff=self.coeff)

def permute(self, permutation: List[int]) -> 'ListOp':
"""Permute the qubits of the operator.
Args:
permutation: A list defining where each qubit should be permuted. The qubit at index
j should be permuted to position permutation[j].
Returns:
A new ListOp representing the permuted operator.
Raises:
AquaError: if indices do not define a new index for each qubit.
"""
new_self = self
Cryoris marked this conversation as resolved.
Show resolved Hide resolved
circuit_size = max(permutation) + 1

try:
if self.num_qubits != len(permutation):
raise AquaError("New index must be defined for each qubit of the operator.")
except ValueError:
raise AquaError("Permute is only possible if all operators in the ListOp have the "
"same number of qubits.") from ValueError
if self.num_qubits < circuit_size:
# pad the operator with identities
new_self = self._expand_dim(circuit_size - self.num_qubits)
qc = QuantumCircuit(circuit_size)
# extend the indices to match the size of the circuit
permutation \
= list(filter(lambda x: x not in permutation, range(circuit_size))) + permutation

# decompose permutation into sequence of transpositions
transpositions = arithmetic.transpositions(permutation)
for trans in transpositions:
qc.swap(trans[0], trans[1])

from qiskit.aqua.operators import CircuitOp

return CircuitOp(qc.reverse_ops()) @ new_self @ CircuitOp(qc)

def compose(self, other: OperatorBase,
permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase:

new_self, other = self._expand_shorter_operator_and_permute(other, permutation)
new_self = cast(ListOp, new_self)

if front:
return other.compose(new_self)
# Avoid circular dependency
# pylint: disable=cyclic-import,import-outside-toplevel
from .composed_op import ComposedOp
return ComposedOp([self, other])
return ComposedOp([new_self, other])

def power(self, exponent: int) -> OperatorBase:
if not isinstance(exponent, int) or exponent <= 0:
Expand Down Expand Up @@ -258,8 +311,8 @@ def to_spmatrix(self) -> Union[spmatrix, List[spmatrix]]:
[op.to_spmatrix() for op in self.oplist]) * self.coeff # type: ignore

def eval(self,
front: Optional[Union[str, Dict[str, complex], 'OperatorBase']] = None
) -> Union['OperatorBase', float, complex, list]:
front: Optional[Union[str, Dict[str, complex], OperatorBase]] = None
) -> Union[OperatorBase, float, complex, list]:
"""
Evaluate the Operator's underlying function, either on a binary string or another Operator.
A square binary Operator can be defined as a function taking a binary function to another
Expand Down
10 changes: 10 additions & 0 deletions qiskit/aqua/operators/list_ops/tensored_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ def num_qubits(self) -> int:
def distributive(self) -> bool:
return False

def _expand_dim(self, num_qubits: int) -> 'TensoredOp':
"""Appends I ^ num_qubits to ``oplist``. Choice of PauliOp as
identity is arbitrary and can be substituted for other PrimitiveOp identity.

Returns:
TensoredOp expanded with identity operator.
"""
from qiskit.aqua.operators import I
return TensoredOp(self.oplist + [I ^ num_qubits], coeff=self.coeff)

def tensor(self, other: OperatorBase) -> OperatorBase:
if isinstance(other, TensoredOp):
return TensoredOp(self.oplist + other.oplist, coeff=self.coeff * other.coeff)
Expand Down
51 changes: 49 additions & 2 deletions qiskit/aqua/operators/operator_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

""" OperatorBase Class """

from typing import Set, Union, Dict, Optional, List, cast
from typing import Set, Union, Dict, Optional, List, cast, Tuple
from numbers import Number
from abc import ABC, abstractmethod
import numpy as np
Expand Down Expand Up @@ -452,6 +452,32 @@ def assign_parameters(self,
"""
raise NotImplementedError

@abstractmethod
def _expand_dim(self, num_qubits: int) -> 'OperatorBase':
"""Expands the operator with identity operator of dimension 2**num_qubits.
Returns:
Operator corresponding to self.tensor(identity_operator), where dimension of identity
operator is 2 ** num_qubits.
"""
raise NotImplementedError

@abstractmethod
def permute(self, permutation: List[int]) -> 'OperatorBase':
"""Permutes the qubits of the operator.
Args:
permutation: A list defining where each qubit should be permuted. The qubit at index
j should be permuted to position permutation[j].
Returns:
A new OperatorBase containing the permuted operator.
Raises:
AquaError: if indices do not define a new index for each qubit.
"""
raise NotImplementedError

def bind_parameters(self,
param_dict: Dict[ParameterExpression,
Union[Number,
Expand Down Expand Up @@ -501,6 +527,24 @@ def _get_param_dict_for_index(unrolled_dict: Dict[ParameterExpression, List[Numb
""" Gets a single non-list-nested param_dict for a given list index from a nested one. """
return {k: v[i] for (k, v) in unrolled_dict.items()}

def _expand_shorter_operator_and_permute(self, other: 'OperatorBase',
permutation: Optional[List[int]] = None) \
-> Tuple['OperatorBase', 'OperatorBase']:
if permutation is not None:
other = other.permute(permutation)
new_self = self
molar-volume marked this conversation as resolved.
Show resolved Hide resolved
if not self.num_qubits == other.num_qubits:
# pylint: disable=cyclic-import,import-outside-toplevel
from .operator_globals import Zero
if other == Zero:
# Zero is special - we'll expand it to the correct qubit number.
other = Zero.__class__('0' * self.num_qubits)
elif other.num_qubits < self.num_qubits:
other = other._expand_dim(self.num_qubits - other.num_qubits)
elif other.num_qubits > self.num_qubits:
new_self = self._expand_dim(other.num_qubits - self.num_qubits)
return new_self, other

# Composition

def __matmul__(self, other: 'OperatorBase') -> 'OperatorBase':
Expand All @@ -515,7 +559,8 @@ def __matmul__(self, other: 'OperatorBase') -> 'OperatorBase':
return self.compose(other)

@abstractmethod
def compose(self, other: 'OperatorBase') -> 'OperatorBase':
def compose(self, other: 'OperatorBase',
permutation: Optional[List[int]] = None, front: bool = False) -> 'OperatorBase':
r""" Return Operator Composition between self and other (linear algebra-style:
A@B(x) = A(B(x))), overloaded by ``@``.
Expand All @@ -529,6 +574,8 @@ def compose(self, other: 'OperatorBase') -> 'OperatorBase':
Args:
other: The ``OperatorBase`` with which to compose self.
permutation: ``List[int]`` which defines permutation on other operator.
front: If front==True, return ``other.compose(self)``.
Returns:
An ``OperatorBase`` equivalent to the function composition of self and other.
Expand Down
28 changes: 19 additions & 9 deletions qiskit/aqua/operators/primitive_ops/circuit_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,30 +108,37 @@ def tensor(self, other: OperatorBase) -> OperatorBase:

return TensoredOp([self, other])

def compose(self, other: OperatorBase) -> OperatorBase:
other = self._check_zero_for_composition_and_expand(other)
def compose(self, other: OperatorBase,
permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase:

new_self, other = self._expand_shorter_operator_and_permute(other, permutation)
new_self = cast(CircuitOp, new_self)

if front:
return other.compose(new_self)
# ignore
# pylint: disable=cyclic-import,import-outside-toplevel
from ..operator_globals import Zero
from ..state_fns import CircuitStateFn
from .pauli_op import PauliOp
from .matrix_op import MatrixOp

if other == Zero ^ self.num_qubits:
return CircuitStateFn(self.primitive, coeff=self.coeff)
if other == Zero ^ new_self.num_qubits:
return CircuitStateFn(new_self.primitive, coeff=new_self.coeff)

if isinstance(other, (PauliOp, CircuitOp, MatrixOp)):
other = other.to_circuit_op()

if isinstance(other, (CircuitOp, CircuitStateFn)):
new_qc = other.primitive.compose(self.primitive) # type: ignore
new_qc = other.primitive.compose(new_self.primitive) # type: ignore
if isinstance(other, CircuitStateFn):
return CircuitStateFn(new_qc,
is_measurement=other.is_measurement,
coeff=self.coeff * other.coeff)
coeff=new_self.coeff * other.coeff)
else:
return CircuitOp(new_qc, coeff=self.coeff * other.coeff)
return CircuitOp(new_qc, coeff=new_self.coeff * other.coeff)

return super().compose(other)
return super(CircuitOp, new_self).compose(other)

def to_matrix(self, massive: bool = False) -> np.ndarray:
if self.num_qubits > 16 and not massive:
Expand Down Expand Up @@ -219,6 +226,9 @@ def reduce(self) -> OperatorBase:
del self.primitive.data[i] # type: ignore
return self

def _expand_dim(self, num_qubits: int) -> 'CircuitOp':
return self.permute(list(range(num_qubits, num_qubits + self.num_qubits)))

def permute(self, permutation: List[int]) -> 'CircuitOp':
r"""
Permute the qubits of the circuit.
Expand All @@ -230,5 +240,5 @@ def permute(self, permutation: List[int]) -> 'CircuitOp':
Returns:
A new CircuitOp containing the permuted circuit.
"""
new_qc = QuantumCircuit(self.num_qubits).compose(self.primitive, qubits=permutation)
new_qc = QuantumCircuit(max(permutation) + 1).compose(self.primitive, qubits=permutation)
return CircuitOp(new_qc, coeff=self.coeff)
Loading